зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1539462 - Remove WebIDE r=ochameau,jryans,janerik,fluent-reviewers,flod
Per deprecation roadmap on https://developer.mozilla.org/en-US/docs/Tools/Deprecated_tools#WebIDE_and_Connect_page Differential Revision: https://phabricator.services.mozilla.com/D46703 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
3055031260
Коммит
5c1a679523
|
@ -1935,8 +1935,7 @@ pref("identity.fxaccounts.service.monitorLoginUrl", "https://monitor.firefox.com
|
|||
pref("corroborator.enabled", true);
|
||||
#endif
|
||||
|
||||
// Disable WebIDE and ConnectPage by default (Bug 1539451)
|
||||
pref("devtools.webide.enabled", false);
|
||||
// Disable ConnectPage by default (Bug 1539451)
|
||||
pref("devtools.connectpage.enabled", false);
|
||||
|
||||
// Toolbox preferences
|
||||
|
@ -2361,15 +2360,5 @@ pref("devtools.popup.disable_autohide", false);
|
|||
// should be removed.
|
||||
pref("devtools.toolbox.content-frame", true);
|
||||
|
||||
pref("devtools.webide.templatesURL", "https://code.cdn.mozilla.net/templates/list.json");
|
||||
pref("devtools.webide.autoinstallADBExtension", true);
|
||||
pref("devtools.webide.autoConnectRuntime", true);
|
||||
pref("devtools.webide.restoreLastProject", true);
|
||||
pref("devtools.webide.enableLocalRuntime", false);
|
||||
pref("devtools.webide.lastConnectedRuntime", "");
|
||||
pref("devtools.webide.lastSelectedProject", "");
|
||||
pref("devtools.webide.zoom", "1");
|
||||
pref("devtools.webide.busyTimeout", 10000);
|
||||
|
||||
// FirstStartup service time-out in ms
|
||||
pref("first-startup.timeout", 30000);
|
||||
|
|
|
@ -815,7 +815,6 @@ add_task(async function checkAllTheFiles() {
|
|||
// Keep only chrome:// files, and filter out either the devtools paths or
|
||||
// the non-devtools paths:
|
||||
let devtoolsPrefixes = [
|
||||
"chrome://webide/",
|
||||
"chrome://devtools",
|
||||
"resource://devtools/",
|
||||
"resource://devtools-client-jsonview/",
|
||||
|
|
|
@ -74,18 +74,6 @@ let whitelist = [
|
|||
errorMessage: /Property contained reference to invalid variable.*color/i,
|
||||
isFromDevTools: true,
|
||||
},
|
||||
{
|
||||
sourceName: /webide\/skin\/logs\.css$/i,
|
||||
intermittent: true,
|
||||
errorMessage: /Property contained reference to invalid variable.*color/i,
|
||||
isFromDevTools: true,
|
||||
},
|
||||
{
|
||||
sourceName: /webide\/skin\/logs\.css$/i,
|
||||
intermittent: true,
|
||||
errorMessage: /Property contained reference to invalid variable.*background/i,
|
||||
isFromDevTools: true,
|
||||
},
|
||||
];
|
||||
|
||||
if (
|
||||
|
@ -429,7 +417,7 @@ add_task(async function checkAllTheCSS() {
|
|||
|
||||
// filter out either the devtools paths or the non-devtools paths:
|
||||
let isDevtools = SimpleTest.harnessParameters.subsuite == "devtools";
|
||||
let devtoolsPathBits = ["webide", "devtools"];
|
||||
let devtoolsPathBits = ["devtools"];
|
||||
uris = uris.filter(
|
||||
uri => isDevtools == devtoolsPathBits.some(path => uri.spec.includes(path))
|
||||
);
|
||||
|
|
|
@ -122,7 +122,6 @@ if (typeof Mozilla == "undefined") {
|
|||
* <li>searchPrefsLink
|
||||
* <li>selectedTabIcon
|
||||
* <li>urlbar
|
||||
* <li>webide
|
||||
* </ul>
|
||||
*
|
||||
* Generate using the following in the Browser Console:
|
||||
|
|
|
@ -258,10 +258,6 @@
|
|||
#endif
|
||||
@RESPATH@/browser/features/*
|
||||
|
||||
; [Webide Files]
|
||||
@RESPATH@/browser/chrome/webide@JAREXT@
|
||||
@RESPATH@/browser/chrome/webide.manifest
|
||||
|
||||
; [DevTools Startup Files]
|
||||
@RESPATH@/browser/chrome/devtools-startup@JAREXT@
|
||||
@RESPATH@/browser/chrome/devtools-startup.manifest
|
||||
|
|
|
@ -35,7 +35,6 @@ module.exports = {
|
|||
"client/scratchpad/**",
|
||||
"client/shared/*.jsm",
|
||||
"client/shared/widgets/*.jsm",
|
||||
"client/webide/**",
|
||||
],
|
||||
"rules": {
|
||||
"consistent-return": "off",
|
||||
|
@ -44,7 +43,6 @@ module.exports = {
|
|||
"files": [
|
||||
"client/framework/**",
|
||||
"client/scratchpad/**",
|
||||
"client/webide/**",
|
||||
],
|
||||
"rules": {
|
||||
"max-nested-callbacks": "off",
|
||||
|
@ -63,7 +61,6 @@ module.exports = {
|
|||
"client/scratchpad/**",
|
||||
"client/shared/*.jsm",
|
||||
"client/shared/widgets/*.jsm",
|
||||
"client/webide/**",
|
||||
],
|
||||
"rules": {
|
||||
"mozilla/no-aArgs": "off",
|
||||
|
@ -81,7 +78,6 @@ module.exports = {
|
|||
"client/framework/**",
|
||||
"client/scratchpad/**",
|
||||
"client/shared/widgets/*.jsm",
|
||||
"client/webide/**",
|
||||
],
|
||||
"rules": {
|
||||
"no-shadow": "off",
|
||||
|
@ -90,7 +86,6 @@ module.exports = {
|
|||
"files": [
|
||||
"client/framework/**",
|
||||
"client/scratchpad/**",
|
||||
"client/webide/**",
|
||||
],
|
||||
"rules": {
|
||||
"strict": "off",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# about:debugging-new
|
||||
|
||||
## What is about:debugging-new
|
||||
The purpose of about:debugging is to be a debugging hub to start inspecting your addons, processes, tabs and workers. This new version of about:debugging will also allow you to debug remote devices (Firefox for Android on a smartphone). The user should be able to connect either via USB or WiFi. This solution is supposed to replace the various existing remote debugging solutions available in Firefox DevTools, WebIDE and the Connect page.
|
||||
The purpose of about:debugging is to be a debugging hub to start inspecting your addons, processes, tabs and workers. This new version of about:debugging will also allow you to debug remote devices (Firefox for Android on a smartphone). The user should be able to connect either via USB or WiFi.
|
||||
|
||||
To try out about:debugging, type `about:debugging` in the Firefox URL bar.
|
||||
|
||||
|
|
|
@ -294,8 +294,8 @@ function switchPerformancePanel() {
|
|||
// the perf actor yet. Also this function is not async, so we can't initialize
|
||||
// the actor yet.
|
||||
// We don't display the new performance panel for remote context in the
|
||||
// toolbox, because this has an overhead. Instead we should use WebIDE (or
|
||||
// the coming about:debugging).
|
||||
// toolbox, because this has an overhead. Instead we should use
|
||||
// about:debugging.
|
||||
return target.isLocalTab;
|
||||
};
|
||||
} else {
|
||||
|
|
|
@ -81,7 +81,7 @@ class ToolboxToolbar extends Component {
|
|||
// |hostTypes| but this is not always the case (e.g. when it is "custom").
|
||||
currentHostType: PropTypes.string,
|
||||
// Are docking options enabled? They are not enabled in certain situations
|
||||
// like when they are in the WebIDE.
|
||||
// like when the toolbox is opened in a tab.
|
||||
areDockOptionsEnabled: PropTypes.bool,
|
||||
// Do we need to add UI for closing the toolbox? We don't when the
|
||||
// toolbox is undocked, for example.
|
||||
|
@ -352,8 +352,8 @@ class ToolboxToolbar extends Component {
|
|||
* @param {string} props.currentHostType
|
||||
* The current docking configuration.
|
||||
* @param {boolean} props.areDockOptionsEnabled
|
||||
* They are not enabled in certain situations like when they are in the
|
||||
* WebIDE.
|
||||
* They are not enabled in certain situations like when the toolbox is
|
||||
* in a tab.
|
||||
* @param {boolean} props.canCloseToolbox
|
||||
* Do we need to add UI for closing the toolbox? We don't when the
|
||||
* toolbox is undocked, for example.
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const defer = require("devtools/shared/defer");
|
||||
const { gDevTools } = require("./devtools");
|
||||
|
||||
// Load target and toolbox lazily as they need gDevTools to be fully initialized
|
||||
|
@ -139,10 +138,6 @@ var gDevToolsBrowser = (exports.gDevToolsBrowser = {
|
|||
}
|
||||
}
|
||||
|
||||
// Enable WebIDE?
|
||||
const webIDEEnabled = Services.prefs.getBoolPref("devtools.webide.enabled");
|
||||
toggleMenuItem("menu_webide", webIDEEnabled);
|
||||
|
||||
// Enable Browser Toolbox?
|
||||
const chromeEnabled = Services.prefs.getBoolPref("devtools.chrome.enabled");
|
||||
const devtoolsRemoteEnabled = Services.prefs.getBoolPref(
|
||||
|
@ -359,9 +354,6 @@ var gDevToolsBrowser = (exports.gDevToolsBrowser = {
|
|||
case "toggleToolboxF12":
|
||||
await gDevToolsBrowser.toggleToolboxCommand(window.gBrowser, startTime);
|
||||
break;
|
||||
case "webide":
|
||||
gDevToolsBrowser.openWebIDE();
|
||||
break;
|
||||
case "browserToolbox":
|
||||
BrowserToolboxProcess.init();
|
||||
break;
|
||||
|
@ -401,26 +393,6 @@ var gDevToolsBrowser = (exports.gDevToolsBrowser = {
|
|||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Open WebIDE
|
||||
*/
|
||||
// Used by browser-sets.inc, command
|
||||
// itself, webide widget
|
||||
openWebIDE() {
|
||||
const win = Services.wm.getMostRecentWindow("devtools:webide");
|
||||
if (win) {
|
||||
win.focus();
|
||||
} else {
|
||||
Services.ww.openWindow(
|
||||
null,
|
||||
"chrome://webide/content/",
|
||||
"webide",
|
||||
"chrome,centerscreen,resizable",
|
||||
null
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async _getContentProcessTarget(processId) {
|
||||
// Create a DebuggerServer in order to connect locally to it
|
||||
DebuggerServer.init();
|
||||
|
@ -514,11 +486,6 @@ var gDevToolsBrowser = (exports.gDevToolsBrowser = {
|
|||
return loadPromise;
|
||||
},
|
||||
|
||||
/**
|
||||
* The deferred promise will be resolved by WebIDE's UI.init()
|
||||
*/
|
||||
isWebIDEInitialized: defer(),
|
||||
|
||||
/**
|
||||
* Add this DevTools's presence to a browser window's document
|
||||
*
|
||||
|
|
|
@ -28,9 +28,9 @@ requestLongerTimeout(2);
|
|||
* client is destroyed when the toolbox is closed, which removes the client
|
||||
* actor pools, and avoids this issue.
|
||||
*
|
||||
* In WebIDE, we do not destroy the DebuggerClient on toolbox close because it
|
||||
* is still used for other purposes like managing apps, etc. that aren't part of
|
||||
* a toolbox. Thus, the same client gets reused across multiple toolboxes,
|
||||
* In remote debugging, we do not destroy the DebuggerClient on toolbox close
|
||||
* because it can still used for other targets.
|
||||
* Thus, the same client gets reused across multiple toolboxes,
|
||||
* which leads to the tools failing if they don't destroy their fronts.
|
||||
*/
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ about-debugging-runtime-profile-button2 = Profile performance
|
|||
about-debugging-runtime-service-workers-not-compatible = Your browser configuration is not compatible with Service Workers. <a>Learn more</a>
|
||||
|
||||
# This string is displayed in the runtime page if the remote browser version is too old.
|
||||
# "Troubleshooting" link points to https://developer.mozilla.org/docs/Tools/WebIDE/Troubleshooting
|
||||
# "Troubleshooting" link points to https://developer.mozilla.org/docs/Tools/about:debugging#Troubleshooting
|
||||
# { $runtimeVersion } is the version of the remote browser (for instance "67.0a1")
|
||||
# { $minVersion } is the minimum version that is compatible with the current Firefox instance (same format)
|
||||
about-debugging-browser-version-too-old = The connected browser has an old version ({ $runtimeVersion }). The minimum supported version is ({ $minVersion }). This is an unsupported setup and may cause DevTools to fail. Please update the connected browser. <a>Troubleshooting</a>
|
||||
|
@ -229,7 +229,7 @@ about-debugging-browser-version-too-old = The connected browser has an old versi
|
|||
about-debugging-browser-version-too-old-67-debugger = The Debugger panel may not work with the connected browser. Please use Firefox { $runtimeVersion } if you need to use the Debugger with this browser.
|
||||
|
||||
# This string is displayed in the runtime page if the remote browser version is too recent.
|
||||
# "Troubleshooting" link points to https://developer.mozilla.org/en-US/docs/Tools/WebIDE/Troubleshooting
|
||||
# "Troubleshooting" link points to https://developer.mozilla.org/docs/Tools/about:debugging#Troubleshooting
|
||||
# { $runtimeID } is the build ID of the remote browser (for instance "20181231", format is yyyyMMdd)
|
||||
# { $localID } is the build ID of the current Firefox instance (same format)
|
||||
# { $runtimeVersion } is the version of the remote browser (for instance "67.0a1")
|
||||
|
|
|
@ -1,29 +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/.
|
||||
|
||||
validator.nonExistingFolder=The project folder doesn’t exist
|
||||
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.
|
||||
validator.invalidManifestURL=Invalid manifest URL ‘%S’
|
||||
# LOCALIZATION NOTE (validator.invalidManifestJSON, validator.noAccessManifestURL):
|
||||
# %1$S is the error message, %2$S is the URI of the manifest.
|
||||
validator.invalidManifestJSON=The webapp manifest isn’t a valid JSON file: %1$S at: %2$S
|
||||
validator.noAccessManifestURL=Unable to read manifest file: %1$S at: %2$S
|
||||
# LOCALIZATION NOTE (validator.invalidHostedManifestURL): %1$S is the URI of
|
||||
# the manifest, %2$S is the error message.
|
||||
validator.invalidHostedManifestURL=Invalid hosted manifest URL ‘%1$S’: %2$S
|
||||
validator.invalidProjectType=Unknown project type ‘%S’
|
||||
# LOCALIZATION NOTE (validator.missNameManifestProperty, validator.missIconsManifestProperty):
|
||||
# don't translate 'icons' and 'name'.
|
||||
validator.missNameManifestProperty=Missing mandatory ‘name’ in Manifest.
|
||||
validator.missIconsManifestProperty=Missing ‘icons’ in Manifest.
|
||||
validator.missIconMarketplace2=app submission to the Marketplace requires a 128px icon
|
||||
validator.invalidAppType=Unknown app type: ‘%S’.
|
||||
validator.invalidHostedPriviledges=Hosted App can’t be type ‘%S’.
|
||||
validator.noCertifiedSupport=‘certified’ apps are not fully supported on the App manager.
|
||||
validator.nonAbsoluteLaunchPath=Launch path has to be an absolute path starting with ‘/’: ‘%S’
|
||||
validator.accessFailedLaunchPath=Unable to access the app starting document ‘%S’
|
||||
# LOCALIZATION NOTE (validator.accessFailedLaunchPathBadHttpCode): %1$S is the URI of
|
||||
# the launch document, %2$S is the http error code.
|
||||
validator.accessFailedLaunchPathBadHttpCode=Unable to access the app starting document ‘%1$S’, got HTTP code %2$S
|
|
@ -49,9 +49,6 @@ browserContentToolboxMenu.accesskey = x
|
|||
toggleProfilerButtonMenu.label = Enable Profiler Toolbar Icon
|
||||
toggleProfilerButtonMenu.accesskey = P
|
||||
|
||||
webide.label = WebIDE
|
||||
webide.accesskey = W
|
||||
|
||||
devtoolsWebReplay.label = Web Replay
|
||||
devtoolsRecordNewTab.label = Open New Recording Tab
|
||||
devtoolsReloadAndRecordTab.label = Reload and Record Tab
|
||||
|
|
|
@ -1,153 +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 windowTitle "Firefox WebIDE">
|
||||
|
||||
<!ENTITY projectMenu_label "Project">
|
||||
<!ENTITY projectMenu_accesskey "P">
|
||||
<!ENTITY projectMenu_newApp_label "New App…">
|
||||
<!ENTITY projectMenu_newApp_accesskey "N">
|
||||
<!ENTITY projectMenu_importPackagedApp_label "Open Packaged App…">
|
||||
<!ENTITY projectMenu_importPackagedApp_accesskey "P">
|
||||
<!ENTITY projectMenu_importHostedApp_label "Open Hosted App…">
|
||||
<!ENTITY projectMenu_importHostedApp_accesskey "H">
|
||||
<!ENTITY projectMenu_selectApp_label "Open App…">
|
||||
<!ENTITY projectMenu_selectApp_accesskey "O">
|
||||
<!ENTITY projectMenu_play_label "Install and Run">
|
||||
<!ENTITY projectMenu_play_accesskey "I">
|
||||
<!ENTITY projectMenu_stop_label "Stop App">
|
||||
<!ENTITY projectMenu_stop_accesskey "S">
|
||||
<!ENTITY projectMenu_debug_label "Debug App">
|
||||
<!ENTITY projectMenu_debug_accesskey "D">
|
||||
<!ENTITY projectMenu_remove_label "Remove Project">
|
||||
<!ENTITY projectMenu_remove_accesskey "R">
|
||||
<!ENTITY projectMenu_showPrefs_label "Preferences">
|
||||
<!ENTITY projectMenu_showPrefs_accesskey "e">
|
||||
<!ENTITY projectMenu_manageComponents_label "Manage Extra Components">
|
||||
<!ENTITY projectMenu_manageComponents_accesskey "M">
|
||||
<!ENTITY projectMenu_refreshTabs_label "Refresh Tabs">
|
||||
|
||||
<!ENTITY runtimeMenu_label "Runtime">
|
||||
<!ENTITY runtimeMenu_accesskey "R">
|
||||
<!ENTITY runtimeMenu_disconnect_label "Disconnect">
|
||||
<!ENTITY runtimeMenu_disconnect_accesskey "D">
|
||||
<!ENTITY runtimeMenu_takeScreenshot_label "Screenshot">
|
||||
<!ENTITY runtimeMenu_takeScreenshot_accesskey "S">
|
||||
<!ENTITY runtimeMenu_showDetails_label "Runtime Info">
|
||||
<!ENTITY runtimeMenu_showDetails_accesskey "E">
|
||||
<!ENTITY runtimeMenu_showDevicePrefs_label "Device Preferences">
|
||||
<!ENTITY runtimeMenu_showDevicePrefs_accesskey "D">
|
||||
<!ENTITY runtimeMenu_showSettings_label "Device Settings">
|
||||
<!ENTITY runtimeMenu_showSettings_accesskey "s">
|
||||
<!ENTITY runtimeMenu_showPerformancePanel_label "Performance">
|
||||
<!ENTITY runtimeMenu_showPerformancePanel_accesskey "p">
|
||||
|
||||
<!ENTITY viewMenu_label "View">
|
||||
<!ENTITY viewMenu_accesskey "V">
|
||||
<!ENTITY viewMenu_zoomin_label "Zoom In">
|
||||
<!ENTITY viewMenu_zoomin_accesskey "I">
|
||||
<!ENTITY viewMenu_zoomout_label "Zoom Out">
|
||||
<!ENTITY viewMenu_zoomout_accesskey "O">
|
||||
<!ENTITY viewMenu_resetzoom_label "Reset Zoom">
|
||||
<!ENTITY viewMenu_resetzoom_accesskey "R">
|
||||
|
||||
<!ENTITY runtimeButton_label "Select Runtime">
|
||||
|
||||
<!-- We try to repicate Firefox' bindings: -->
|
||||
<!-- quit app -->
|
||||
<!ENTITY key_quit "W">
|
||||
<!-- open menu -->
|
||||
<!ENTITY key_showProjectPanel "O">
|
||||
<!-- reload app -->
|
||||
<!ENTITY key_play "R">
|
||||
<!-- show toolbox -->
|
||||
<!ENTITY key_toggleToolbox "VK_F12">
|
||||
<!-- zoom -->
|
||||
<!ENTITY key_zoomin "+">
|
||||
<!ENTITY key_zoomin2 "=">
|
||||
<!ENTITY key_zoomout "-">
|
||||
<!ENTITY key_resetzoom "0">
|
||||
|
||||
<!ENTITY projectPanel_myProjects "My Projects">
|
||||
<!ENTITY projectPanel_runtimeApps "Runtime Apps">
|
||||
<!ENTITY projectPanel_tabs "Tabs">
|
||||
<!ENTITY runtimePanel_usb "USB Devices">
|
||||
<!ENTITY runtimePanel_wifi "Wi-Fi Devices">
|
||||
<!ENTITY runtimePanel_other "Other">
|
||||
<!ENTITY runtimePanel_nousbdevice "Can’t see your device?">
|
||||
<!ENTITY runtimePanel_refreshDevices_label "Refresh Devices">
|
||||
|
||||
<!-- Lense -->
|
||||
<!ENTITY details_valid_header "valid">
|
||||
<!ENTITY details_warning_header "warnings">
|
||||
<!ENTITY details_error_header "errors">
|
||||
<!ENTITY details_description "Description">
|
||||
<!ENTITY details_location "Location">
|
||||
<!ENTITY details_manifestURL "App ID">
|
||||
<!ENTITY details_removeProject_button "Remove Project">
|
||||
|
||||
<!-- New App -->
|
||||
<!ENTITY newAppWindowTitle "New App">
|
||||
<!ENTITY newAppHeader "Select template">
|
||||
<!ENTITY newAppLoadingTemplate "Loading templates…">
|
||||
<!ENTITY newAppProjectName "Project Name:">
|
||||
|
||||
|
||||
<!-- Decks -->
|
||||
|
||||
<!ENTITY deck_close "Close">
|
||||
|
||||
<!-- Addons -->
|
||||
<!ENTITY addons_title "Extra Components">
|
||||
<!ENTITY addons_aboutaddons "Open Add-ons Manager">
|
||||
|
||||
<!-- Prefs -->
|
||||
<!ENTITY prefs_title "Preferences">
|
||||
<!ENTITY prefs_general_title "General">
|
||||
<!ENTITY prefs_restore "Restore Defaults">
|
||||
<!ENTITY prefs_manage_components "Manage Extra Components">
|
||||
<!ENTITY prefs_options_autoconnectruntime "Reconnect to previous runtime">
|
||||
<!ENTITY prefs_options_autoconnectruntime_tooltip "Reconnect to previous runtime when WebIDE starts">
|
||||
<!ENTITY prefs_options_rememberlastproject "Remember last project">
|
||||
<!ENTITY prefs_options_rememberlastproject_tooltip "Restore previous project when WebIDE starts">
|
||||
<!ENTITY prefs_options_templatesurl "Templates URL">
|
||||
<!ENTITY prefs_options_templatesurl_tooltip "Index of available templates">
|
||||
|
||||
<!-- Runtime Details -->
|
||||
<!ENTITY runtimedetails_title "Runtime Info">
|
||||
|
||||
<!-- Device Preferences and Settings -->
|
||||
<!ENTITY device_typeboolean "Boolean">
|
||||
<!ENTITY device_typenumber "Integer">
|
||||
<!ENTITY device_typestring "String">
|
||||
<!ENTITY device_typenone "Select a type">
|
||||
|
||||
<!-- Device Preferences -->
|
||||
<!ENTITY devicepreference_title "Device Preferences">
|
||||
<!ENTITY devicepreference_search "Search preferences">
|
||||
<!ENTITY devicepreference_newname "New preference name">
|
||||
<!ENTITY devicepreference_newtext "Preference value">
|
||||
<!ENTITY devicepreference_addnew "Add new preference">
|
||||
|
||||
<!-- WiFi Authentication -->
|
||||
<!-- LOCALIZATION NOTE (wifi_auth_header): The header displayed on the dialog
|
||||
that instructs the user to transfer an authentication token to the
|
||||
server. -->
|
||||
<!ENTITY wifi_auth_header "Client Identification">
|
||||
<!-- LOCALIZATION NOTE (wifi_auth_scan_request): Instructions requesting the
|
||||
user to transfer authentication info by scanning a QR code. -->
|
||||
<!ENTITY wifi_auth_scan_request "The endpoint you are connecting to needs more information to authenticate this connection. Please scan the QR code below via the prompt on your other device.">
|
||||
<!-- LOCALIZATION NOTE (wifi_auth_no_scanner): Link text to assist users with
|
||||
devices that can't scan a QR code. -->
|
||||
<!ENTITY wifi_auth_no_scanner "No QR scanner prompt?">
|
||||
<!-- LOCALIZATION NOTE (wifi_auth_yes_scanner): Link text to assist users with
|
||||
devices that can scan a QR code. -->
|
||||
<!ENTITY wifi_auth_yes_scanner "Have a QR scanner prompt?">
|
||||
<!-- LOCALIZATION NOTE (wifi_auth_token_request): Instructions requesting the
|
||||
user to transfer authentication info by transferring a token. -->
|
||||
<!ENTITY wifi_auth_token_request "If your other device asks for a token instead of scanning a QR code, please copy the value below to the other device:">
|
||||
<!ENTITY wifi_auth_qr_size_note "If the QR code appears too small for the connection to be successfully established, try zooming or enlarging the window.">
|
||||
|
||||
<!-- Logs panel -->
|
||||
<!ENTITY logs_title "Pre-packaging Command Logs">
|
|
@ -1,85 +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/.
|
||||
|
||||
title_noApp=Firefox WebIDE
|
||||
title_app=Firefox WebIDE: %S
|
||||
|
||||
runtimeButton_label=Select Runtime
|
||||
|
||||
mainProcess_label=Main Process
|
||||
|
||||
local_runtime=Local Runtime
|
||||
remote_runtime=Remote Runtime
|
||||
remote_runtime_promptTitle=Remote Runtime
|
||||
remote_runtime_promptMessage=hostname:port
|
||||
|
||||
importPackagedApp_title=Select Directory
|
||||
importHostedApp_title=Open Hosted App
|
||||
importHostedApp_header=Enter Manifest URL
|
||||
|
||||
selectCustomBinary_title=Select custom B2G binary
|
||||
selectCustomProfile_title=Select custom Gaia profile
|
||||
|
||||
notification_showTroubleShooting_label=Troubleshooting
|
||||
notification_showTroubleShooting_accesskey=T
|
||||
|
||||
# LOCALIZATION NOTE (project_tab_loading): This is shown as a temporary tab
|
||||
# title for browser tab projects when the tab is still loading.
|
||||
project_tab_loading=Loading…
|
||||
|
||||
# These messages appear in a notification box when an error occur.
|
||||
|
||||
error_cantInstallNotFullyConnected=Can’t install project. Not fully connected.
|
||||
error_cantInstallValidationErrors=Can’t install project. Validation errors.
|
||||
|
||||
# Variable: name of the operation (in english)
|
||||
error_operationTimeout=Operation timed out: %1$S
|
||||
error_operationFail=Operation failed: %1$S
|
||||
|
||||
# Variable: app name
|
||||
error_cantConnectToApp=Can’t connect to app: %1$S
|
||||
|
||||
error_appProjectsLoadFailed=Unable to load project list. This can occur if you’ve used this profile with a newer version of Firefox.
|
||||
error_folderCreationFailed=Unable to create project folder in the selected directory.
|
||||
|
||||
# Variable: runtime app build ID (looks like this %Y%M%D format) and firefox build ID (same format)
|
||||
error_runtimeVersionTooRecent=The connected runtime has a more recent build date (%1$S) than your desktop Firefox (%2$S) does. This is an unsupported setup and may cause DevTools to fail. Please update Firefox.
|
||||
|
||||
# Variable: runtime app version (looks like this 52.a3) and firefox version (same format)
|
||||
error_runtimeVersionTooOld=The connected runtime has an old version (%1$S). The minimum supported version is (%2$S). This is an unsupported setup and may cause DevTools to fail. Please update the connected runtime.
|
||||
|
||||
# LOCALIZATION NOTE (error_runtimeVersionTooOld67Debugger): Dedicated message
|
||||
# for a backward compatibility issue that occurs when connecting:
|
||||
# - from Fx 67 to 66 or to 65
|
||||
# - from Fx 68 to 66
|
||||
# Those are normally in range for DevTools compatibility policy, but specific non
|
||||
# backward compatible changes broke the debugger in those scenarios (Bug 1528219).
|
||||
# Variable: runtime app version (looks like this 52.a3)
|
||||
error_runtimeVersionTooOld67Debugger=The Debugger panel may not work with the connected runtime. Please use Firefox %S if you need to use the Debugger with this runtime.
|
||||
|
||||
# LOCALIZATION NOTE (error_webIDEDeprecated2): Text for the deprecation message displayed when starting WebIDE.
|
||||
error_webIDEDeprecated2=WebIDE will be disabled in an upcoming release. Remote debugging is now available in about:debugging.
|
||||
|
||||
# LOCALIZATION NOTE (notification_openAboutDebugging): Text for a button displayed in the deprecation message for WebIDE.
|
||||
# Clicking on the button will open a tab on about:debugging.
|
||||
notification_openAboutDebugging.label=Open about:debugging
|
||||
notification_openAboutDebugging.accesskey=O
|
||||
|
||||
addons_install_button=install
|
||||
addons_uninstall_button=uninstall
|
||||
addons_adb_warning=USB devices won’t be detected without this add-on
|
||||
addons_status_unknown=?
|
||||
addons_status_installed=Installed
|
||||
addons_status_uninstalled=Not Installed
|
||||
addons_status_preparing=preparing
|
||||
addons_status_downloading=downloading
|
||||
addons_status_installing=installing
|
||||
|
||||
# LOCALIZATION NOTE (runtimePanel_noadbextension): Displayed in the WebIDE right sidebar
|
||||
# when the ADB Extension is not installed, %S will be replaced with the name of extension
|
||||
# ("ADB Extension").
|
||||
runtimePanel_noadbextension=Install %S
|
||||
|
||||
# Device preferences and settings
|
||||
device_reset_default=Reset to default
|
|
@ -96,14 +96,6 @@ exports.menuitems = [
|
|||
gDevToolsBrowser.openAboutDebugging(window.gBrowser);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "menu_webide",
|
||||
l10nKey: "webide",
|
||||
oncommand() {
|
||||
gDevToolsBrowser.openWebIDE();
|
||||
},
|
||||
keyId: "webide",
|
||||
},
|
||||
{
|
||||
id: "menu_browserToolbox",
|
||||
l10nKey: "browserToolboxMenu",
|
||||
|
|
|
@ -28,7 +28,6 @@ DIRS += [
|
|||
'styleeditor',
|
||||
'themes',
|
||||
'webconsole',
|
||||
'webide',
|
||||
'webreplay',
|
||||
]
|
||||
|
||||
|
|
|
@ -753,7 +753,6 @@ function getChartsFromToolId(id) {
|
|||
case "STYLEEDITOR":
|
||||
case "TOOLBOX":
|
||||
case "WEBCONSOLE":
|
||||
case "WEBIDE":
|
||||
timerHist = `DEVTOOLS_${id}_TIME_ACTIVE_SECONDS`;
|
||||
countHist = `DEVTOOLS_${id}_OPENED_COUNT`;
|
||||
break;
|
||||
|
|
|
@ -1,122 +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 { loader, require } = ChromeUtils.import(
|
||||
"resource://devtools/shared/Loader.jsm"
|
||||
);
|
||||
|
||||
const Services = require("Services");
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/webide.properties"
|
||||
);
|
||||
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"adbAddon",
|
||||
"devtools/shared/adb/adb-addon",
|
||||
true
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
document.querySelector("#aboutaddons").onclick = function() {
|
||||
const browserWin = Services.wm.getMostRecentWindow(
|
||||
gDevTools.chromeWindowType
|
||||
);
|
||||
if (browserWin && browserWin.BrowserOpenAddonsMgr) {
|
||||
browserWin.BrowserOpenAddonsMgr("addons://list/extension");
|
||||
}
|
||||
};
|
||||
document.querySelector("#close").onclick = CloseUI;
|
||||
BuildUI();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
function CloseUI() {
|
||||
window.parent.UI.openProject();
|
||||
}
|
||||
|
||||
function BuildUI() {
|
||||
function onAddonUpdate(arg) {
|
||||
progress.removeAttribute("value");
|
||||
li.setAttribute("status", adbAddon.status);
|
||||
status.textContent = Strings.GetStringFromName(
|
||||
"addons_status_" + adbAddon.status
|
||||
);
|
||||
}
|
||||
|
||||
function onAddonFailure(arg) {
|
||||
window.parent.UI.reportError("error_operationFail", arg);
|
||||
}
|
||||
|
||||
function onAddonProgress(arg) {
|
||||
if (arg == -1) {
|
||||
progress.removeAttribute("value");
|
||||
} else {
|
||||
progress.value = arg;
|
||||
}
|
||||
}
|
||||
|
||||
adbAddon.on("update", onAddonUpdate);
|
||||
adbAddon.on("failure", onAddonFailure);
|
||||
adbAddon.on("progress", onAddonProgress);
|
||||
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
adbAddon.off("update", onAddonUpdate);
|
||||
adbAddon.off("failure", onAddonFailure);
|
||||
adbAddon.off("progress", onAddonProgress);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
const li = document.createElement("li");
|
||||
li.setAttribute("status", adbAddon.status);
|
||||
|
||||
const name = document.createElement("span");
|
||||
name.className = "name";
|
||||
|
||||
li.setAttribute("addon", "adb");
|
||||
name.textContent = "ADB Extension";
|
||||
|
||||
li.appendChild(name);
|
||||
|
||||
const status = document.createElement("span");
|
||||
status.className = "status";
|
||||
status.textContent = Strings.GetStringFromName(
|
||||
"addons_status_" + adbAddon.status
|
||||
);
|
||||
li.appendChild(status);
|
||||
|
||||
const installButton = document.createElement("button");
|
||||
installButton.className = "install-button";
|
||||
installButton.onclick = () => adbAddon.install("webide");
|
||||
installButton.textContent = Strings.GetStringFromName(
|
||||
"addons_install_button"
|
||||
);
|
||||
li.appendChild(installButton);
|
||||
|
||||
const uninstallButton = document.createElement("button");
|
||||
uninstallButton.className = "uninstall-button";
|
||||
uninstallButton.onclick = () => adbAddon.uninstall();
|
||||
uninstallButton.textContent = Strings.GetStringFromName(
|
||||
"addons_uninstall_button"
|
||||
);
|
||||
li.appendChild(uninstallButton);
|
||||
|
||||
const progress = document.createElement("progress");
|
||||
li.appendChild(progress);
|
||||
|
||||
const warning = document.createElement("p");
|
||||
warning.textContent = Strings.GetStringFromName("addons_adb_warning");
|
||||
warning.className = "warning";
|
||||
li.appendChild(warning);
|
||||
|
||||
document.querySelector("ul").appendChild(li);
|
||||
}
|
|
@ -1,31 +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 % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/addons.css" type="text/css"/>
|
||||
<script src="chrome://webide/content/addons.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="controls">
|
||||
<a id="aboutaddons">&addons_aboutaddons;</a>
|
||||
<a id="close">&deck_close;</a>
|
||||
</div>
|
||||
|
||||
<h1>&addons_title;</h1>
|
||||
|
||||
<ul></ul>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,131 +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 { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const { AppManager } = require("devtools/client/webide/modules/app-manager");
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
document.addEventListener("visibilitychange", updateUI, true);
|
||||
AppManager.on("app-manager-update", onAppManagerUpdate);
|
||||
updateUI();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
AppManager.off("app-manager-update", onAppManagerUpdate);
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
function onAppManagerUpdate(what, details) {
|
||||
if (what == "project" || what == "project-validated") {
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
function resetUI() {
|
||||
document.querySelector("#toolbar").classList.add("hidden");
|
||||
document.querySelector("#type").classList.add("hidden");
|
||||
document.querySelector("#descriptionHeader").classList.add("hidden");
|
||||
document.querySelector("#manifestURLHeader").classList.add("hidden");
|
||||
document.querySelector("#locationHeader").classList.add("hidden");
|
||||
|
||||
document.body.className = "";
|
||||
document.querySelector("#icon").src = "";
|
||||
document.querySelector("h1").textContent = "";
|
||||
document.querySelector("#description").textContent = "";
|
||||
document.querySelector("#type").textContent = "";
|
||||
document.querySelector("#manifestURL").textContent = "";
|
||||
document.querySelector("#location").textContent = "";
|
||||
|
||||
document.querySelector("#errorslist").innerHTML = "";
|
||||
document.querySelector("#warningslist").innerHTML = "";
|
||||
}
|
||||
|
||||
function updateUI() {
|
||||
resetUI();
|
||||
|
||||
const project = AppManager.selectedProject;
|
||||
if (!project) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.type != "runtimeApp" && project.type != "mainProcess") {
|
||||
document.querySelector("#toolbar").classList.remove("hidden");
|
||||
document.querySelector("#locationHeader").classList.remove("hidden");
|
||||
document.querySelector("#location").textContent = project.location;
|
||||
}
|
||||
|
||||
document.body.className = project.validationStatus;
|
||||
document.querySelector("#icon").src = project.icon;
|
||||
document.querySelector("h1").textContent = project.name;
|
||||
|
||||
let manifest;
|
||||
if (project.type == "runtimeApp") {
|
||||
manifest = project.app.manifest;
|
||||
} else {
|
||||
manifest = project.manifest;
|
||||
}
|
||||
|
||||
if (manifest) {
|
||||
if (manifest.description) {
|
||||
document.querySelector("#descriptionHeader").classList.remove("hidden");
|
||||
document.querySelector("#description").textContent = manifest.description;
|
||||
}
|
||||
|
||||
document.querySelector("#type").classList.remove("hidden");
|
||||
|
||||
if (project.type == "runtimeApp") {
|
||||
const manifestURL = AppManager.getProjectManifestURL(project);
|
||||
document.querySelector("#type").textContent = manifest.type || "web";
|
||||
document.querySelector("#manifestURLHeader").classList.remove("hidden");
|
||||
document.querySelector("#manifestURL").textContent = manifestURL;
|
||||
} else if (project.type == "mainProcess") {
|
||||
document.querySelector("#type").textContent = project.name;
|
||||
} else {
|
||||
document.querySelector("#type").textContent =
|
||||
project.type + " " + (manifest.type || "web");
|
||||
}
|
||||
|
||||
if (project.type == "packaged") {
|
||||
const manifestURL = AppManager.getProjectManifestURL(project);
|
||||
if (manifestURL) {
|
||||
document.querySelector("#manifestURLHeader").classList.remove("hidden");
|
||||
document.querySelector("#manifestURL").textContent = manifestURL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const errorsNode = document.querySelector("#errorslist");
|
||||
const warningsNode = document.querySelector("#warningslist");
|
||||
|
||||
if (project.errors) {
|
||||
for (const e of project.errors) {
|
||||
const li = document.createElement("li");
|
||||
li.textContent = e;
|
||||
errorsNode.appendChild(li);
|
||||
}
|
||||
}
|
||||
|
||||
if (project.warnings) {
|
||||
for (const w of project.warnings) {
|
||||
const li = document.createElement("li");
|
||||
li.textContent = w;
|
||||
warningsNode.appendChild(li);
|
||||
}
|
||||
}
|
||||
|
||||
AppManager.update("details");
|
||||
}
|
||||
|
||||
// Used in details.xhtml.
|
||||
/* exported removeProject */
|
||||
function removeProject() {
|
||||
AppManager.removeSelectedProject();
|
||||
}
|
|
@ -1,52 +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 % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/details.css" type="text/css"/>
|
||||
<script src="chrome://webide/content/details.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="toolbar">
|
||||
<button onclick="removeProject()">&details_removeProject_button;</button>
|
||||
<p id="validation_status">
|
||||
<span class="valid">&details_valid_header;</span>
|
||||
<span class="warning">&details_warning_header;</span>
|
||||
<span class="error">&details_error_header;</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<header>
|
||||
<img id="icon"></img>
|
||||
<div>
|
||||
<h1></h1>
|
||||
<p id="type"></p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<h3 id="descriptionHeader">&details_description;</h3>
|
||||
<p id="description"></p>
|
||||
|
||||
<h3 id="locationHeader">&details_location;</h3>
|
||||
<p id="location"></p>
|
||||
|
||||
<h3 id="manifestURLHeader">&details_manifestURL;</h3>
|
||||
<p id="manifestURL"></p>
|
||||
</main>
|
||||
|
||||
<ul class="validation_messages" id="errorslist"></ul>
|
||||
<ul class="validation_messages" id="warningslist"></ul>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,93 +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 { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const { AppManager } = require("devtools/client/webide/modules/app-manager");
|
||||
const { Connection } = require("devtools/shared/client/connection-manager");
|
||||
const ConfigView = require("devtools/client/webide/modules/config-view");
|
||||
|
||||
var configView = new ConfigView(window);
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
AppManager.on("app-manager-update", OnAppManagerUpdate);
|
||||
document.getElementById("close").onclick = CloseUI;
|
||||
document.getElementById("device-fields").onchange = UpdateField;
|
||||
document.getElementById("device-fields").onclick = CheckReset;
|
||||
document.getElementById("search-bar").onkeyup = document.getElementById(
|
||||
"search-bar"
|
||||
).onclick = SearchField;
|
||||
document.getElementById("custom-value").onclick = UpdateNewField;
|
||||
document.getElementById("custom-value-type").onchange = ClearNewFields;
|
||||
document.getElementById("add-custom-field").onkeyup = CheckNewFieldSubmit;
|
||||
BuildUI();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
AppManager.off("app-manager-update", OnAppManagerUpdate);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
function CloseUI() {
|
||||
window.parent.UI.openProject();
|
||||
}
|
||||
|
||||
function OnAppManagerUpdate(what) {
|
||||
if (what == "connection" || what == "runtime-global-actors") {
|
||||
BuildUI();
|
||||
}
|
||||
}
|
||||
|
||||
function CheckNewFieldSubmit(event) {
|
||||
configView.checkNewFieldSubmit(event);
|
||||
}
|
||||
|
||||
function UpdateNewField() {
|
||||
configView.updateNewField();
|
||||
}
|
||||
|
||||
function ClearNewFields() {
|
||||
configView.clearNewFields();
|
||||
}
|
||||
|
||||
function CheckReset(event) {
|
||||
configView.checkReset(event);
|
||||
}
|
||||
|
||||
function UpdateField(event) {
|
||||
configView.updateField(event);
|
||||
}
|
||||
|
||||
function SearchField(event) {
|
||||
configView.search(event);
|
||||
}
|
||||
|
||||
// Used by tests
|
||||
/* exported getAllPrefs */
|
||||
var getAllPrefs;
|
||||
function BuildUI() {
|
||||
configView.resetTable();
|
||||
|
||||
if (
|
||||
AppManager.connection &&
|
||||
AppManager.connection.status == Connection.Status.CONNECTED &&
|
||||
AppManager.preferenceFront
|
||||
) {
|
||||
configView.front = AppManager.preferenceFront;
|
||||
configView.kind = "Pref";
|
||||
configView.includeTypeName = true;
|
||||
|
||||
getAllPrefs = AppManager.preferenceFront
|
||||
.getAllPrefs()
|
||||
.then(json => configView.generateDisplay(json));
|
||||
} else {
|
||||
CloseUI();
|
||||
}
|
||||
}
|
|
@ -1,49 +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 % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/config-view.css" type="text/css"/>
|
||||
<script src="chrome://webide/content/devicepreferences.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div id="controls">
|
||||
<a id="close">&deck_close;</a>
|
||||
</div>
|
||||
<h1>&devicepreference_title;</h1>
|
||||
<div id="search">
|
||||
<input type="text" id="search-bar" placeholder="&devicepreference_search;"/>
|
||||
</div>
|
||||
</header>
|
||||
<table id="device-fields">
|
||||
<tr id="add-custom-field">
|
||||
<td>
|
||||
<select id="custom-value-type">
|
||||
<option value="" selected="selected">&device_typenone;</option>
|
||||
<option value="boolean">&device_typeboolean;</option>
|
||||
<option value="number">&device_typenumber;</option>
|
||||
<option value="string">&device_typestring;</option>
|
||||
</select>
|
||||
<input type="text" id="custom-value-name" placeholder="&devicepreference_newname;"/>
|
||||
</td>
|
||||
<td class="custom-input">
|
||||
<input type="text" id="custom-value-text" placeholder="&devicepreference_newtext;"/>
|
||||
</td>
|
||||
<td>
|
||||
<button id="custom-value" class="new-editable">&devicepreference_addnew;</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,28 +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/.
|
||||
|
||||
webide.jar:
|
||||
% content webide %content/
|
||||
content/webide.xul (webide.xul)
|
||||
content/webide.js (webide.js)
|
||||
content/newapp.xul (newapp.xul)
|
||||
content/newapp.js (newapp.js)
|
||||
content/details.xhtml (details.xhtml)
|
||||
content/details.js (details.js)
|
||||
content/addons.js (addons.js)
|
||||
content/addons.xhtml (addons.xhtml)
|
||||
content/runtimedetails.js (runtimedetails.js)
|
||||
content/runtimedetails.xhtml (runtimedetails.xhtml)
|
||||
content/prefs.js (prefs.js)
|
||||
content/prefs.xhtml (prefs.xhtml)
|
||||
content/devicepreferences.js (devicepreferences.js)
|
||||
content/devicepreferences.xhtml (devicepreferences.xhtml)
|
||||
content/wifi-auth.js (wifi-auth.js)
|
||||
content/wifi-auth.xhtml (wifi-auth.xhtml)
|
||||
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)
|
|
@ -1,33 +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 % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="resource://devtools/client/themes/common.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/logs.css" type="text/css"/>
|
||||
<script src="chrome://devtools/content/shared/theme-switching.js"></script>
|
||||
<script src="logs.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="controls">
|
||||
<a id="close">&deck_close;</a>
|
||||
</div>
|
||||
|
||||
<h1>&logs_title;</h1>
|
||||
|
||||
<ul id="logs" class="devtools-monospace">
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
|
@ -1,192 +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";
|
||||
|
||||
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const Services = require("Services");
|
||||
const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
|
||||
const { AppProjects } = require("devtools/client/webide/modules/app-projects");
|
||||
const { AppManager } = require("devtools/client/webide/modules/app-manager");
|
||||
const { getJSON } = require("devtools/client/shared/getjson");
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"ZipUtils",
|
||||
"resource://gre/modules/ZipUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Downloads",
|
||||
"resource://gre/modules/Downloads.jsm"
|
||||
);
|
||||
|
||||
const TEMPLATES_URL = "devtools.webide.templatesURL";
|
||||
|
||||
var gTemplateList = null;
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
const projectNameNode = document.querySelector("#project-name");
|
||||
projectNameNode.addEventListener("input", canValidate, true);
|
||||
getTemplatesJSON();
|
||||
document.addEventListener("dialogaccept", doOK);
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
function getTemplatesJSON() {
|
||||
getJSON(TEMPLATES_URL).then(
|
||||
list => {
|
||||
if (!Array.isArray(list)) {
|
||||
throw new Error("JSON response not an array");
|
||||
}
|
||||
if (list.length == 0) {
|
||||
throw new Error("JSON response is an empty array");
|
||||
}
|
||||
gTemplateList = list;
|
||||
const templatelistNode = document.querySelector("#templatelist");
|
||||
templatelistNode.innerHTML = "";
|
||||
for (const template of list) {
|
||||
const richlistitemNode = document.createXULElement("richlistitem");
|
||||
const imageNode = document.createXULElement("image");
|
||||
imageNode.setAttribute("src", template.icon);
|
||||
const labelNode = document.createXULElement("label");
|
||||
labelNode.setAttribute("value", template.name);
|
||||
const descriptionNode = document.createXULElement("description");
|
||||
descriptionNode.textContent = template.description;
|
||||
const vboxNode = document.createXULElement("vbox");
|
||||
vboxNode.setAttribute("flex", "1");
|
||||
richlistitemNode.appendChild(imageNode);
|
||||
vboxNode.appendChild(labelNode);
|
||||
vboxNode.appendChild(descriptionNode);
|
||||
richlistitemNode.appendChild(vboxNode);
|
||||
templatelistNode.appendChild(richlistitemNode);
|
||||
}
|
||||
templatelistNode.selectedIndex = 0;
|
||||
|
||||
/* Chrome mochitest support */
|
||||
const testOptions = window.arguments[0].testOptions;
|
||||
if (testOptions) {
|
||||
templatelistNode.selectedIndex = testOptions.index;
|
||||
document.querySelector("#project-name").value = testOptions.name;
|
||||
doOK();
|
||||
}
|
||||
},
|
||||
e => {
|
||||
failAndBail("Can't download app templates: " + e);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function failAndBail(msg) {
|
||||
Services.prompt.alert(window, "error", msg);
|
||||
window.close();
|
||||
}
|
||||
|
||||
function canValidate() {
|
||||
const projectNameNode = document.querySelector("#project-name");
|
||||
const dialogNode = document.querySelector("dialog");
|
||||
if (projectNameNode.value.length > 0) {
|
||||
dialogNode.removeAttribute("buttondisabledaccept");
|
||||
} else {
|
||||
dialogNode.setAttribute("buttondisabledaccept", "true");
|
||||
}
|
||||
}
|
||||
|
||||
function doOK(event) {
|
||||
const projectName = document.querySelector("#project-name").value;
|
||||
|
||||
if (!projectName) {
|
||||
console.error("No project name");
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gTemplateList) {
|
||||
console.error("No template index");
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const templatelistNode = document.querySelector("#templatelist");
|
||||
if (templatelistNode.selectedIndex < 0) {
|
||||
console.error("No template selected");
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Chrome mochitest support */
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
const testOptions = window.arguments[0].testOptions;
|
||||
if (testOptions) {
|
||||
resolve(testOptions.folder);
|
||||
} else {
|
||||
const fp = Cc["@mozilla.org/filepicker;1"].createInstance(
|
||||
Ci.nsIFilePicker
|
||||
);
|
||||
fp.init(
|
||||
window,
|
||||
"Select directory where to create app directory",
|
||||
Ci.nsIFilePicker.modeGetFolder
|
||||
);
|
||||
fp.open(res => {
|
||||
if (res == Ci.nsIFilePicker.returnCancel) {
|
||||
console.error("No directory selected");
|
||||
reject(null);
|
||||
} else {
|
||||
resolve(fp.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const bail = e => {
|
||||
console.error(e);
|
||||
window.close();
|
||||
};
|
||||
|
||||
promise.then(folder => {
|
||||
// Create subfolder with fs-friendly name of project
|
||||
const subfolder = projectName.replace(/[\\/:*?"<>|]/g, "").toLowerCase();
|
||||
const win = Services.wm.getMostRecentWindow("devtools:webide");
|
||||
folder.append(subfolder);
|
||||
|
||||
try {
|
||||
folder.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
||||
} catch (e) {
|
||||
win.UI.reportError("error_folderCreationFailed");
|
||||
window.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Download boilerplate zip
|
||||
const template = gTemplateList[templatelistNode.selectedIndex];
|
||||
const source = template.file;
|
||||
const target = folder.clone();
|
||||
target.append(subfolder + ".zip");
|
||||
Downloads.fetch(source, target).then(() => {
|
||||
ZipUtils.extractFiles(target, folder);
|
||||
target.remove(false);
|
||||
AppProjects.addPackaged(folder).then(project => {
|
||||
window.arguments[0].location = project.location;
|
||||
AppManager.validateAndUpdateProject(project).then(() => {
|
||||
if (project.manifest) {
|
||||
project.manifest.name = projectName;
|
||||
AppManager.writeManifest(project).then(() => {
|
||||
AppManager.validateAndUpdateProject(project).then(() => {
|
||||
window.close();
|
||||
}, bail);
|
||||
}, bail);
|
||||
} else {
|
||||
bail("Manifest not found");
|
||||
}
|
||||
}, bail);
|
||||
}, bail);
|
||||
}, bail);
|
||||
}, bail);
|
||||
|
||||
event.preventDefault();
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.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/. -->
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://webide/skin/newapp.css"?>
|
||||
|
||||
<dialog id="webide:newapp" title="&newAppWindowTitle;"
|
||||
width="600" height="400"
|
||||
buttons="accept,cancel"
|
||||
buttondisabledaccept="true"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script src="newapp.js"></script>
|
||||
<label class="header-name" value="&newAppHeader;"/>
|
||||
|
||||
<richlistbox id="templatelist" flex="1">
|
||||
<description>&newAppLoadingTemplate;</description>
|
||||
</richlistbox>
|
||||
<vbox>
|
||||
<label class="header-name" control="project-name" value="&newAppProjectName;"/>
|
||||
<textbox id="project-name"/>
|
||||
</vbox>
|
||||
|
||||
</dialog>
|
|
@ -1,111 +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";
|
||||
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
// Listen to preference changes
|
||||
const inputs = document.querySelectorAll("[data-pref]");
|
||||
for (const i of inputs) {
|
||||
const pref = i.dataset.pref;
|
||||
Services.prefs.addObserver(pref, FillForm);
|
||||
i.addEventListener("change", SaveForm);
|
||||
}
|
||||
|
||||
// Buttons
|
||||
document.querySelector("#close").onclick = CloseUI;
|
||||
document.querySelector("#restore").onclick = RestoreDefaults;
|
||||
document.querySelector("#manageComponents").onclick = ShowAddons;
|
||||
|
||||
// Initialize the controls
|
||||
FillForm();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
const inputs = document.querySelectorAll("[data-pref]");
|
||||
for (const i of inputs) {
|
||||
const pref = i.dataset.pref;
|
||||
i.removeEventListener("change", SaveForm);
|
||||
Services.prefs.removeObserver(pref, FillForm);
|
||||
}
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
function CloseUI() {
|
||||
window.parent.UI.openProject();
|
||||
}
|
||||
|
||||
function ShowAddons() {
|
||||
window.parent.Cmds.showAddons();
|
||||
}
|
||||
|
||||
function FillForm() {
|
||||
const inputs = document.querySelectorAll("[data-pref]");
|
||||
for (const i of inputs) {
|
||||
const pref = i.dataset.pref;
|
||||
const val = GetPref(pref);
|
||||
if (i.type == "checkbox") {
|
||||
i.checked = val;
|
||||
} else {
|
||||
i.value = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SaveForm(e) {
|
||||
const inputs = document.querySelectorAll("[data-pref]");
|
||||
for (const i of inputs) {
|
||||
const pref = i.dataset.pref;
|
||||
if (i.type == "checkbox") {
|
||||
SetPref(pref, i.checked);
|
||||
} else {
|
||||
SetPref(pref, i.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetPref(name) {
|
||||
const type = Services.prefs.getPrefType(name);
|
||||
switch (type) {
|
||||
case Services.prefs.PREF_STRING:
|
||||
return Services.prefs.getCharPref(name);
|
||||
case Services.prefs.PREF_INT:
|
||||
return Services.prefs.getIntPref(name);
|
||||
case Services.prefs.PREF_BOOL:
|
||||
return Services.prefs.getBoolPref(name);
|
||||
default:
|
||||
throw new Error("Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
function SetPref(name, value) {
|
||||
const type = Services.prefs.getPrefType(name);
|
||||
switch (type) {
|
||||
case Services.prefs.PREF_STRING:
|
||||
return Services.prefs.setCharPref(name, value);
|
||||
case Services.prefs.PREF_INT:
|
||||
return Services.prefs.setIntPref(name, value);
|
||||
case Services.prefs.PREF_BOOL:
|
||||
return Services.prefs.setBoolPref(name, value);
|
||||
default:
|
||||
throw new Error("Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
function RestoreDefaults() {
|
||||
const inputs = document.querySelectorAll("[data-pref]");
|
||||
for (const i of inputs) {
|
||||
const pref = i.dataset.pref;
|
||||
Services.prefs.clearUserPref(pref);
|
||||
}
|
||||
}
|
|
@ -1,52 +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 % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
|
||||
<script src="chrome://webide/content/prefs.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="controls">
|
||||
<a id="restore">&prefs_restore;</a>
|
||||
<a id="manageComponents">&prefs_manage_components;</a>
|
||||
<a id="close">&deck_close;</a>
|
||||
</div>
|
||||
|
||||
<h1>&prefs_title;</h1>
|
||||
|
||||
<h2>&prefs_general_title;</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<label title="&prefs_options_rememberlastproject_tooltip;">
|
||||
<input type="checkbox" data-pref="devtools.webide.restoreLastProject"/>
|
||||
<span>&prefs_options_rememberlastproject;</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label title="&prefs_options_autoconnectruntime_tooltip;">
|
||||
<input type="checkbox" data-pref="devtools.webide.autoConnectRuntime"/>
|
||||
<span>&prefs_options_autoconnectruntime;</span>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="text-input" title="&prefs_options_templatesurl_tooltip;">
|
||||
<span>&prefs_options_templatesurl;</span>
|
||||
<input data-pref="devtools.webide.templatesURL"/>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,47 +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/. */
|
||||
|
||||
/* eslint-env browser */
|
||||
|
||||
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const ProjectList = require("devtools/client/webide/modules/project-list");
|
||||
|
||||
var projectList = new ProjectList(window, window.parent);
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
document.getElementById("new-app").onclick = CreateNewApp;
|
||||
document.getElementById("hosted-app").onclick = ImportHostedApp;
|
||||
document.getElementById("packaged-app").onclick = ImportPackagedApp;
|
||||
document.getElementById("refresh-tabs").onclick = RefreshTabs;
|
||||
projectList.update();
|
||||
projectList.updateCommands();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
projectList.destroy();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
function RefreshTabs() {
|
||||
projectList.refreshTabs();
|
||||
}
|
||||
|
||||
function CreateNewApp() {
|
||||
projectList.newApp();
|
||||
}
|
||||
|
||||
function ImportHostedApp() {
|
||||
projectList.importHostedApp();
|
||||
}
|
||||
|
||||
function ImportPackagedApp() {
|
||||
projectList.importPackagedApp();
|
||||
}
|
|
@ -1,35 +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 % webideDTD SYSTEM "chrome://devtools/locale/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 src="chrome://webide/content/project-listing.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="project-panel">
|
||||
<div id="project-panel-box">
|
||||
<button class="panel-item project-panel-item-newapp" id="new-app">&projectMenu_newApp_label;</button>
|
||||
<button class="panel-item project-panel-item-openpackaged" id="packaged-app">&projectMenu_importPackagedApp_label;</button>
|
||||
<button class="panel-item project-panel-item-openhosted" id="hosted-app">&projectMenu_importHostedApp_label;</button>
|
||||
<label class="panel-header">&projectPanel_myProjects;</label>
|
||||
<div id="project-panel-projects"></div>
|
||||
<label class="panel-header" id="panel-header-runtimeapps" hidden="true">&projectPanel_runtimeApps;</label>
|
||||
<div id="project-panel-runtimeapps"/>
|
||||
<label class="panel-header" id="panel-header-tabs" hidden="true">&projectPanel_tabs;
|
||||
<button class="project-panel-item-refreshtabs refresh-icon" id="refresh-tabs" title="&projectMenu_refreshTabs_label;"></button>
|
||||
</label>
|
||||
<div id="project-panel-tabs"/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,16 +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/. */
|
||||
|
||||
/* exported ProjectPanel */
|
||||
var ProjectPanel = {
|
||||
// TODO: Expand function to save toggle state.
|
||||
toggleSidebar: function() {
|
||||
document
|
||||
.querySelector("#project-listing-panel")
|
||||
.setAttribute("sidebar-displayed", true);
|
||||
document
|
||||
.querySelector("#project-listing-splitter")
|
||||
.setAttribute("sidebar-displayed", true);
|
||||
},
|
||||
};
|
|
@ -1,78 +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 { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const RuntimeList = require("devtools/client/webide/modules/runtime-list");
|
||||
|
||||
var runtimeList = new RuntimeList(window, window.parent);
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
document.getElementById("runtime-screenshot").onclick = TakeScreenshot;
|
||||
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-performance"
|
||||
).onclick = ShowPerformancePanel;
|
||||
document.getElementById(
|
||||
"runtime-panel-noadbextension"
|
||||
).onclick = ShowAddons;
|
||||
document.getElementById(
|
||||
"runtime-panel-nousbdevice"
|
||||
).onclick = ShowTroubleShooting;
|
||||
document.getElementById("refresh-devices").onclick = RefreshScanners;
|
||||
runtimeList.update();
|
||||
runtimeList.updateCommands();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
runtimeList.destroy();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
function TakeScreenshot() {
|
||||
runtimeList.takeScreenshot();
|
||||
}
|
||||
|
||||
function ShowRuntimeDetails() {
|
||||
runtimeList.showRuntimeDetails();
|
||||
}
|
||||
|
||||
function ShowDevicePreferences() {
|
||||
runtimeList.showDevicePreferences();
|
||||
}
|
||||
|
||||
function ShowSettings() {
|
||||
runtimeList.showSettings();
|
||||
}
|
||||
|
||||
function ShowPerformancePanel() {
|
||||
runtimeList.showPerformancePanel();
|
||||
}
|
||||
|
||||
function RefreshScanners() {
|
||||
runtimeList.refreshScanners();
|
||||
}
|
||||
|
||||
function DisconnectRuntime() {
|
||||
window.parent.Cmds.disconnectRuntime();
|
||||
}
|
||||
|
||||
function ShowAddons() {
|
||||
runtimeList.showAddons();
|
||||
}
|
||||
|
||||
function ShowTroubleShooting() {
|
||||
runtimeList.showTroubleShooting();
|
||||
}
|
|
@ -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 % webideDTD SYSTEM "chrome://devtools/locale/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 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;
|
||||
<button class="runtime-panel-item-refreshdevices refresh-icon" id="refresh-devices" title="&runtimePanel_refreshDevices_label;"></button>
|
||||
</label>
|
||||
<button class="panel-item" id="runtime-panel-nousbdevice">&runtimePanel_nousbdevice;</button>
|
||||
<button class="panel-item" id="runtime-panel-noadbextension"></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_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-preferences">&runtimeMenu_showDevicePrefs_label;</button>
|
||||
<button class="panel-item" id="runtime-settings">&runtimeMenu_showSettings_label;</button>
|
||||
<button class="panel-item" id="runtime-performance">&runtimeMenu_showPerformancePanel_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>
|
|
@ -1,16 +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/. */
|
||||
|
||||
/* exported RuntimePanel */
|
||||
var 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);
|
||||
},
|
||||
};
|
|
@ -1,68 +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 { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const { AppManager } = require("devtools/client/webide/modules/app-manager");
|
||||
const { Connection } = require("devtools/shared/client/connection-manager");
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
document.querySelector("#close").onclick = CloseUI;
|
||||
AppManager.on("app-manager-update", OnAppManagerUpdate);
|
||||
BuildUI();
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
AppManager.off("app-manager-update", OnAppManagerUpdate);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
function CloseUI() {
|
||||
window.parent.UI.openProject();
|
||||
}
|
||||
|
||||
function OnAppManagerUpdate(what) {
|
||||
if (what == "connection" || what == "runtime-global-actors") {
|
||||
BuildUI();
|
||||
}
|
||||
}
|
||||
|
||||
function generateFields(json) {
|
||||
const table = document.querySelector("table");
|
||||
for (const name in json) {
|
||||
const tr = document.createElement("tr");
|
||||
let td = document.createElement("td");
|
||||
td.textContent = name;
|
||||
tr.appendChild(td);
|
||||
td = document.createElement("td");
|
||||
td.textContent = json[name];
|
||||
tr.appendChild(td);
|
||||
table.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
// Used by tests
|
||||
/* exported getDescriptionPromise */
|
||||
var getDescriptionPromise;
|
||||
function BuildUI() {
|
||||
const table = document.querySelector("table");
|
||||
table.innerHTML = "";
|
||||
if (
|
||||
AppManager.connection &&
|
||||
AppManager.connection.status == Connection.Status.CONNECTED &&
|
||||
AppManager.deviceFront
|
||||
) {
|
||||
getDescriptionPromise = AppManager.deviceFront
|
||||
.getDescription()
|
||||
.then(json => generateFields(json));
|
||||
} else {
|
||||
CloseUI();
|
||||
}
|
||||
}
|
|
@ -1,29 +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 % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/runtimedetails.css" type="text/css"/>
|
||||
<script src="chrome://webide/content/runtimedetails.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="controls">
|
||||
<a id="close">&deck_close;</a>
|
||||
</div>
|
||||
|
||||
<h1>&runtimedetails_title;</h1>
|
||||
|
||||
<table></table>
|
||||
</body>
|
||||
</html>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,168 +0,0 @@
|
|||
<?xml version="1.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/. -->
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="resource://devtools/client/themes/common.css"?>
|
||||
<?xml-stylesheet href="chrome://webide/skin/webide.css"?>
|
||||
|
||||
<window id="webide"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="&windowTitle;"
|
||||
windowtype="devtools:webide"
|
||||
macanimationtype="document"
|
||||
fullscreenbutton="true"
|
||||
screenX="4" screenY="4"
|
||||
width="800" height="600"
|
||||
persist="screenX screenY width height sizemode">
|
||||
|
||||
<script src="chrome://global/content/globalOverlay.js"></script>
|
||||
<script src="project-panel.js"></script>
|
||||
<script src="runtime-panel.js"></script>
|
||||
<script src="webide.js"></script>
|
||||
<script src="chrome://global/content/editMenuOverlay.js"/>
|
||||
|
||||
<commandset id="mainCommandSet">
|
||||
<commandset id="webideCommands">
|
||||
<command id="cmd_quit" oncommand="Cmds.quit()"/>
|
||||
<command id="cmd_newApp" oncommand="Cmds.newApp()" label="&projectMenu_newApp_label;"/>
|
||||
<command id="cmd_importPackagedApp" oncommand="Cmds.importPackagedApp()" label="&projectMenu_importPackagedApp_label;"/>
|
||||
<command id="cmd_importHostedApp" oncommand="Cmds.importHostedApp()" label="&projectMenu_importHostedApp_label;"/>
|
||||
<command id="cmd_showDevicePrefs" label="&runtimeMenu_showDevicePrefs_label;" oncommand="Cmds.showDevicePrefs()"/>
|
||||
<command id="cmd_showPerformancePanel" label="&runtimeMenu_showPerformancePanel_label;" oncommand="Cmds.showPerformancePanel()"/>
|
||||
<command id="cmd_showSettings" label="&runtimeMenu_showSettings_label;" oncommand="Cmds.showSettings()"/>
|
||||
<command id="cmd_removeProject" oncommand="Cmds.removeProject()" label="&projectMenu_remove_label;"/>
|
||||
<command id="cmd_showProjectPanel" oncommand="Cmds.showProjectPanel()"/>
|
||||
<command id="cmd_showRuntimePanel" oncommand="Cmds.showRuntimePanel()"/>
|
||||
<command id="cmd_disconnectRuntime" oncommand="Cmds.disconnectRuntime()" label="&runtimeMenu_disconnect_label;"/>
|
||||
<command id="cmd_showRuntimeDetails" oncommand="Cmds.showRuntimeDetails()" label="&runtimeMenu_showDetails_label;"/>
|
||||
<command id="cmd_takeScreenshot" oncommand="Cmds.takeScreenshot()" label="&runtimeMenu_takeScreenshot_label;"/>
|
||||
<command id="cmd_showAddons" oncommand="Cmds.showAddons()"/>
|
||||
<command id="cmd_showPrefs" oncommand="Cmds.showPrefs()"/>
|
||||
<command id="cmd_showTroubleShooting" oncommand="Cmds.showTroubleShooting()"/>
|
||||
<command id="cmd_play" oncommand="Cmds.play()"/>
|
||||
<command id="cmd_stop" oncommand="Cmds.stop()" label="&projectMenu_stop_label;"/>
|
||||
<command id="cmd_toggleToolbox" oncommand="Cmds.toggleToolbox()"/>
|
||||
<command id="cmd_zoomin" label="&viewMenu_zoomin_label;" oncommand="Cmds.zoomIn()"/>
|
||||
<command id="cmd_zoomout" label="&viewMenu_zoomout_label;" oncommand="Cmds.zoomOut()"/>
|
||||
<command id="cmd_resetzoom" label="&viewMenu_resetzoom_label;" oncommand="Cmds.resetZoom()"/>
|
||||
</commandset>
|
||||
</commandset>
|
||||
|
||||
<toolbar type="menubar">
|
||||
<menubar id="main-menubar">
|
||||
<menu id="menu-project" label="&projectMenu_label;" accesskey="&projectMenu_accesskey;">
|
||||
<menupopup id="menu-project-popup">
|
||||
<menuitem command="cmd_newApp" accesskey="&projectMenu_newApp_accesskey;"/>
|
||||
<menuitem command="cmd_importPackagedApp" accesskey="&projectMenu_importPackagedApp_accesskey;"/>
|
||||
<menuitem command="cmd_importHostedApp" accesskey="&projectMenu_importHostedApp_accesskey;"/>
|
||||
<menuitem id="menuitem-show_projectPanel" command="cmd_showProjectPanel" key="key_showProjectPanel" label="&projectMenu_selectApp_label;" accesskey="&projectMenu_selectApp_accesskey;"/>
|
||||
<menuseparator/>
|
||||
<menuitem command="cmd_play" key="key_play" label="&projectMenu_play_label;" accesskey="&projectMenu_play_accesskey;"/>
|
||||
<menuitem command="cmd_stop" accesskey="&projectMenu_stop_accesskey;"/>
|
||||
<menuitem command="cmd_toggleToolbox" key="key_toggleToolbox" label="&projectMenu_debug_label;" accesskey="&projectMenu_debug_accesskey;"/>
|
||||
<menuseparator/>
|
||||
<menuitem command="cmd_removeProject" accesskey="&projectMenu_remove_accesskey;"/>
|
||||
<menuseparator/>
|
||||
<menuitem command="cmd_showPrefs" label="&projectMenu_showPrefs_label;" accesskey="&projectMenu_showPrefs_accesskey;"/>
|
||||
<menuitem command="cmd_showAddons" label="&projectMenu_manageComponents_label;" accesskey="&projectMenu_manageComponents_accesskey;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
<menu id="menu-runtime" label="&runtimeMenu_label;" accesskey="&runtimeMenu_accesskey;">
|
||||
<menupopup id="menu-runtime-popup">
|
||||
<menuitem command="cmd_takeScreenshot" accesskey="&runtimeMenu_takeScreenshot_accesskey;"/>
|
||||
<menuitem command="cmd_showRuntimeDetails" accesskey="&runtimeMenu_showDetails_accesskey;"/>
|
||||
<menuitem command="cmd_showDevicePrefs" accesskey="&runtimeMenu_showDevicePrefs_accesskey;"/>
|
||||
<menuitem command="cmd_showSettings" accesskey="&runtimeMenu_showSettings_accesskey;"/>
|
||||
<menuitem command="cmd_showPerformancePanel" accesskey="&runtimeMenu_showPerformancePanel_accesskey;"/>
|
||||
<menuseparator/>
|
||||
<menuitem command="cmd_disconnectRuntime" accesskey="&runtimeMenu_disconnect_accesskey;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
<menu id="menu-view" label="&viewMenu_label;" accesskey="&viewMenu_accesskey;">
|
||||
<menupopup id="menu-ViewPopup">
|
||||
<menuseparator/>
|
||||
<menuitem command="cmd_zoomin" key="key_zoomin" accesskey="&viewMenu_zoomin_accesskey;"/>
|
||||
<menuitem command="cmd_zoomout" key="key_zoomout" accesskey="&viewMenu_zoomout_accesskey;"/>
|
||||
<menuitem command="cmd_resetzoom" key="key_resetzoom" accesskey="&viewMenu_resetzoom_accesskey;"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
|
||||
</menubar>
|
||||
</toolbar>
|
||||
|
||||
<keyset id="mainKeyset">
|
||||
<key key="&key_quit;" id="key_quit" command="cmd_quit" modifiers="accel"/>
|
||||
<key key="&key_showProjectPanel;" id="key_showProjectPanel" command="cmd_showProjectPanel" modifiers="accel"/>
|
||||
<key key="&key_play;" id="key_play" command="cmd_play" modifiers="accel"/>
|
||||
<key keycode="&key_toggleToolbox;" id="key_toggleToolbox" command="cmd_toggleToolbox"/>
|
||||
<key key="&key_zoomin;" id="key_zoomin" command="cmd_zoomin" modifiers="accel"/>
|
||||
<key key="&key_zoomin2;" id="key_zoomin2" command="cmd_zoomin" modifiers="accel"/>
|
||||
<key key="&key_zoomout;" id="key_zoomout" command="cmd_zoomout" modifiers="accel"/>
|
||||
<key key="&key_resetzoom;" id="key_resetzoom" command="cmd_resetzoom" modifiers="accel"/>
|
||||
</keyset>
|
||||
|
||||
<tooltip id="aHTMLTooltip" page="true"/>
|
||||
|
||||
<toolbar id="main-toolbar">
|
||||
|
||||
<vbox flex="1">
|
||||
<hbox id="action-buttons-container" class="busy">
|
||||
<toolbarbutton id="action-button-play" class="action-button" command="cmd_play" tooltiptext="&projectMenu_play_label;"/>
|
||||
<toolbarbutton id="action-button-stop" class="action-button" command="cmd_stop" tooltiptext="&projectMenu_stop_label;"/>
|
||||
<toolbarbutton id="action-button-debug" class="action-button" command="cmd_toggleToolbox" tooltiptext="&projectMenu_debug_label;"/>
|
||||
<hbox id="action-busy" align="center">
|
||||
<html:img id="action-busy-undetermined" src="chrome://webide/skin/throbber.svg"/>
|
||||
<html:progress id="action-busy-determined"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
||||
<hbox id="panel-buttons-container">
|
||||
<spacer flex="1"/>
|
||||
<toolbarbutton id="runtime-panel-button" class="panel-button">
|
||||
<image class="panel-button-image"/>
|
||||
<label class="panel-button-label" value="&runtimeButton_label;"/>
|
||||
</toolbarbutton>
|
||||
</hbox>
|
||||
|
||||
</vbox>
|
||||
</toolbar>
|
||||
|
||||
<vbox flex="1" id="containerbox">
|
||||
<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" tooltip="aHTMLTooltip"/>
|
||||
</div>
|
||||
</vbox>
|
||||
<splitter class="devtools-side-splitter" id="project-listing-splitter"/>
|
||||
<deck flex="1" id="deck" selectedIndex="-1">
|
||||
<iframe id="deck-panel-details" flex="1" src="details.xhtml"/>
|
||||
<iframe id="deck-panel-addons" flex="1" src="addons.xhtml"/>
|
||||
<iframe id="deck-panel-prefs" flex="1" src="prefs.xhtml"/>
|
||||
<iframe id="deck-panel-runtimedetails" flex="1" lazysrc="runtimedetails.xhtml"/>
|
||||
<iframe id="deck-panel-devicepreferences" flex="1" lazysrc="devicepreferences.xhtml"/>
|
||||
<iframe id="deck-panel-performance" flex="1" lazysrc="chrome://devtools/content/performance-new/index.xhtml"/>
|
||||
</deck>
|
||||
<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" tooltip="aHTMLTooltip"/>
|
||||
</div>
|
||||
</vbox>
|
||||
</div>
|
||||
<splitter hidden="true" class="devtools-horizontal-splitter" orient="vertical"/>
|
||||
<!-- toolbox iframe will be inserted here -->
|
||||
</vbox>
|
||||
|
||||
</window>
|
|
@ -1,44 +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";
|
||||
|
||||
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
const QR = require("devtools/shared/qrcode/index");
|
||||
|
||||
window.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
document.getElementById("close").onclick = () => window.close();
|
||||
document.getElementById("no-scanner").onclick = showToken;
|
||||
document.getElementById("yes-scanner").onclick = hideToken;
|
||||
buildUI();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
function buildUI() {
|
||||
const { oob } = window.arguments[0];
|
||||
createQR(oob);
|
||||
createToken(oob);
|
||||
}
|
||||
|
||||
function createQR(oob) {
|
||||
const oobData = JSON.stringify(oob);
|
||||
const imgData = QR.encodeToDataURI(oobData, "L" /* low quality */);
|
||||
document.querySelector("#qr-code img").src = imgData.src;
|
||||
}
|
||||
|
||||
function createToken(oob) {
|
||||
const token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k;
|
||||
document.querySelector("#token pre").textContent = token;
|
||||
}
|
||||
|
||||
function showToken() {
|
||||
document.querySelector("body").setAttribute("token", "true");
|
||||
}
|
||||
|
||||
function hideToken() {
|
||||
document.querySelector("body").removeAttribute("token");
|
||||
}
|
|
@ -1,45 +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 % webideDTD SYSTEM "chrome://devtools/locale/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html id="devtools:wifi-auth" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/wifi-auth.css" type="text/css"/>
|
||||
<script src="chrome://webide/content/wifi-auth.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="controls">
|
||||
<a id="close">&deck_close;</a>
|
||||
</div>
|
||||
|
||||
<h3 id="header">&wifi_auth_header;</h3>
|
||||
<div id="scan-request">&wifi_auth_scan_request;</div>
|
||||
|
||||
<div id="qr-code">
|
||||
<div id="qr-code-wrapper">
|
||||
<img/>
|
||||
</div>
|
||||
<a id="no-scanner" class="toggle-scanner">&wifi_auth_no_scanner;</a>
|
||||
<div id="qr-size-note">
|
||||
<h5>&wifi_auth_qr_size_note;</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="token">
|
||||
<div>&wifi_auth_token_request;</div>
|
||||
<pre id="token-value"/>
|
||||
<a id="yes-scanner" class="toggle-scanner">&wifi_auth_yes_scanner;</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,820 +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 Services = require("Services");
|
||||
const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { OS } = require("resource://gre/modules/osfile.jsm");
|
||||
const { AppProjects } = require("devtools/client/webide/modules/app-projects");
|
||||
const TabStore = require("devtools/client/webide/modules/tab-store");
|
||||
const {
|
||||
AppValidator,
|
||||
} = require("devtools/client/webide/modules/app-validator");
|
||||
const {
|
||||
ConnectionManager,
|
||||
Connection,
|
||||
} = require("devtools/shared/client/connection-manager");
|
||||
const { RuntimeScanners } = require("devtools/client/webide/modules/runtimes");
|
||||
const {
|
||||
RuntimeTypes,
|
||||
} = require("devtools/client/webide/modules/runtime-types");
|
||||
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
|
||||
const Telemetry = require("devtools/client/shared/telemetry");
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/webide.properties"
|
||||
);
|
||||
|
||||
var AppManager = (exports.AppManager = {
|
||||
DEFAULT_PROJECT_ICON: "chrome://webide/skin/default-app-icon.png",
|
||||
DEFAULT_PROJECT_NAME: "--",
|
||||
|
||||
_initialized: false,
|
||||
|
||||
init: function() {
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
|
||||
const port = Services.prefs.getIntPref("devtools.debugger.remote-port");
|
||||
this.connection = ConnectionManager.createConnection("localhost", port);
|
||||
this.onConnectionChanged = this.onConnectionChanged.bind(this);
|
||||
this.connection.on(
|
||||
Connection.Events.STATUS_CHANGED,
|
||||
this.onConnectionChanged
|
||||
);
|
||||
|
||||
this.tabStore = new TabStore(this.connection);
|
||||
this.onTabList = this.onTabList.bind(this);
|
||||
this.onTabNavigate = this.onTabNavigate.bind(this);
|
||||
this.onTabClosed = this.onTabClosed.bind(this);
|
||||
this.tabStore.on("tab-list", this.onTabList);
|
||||
this.tabStore.on("navigate", this.onTabNavigate);
|
||||
this.tabStore.on("closed", this.onTabClosed);
|
||||
|
||||
this._clearRuntimeList();
|
||||
this._rebuildRuntimeList = this._rebuildRuntimeList.bind(this);
|
||||
RuntimeScanners.on("runtime-list-updated", this._rebuildRuntimeList);
|
||||
RuntimeScanners.enable();
|
||||
this._rebuildRuntimeList();
|
||||
|
||||
this._telemetry = new Telemetry();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
this._initialized = false;
|
||||
|
||||
this.selectedProject = null;
|
||||
this.selectedRuntime = null;
|
||||
RuntimeScanners.off("runtime-list-updated", this._rebuildRuntimeList);
|
||||
RuntimeScanners.disable();
|
||||
this.runtimeList = null;
|
||||
this.tabStore.off("tab-list", this.onTabList);
|
||||
this.tabStore.off("navigate", this.onTabNavigate);
|
||||
this.tabStore.off("closed", this.onTabClosed);
|
||||
this.tabStore.destroy();
|
||||
this.tabStore = null;
|
||||
this.connection.off(
|
||||
Connection.Events.STATUS_CHANGED,
|
||||
this.onConnectionChanged
|
||||
);
|
||||
this._rootForm = null;
|
||||
this.connection.disconnect();
|
||||
this.connection = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* This module emits various events when state changes occur. The basic event
|
||||
* naming scheme is that event "X" means "X has changed" or "X is available".
|
||||
* Some names are more detailed to clarify their precise meaning.
|
||||
*
|
||||
* The events this module may emit include:
|
||||
* before-project:
|
||||
* The selected project is about to change. The event includes a special
|
||||
* |cancel| callback that will abort the project change if desired.
|
||||
* connection:
|
||||
* The connection status has changed (connected, disconnected, etc.)
|
||||
* project:
|
||||
* The selected project has changed.
|
||||
* project-started:
|
||||
* The selected project started running on the connected runtime.
|
||||
* project-stopped:
|
||||
* The selected project stopped running on the connected runtime.
|
||||
* project-removed:
|
||||
* The selected project was removed from the project list.
|
||||
* project-validated:
|
||||
* The selected project just completed validation. As part of validation,
|
||||
* many pieces of metadata about the project are refreshed, including its
|
||||
* name, manifest details, etc.
|
||||
* runtime:
|
||||
* The selected runtime has changed.
|
||||
* 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
|
||||
* like preferences and settings.
|
||||
* runtime-details:
|
||||
* The selected runtime's details have changed, such as its user-visible
|
||||
* name.
|
||||
* runtime-list:
|
||||
* The list of available runtimes has changed, or any of the user-visible
|
||||
* details (like names) for the non-selected runtimes has changed.
|
||||
* runtime-telemetry:
|
||||
* Detailed runtime telemetry has been recorded. Used by tests.
|
||||
* runtime-targets:
|
||||
* 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 distinguish
|
||||
* "apps" and "tabs".
|
||||
*/
|
||||
update: function(what, details) {
|
||||
// Anything we want to forward to the UI
|
||||
this.emit("app-manager-update", what, details);
|
||||
},
|
||||
|
||||
reportError: function(l10nProperty, ...l10nArgs) {
|
||||
const win = Services.wm.getMostRecentWindow("devtools:webide");
|
||||
if (win) {
|
||||
win.UI.reportError(l10nProperty, ...l10nArgs);
|
||||
} else {
|
||||
let text;
|
||||
if (l10nArgs.length > 0) {
|
||||
text = Strings.formatStringFromName(l10nProperty, l10nArgs);
|
||||
} else {
|
||||
text = Strings.GetStringFromName(l10nProperty);
|
||||
}
|
||||
console.error(text);
|
||||
}
|
||||
},
|
||||
|
||||
onConnectionChanged: async function() {
|
||||
console.log("Connection status changed: " + this.connection.status);
|
||||
|
||||
if (this.connection.status == Connection.Status.DISCONNECTED) {
|
||||
this.selectedRuntime = null;
|
||||
}
|
||||
|
||||
if (!this.connected) {
|
||||
this._rootForm = null;
|
||||
this.deviceFront = null;
|
||||
this.preferenceFront = null;
|
||||
this.perfFront = null;
|
||||
} else {
|
||||
const response = await this.connection.client.mainRoot.rootForm;
|
||||
this._rootForm = response;
|
||||
try {
|
||||
this.deviceFront = await this.connection.client.mainRoot.getFront(
|
||||
"device"
|
||||
);
|
||||
this.preferenceFront = await this.connection.client.mainRoot.getFront(
|
||||
"preference"
|
||||
);
|
||||
this.perfFront = await this.connection.client.mainRoot.getFront("perf");
|
||||
this._recordRuntimeInfo();
|
||||
} catch (e) {
|
||||
// This may fail on <FF55 (because of lack of bug 1352157) but we will want to
|
||||
// emit runtime-global-actors in order to call checkRuntimeVersion and display
|
||||
// the compatibility popup.
|
||||
console.error(e);
|
||||
}
|
||||
this.update("runtime-global-actors");
|
||||
}
|
||||
|
||||
this.update("connection");
|
||||
},
|
||||
|
||||
get connected() {
|
||||
return (
|
||||
this.connection && this.connection.status == Connection.Status.CONNECTED
|
||||
);
|
||||
},
|
||||
|
||||
get apps() {
|
||||
if (this._appsFront) {
|
||||
return this._appsFront.apps;
|
||||
}
|
||||
return new Map();
|
||||
},
|
||||
|
||||
isProjectRunning: function() {
|
||||
if (
|
||||
this.selectedProject.type == "mainProcess" ||
|
||||
this.selectedProject.type == "tab"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const app = this._getProjectFront(this.selectedProject);
|
||||
return app && app.running;
|
||||
},
|
||||
|
||||
checkIfProjectIsRunning: function() {
|
||||
if (this.selectedProject) {
|
||||
if (this.isProjectRunning()) {
|
||||
this.update("project-started");
|
||||
} else {
|
||||
this.update("project-stopped");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
listTabs: function() {
|
||||
return this.tabStore.listTabs();
|
||||
},
|
||||
|
||||
onTabList: function() {
|
||||
this.update("runtime-targets", { type: "tabs" });
|
||||
},
|
||||
|
||||
// TODO: Merge this into TabProject as part of project-agnostic work
|
||||
onTabNavigate: function() {
|
||||
this.update("runtime-targets", { type: "tabs" });
|
||||
if (this.selectedProject.type !== "tab") {
|
||||
return;
|
||||
}
|
||||
const tab = (this.selectedProject.app = this.tabStore.selectedTab);
|
||||
const uri = NetUtil.newURI(tab.url);
|
||||
// Wanted to use nsIFaviconService here, but it only works for visited
|
||||
// tabs, so that's no help for any remote tabs. Maybe some favicon wizard
|
||||
// knows how to get high-res favicons easily, or we could offer actor
|
||||
// support for this (bug 1061654).
|
||||
tab.favicon = uri.prePath + "/favicon.ico";
|
||||
tab.name = tab.title || Strings.GetStringFromName("project_tab_loading");
|
||||
if (uri.scheme.startsWith("http")) {
|
||||
tab.name = uri.host + ": " + tab.name;
|
||||
}
|
||||
this.selectedProject.location = tab.url;
|
||||
this.selectedProject.name = tab.name;
|
||||
this.selectedProject.icon = tab.favicon;
|
||||
this.update("project-validated");
|
||||
},
|
||||
|
||||
onTabClosed: function() {
|
||||
if (this.selectedProject.type !== "tab") {
|
||||
return;
|
||||
}
|
||||
this.selectedProject = null;
|
||||
},
|
||||
|
||||
reloadTab: function() {
|
||||
if (this.selectedProject && this.selectedProject.type != "tab") {
|
||||
return Promise.reject("tried to reload non-tab project");
|
||||
}
|
||||
return this.getTarget().then(target => {
|
||||
target.reload();
|
||||
}, console.error);
|
||||
},
|
||||
|
||||
getTarget: function() {
|
||||
if (this.selectedProject.type == "mainProcess") {
|
||||
return this.connection.client.mainRoot.getMainProcess();
|
||||
}
|
||||
|
||||
if (this.selectedProject.type == "tab") {
|
||||
return this.tabStore.getTargetForTab();
|
||||
}
|
||||
|
||||
const app = this._getProjectFront(this.selectedProject);
|
||||
if (!app) {
|
||||
return Promise.reject("Can't find app front for selected project");
|
||||
}
|
||||
|
||||
return (async function() {
|
||||
// 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 target actors required to create its target.
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
try {
|
||||
return await app.getTarget();
|
||||
} catch (e) {}
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, 500);
|
||||
});
|
||||
}
|
||||
|
||||
AppManager.reportError(
|
||||
"error_cantConnectToApp",
|
||||
app.manifest.manifestURL
|
||||
);
|
||||
throw new Error("can't connect to app");
|
||||
})();
|
||||
},
|
||||
|
||||
getProjectManifestURL: function(project) {
|
||||
let manifest = null;
|
||||
if (project.type == "runtimeApp") {
|
||||
manifest = project.app.manifestURL;
|
||||
}
|
||||
|
||||
if (project.type == "hosted") {
|
||||
manifest = project.location;
|
||||
}
|
||||
|
||||
if (project.type == "packaged" && project.packagedAppOrigin) {
|
||||
manifest = "app://" + project.packagedAppOrigin + "/manifest.webapp";
|
||||
}
|
||||
|
||||
return manifest;
|
||||
},
|
||||
|
||||
_getProjectFront: function(project) {
|
||||
const manifest = this.getProjectManifestURL(project);
|
||||
if (manifest && this._appsFront) {
|
||||
return this._appsFront.apps.get(manifest);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_selectedProject: null,
|
||||
set selectedProject(project) {
|
||||
// A regular comparison doesn't work as we recreate a new object every time
|
||||
const prev = this._selectedProject;
|
||||
if (!prev && !project) {
|
||||
return;
|
||||
} else if (prev && project && prev.type === project.type) {
|
||||
const type = project.type;
|
||||
if (type === "runtimeApp") {
|
||||
if (prev.app.manifestURL === project.app.manifestURL) {
|
||||
return;
|
||||
}
|
||||
} else if (type === "tab") {
|
||||
if (prev.app.actor === project.app.actor) {
|
||||
return;
|
||||
}
|
||||
} else if (type === "packaged" || type === "hosted") {
|
||||
if (prev.location === project.location) {
|
||||
return;
|
||||
}
|
||||
} else if (type === "mainProcess") {
|
||||
return;
|
||||
} else {
|
||||
throw new Error("Unsupported project type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
this.update("before-project", {
|
||||
cancel: () => {
|
||||
cancelled = true;
|
||||
},
|
||||
});
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._selectedProject = project;
|
||||
|
||||
// Clear out tab store's selected state, if any
|
||||
this.tabStore.selectedTab = null;
|
||||
|
||||
if (project) {
|
||||
if (project.type == "packaged" || project.type == "hosted") {
|
||||
this.validateAndUpdateProject(project);
|
||||
}
|
||||
if (project.type == "tab") {
|
||||
this.tabStore.selectedTab = project.app;
|
||||
}
|
||||
}
|
||||
|
||||
this.update("project");
|
||||
this.checkIfProjectIsRunning();
|
||||
},
|
||||
get selectedProject() {
|
||||
return this._selectedProject;
|
||||
},
|
||||
|
||||
async removeSelectedProject() {
|
||||
const location = this.selectedProject.location;
|
||||
AppManager.selectedProject = null;
|
||||
// If the user cancels the removeProject operation, don't remove the project
|
||||
if (AppManager.selectedProject != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await AppProjects.remove(location);
|
||||
AppManager.update("project-removed");
|
||||
},
|
||||
|
||||
_selectedRuntime: null,
|
||||
set selectedRuntime(value) {
|
||||
this._selectedRuntime = value;
|
||||
if (
|
||||
!value &&
|
||||
this.selectedProject &&
|
||||
(this.selectedProject.type == "mainProcess" ||
|
||||
this.selectedProject.type == "runtimeApp" ||
|
||||
this.selectedProject.type == "tab")
|
||||
) {
|
||||
this.selectedProject = null;
|
||||
}
|
||||
this.update("runtime");
|
||||
},
|
||||
|
||||
get selectedRuntime() {
|
||||
return this._selectedRuntime;
|
||||
},
|
||||
|
||||
connectToRuntime: function(runtime) {
|
||||
if (this.connected && this.selectedRuntime === runtime) {
|
||||
// Already connected
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const deferred = new Promise((resolve, reject) => {
|
||||
this.disconnectRuntime().then(() => {
|
||||
this.selectedRuntime = runtime;
|
||||
|
||||
const onConnectedOrDisconnected = () => {
|
||||
this.connection.off(
|
||||
Connection.Events.CONNECTED,
|
||||
onConnectedOrDisconnected
|
||||
);
|
||||
this.connection.off(
|
||||
Connection.Events.DISCONNECTED,
|
||||
onConnectedOrDisconnected
|
||||
);
|
||||
if (this.connected) {
|
||||
resolve();
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
this.connection.on(
|
||||
Connection.Events.CONNECTED,
|
||||
onConnectedOrDisconnected
|
||||
);
|
||||
this.connection.on(
|
||||
Connection.Events.DISCONNECTED,
|
||||
onConnectedOrDisconnected
|
||||
);
|
||||
try {
|
||||
// Reset the connection's state to defaults
|
||||
this.connection.resetOptions();
|
||||
// Only watch for errors here. Final resolution occurs above, once
|
||||
// we've reached the CONNECTED state.
|
||||
this.selectedRuntime.connect(this.connection).catch(e => reject(e));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
|
||||
// Record connection result in telemetry
|
||||
const logResult = result => {
|
||||
this._telemetry
|
||||
.getHistogramById("DEVTOOLS_WEBIDE_CONNECTION_RESULT")
|
||||
.add(result);
|
||||
if (runtime.type) {
|
||||
this._telemetry
|
||||
.getHistogramById(`DEVTOOLS_WEBIDE_${runtime.type}_CONNECTION_RESULT`)
|
||||
.add(result);
|
||||
}
|
||||
};
|
||||
deferred.then(() => logResult(true), () => logResult(false));
|
||||
|
||||
// If successful, record connection time in telemetry
|
||||
deferred
|
||||
.then(() => {
|
||||
const timerId = "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS";
|
||||
this._telemetry.start(timerId, this);
|
||||
this.connection.once(Connection.Events.STATUS_CHANGED, () => {
|
||||
this._telemetry.finish(timerId, this);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// Empty rejection handler to silence uncaught rejection warnings
|
||||
// |connectToRuntime| caller should listen for rejections.
|
||||
// Bug 1121100 may find a better way to silence these.
|
||||
});
|
||||
|
||||
return deferred;
|
||||
},
|
||||
|
||||
async _recordRuntimeInfo() {
|
||||
if (!this.connected) {
|
||||
return;
|
||||
}
|
||||
const runtime = this.selectedRuntime;
|
||||
this._telemetry
|
||||
.getKeyedHistogramById("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE")
|
||||
.add(runtime.type || "UNKNOWN", true);
|
||||
this._telemetry
|
||||
.getKeyedHistogramById("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID")
|
||||
.add(runtime.id || "unknown", true);
|
||||
if (!this.deviceFront) {
|
||||
this.update("runtime-telemetry");
|
||||
return;
|
||||
}
|
||||
const d = await this.deviceFront.getDescription();
|
||||
this._telemetry
|
||||
.getKeyedHistogramById("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PROCESSOR")
|
||||
.add(d.processor, true);
|
||||
this._telemetry
|
||||
.getKeyedHistogramById("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_OS")
|
||||
.add(d.os, true);
|
||||
this._telemetry
|
||||
.getKeyedHistogramById(
|
||||
"DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PLATFORM_VERSION"
|
||||
)
|
||||
.add(d.platformversion, true);
|
||||
this._telemetry
|
||||
.getKeyedHistogramById("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_APP_TYPE")
|
||||
.add(d.apptype, true);
|
||||
this._telemetry
|
||||
.getKeyedHistogramById("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_VERSION")
|
||||
.add(d.version, true);
|
||||
this.update("runtime-telemetry");
|
||||
},
|
||||
|
||||
isMainProcessDebuggable: function() {
|
||||
// Fx <39 exposes chrome target actors on RootActor
|
||||
// Fx >=39 exposes a dedicated actor via getProcess request
|
||||
return (
|
||||
(this.connection.client &&
|
||||
this.connection.client.mainRoot &&
|
||||
this.connection.client.mainRoot.traits.allowChromeProcess) ||
|
||||
(this._rootForm && this._rootForm.consoleActor)
|
||||
);
|
||||
},
|
||||
|
||||
disconnectRuntime: function() {
|
||||
if (!this.connected) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
this.connection.once(Connection.Events.DISCONNECTED, () => resolve());
|
||||
this.connection.disconnect();
|
||||
});
|
||||
},
|
||||
|
||||
launchRuntimeApp: function() {
|
||||
if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
|
||||
return Promise.reject("attempting to launch a non-runtime app");
|
||||
}
|
||||
const app = this._getProjectFront(this.selectedProject);
|
||||
return app.launch();
|
||||
},
|
||||
|
||||
launchOrReloadRuntimeApp: function() {
|
||||
if (this.selectedProject && this.selectedProject.type != "runtimeApp") {
|
||||
return Promise.reject("attempting to launch / reload a non-runtime app");
|
||||
}
|
||||
const app = this._getProjectFront(this.selectedProject);
|
||||
if (!app.running) {
|
||||
return app.launch();
|
||||
}
|
||||
return app.reload();
|
||||
},
|
||||
|
||||
runtimeCanHandleApps: function() {
|
||||
return !!this._appsFront;
|
||||
},
|
||||
|
||||
installAndRunProject: function() {
|
||||
const project = this.selectedProject;
|
||||
|
||||
if (!project || (project.type != "packaged" && project.type != "hosted")) {
|
||||
console.error("Can't install project. Unknown type of project.");
|
||||
return Promise.reject("Can't install");
|
||||
}
|
||||
|
||||
if (!this._rootForm) {
|
||||
this.reportError("error_cantInstallNotFullyConnected");
|
||||
return Promise.reject("Can't install");
|
||||
}
|
||||
|
||||
if (!this._appsFront) {
|
||||
console.error("Runtime doesn't have a webappsActor");
|
||||
return Promise.reject("Can't install");
|
||||
}
|
||||
|
||||
return (async function() {
|
||||
const self = AppManager;
|
||||
|
||||
// Validate project
|
||||
await self.validateAndUpdateProject(project);
|
||||
|
||||
if (project.errorsCount > 0) {
|
||||
self.reportError("error_cantInstallValidationErrors");
|
||||
return;
|
||||
}
|
||||
|
||||
if (project.type != "packaged" && project.type != "hosted") {
|
||||
return Promise.reject("Don't know how to install project");
|
||||
}
|
||||
|
||||
let response;
|
||||
if (project.type == "packaged") {
|
||||
const packageDir = project.location;
|
||||
console.log("Installing app from " + packageDir);
|
||||
|
||||
response = await self._appsFront.installPackaged(
|
||||
packageDir,
|
||||
project.packagedAppOrigin
|
||||
);
|
||||
|
||||
// If the packaged app specified a custom origin override,
|
||||
// we need to update the local project origin
|
||||
project.packagedAppOrigin = response.appId;
|
||||
// And ensure the indexed db on disk is also updated
|
||||
AppProjects.update(project);
|
||||
}
|
||||
|
||||
if (project.type == "hosted") {
|
||||
const manifestURLObject = Services.io.newURI(project.location);
|
||||
const origin = Services.io.newURI(manifestURLObject.prePath);
|
||||
const appId = origin.host;
|
||||
const metadata = {
|
||||
origin: origin.spec,
|
||||
manifestURL: project.location,
|
||||
};
|
||||
response = await self._appsFront.installHosted(
|
||||
appId,
|
||||
metadata,
|
||||
project.manifest
|
||||
);
|
||||
}
|
||||
|
||||
// Addons don't have any document to load (yet?)
|
||||
// So that there is no need to run them, installing is enough
|
||||
if (
|
||||
project.manifest.manifest_version ||
|
||||
project.manifest.role === "addon"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { app } = response;
|
||||
if (!app.running) {
|
||||
const deferred = new Promise(resolve => {
|
||||
self.on("app-manager-update", function onUpdate(what) {
|
||||
if (what == "project-started") {
|
||||
self.off("app-manager-update", onUpdate);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
await app.launch();
|
||||
await deferred;
|
||||
} else {
|
||||
await app.reload();
|
||||
}
|
||||
})();
|
||||
},
|
||||
|
||||
stopRunningApp: function() {
|
||||
const app = this._getProjectFront(this.selectedProject);
|
||||
return app.close();
|
||||
},
|
||||
|
||||
/* PROJECT VALIDATION */
|
||||
|
||||
validateAndUpdateProject: function(project) {
|
||||
if (!project) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
return (async function() {
|
||||
const packageDir = project.location;
|
||||
const validation = new AppValidator({
|
||||
type: project.type,
|
||||
// Build process may place the manifest in a non-root directory
|
||||
location: packageDir,
|
||||
});
|
||||
|
||||
await validation.validate();
|
||||
|
||||
if (validation.manifest) {
|
||||
const manifest = validation.manifest;
|
||||
let iconPath;
|
||||
if (manifest.icons) {
|
||||
const size = Object.keys(manifest.icons).sort((a, b) => b - a)[0];
|
||||
if (size) {
|
||||
iconPath = manifest.icons[size];
|
||||
}
|
||||
}
|
||||
if (!iconPath) {
|
||||
project.icon = AppManager.DEFAULT_PROJECT_ICON;
|
||||
} else if (project.type == "hosted") {
|
||||
const manifestURL = Services.io.newURI(project.location);
|
||||
const origin = Services.io.newURI(manifestURL.prePath);
|
||||
project.icon = Services.io.newURI(iconPath, null, origin).spec;
|
||||
} else if (project.type == "packaged") {
|
||||
const projectFolder = FileUtils.File(packageDir);
|
||||
const folderURI = Services.io.newFileURI(projectFolder).spec;
|
||||
project.icon = folderURI + iconPath.replace(/^\/|\\/, "");
|
||||
}
|
||||
project.manifest = validation.manifest;
|
||||
|
||||
if ("name" in project.manifest) {
|
||||
project.name = project.manifest.name;
|
||||
} else {
|
||||
project.name = AppManager.DEFAULT_PROJECT_NAME;
|
||||
}
|
||||
} else {
|
||||
project.manifest = null;
|
||||
project.icon = AppManager.DEFAULT_PROJECT_ICON;
|
||||
project.name = AppManager.DEFAULT_PROJECT_NAME;
|
||||
}
|
||||
|
||||
project.validationStatus = "valid";
|
||||
|
||||
if (validation.warnings.length > 0) {
|
||||
project.warningsCount = validation.warnings.length;
|
||||
project.warnings = validation.warnings;
|
||||
project.validationStatus = "warning";
|
||||
} else {
|
||||
project.warnings = "";
|
||||
project.warningsCount = 0;
|
||||
}
|
||||
|
||||
if (validation.errors.length > 0) {
|
||||
project.errorsCount = validation.errors.length;
|
||||
project.errors = validation.errors;
|
||||
project.validationStatus = "error";
|
||||
} else {
|
||||
project.errors = "";
|
||||
project.errorsCount = 0;
|
||||
}
|
||||
|
||||
if (project.warningsCount && project.errorsCount) {
|
||||
project.validationStatus = "error warning";
|
||||
}
|
||||
|
||||
if (
|
||||
project.type === "hosted" &&
|
||||
project.location !== validation.manifestURL
|
||||
) {
|
||||
await AppProjects.updateLocation(project, validation.manifestURL);
|
||||
} else if (AppProjects.get(project.location)) {
|
||||
await AppProjects.update(project);
|
||||
}
|
||||
|
||||
if (AppManager.selectedProject === project) {
|
||||
AppManager.update("project-validated");
|
||||
}
|
||||
})();
|
||||
},
|
||||
|
||||
/* RUNTIME LIST */
|
||||
|
||||
_clearRuntimeList: function() {
|
||||
this.runtimeList = {
|
||||
usb: [],
|
||||
wifi: [],
|
||||
other: [],
|
||||
};
|
||||
},
|
||||
|
||||
_rebuildRuntimeList: function() {
|
||||
const runtimes = RuntimeScanners.listRuntimes();
|
||||
this._clearRuntimeList();
|
||||
|
||||
// Reorganize runtimes by type
|
||||
for (const runtime of runtimes) {
|
||||
switch (runtime.type) {
|
||||
case RuntimeTypes.USB:
|
||||
this.runtimeList.usb.push(runtime);
|
||||
break;
|
||||
case RuntimeTypes.WIFI:
|
||||
this.runtimeList.wifi.push(runtime);
|
||||
break;
|
||||
default:
|
||||
this.runtimeList.other.push(runtime);
|
||||
}
|
||||
}
|
||||
|
||||
this.update("runtime-details");
|
||||
this.update("runtime-list");
|
||||
},
|
||||
|
||||
/* MANIFEST UTILS */
|
||||
|
||||
writeManifest: function(project) {
|
||||
if (project.type != "packaged") {
|
||||
return Promise.reject("Not a packaged app");
|
||||
}
|
||||
|
||||
if (!project.manifest) {
|
||||
project.manifest = {};
|
||||
}
|
||||
|
||||
const folder = project.location;
|
||||
const manifestPath = OS.Path.join(folder, "manifest.webapp");
|
||||
const text = JSON.stringify(project.manifest, null, 2);
|
||||
const encoder = new TextEncoder();
|
||||
const array = encoder.encode(text);
|
||||
return OS.File.writeAtomic(manifestPath, array, {
|
||||
tmpPath: manifestPath + ".tmp",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
EventEmitter.decorate(AppManager);
|
|
@ -1,242 +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 { Cc, Ci, Cr } = require("chrome");
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(
|
||||
Ci.nsIUUIDGenerator
|
||||
);
|
||||
const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
/**
|
||||
* IndexedDB wrapper that just save project objects
|
||||
*
|
||||
* The only constraint is that project objects have to have
|
||||
* a unique `location` object.
|
||||
*/
|
||||
|
||||
const IDB = {
|
||||
_db: null,
|
||||
databaseName: "AppProjects",
|
||||
|
||||
open: function() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(IDB.databaseName, 5);
|
||||
request.onerror = function(event) {
|
||||
reject(
|
||||
"Unable to open AppProjects indexedDB: " +
|
||||
this.error.name +
|
||||
" - " +
|
||||
this.error.message
|
||||
);
|
||||
};
|
||||
request.onupgradeneeded = function(event) {
|
||||
const db = event.target.result;
|
||||
db.createObjectStore("projects", { keyPath: "location" });
|
||||
};
|
||||
|
||||
request.onsuccess = function() {
|
||||
const db = (IDB._db = request.result);
|
||||
const objectStore = db.transaction("projects").objectStore("projects");
|
||||
const projects = [];
|
||||
const toRemove = [];
|
||||
objectStore.openCursor().onsuccess = function(event) {
|
||||
const cursor = event.target.result;
|
||||
if (cursor) {
|
||||
if (cursor.value.location) {
|
||||
// We need to make sure this object has a `.location` property.
|
||||
// The UI depends on this property.
|
||||
// This should not be needed as we make sure to register valid
|
||||
// projects, but in the past (before bug 924568), we might have
|
||||
// registered invalid objects.
|
||||
|
||||
// We also want to make sure the location is valid.
|
||||
// If the location doesn't exist, we remove the project.
|
||||
|
||||
try {
|
||||
const file = FileUtils.File(cursor.value.location);
|
||||
if (file.exists()) {
|
||||
projects.push(cursor.value);
|
||||
} else {
|
||||
toRemove.push(cursor.value.location);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_FILE_UNRECOGNIZED_PATH) {
|
||||
// A URL
|
||||
projects.push(cursor.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.continue();
|
||||
} else {
|
||||
const removePromises = [];
|
||||
for (const location of toRemove) {
|
||||
removePromises.push(IDB.remove(location));
|
||||
}
|
||||
Promise.all(removePromises).then(() => {
|
||||
resolve(projects);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
add: function(project) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!project.location) {
|
||||
// We need to make sure this object has a `.location` property.
|
||||
reject("Missing location property on project object.");
|
||||
} else {
|
||||
const transaction = IDB._db.transaction(["projects"], "readwrite");
|
||||
const objectStore = transaction.objectStore("projects");
|
||||
const request = objectStore.add(project);
|
||||
request.onerror = function(event) {
|
||||
reject(
|
||||
"Unable to add project to the AppProjects indexedDB: " +
|
||||
this.error.name +
|
||||
" - " +
|
||||
this.error.message
|
||||
);
|
||||
};
|
||||
request.onsuccess = function() {
|
||||
resolve();
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
update: function(project) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = IDB._db.transaction(["projects"], "readwrite");
|
||||
const objectStore = transaction.objectStore("projects");
|
||||
const request = objectStore.put(project);
|
||||
request.onerror = function(event) {
|
||||
reject(
|
||||
"Unable to update project to the AppProjects indexedDB: " +
|
||||
this.error.name +
|
||||
" - " +
|
||||
this.error.message
|
||||
);
|
||||
};
|
||||
request.onsuccess = function() {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
remove: function(location) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = IDB._db
|
||||
.transaction(["projects"], "readwrite")
|
||||
.objectStore("projects")
|
||||
.delete(location);
|
||||
request.onsuccess = function(event) {
|
||||
resolve();
|
||||
};
|
||||
request.onerror = function() {
|
||||
reject(
|
||||
"Unable to delete project to the AppProjects indexedDB: " +
|
||||
this.error.name +
|
||||
" - " +
|
||||
this.error.message
|
||||
);
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
var loadDeferred = IDB.open().then(function(projects) {
|
||||
AppProjects.projects = projects;
|
||||
AppProjects.emit("ready", projects);
|
||||
});
|
||||
|
||||
const AppProjects = {
|
||||
load: function() {
|
||||
return loadDeferred;
|
||||
},
|
||||
|
||||
addPackaged: function(folder) {
|
||||
const file = FileUtils.File(folder.path);
|
||||
if (!file.exists()) {
|
||||
return Promise.reject("path doesn't exist");
|
||||
}
|
||||
const existingProject = this.get(folder.path);
|
||||
if (existingProject) {
|
||||
return Promise.reject("Already added");
|
||||
}
|
||||
const project = {
|
||||
type: "packaged",
|
||||
location: folder.path,
|
||||
// We need a unique id, that is the app origin,
|
||||
// in order to identify the app when being installed on the device.
|
||||
// The packaged app local path is a valid id, but only on the client.
|
||||
// This origin will be used to generate the true id of an app:
|
||||
// its manifest URL.
|
||||
// If the app ends up specifying an explicit origin in its manifest,
|
||||
// we will override this random UUID on app install.
|
||||
packagedAppOrigin: generateUUID()
|
||||
.toString()
|
||||
.slice(1, -1),
|
||||
};
|
||||
return IDB.add(project).then(() => {
|
||||
this.projects.push(project);
|
||||
return project;
|
||||
});
|
||||
},
|
||||
|
||||
addHosted: function(manifestURL) {
|
||||
const existingProject = this.get(manifestURL);
|
||||
if (existingProject) {
|
||||
return Promise.reject("Already added");
|
||||
}
|
||||
const project = {
|
||||
type: "hosted",
|
||||
location: manifestURL,
|
||||
};
|
||||
return IDB.add(project).then(() => {
|
||||
this.projects.push(project);
|
||||
return project;
|
||||
});
|
||||
},
|
||||
|
||||
update: function(project) {
|
||||
return IDB.update(project);
|
||||
},
|
||||
|
||||
updateLocation: function(project, newLocation) {
|
||||
return IDB.remove(project.location).then(() => {
|
||||
project.location = newLocation;
|
||||
return IDB.add(project);
|
||||
});
|
||||
},
|
||||
|
||||
remove: function(location) {
|
||||
return IDB.remove(location).then(() => {
|
||||
for (let i = 0; i < this.projects.length; i++) {
|
||||
if (this.projects[i].location == location) {
|
||||
this.projects.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Error("Unable to find project in AppProjects store");
|
||||
});
|
||||
},
|
||||
|
||||
get: function(location) {
|
||||
for (let i = 0; i < this.projects.length; i++) {
|
||||
if (this.projects[i].location == location) {
|
||||
return this.projects[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
projects: [],
|
||||
};
|
||||
|
||||
EventEmitter.decorate(AppProjects);
|
||||
|
||||
exports.AppProjects = AppProjects;
|
|
@ -1,345 +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";
|
||||
|
||||
var { Ci } = require("chrome");
|
||||
|
||||
const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
|
||||
const Services = require("Services");
|
||||
var strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/app-manager.properties"
|
||||
);
|
||||
|
||||
function AppValidator({ type, location }) {
|
||||
this.type = type;
|
||||
this.location = location;
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
}
|
||||
|
||||
AppValidator.prototype.error = function(message) {
|
||||
this.errors.push(message);
|
||||
};
|
||||
|
||||
AppValidator.prototype.warning = function(message) {
|
||||
this.warnings.push(message);
|
||||
};
|
||||
|
||||
AppValidator.prototype._getPackagedManifestFile = function() {
|
||||
const manifestFile = FileUtils.File(this.location);
|
||||
if (!manifestFile.exists()) {
|
||||
this.error(strings.GetStringFromName("validator.nonExistingFolder"));
|
||||
return null;
|
||||
}
|
||||
if (!manifestFile.isDirectory()) {
|
||||
this.error(strings.GetStringFromName("validator.expectProjectFolder"));
|
||||
return null;
|
||||
}
|
||||
|
||||
const appManifestFile = manifestFile.clone();
|
||||
appManifestFile.append("manifest.webapp");
|
||||
|
||||
const jsonManifestFile = manifestFile.clone();
|
||||
jsonManifestFile.append("manifest.json");
|
||||
|
||||
const hasAppManifest = appManifestFile.exists() && appManifestFile.isFile();
|
||||
const hasJsonManifest =
|
||||
jsonManifestFile.exists() && jsonManifestFile.isFile();
|
||||
|
||||
if (!hasAppManifest && !hasJsonManifest) {
|
||||
this.error(strings.GetStringFromName("validator.noManifestFile"));
|
||||
return null;
|
||||
}
|
||||
|
||||
return hasAppManifest ? appManifestFile : jsonManifestFile;
|
||||
};
|
||||
|
||||
AppValidator.prototype._getPackagedManifestURL = function() {
|
||||
const manifestFile = this._getPackagedManifestFile();
|
||||
if (!manifestFile) {
|
||||
return null;
|
||||
}
|
||||
return Services.io.newFileURI(manifestFile).spec;
|
||||
};
|
||||
|
||||
AppValidator.checkManifest = function(manifestURL) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let error;
|
||||
|
||||
const req = new XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
|
||||
try {
|
||||
req.open("GET", manifestURL, true);
|
||||
req.channel.loadFlags |=
|
||||
Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.invalidManifestURL", [
|
||||
manifestURL,
|
||||
]);
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
req.onload = function() {
|
||||
let manifest = null;
|
||||
try {
|
||||
manifest = JSON.parse(req.responseText);
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.invalidManifestJSON", [
|
||||
e,
|
||||
manifestURL,
|
||||
]);
|
||||
reject(error);
|
||||
}
|
||||
|
||||
resolve({ manifest, manifestURL });
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
error = strings.formatStringFromName("validator.noAccessManifestURL", [
|
||||
req.statusText,
|
||||
manifestURL,
|
||||
]);
|
||||
reject(error);
|
||||
};
|
||||
|
||||
try {
|
||||
req.send(null);
|
||||
} catch (e) {
|
||||
error = strings.formatStringFromName("validator.noAccessManifestURL", [
|
||||
e,
|
||||
manifestURL,
|
||||
]);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.findManifestAtOrigin = function(manifestURL) {
|
||||
const fixedManifest =
|
||||
Services.io.newURI(manifestURL).prePath + "/manifest.webapp";
|
||||
return AppValidator.checkManifest(fixedManifest);
|
||||
};
|
||||
|
||||
AppValidator.findManifestPath = function(manifestURL) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (manifestURL.endsWith("manifest.webapp")) {
|
||||
reject();
|
||||
} else {
|
||||
const fixedManifest = manifestURL + "/manifest.webapp";
|
||||
resolve(AppValidator.checkManifest(fixedManifest));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.checkAlternateManifest = function(manifestURL) {
|
||||
return (async function() {
|
||||
let result;
|
||||
try {
|
||||
result = await AppValidator.findManifestPath(manifestURL);
|
||||
} catch (e) {
|
||||
result = await AppValidator.findManifestAtOrigin(manifestURL);
|
||||
}
|
||||
|
||||
return result;
|
||||
})();
|
||||
};
|
||||
|
||||
AppValidator.prototype._fetchManifest = function(manifestURL) {
|
||||
return new Promise(resolve => {
|
||||
this.manifestURL = manifestURL;
|
||||
|
||||
AppValidator.checkManifest(manifestURL).then(
|
||||
({ manifest, manifestURL }) => {
|
||||
resolve(manifest);
|
||||
},
|
||||
error => {
|
||||
AppValidator.checkAlternateManifest(manifestURL).then(
|
||||
({ manifest, manifestURL }) => {
|
||||
this.manifestURL = manifestURL;
|
||||
resolve(manifest);
|
||||
},
|
||||
() => {
|
||||
this.error(error);
|
||||
resolve(null);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.prototype._getManifest = function() {
|
||||
let manifestURL;
|
||||
if (this.type == "packaged") {
|
||||
manifestURL = this._getPackagedManifestURL();
|
||||
if (!manifestURL) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
} else if (this.type == "hosted") {
|
||||
manifestURL = this.location;
|
||||
try {
|
||||
Services.io.newURI(manifestURL);
|
||||
} catch (e) {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.invalidHostedManifestURL", [
|
||||
manifestURL,
|
||||
e.message,
|
||||
])
|
||||
);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
} else {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.invalidProjectType", [this.type])
|
||||
);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return this._fetchManifest(manifestURL);
|
||||
};
|
||||
|
||||
AppValidator.prototype.validateManifest = function(manifest) {
|
||||
if (!manifest.name) {
|
||||
this.error(strings.GetStringFromName("validator.missNameManifestProperty"));
|
||||
}
|
||||
|
||||
if (!manifest.icons || Object.keys(manifest.icons).length === 0) {
|
||||
this.warning(
|
||||
strings.GetStringFromName("validator.missIconsManifestProperty")
|
||||
);
|
||||
} else if (!manifest.icons["128"]) {
|
||||
this.warning(strings.GetStringFromName("validator.missIconMarketplace2"));
|
||||
}
|
||||
};
|
||||
|
||||
AppValidator.prototype._getOriginURL = function() {
|
||||
if (this.type == "packaged") {
|
||||
const manifestURL = Services.io.newURI(this.manifestURL);
|
||||
return Services.io.newURI(".", null, manifestURL).spec;
|
||||
} else if (this.type == "hosted") {
|
||||
return Services.io.newURI(this.location).prePath;
|
||||
}
|
||||
};
|
||||
|
||||
AppValidator.prototype.validateLaunchPath = function(manifest) {
|
||||
return new Promise(resolve => {
|
||||
// The launch_path field has to start with a `/`
|
||||
if (manifest.launch_path && manifest.launch_path[0] !== "/") {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [
|
||||
manifest.launch_path,
|
||||
])
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
const origin = this._getOriginURL();
|
||||
let path;
|
||||
if (this.type == "packaged") {
|
||||
path = "." + (manifest.launch_path || "/index.html");
|
||||
} else if (this.type == "hosted") {
|
||||
path = manifest.launch_path || "/";
|
||||
}
|
||||
let indexURL;
|
||||
try {
|
||||
indexURL = Services.io.newURI(path, null, Services.io.newURI(origin))
|
||||
.spec;
|
||||
} catch (e) {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.accessFailedLaunchPath", [
|
||||
origin + path,
|
||||
])
|
||||
);
|
||||
return resolve();
|
||||
}
|
||||
|
||||
const req = new XMLHttpRequest();
|
||||
req.overrideMimeType("text/plain");
|
||||
try {
|
||||
req.open("HEAD", indexURL, true);
|
||||
req.channel.loadFlags |=
|
||||
Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
||||
} catch (e) {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.accessFailedLaunchPath", [
|
||||
indexURL,
|
||||
])
|
||||
);
|
||||
return resolve();
|
||||
}
|
||||
req.onload = () => {
|
||||
if (req.status >= 400) {
|
||||
this.error(
|
||||
strings.formatStringFromName(
|
||||
"validator.accessFailedLaunchPathBadHttpCode",
|
||||
[indexURL, req.status]
|
||||
)
|
||||
);
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
req.onerror = () => {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.accessFailedLaunchPath", [
|
||||
indexURL,
|
||||
])
|
||||
);
|
||||
resolve();
|
||||
};
|
||||
|
||||
try {
|
||||
req.send(null);
|
||||
} catch (e) {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.accessFailedLaunchPath", [
|
||||
indexURL,
|
||||
])
|
||||
);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
AppValidator.prototype.validateType = function(manifest) {
|
||||
const appType = manifest.type || "web";
|
||||
if (!["web", "privileged", "certified"].includes(appType)) {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.invalidAppType", [appType])
|
||||
);
|
||||
} else if (
|
||||
this.type == "hosted" &&
|
||||
["certified", "privileged"].includes(appType)
|
||||
) {
|
||||
this.error(
|
||||
strings.formatStringFromName("validator.invalidHostedPriviledges", [
|
||||
appType,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
// certified app are not fully supported on the simulator
|
||||
if (appType === "certified") {
|
||||
this.warning(strings.GetStringFromName("validator.noCertifiedSupport"));
|
||||
}
|
||||
};
|
||||
|
||||
AppValidator.prototype.validate = function() {
|
||||
this.errors = [];
|
||||
this.warnings = [];
|
||||
return this._getManifest().then(manifest => {
|
||||
if (manifest) {
|
||||
this.manifest = manifest;
|
||||
|
||||
// Skip validations for add-ons
|
||||
if (manifest.role === "addon" || manifest.manifest_version) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.validateManifest(manifest);
|
||||
this.validateType(manifest);
|
||||
return this.validateLaunchPath(manifest);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.AppValidator = AppValidator;
|
|
@ -1,395 +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 EventEmitter = require("devtools/shared/event-emitter");
|
||||
const Services = require("Services");
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/webide.properties"
|
||||
);
|
||||
|
||||
var ConfigView;
|
||||
|
||||
module.exports = ConfigView = function(window) {
|
||||
EventEmitter.decorate(this);
|
||||
this._doc = window.document;
|
||||
this._keys = [];
|
||||
return this;
|
||||
};
|
||||
|
||||
ConfigView.prototype = {
|
||||
_renderByType: function(input, name, value, customType) {
|
||||
value = customType || typeof value;
|
||||
|
||||
switch (value) {
|
||||
case "boolean":
|
||||
input.setAttribute("data-type", "boolean");
|
||||
input.setAttribute("type", "checkbox");
|
||||
break;
|
||||
case "number":
|
||||
input.setAttribute("data-type", "number");
|
||||
input.setAttribute("type", "number");
|
||||
break;
|
||||
case "object":
|
||||
input.setAttribute("data-type", "object");
|
||||
input.setAttribute("type", "text");
|
||||
break;
|
||||
default:
|
||||
input.setAttribute("data-type", "string");
|
||||
input.setAttribute("type", "text");
|
||||
break;
|
||||
}
|
||||
return input;
|
||||
},
|
||||
|
||||
set front(front) {
|
||||
this._front = front;
|
||||
},
|
||||
|
||||
set keys(keys) {
|
||||
this._keys = keys;
|
||||
},
|
||||
|
||||
get keys() {
|
||||
return this._keys;
|
||||
},
|
||||
|
||||
set kind(kind) {
|
||||
this._kind = kind;
|
||||
},
|
||||
|
||||
set includeTypeName(include) {
|
||||
this._includeTypeName = include;
|
||||
},
|
||||
|
||||
search: function(event) {
|
||||
if (event.target.value.length) {
|
||||
const stringMatch = new RegExp(event.target.value, "i");
|
||||
|
||||
for (let i = 0; i < this._keys.length; i++) {
|
||||
const key = this._keys[i];
|
||||
const row = this._doc.getElementById("row-" + key);
|
||||
if (key.match(stringMatch)) {
|
||||
row.classList.remove("hide");
|
||||
} else if (row) {
|
||||
row.classList.add("hide");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const trs = this._doc
|
||||
.getElementById("device-fields")
|
||||
.querySelectorAll("tr");
|
||||
|
||||
for (let i = 0; i < trs.length; i++) {
|
||||
trs[i].classList.remove("hide");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
generateDisplay: function(json) {
|
||||
const deviceItems = Object.keys(json);
|
||||
deviceItems.sort();
|
||||
this.keys = deviceItems;
|
||||
for (let i = 0; i < this.keys.length; i++) {
|
||||
const key = this.keys[i];
|
||||
this.generateField(key, json[key].value, json[key].hasUserValue);
|
||||
}
|
||||
},
|
||||
|
||||
generateField: function(name, value, hasUserValue, customType, newRow) {
|
||||
const table = this._doc.querySelector("table");
|
||||
const sResetDefault = Strings.GetStringFromName("device_reset_default");
|
||||
|
||||
if (!this._keys.includes(name)) {
|
||||
this._keys.push(name);
|
||||
}
|
||||
|
||||
let input = this._doc.createElement("input");
|
||||
const tr = this._doc.createElement("tr");
|
||||
tr.setAttribute("id", "row-" + name);
|
||||
tr.classList.add("edit-row");
|
||||
let td = this._doc.createElement("td");
|
||||
td.classList.add("field-name");
|
||||
td.textContent = name;
|
||||
tr.appendChild(td);
|
||||
td = this._doc.createElement("td");
|
||||
input.classList.add("editable");
|
||||
input.setAttribute("id", name);
|
||||
input = this._renderByType(input, name, value, customType);
|
||||
|
||||
if (customType === "boolean" || input.type === "checkbox") {
|
||||
input.checked = value;
|
||||
} else {
|
||||
if (typeof value === "object") {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
input.value = value;
|
||||
}
|
||||
|
||||
if (!(this._includeTypeName || isNaN(parseInt(value, 10)))) {
|
||||
input.type = "number";
|
||||
}
|
||||
|
||||
td.appendChild(input);
|
||||
tr.appendChild(td);
|
||||
td = this._doc.createElement("td");
|
||||
td.setAttribute("id", "td-" + name);
|
||||
|
||||
const button = this._doc.createElement("button");
|
||||
button.setAttribute("data-id", name);
|
||||
button.setAttribute("id", "btn-" + name);
|
||||
button.classList.add("reset");
|
||||
button.textContent = sResetDefault;
|
||||
td.appendChild(button);
|
||||
|
||||
if (!hasUserValue) {
|
||||
button.classList.add("hide");
|
||||
}
|
||||
|
||||
tr.appendChild(td);
|
||||
|
||||
// If this is a new field, add it to the top of the table.
|
||||
if (newRow) {
|
||||
const existing = table.querySelector("#" + name);
|
||||
|
||||
if (!existing) {
|
||||
table.insertBefore(tr, newRow);
|
||||
} else {
|
||||
existing.value = value;
|
||||
}
|
||||
} else {
|
||||
table.appendChild(tr);
|
||||
}
|
||||
},
|
||||
|
||||
resetTable: function() {
|
||||
const table = this._doc.querySelector("table");
|
||||
const trs = table.querySelectorAll("tr:not(#add-custom-field)");
|
||||
|
||||
for (let i = 0; i < trs.length; i++) {
|
||||
table.removeChild(trs[i]);
|
||||
}
|
||||
|
||||
return table;
|
||||
},
|
||||
|
||||
_getCallType: function(type, name) {
|
||||
let frontName = "get";
|
||||
|
||||
if (this._includeTypeName) {
|
||||
frontName += type;
|
||||
}
|
||||
|
||||
return this._front[frontName + this._kind](name);
|
||||
},
|
||||
|
||||
_setCallType: function(type, name, value) {
|
||||
let frontName = "set";
|
||||
|
||||
if (this._includeTypeName) {
|
||||
frontName += type;
|
||||
}
|
||||
|
||||
return this._front[frontName + this._kind](name, value);
|
||||
},
|
||||
|
||||
_saveByType: function(options) {
|
||||
const fieldName = options.id;
|
||||
const inputType = options.type;
|
||||
let value = options.value;
|
||||
const input = this._doc.getElementById(fieldName);
|
||||
|
||||
switch (inputType) {
|
||||
case "boolean":
|
||||
this._setCallType("Bool", fieldName, input.checked);
|
||||
break;
|
||||
case "number":
|
||||
this._setCallType("Int", fieldName, value);
|
||||
break;
|
||||
case "object":
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (e) {}
|
||||
this._setCallType("Object", fieldName, value);
|
||||
break;
|
||||
default:
|
||||
this._setCallType("Char", fieldName, value);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
updateField: function(event) {
|
||||
if (event.target) {
|
||||
const inputType = event.target.getAttribute("data-type");
|
||||
let inputValue = event.target.checked || event.target.value;
|
||||
|
||||
if (
|
||||
event.target.nodeName == "input" &&
|
||||
event.target.validity.valid &&
|
||||
event.target.classList.contains("editable")
|
||||
) {
|
||||
const id = event.target.id;
|
||||
if (inputType === "boolean") {
|
||||
if (event.target.checked) {
|
||||
inputValue = true;
|
||||
} else {
|
||||
inputValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
this._saveByType({
|
||||
id: id,
|
||||
type: inputType,
|
||||
value: inputValue,
|
||||
});
|
||||
this._doc.getElementById("btn-" + id).classList.remove("hide");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_resetToDefault: function(name, input, button) {
|
||||
this._front["clearUser" + this._kind](name);
|
||||
const dataType = input.getAttribute("data-type");
|
||||
const tr = this._doc.getElementById("row-" + name);
|
||||
|
||||
switch (dataType) {
|
||||
case "boolean":
|
||||
this._defaultField = this._getCallType("Bool", name);
|
||||
this._defaultField.then(
|
||||
boolean => {
|
||||
input.checked = boolean;
|
||||
},
|
||||
() => {
|
||||
input.checked = false;
|
||||
tr.remove();
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "number":
|
||||
this._defaultField = this._getCallType("Int", name);
|
||||
this._defaultField.then(
|
||||
number => {
|
||||
input.value = number;
|
||||
},
|
||||
() => {
|
||||
tr.remove();
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "object":
|
||||
this._defaultField = this._getCallType("Object", name);
|
||||
this._defaultField.then(
|
||||
object => {
|
||||
input.value = JSON.stringify(object);
|
||||
},
|
||||
() => {
|
||||
tr.remove();
|
||||
}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
this._defaultField = this._getCallType("Char", name);
|
||||
this._defaultField.then(
|
||||
string => {
|
||||
input.value = string;
|
||||
},
|
||||
() => {
|
||||
tr.remove();
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
button.classList.add("hide");
|
||||
},
|
||||
|
||||
checkReset: function(event) {
|
||||
if (event.target.classList.contains("reset")) {
|
||||
const btnId = event.target.getAttribute("data-id");
|
||||
const input = this._doc.getElementById(btnId);
|
||||
this._resetToDefault(btnId, input, event.target);
|
||||
}
|
||||
},
|
||||
|
||||
updateFieldType: function() {
|
||||
const table = this._doc.querySelector("table");
|
||||
const customValueType = table.querySelector("#custom-value-type").value;
|
||||
const customTextEl = table.querySelector("#custom-value-text");
|
||||
|
||||
if (customValueType.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (customValueType) {
|
||||
case "boolean":
|
||||
customTextEl.type = "checkbox";
|
||||
break;
|
||||
case "number":
|
||||
customTextEl.type = "number";
|
||||
break;
|
||||
default:
|
||||
customTextEl.type = "text";
|
||||
break;
|
||||
}
|
||||
|
||||
return customValueType;
|
||||
},
|
||||
|
||||
clearNewFields: function() {
|
||||
const table = this._doc.querySelector("table");
|
||||
const customTextEl = table.querySelector("#custom-value-text");
|
||||
if (customTextEl.checked) {
|
||||
customTextEl.checked = false;
|
||||
} else {
|
||||
customTextEl.value = "";
|
||||
}
|
||||
|
||||
this.updateFieldType();
|
||||
},
|
||||
|
||||
updateNewField: function() {
|
||||
const table = this._doc.querySelector("table");
|
||||
const customValueType = this.updateFieldType();
|
||||
|
||||
if (!customValueType) {
|
||||
return;
|
||||
}
|
||||
|
||||
const customRow = table.querySelector("tr:nth-of-type(2)");
|
||||
const customTextEl = table.querySelector("#custom-value-text");
|
||||
const customTextNameEl = table.querySelector("#custom-value-name");
|
||||
|
||||
if (customTextEl.validity.valid) {
|
||||
let customText = customTextEl.value;
|
||||
|
||||
if (customValueType === "boolean") {
|
||||
customText = customTextEl.checked;
|
||||
}
|
||||
|
||||
const customTextName = customTextNameEl.value.replace(
|
||||
/[^A-Za-z0-9\.\-_]/gi,
|
||||
""
|
||||
);
|
||||
this.generateField(
|
||||
customTextName,
|
||||
customText,
|
||||
true,
|
||||
customValueType,
|
||||
customRow
|
||||
);
|
||||
this._saveByType({
|
||||
id: customTextName,
|
||||
type: customValueType,
|
||||
value: customText,
|
||||
});
|
||||
customTextNameEl.value = "";
|
||||
this.clearNewFields();
|
||||
}
|
||||
},
|
||||
|
||||
checkNewFieldSubmit: function(event) {
|
||||
if (event.keyCode === 13) {
|
||||
this._doc.getElementById("custom-value").click();
|
||||
}
|
||||
},
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DevToolsModules(
|
||||
'app-manager.js',
|
||||
'app-projects.js',
|
||||
'app-validator.js',
|
||||
'config-view.js',
|
||||
'project-list.js',
|
||||
'runtime-list.js',
|
||||
'runtime-types.js',
|
||||
'runtimes.js',
|
||||
'tab-store.js',
|
||||
'utils.js'
|
||||
)
|
|
@ -1,417 +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 Services = require("Services");
|
||||
const { AppProjects } = require("devtools/client/webide/modules/app-projects");
|
||||
const { AppManager } = require("devtools/client/webide/modules/app-manager");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const utils = require("devtools/client/webide/modules/utils");
|
||||
const Telemetry = require("devtools/client/shared/telemetry");
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/webide.properties"
|
||||
);
|
||||
|
||||
const TELEMETRY_WEBIDE_NEW_PROJECT_COUNT = "DEVTOOLS_WEBIDE_NEW_PROJECT_COUNT";
|
||||
|
||||
var ProjectList;
|
||||
|
||||
module.exports = ProjectList = function(win, parentWindow) {
|
||||
EventEmitter.decorate(this);
|
||||
this._doc = win.document;
|
||||
this._UI = parentWindow.UI;
|
||||
this._parentWindow = parentWindow;
|
||||
this._telemetry = new Telemetry();
|
||||
this._panelNodeEl = "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);
|
||||
};
|
||||
|
||||
ProjectList.prototype = {
|
||||
get doc() {
|
||||
return this._doc;
|
||||
},
|
||||
|
||||
appManagerUpdate: function(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-targets":
|
||||
case "connection":
|
||||
this.update(details);
|
||||
break;
|
||||
case "project":
|
||||
this.updateCommands();
|
||||
this.update(details);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onWebIDEUpdate: function(what, details) {
|
||||
if (what == "busy" || what == "unbusy") {
|
||||
this.updateCommands();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* testOptions: { chrome mochitest support
|
||||
* folder: nsIFile, where to store the app
|
||||
* index: Number, index of the app in the template list
|
||||
* name: String name of the app
|
||||
* }
|
||||
*/
|
||||
newApp: function(testOptions) {
|
||||
const parentWindow = this._parentWindow;
|
||||
const self = this;
|
||||
return this._UI.busyUntil(
|
||||
(async function() {
|
||||
// Open newapp.xul, which will feed ret.location
|
||||
const ret = { location: null, testOptions: testOptions };
|
||||
parentWindow.openDialog(
|
||||
"chrome://webide/content/newapp.xul",
|
||||
"newapp",
|
||||
"chrome,modal",
|
||||
ret
|
||||
);
|
||||
if (!ret.location) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve added project
|
||||
const project = AppProjects.get(ret.location);
|
||||
|
||||
// Select project
|
||||
AppManager.selectedProject = project;
|
||||
|
||||
self._telemetry
|
||||
.getHistogramById(TELEMETRY_WEBIDE_NEW_PROJECT_COUNT)
|
||||
.add(true);
|
||||
})(),
|
||||
"creating new app"
|
||||
);
|
||||
},
|
||||
|
||||
importPackagedApp: function(location) {
|
||||
const parentWindow = this._parentWindow;
|
||||
const UI = this._UI;
|
||||
return UI.busyUntil(
|
||||
(async function() {
|
||||
const directory = await utils.getPackagedDirectory(
|
||||
parentWindow,
|
||||
location
|
||||
);
|
||||
|
||||
if (!directory) {
|
||||
// User cancelled directory selection
|
||||
return;
|
||||
}
|
||||
|
||||
await UI.importAndSelectApp(directory);
|
||||
})(),
|
||||
"importing packaged app"
|
||||
);
|
||||
},
|
||||
|
||||
importHostedApp: function(location) {
|
||||
const parentWindow = this._parentWindow;
|
||||
const UI = this._UI;
|
||||
return UI.busyUntil(
|
||||
(async function() {
|
||||
const url = utils.getHostedURL(parentWindow, location);
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
await UI.importAndSelectApp(url);
|
||||
})(),
|
||||
"importing hosted app"
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* opts: {
|
||||
* panel: Object, currenl project panel node
|
||||
* name: String, name of the project
|
||||
* icon: String path of the project icon
|
||||
* }
|
||||
*/
|
||||
_renderProjectItem: function(opts) {
|
||||
const span =
|
||||
opts.panel.querySelector("span") || this._doc.createElement("span");
|
||||
span.textContent = opts.name;
|
||||
const icon =
|
||||
opts.panel.querySelector("img") || this._doc.createElement("img");
|
||||
icon.className = "project-image";
|
||||
icon.setAttribute("src", opts.icon);
|
||||
opts.panel.appendChild(icon);
|
||||
opts.panel.appendChild(span);
|
||||
opts.panel.setAttribute("title", opts.name);
|
||||
},
|
||||
|
||||
refreshTabs: function() {
|
||||
if (AppManager.connected) {
|
||||
return AppManager.listTabs()
|
||||
.then(() => {
|
||||
this.updateTabs();
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
},
|
||||
|
||||
updateTabs: function() {
|
||||
const tabsHeaderNode = this._doc.querySelector("#panel-header-tabs");
|
||||
const tabsNode = this._doc.querySelector("#project-panel-tabs");
|
||||
|
||||
while (tabsNode.hasChildNodes()) {
|
||||
tabsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
if (!AppManager.connected) {
|
||||
tabsHeaderNode.setAttribute("hidden", "true");
|
||||
return;
|
||||
}
|
||||
|
||||
const tabs = AppManager.tabStore.tabs;
|
||||
|
||||
tabsHeaderNode.removeAttribute("hidden");
|
||||
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
const tab = tabs[i];
|
||||
const URL = this._parentWindow.URL;
|
||||
let url;
|
||||
try {
|
||||
url = new URL(tab.url);
|
||||
} catch (e) {
|
||||
// Don't try to handle invalid URLs
|
||||
continue;
|
||||
}
|
||||
// Wanted to use nsIFaviconService here, but it only works for visited
|
||||
// tabs, so that's no help for any remote tabs. Maybe some favicon wizard
|
||||
// knows how to get high-res favicons easily, or we could offer actor
|
||||
// support for this (bug 1061654).
|
||||
if (url.origin) {
|
||||
tab.favicon = url.origin + "/favicon.ico";
|
||||
}
|
||||
tab.name = tab.title || Strings.GetStringFromName("project_tab_loading");
|
||||
if (url.protocol.startsWith("http")) {
|
||||
tab.name = url.hostname + ": " + tab.name;
|
||||
}
|
||||
const panelItemNode = this._doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
tabsNode.appendChild(panelItemNode);
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: tab.name,
|
||||
icon: tab.favicon || AppManager.DEFAULT_PROJECT_ICON,
|
||||
});
|
||||
panelItemNode.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
AppManager.selectedProject = {
|
||||
type: "tab",
|
||||
app: tab,
|
||||
icon: tab.favicon || AppManager.DEFAULT_PROJECT_ICON,
|
||||
location: tab.url,
|
||||
name: tab.name,
|
||||
};
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
updateApps: function() {
|
||||
const doc = this._doc;
|
||||
const runtimeappsHeaderNode = doc.querySelector(
|
||||
"#panel-header-runtimeapps"
|
||||
);
|
||||
let sortedApps = [];
|
||||
for (const [, /* manifestURL */ app] of AppManager.apps) {
|
||||
sortedApps.push(app);
|
||||
}
|
||||
sortedApps = sortedApps.sort((a, b) => {
|
||||
return a.manifest.name > b.manifest.name;
|
||||
});
|
||||
const mainProcess = AppManager.isMainProcessDebuggable();
|
||||
if (AppManager.connected && (sortedApps.length > 0 || mainProcess)) {
|
||||
runtimeappsHeaderNode.removeAttribute("hidden");
|
||||
} else {
|
||||
runtimeappsHeaderNode.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
const runtimeAppsNode = doc.querySelector("#project-panel-runtimeapps");
|
||||
while (runtimeAppsNode.hasChildNodes()) {
|
||||
runtimeAppsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
if (mainProcess) {
|
||||
const panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: Strings.GetStringFromName("mainProcess_label"),
|
||||
icon: AppManager.DEFAULT_PROJECT_ICON,
|
||||
});
|
||||
runtimeAppsNode.appendChild(panelItemNode);
|
||||
panelItemNode.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
AppManager.selectedProject = {
|
||||
type: "mainProcess",
|
||||
name: Strings.GetStringFromName("mainProcess_label"),
|
||||
icon: AppManager.DEFAULT_PROJECT_ICON,
|
||||
};
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
for (let i = 0; i < sortedApps.length; i++) {
|
||||
const app = sortedApps[i];
|
||||
const panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: app.manifest.name,
|
||||
icon: app.iconURL || AppManager.DEFAULT_PROJECT_ICON,
|
||||
});
|
||||
runtimeAppsNode.appendChild(panelItemNode);
|
||||
panelItemNode.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
AppManager.selectedProject = {
|
||||
type: "runtimeApp",
|
||||
app: app.manifest,
|
||||
icon: app.iconURL || AppManager.DEFAULT_PROJECT_ICON,
|
||||
name: app.manifest.name,
|
||||
};
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
updateCommands: function() {
|
||||
const doc = this._doc;
|
||||
|
||||
const newAppCmd = doc.querySelector("#new-app");
|
||||
const packagedAppCmd = doc.querySelector("#packaged-app");
|
||||
const hostedAppCmd = doc.querySelector("#hosted-app");
|
||||
|
||||
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)
|
||||
* An |options| object containing a type of |apps| or |tabs| will limit
|
||||
* what is updated to only those sections.
|
||||
*/
|
||||
update: function(options) {
|
||||
if (options && options.type === "apps") {
|
||||
return this.updateApps();
|
||||
} else if (options && options.type === "tabs") {
|
||||
return this.updateTabs();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const doc = this._doc;
|
||||
const projectsNode = doc.querySelector("#project-panel-projects");
|
||||
|
||||
while (projectsNode.hasChildNodes()) {
|
||||
projectsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
AppProjects.load().then(() => {
|
||||
const projects = AppProjects.projects;
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
const project = projects[i];
|
||||
const panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
projectsNode.appendChild(panelItemNode);
|
||||
if (!project.validationStatus) {
|
||||
// The result of the validation process (storing names, icons, …) is not stored in
|
||||
// the IndexedDB database when App Manager v1 is used.
|
||||
// We need to run the validation again and update the name and icon of the app.
|
||||
AppManager.validateAndUpdateProject(project).then(() => {
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name,
|
||||
icon: project.icon,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name || AppManager.DEFAULT_PROJECT_NAME,
|
||||
icon: project.icon || AppManager.DEFAULT_PROJECT_ICON,
|
||||
});
|
||||
}
|
||||
panelItemNode.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
AppManager.selectedProject = project;
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
resolve();
|
||||
}, reject);
|
||||
|
||||
// List remote apps and the main process, if they exist
|
||||
this.updateApps();
|
||||
|
||||
// Build the tab list right now, so it's fast...
|
||||
this.updateTabs();
|
||||
|
||||
// But re-list them and rebuild, in case any tabs navigated since the last
|
||||
// time they were listed.
|
||||
if (AppManager.connected) {
|
||||
AppManager.listTabs()
|
||||
.then(() => {
|
||||
this.updateTabs();
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._doc = null;
|
||||
AppManager.off("app-manager-update", this.appManagerUpdate);
|
||||
this._UI.off("webide-update", this.onWebIDEUpdate);
|
||||
this._UI = null;
|
||||
this._parentWindow = null;
|
||||
this._panelNodeEl = null;
|
||||
},
|
||||
};
|
|
@ -1,226 +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";
|
||||
|
||||
const Services = require("Services");
|
||||
const { AppManager } = require("devtools/client/webide/modules/app-manager");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {
|
||||
RuntimeScanners,
|
||||
WiFiScanner,
|
||||
} = require("devtools/client/webide/modules/runtimes");
|
||||
const { adbAddon, ADB_ADDON_STATES } = require("devtools/shared/adb/adb-addon");
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/webide.properties"
|
||||
);
|
||||
|
||||
var 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 = "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;
|
||||
},
|
||||
|
||||
appManagerUpdate: function(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(what, details) {
|
||||
if (what == "busy" || what == "unbusy") {
|
||||
this.updateCommands();
|
||||
}
|
||||
},
|
||||
|
||||
takeScreenshot: function() {
|
||||
this._Cmds.takeScreenshot();
|
||||
},
|
||||
|
||||
showRuntimeDetails: function() {
|
||||
this._Cmds.showRuntimeDetails();
|
||||
},
|
||||
|
||||
showDevicePreferences: function() {
|
||||
this._Cmds.showDevicePrefs();
|
||||
},
|
||||
|
||||
showSettings: function() {
|
||||
this._Cmds.showSettings();
|
||||
},
|
||||
|
||||
showPerformancePanel: function() {
|
||||
this._Cmds.showPerformancePanel();
|
||||
},
|
||||
|
||||
showTroubleShooting: function() {
|
||||
this._Cmds.showTroubleShooting();
|
||||
},
|
||||
|
||||
showAddons: function() {
|
||||
this._Cmds.showAddons();
|
||||
},
|
||||
|
||||
refreshScanners: function() {
|
||||
RuntimeScanners.scan();
|
||||
},
|
||||
|
||||
updateCommands: function() {
|
||||
const doc = this._doc;
|
||||
|
||||
// Runtime commands
|
||||
const screenshotCmd = doc.querySelector("#runtime-screenshot");
|
||||
const detailsCmd = doc.querySelector("#runtime-details");
|
||||
const disconnectCmd = doc.querySelector("#runtime-disconnect");
|
||||
const devicePrefsCmd = doc.querySelector("#runtime-preferences");
|
||||
const settingsCmd = doc.querySelector("#runtime-settings");
|
||||
const performanceCmd = doc.querySelector("#runtime-performance");
|
||||
|
||||
// Display the performance button only if the pref is enabled
|
||||
performanceCmd.hidden = !Services.prefs.getBoolPref(
|
||||
"devtools.performance.new-panel-enabled",
|
||||
false
|
||||
);
|
||||
|
||||
if (AppManager.connected) {
|
||||
if (AppManager.deviceFront) {
|
||||
detailsCmd.removeAttribute("disabled");
|
||||
screenshotCmd.removeAttribute("disabled");
|
||||
}
|
||||
if (AppManager.preferenceFront) {
|
||||
devicePrefsCmd.removeAttribute("disabled");
|
||||
}
|
||||
disconnectCmd.removeAttribute("disabled");
|
||||
if (AppManager.perfFront) {
|
||||
performanceCmd.removeAttribute("disabled");
|
||||
}
|
||||
} else {
|
||||
detailsCmd.setAttribute("disabled", "true");
|
||||
screenshotCmd.setAttribute("disabled", "true");
|
||||
disconnectCmd.setAttribute("disabled", "true");
|
||||
devicePrefsCmd.setAttribute("disabled", "true");
|
||||
settingsCmd.setAttribute("disabled", "true");
|
||||
performanceCmd.setAttribute("disabled", "true");
|
||||
}
|
||||
},
|
||||
|
||||
update: function() {
|
||||
const doc = this._doc;
|
||||
const wifiHeaderNode = doc.querySelector("#runtime-header-wifi");
|
||||
|
||||
if (WiFiScanner.allowed) {
|
||||
wifiHeaderNode.removeAttribute("hidden");
|
||||
} else {
|
||||
wifiHeaderNode.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
const usbListNode = doc.querySelector("#runtime-panel-usb");
|
||||
const wifiListNode = doc.querySelector("#runtime-panel-wifi");
|
||||
const otherListNode = doc.querySelector("#runtime-panel-other");
|
||||
const noADBExtensionNode = doc.querySelector(
|
||||
"#runtime-panel-noadbextension"
|
||||
);
|
||||
const noUSBNode = doc.querySelector("#runtime-panel-nousbdevice");
|
||||
noADBExtensionNode.textContent = Strings.formatStringFromName(
|
||||
"runtimePanel_noadbextension",
|
||||
["ADB Extension"]
|
||||
);
|
||||
|
||||
if (adbAddon.status === ADB_ADDON_STATES.INSTALLED) {
|
||||
noADBExtensionNode.setAttribute("hidden", "true");
|
||||
} else {
|
||||
noADBExtensionNode.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
const runtimeList = AppManager.runtimeList;
|
||||
|
||||
if (!runtimeList) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
runtimeList.usb.length === 0 &&
|
||||
adbAddon.status === ADB_ADDON_STATES.INSTALLED
|
||||
) {
|
||||
noUSBNode.removeAttribute("hidden");
|
||||
} else {
|
||||
noUSBNode.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
for (const [type, parent] of [
|
||||
["usb", usbListNode],
|
||||
["wifi", wifiListNode],
|
||||
["other", otherListNode],
|
||||
]) {
|
||||
while (parent.hasChildNodes()) {
|
||||
parent.firstChild.remove();
|
||||
}
|
||||
for (const runtime of runtimeList[type]) {
|
||||
const r = runtime;
|
||||
const panelItemNode = doc.createElement(this._panelBoxEl);
|
||||
panelItemNode.className = "panel-item-complex";
|
||||
|
||||
const connectButton = doc.createElement(this._panelNodeEl);
|
||||
connectButton.className = "panel-item runtime-panel-item-" + type;
|
||||
connectButton.textContent = r.name;
|
||||
|
||||
connectButton.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
this._UI.dismissErrorNotification();
|
||||
this._UI.connectToRuntime(r);
|
||||
},
|
||||
true
|
||||
);
|
||||
panelItemNode.appendChild(connectButton);
|
||||
|
||||
if (r.configure) {
|
||||
const 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);
|
||||
this._UI.off("webide-update", this.onWebIDEUpdate);
|
||||
this._UI = null;
|
||||
this._Cmds = null;
|
||||
this._parentWindow = null;
|
||||
this._panelNodeEl = null;
|
||||
},
|
||||
};
|
|
@ -1,17 +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";
|
||||
|
||||
// These type strings are used for logging events to Telemetry.
|
||||
// You must update Histograms.json if new types are added.
|
||||
const RuntimeTypes = {
|
||||
USB: "USB",
|
||||
WIFI: "WIFI",
|
||||
REMOTE: "REMOTE",
|
||||
LOCAL: "LOCAL",
|
||||
OTHER: "OTHER",
|
||||
};
|
||||
|
||||
exports.RuntimeTypes = RuntimeTypes;
|
|
@ -1,491 +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";
|
||||
|
||||
const Services = require("Services");
|
||||
const { DebuggerServer } = require("devtools/server/debugger-server");
|
||||
const discovery = require("devtools/shared/discovery/discovery");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {
|
||||
RuntimeTypes,
|
||||
} = require("devtools/client/webide/modules/runtime-types");
|
||||
const promise = require("promise");
|
||||
|
||||
loader.lazyRequireGetter(this, "adb", "devtools/shared/adb/adb", true);
|
||||
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"AuthenticationResult",
|
||||
"devtools/shared/security/auth",
|
||||
true
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"DevToolsUtils",
|
||||
"devtools/shared/DevToolsUtils"
|
||||
);
|
||||
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/webide.properties"
|
||||
);
|
||||
|
||||
/**
|
||||
* Runtime and Scanner API
|
||||
*
|
||||
* |RuntimeScanners| maintains a set of |Scanner| objects that produce one or
|
||||
* more |Runtime|s to connect to. Add-ons can extend the set of known runtimes
|
||||
* by registering additional |Scanner|s that emit them.
|
||||
*
|
||||
* Each |Scanner| must support the following API:
|
||||
*
|
||||
* enable()
|
||||
* Bind any event handlers and start any background work the scanner needs to
|
||||
* maintain an updated set of |Runtime|s.
|
||||
* Called when the first consumer (such as WebIDE) actively interested in
|
||||
* maintaining the |Runtime| list enables the registry.
|
||||
* disable()
|
||||
* Unbind any event handlers and stop any background work the scanner needs to
|
||||
* maintain an updated set of |Runtime|s.
|
||||
* Called when the last consumer (such as WebIDE) actively interested in
|
||||
* maintaining the |Runtime| list disables the registry.
|
||||
* emits "runtime-list-updated"
|
||||
* If the set of runtimes a |Scanner| manages has changed, it must emit this
|
||||
* event to notify consumers of changes.
|
||||
* scan()
|
||||
* Actively refreshes the list of runtimes the scanner knows about. If your
|
||||
* scanner uses an active scanning approach (as opposed to listening for
|
||||
* events when changes occur), the bulk of the work would be done here.
|
||||
* @return Promise
|
||||
* Should be resolved when scanning is complete. If scanning has no
|
||||
* well-defined end point, you can resolve immediately, as long as
|
||||
* update event is emitted later when changes are noticed.
|
||||
* listRuntimes()
|
||||
* Return the current list of runtimes known to the |Scanner| instance.
|
||||
* @return Iterable
|
||||
*
|
||||
* Each |Runtime| must support the following API:
|
||||
*
|
||||
* |type| field
|
||||
* The |type| must be one of the values from the |RuntimeTypes| object. This
|
||||
* is used for Telemetry and to support displaying sets of |Runtime|s
|
||||
* categorized by type.
|
||||
* |id| field
|
||||
* An identifier that is unique in the set of all runtimes with the same
|
||||
* |type|. WebIDE tries to save the last used runtime via type + id, and
|
||||
* tries to locate it again in the next session, so this value should attempt
|
||||
* to be stable across Firefox sessions.
|
||||
* |name| field
|
||||
* A user-visible label to identify the runtime that will be displayed in a
|
||||
* runtime list.
|
||||
* |prolongedConnection| field
|
||||
* A boolean value which should be |true| if the connection process is
|
||||
* expected to take a unknown or large amount of time. A UI may use this as a
|
||||
* hint to skip timeouts or other time-based code paths.
|
||||
* connect()
|
||||
* Configure the passed |connection| object with any settings need to
|
||||
* successfully connect to the runtime, and call the |connection|'s connect()
|
||||
* method.
|
||||
* @param Connection connection
|
||||
* A |Connection| object from the DevTools |ConnectionManager|.
|
||||
* @return Promise
|
||||
* Resolved once you've called the |connection|'s connect() method.
|
||||
* configure() OPTIONAL
|
||||
* Show a configuration screen if the runtime is configurable.
|
||||
*/
|
||||
|
||||
/* SCANNER REGISTRY */
|
||||
|
||||
var RuntimeScanners = {
|
||||
_enabledCount: 0,
|
||||
_scanners: new Set(),
|
||||
|
||||
get enabled() {
|
||||
return !!this._enabledCount;
|
||||
},
|
||||
|
||||
add(scanner) {
|
||||
if (this.enabled) {
|
||||
// Enable any scanner added while globally enabled
|
||||
this._enableScanner(scanner);
|
||||
}
|
||||
this._scanners.add(scanner);
|
||||
this._emitUpdated();
|
||||
},
|
||||
|
||||
remove(scanner) {
|
||||
this._scanners.delete(scanner);
|
||||
if (this.enabled) {
|
||||
// Disable any scanner removed while globally enabled
|
||||
this._disableScanner(scanner);
|
||||
}
|
||||
this._emitUpdated();
|
||||
},
|
||||
|
||||
has(scanner) {
|
||||
return this._scanners.has(scanner);
|
||||
},
|
||||
|
||||
scan() {
|
||||
if (!this.enabled) {
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
if (this._scanPromise) {
|
||||
return this._scanPromise;
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
|
||||
for (const scanner of this._scanners) {
|
||||
promises.push(scanner.scan());
|
||||
}
|
||||
|
||||
this._scanPromise = promise.all(promises);
|
||||
|
||||
// Reset pending promise
|
||||
this._scanPromise.then(
|
||||
() => {
|
||||
this._scanPromise = null;
|
||||
},
|
||||
() => {
|
||||
this._scanPromise = null;
|
||||
}
|
||||
);
|
||||
|
||||
return this._scanPromise;
|
||||
},
|
||||
|
||||
listRuntimes: function*() {
|
||||
for (const scanner of this._scanners) {
|
||||
for (const runtime of scanner.listRuntimes()) {
|
||||
yield runtime;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_emitUpdated() {
|
||||
this.emit("runtime-list-updated");
|
||||
},
|
||||
|
||||
enable() {
|
||||
if (this._enabledCount++ !== 0) {
|
||||
// Already enabled scanners during a previous call
|
||||
return;
|
||||
}
|
||||
this._emitUpdated = this._emitUpdated.bind(this);
|
||||
for (const scanner of this._scanners) {
|
||||
this._enableScanner(scanner);
|
||||
}
|
||||
},
|
||||
|
||||
_enableScanner(scanner) {
|
||||
scanner.enable();
|
||||
scanner.on("runtime-list-updated", this._emitUpdated);
|
||||
},
|
||||
|
||||
disable() {
|
||||
if (--this._enabledCount !== 0) {
|
||||
// Already disabled scanners during a previous call
|
||||
return;
|
||||
}
|
||||
for (const scanner of this._scanners) {
|
||||
this._disableScanner(scanner);
|
||||
}
|
||||
},
|
||||
|
||||
_disableScanner(scanner) {
|
||||
scanner.off("runtime-list-updated", this._emitUpdated);
|
||||
scanner.disable();
|
||||
},
|
||||
};
|
||||
|
||||
EventEmitter.decorate(RuntimeScanners);
|
||||
|
||||
exports.RuntimeScanners = RuntimeScanners;
|
||||
|
||||
/* SCANNERS */
|
||||
|
||||
var UsbScanner = {
|
||||
init() {
|
||||
this._emitUpdated = this._emitUpdated.bind(this);
|
||||
},
|
||||
enable() {
|
||||
adb.registerListener(this._emitUpdated);
|
||||
},
|
||||
disable() {
|
||||
adb.unregisterListener(this._emitUpdated);
|
||||
},
|
||||
scan() {
|
||||
return adb.updateRuntimes();
|
||||
},
|
||||
listRuntimes() {
|
||||
return adb.getRuntimes();
|
||||
},
|
||||
_emitUpdated() {
|
||||
this.emit("runtime-list-updated");
|
||||
},
|
||||
};
|
||||
EventEmitter.decorate(UsbScanner);
|
||||
UsbScanner.init();
|
||||
RuntimeScanners.add(UsbScanner);
|
||||
|
||||
var WiFiScanner = {
|
||||
_runtimes: [],
|
||||
|
||||
init() {
|
||||
this.updateRegistration();
|
||||
Services.prefs.addObserver(this.ALLOWED_PREF, this);
|
||||
},
|
||||
|
||||
enable() {
|
||||
this._updateRuntimes = this._updateRuntimes.bind(this);
|
||||
discovery.on("devtools-device-added", this._updateRuntimes);
|
||||
discovery.on("devtools-device-updated", this._updateRuntimes);
|
||||
discovery.on("devtools-device-removed", this._updateRuntimes);
|
||||
this._updateRuntimes();
|
||||
},
|
||||
|
||||
disable() {
|
||||
discovery.off("devtools-device-added", this._updateRuntimes);
|
||||
discovery.off("devtools-device-updated", this._updateRuntimes);
|
||||
discovery.off("devtools-device-removed", this._updateRuntimes);
|
||||
},
|
||||
|
||||
_emitUpdated() {
|
||||
this.emit("runtime-list-updated");
|
||||
},
|
||||
|
||||
_updateRuntimes() {
|
||||
this._runtimes = [];
|
||||
for (const device of discovery.getRemoteDevicesWithService("devtools")) {
|
||||
this._runtimes.push(new WiFiRuntime(device));
|
||||
}
|
||||
this._emitUpdated();
|
||||
},
|
||||
|
||||
scan() {
|
||||
discovery.scan();
|
||||
return promise.resolve();
|
||||
},
|
||||
|
||||
listRuntimes: function() {
|
||||
return this._runtimes;
|
||||
},
|
||||
|
||||
ALLOWED_PREF: "devtools.remote.wifi.scan",
|
||||
|
||||
get allowed() {
|
||||
return Services.prefs.getBoolPref(this.ALLOWED_PREF);
|
||||
},
|
||||
|
||||
updateRegistration() {
|
||||
if (this.allowed) {
|
||||
RuntimeScanners.add(WiFiScanner);
|
||||
} else {
|
||||
RuntimeScanners.remove(WiFiScanner);
|
||||
}
|
||||
this._emitUpdated();
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (data !== WiFiScanner.ALLOWED_PREF) {
|
||||
return;
|
||||
}
|
||||
WiFiScanner.updateRegistration();
|
||||
},
|
||||
};
|
||||
|
||||
EventEmitter.decorate(WiFiScanner);
|
||||
WiFiScanner.init();
|
||||
|
||||
exports.WiFiScanner = WiFiScanner;
|
||||
|
||||
var StaticScanner = {
|
||||
enable() {},
|
||||
disable() {},
|
||||
scan() {
|
||||
return promise.resolve();
|
||||
},
|
||||
listRuntimes() {
|
||||
const runtimes = [gRemoteRuntime];
|
||||
if (Services.prefs.getBoolPref("devtools.webide.enableLocalRuntime")) {
|
||||
runtimes.push(gLocalRuntime);
|
||||
}
|
||||
return runtimes;
|
||||
},
|
||||
};
|
||||
|
||||
EventEmitter.decorate(StaticScanner);
|
||||
RuntimeScanners.add(StaticScanner);
|
||||
|
||||
exports.RuntimeTypes = RuntimeTypes;
|
||||
|
||||
function WiFiRuntime(deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
WiFiRuntime.prototype = {
|
||||
type: RuntimeTypes.WIFI,
|
||||
// Mark runtime as taking a long time to connect
|
||||
prolongedConnection: true,
|
||||
connect: function(connection) {
|
||||
const service = discovery.getRemoteService("devtools", this.deviceName);
|
||||
if (!service) {
|
||||
return promise.reject(new Error("Can't find device: " + this.name));
|
||||
}
|
||||
connection.advertisement = service;
|
||||
connection.authenticator.sendOOB = this.sendOOB;
|
||||
// Disable the default connection timeout, since QR scanning can take an
|
||||
// unknown amount of time. This prevents spurious errors (even after
|
||||
// eventual success) from being shown.
|
||||
connection.timeoutDelay = 0;
|
||||
connection.connect();
|
||||
return promise.resolve();
|
||||
},
|
||||
get id() {
|
||||
return this.deviceName;
|
||||
},
|
||||
get name() {
|
||||
return this.deviceName;
|
||||
},
|
||||
|
||||
/**
|
||||
* During OOB_CERT authentication, a notification dialog like this is used to
|
||||
* to display a token which the user must transfer through some mechanism to the
|
||||
* server to authenticate the devices.
|
||||
*
|
||||
* This implementation presents the token as text for the user to transfer
|
||||
* manually. For a mobile device, you should override this implementation with
|
||||
* something more convenient, such as displaying a QR code.
|
||||
*
|
||||
* This method receives an object containing:
|
||||
* @param host string
|
||||
* The host name or IP address of the debugger server.
|
||||
* @param port number
|
||||
* The port number of the debugger server.
|
||||
* @param cert object (optional)
|
||||
* The server's cert details.
|
||||
* @param authResult AuthenticationResult
|
||||
* Authentication result sent from the server.
|
||||
* @param oob object (optional)
|
||||
* The token data to be transferred during OOB_CERT step 8:
|
||||
* * sha256: hash(ClientCert)
|
||||
* * k : K(random 128-bit number)
|
||||
* @return object containing:
|
||||
* * close: Function to hide the notification
|
||||
*/
|
||||
sendOOB(session) {
|
||||
const WINDOW_ID = "devtools:wifi-auth";
|
||||
const { authResult } = session;
|
||||
// Only show in the PENDING state
|
||||
if (authResult != AuthenticationResult.PENDING) {
|
||||
throw new Error("Expected PENDING result, got " + authResult);
|
||||
}
|
||||
|
||||
// Listen for the window our prompt opens, so we can close it programatically
|
||||
let promptWindow;
|
||||
const windowListener = {
|
||||
onOpenWindow(xulWindow) {
|
||||
const win = xulWindow.docShell.domWindow;
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
if (win.document.documentElement.getAttribute("id") != WINDOW_ID) {
|
||||
return;
|
||||
}
|
||||
// Found the window
|
||||
promptWindow = win;
|
||||
Services.wm.removeListener(windowListener);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
},
|
||||
onCloseWindow() {},
|
||||
};
|
||||
Services.wm.addListener(windowListener);
|
||||
|
||||
// |openDialog| is typically a blocking API, so |executeSoon| to get around this
|
||||
DevToolsUtils.executeSoon(() => {
|
||||
// Height determines the size of the QR code. Force a minimum size to
|
||||
// improve scanability.
|
||||
const MIN_HEIGHT = 600;
|
||||
const win = Services.wm.getMostRecentWindow("devtools:webide");
|
||||
const width = win.outerWidth * 0.8;
|
||||
const height = Math.max(win.outerHeight * 0.5, MIN_HEIGHT);
|
||||
win.openDialog(
|
||||
"chrome://webide/content/wifi-auth.xhtml",
|
||||
WINDOW_ID,
|
||||
"modal=yes,width=" + width + ",height=" + height,
|
||||
session
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
close() {
|
||||
if (!promptWindow) {
|
||||
return;
|
||||
}
|
||||
promptWindow.close();
|
||||
promptWindow = null;
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// For testing use only
|
||||
exports._WiFiRuntime = WiFiRuntime;
|
||||
|
||||
var gLocalRuntime = {
|
||||
type: RuntimeTypes.LOCAL,
|
||||
connect: function(connection) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
DebuggerServer.allowChromeProcess = true;
|
||||
connection.host = null; // Force Pipe transport
|
||||
connection.port = null;
|
||||
connection.connect();
|
||||
return promise.resolve();
|
||||
},
|
||||
get id() {
|
||||
return "local";
|
||||
},
|
||||
get name() {
|
||||
return Strings.GetStringFromName("local_runtime");
|
||||
},
|
||||
};
|
||||
|
||||
// For testing use only
|
||||
exports._gLocalRuntime = gLocalRuntime;
|
||||
|
||||
var gRemoteRuntime = {
|
||||
type: RuntimeTypes.REMOTE,
|
||||
connect: function(connection) {
|
||||
const win = Services.wm.getMostRecentWindow("devtools:webide");
|
||||
if (!win) {
|
||||
return promise.reject(new Error("No WebIDE window found"));
|
||||
}
|
||||
const ret = { value: connection.host + ":" + connection.port };
|
||||
const title = Strings.GetStringFromName("remote_runtime_promptTitle");
|
||||
const message = Strings.GetStringFromName("remote_runtime_promptMessage");
|
||||
const ok = Services.prompt.prompt(win, title, message, ret, null, {});
|
||||
const [host, port] = ret.value.split(":");
|
||||
if (!ok) {
|
||||
return promise.reject({ canceled: true });
|
||||
}
|
||||
if (!host || !port) {
|
||||
return promise.reject(new Error("Invalid host or port"));
|
||||
}
|
||||
connection.host = host;
|
||||
connection.port = port;
|
||||
connection.connect();
|
||||
return promise.resolve();
|
||||
},
|
||||
get name() {
|
||||
return Strings.GetStringFromName("remote_runtime");
|
||||
},
|
||||
};
|
||||
|
||||
// For testing use only
|
||||
exports._gRemoteRuntime = gRemoteRuntime;
|
|
@ -1,177 +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 EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { Connection } = require("devtools/shared/client/connection-manager");
|
||||
|
||||
const _knownTabStores = new WeakMap();
|
||||
|
||||
var TabStore;
|
||||
|
||||
module.exports = TabStore = function(connection) {
|
||||
// If we already know about this connection,
|
||||
// let's re-use the existing store.
|
||||
if (_knownTabStores.has(connection)) {
|
||||
return _knownTabStores.get(connection);
|
||||
}
|
||||
|
||||
_knownTabStores.set(connection, this);
|
||||
|
||||
EventEmitter.decorate(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._onTabNavigated = this._onTabNavigated.bind(this);
|
||||
this._onStatusChanged();
|
||||
return this;
|
||||
};
|
||||
|
||||
TabStore.prototype = {
|
||||
destroy: function() {
|
||||
if (this._connection) {
|
||||
// While this.destroy is bound using .once() above, that event may not
|
||||
// have occurred when the TabStore 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
|
||||
);
|
||||
_knownTabStores.delete(this._connection);
|
||||
this._connection = null;
|
||||
}
|
||||
},
|
||||
|
||||
_resetStore: function() {
|
||||
this.tabs = [];
|
||||
this._selectedTab = null;
|
||||
this._selectedTabTargetPromise = null;
|
||||
},
|
||||
|
||||
_onStatusChanged: function() {
|
||||
if (this._connection.status == Connection.Status.CONNECTED) {
|
||||
// Watch for changes to remote browser tabs
|
||||
this._connection.client.mainRoot.on(
|
||||
"tabListChanged",
|
||||
this._onTabListChanged
|
||||
);
|
||||
this.listTabs();
|
||||
} else {
|
||||
if (this._connection.client) {
|
||||
this._connection.client.mainRoot.off(
|
||||
"tabListChanged",
|
||||
this._onTabListChanged
|
||||
);
|
||||
}
|
||||
this._resetStore();
|
||||
}
|
||||
},
|
||||
|
||||
_onTabListChanged: function() {
|
||||
this.listTabs()
|
||||
.then(() => this.emit("tab-list"))
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
_onTabNavigated: function(e, { from, title, url }) {
|
||||
if (!this._selectedTab || from !== this._selectedTab.actor) {
|
||||
return;
|
||||
}
|
||||
this._selectedTab.url = url;
|
||||
this._selectedTab.title = title;
|
||||
this.emit("navigate");
|
||||
},
|
||||
|
||||
listTabs: function() {
|
||||
if (!this._connection || !this._connection.client) {
|
||||
return Promise.reject(new Error("Can't listTabs, not connected."));
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this._connection.client.mainRoot.listTabs().then(
|
||||
tabs => {
|
||||
// To avoid refactoring WebIDE while switching from form to Target Front for
|
||||
// listTabs. Convert front to form list here.
|
||||
tabs = tabs.map(tab => tab.targetForm);
|
||||
const tabsChanged =
|
||||
JSON.stringify(this.tabs) !== JSON.stringify(tabs);
|
||||
this.tabs = tabs;
|
||||
this._checkSelectedTab();
|
||||
if (tabsChanged) {
|
||||
this.emit("tab-list");
|
||||
}
|
||||
resolve(tabs);
|
||||
},
|
||||
error => {
|
||||
this._connection.disconnect();
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
// TODO: Tab "selection" should really take place by creating a TabProject
|
||||
// which is the selected project. This should be done as part of the
|
||||
// project-agnostic work.
|
||||
_selectedTab: null,
|
||||
_selectedTabTargetPromise: null,
|
||||
get selectedTab() {
|
||||
return this._selectedTab;
|
||||
},
|
||||
set selectedTab(tab) {
|
||||
if (this._selectedTab === tab) {
|
||||
return;
|
||||
}
|
||||
this._selectedTab = tab;
|
||||
this._selectedTabTargetPromise = null;
|
||||
// Attach to the tab to follow navigation events
|
||||
if (this._selectedTab) {
|
||||
this.getTargetForTab();
|
||||
}
|
||||
},
|
||||
|
||||
_checkSelectedTab: function() {
|
||||
if (!this._selectedTab) {
|
||||
return;
|
||||
}
|
||||
const alive = this.tabs.some(tab => {
|
||||
return tab.actor === this._selectedTab.actor;
|
||||
});
|
||||
if (!alive) {
|
||||
this._selectedTab = null;
|
||||
this._selectedTabTargetPromise = null;
|
||||
this.emit("closed");
|
||||
}
|
||||
},
|
||||
|
||||
getTargetForTab: function() {
|
||||
if (this._selectedTabTargetPromise) {
|
||||
return this._selectedTabTargetPromise;
|
||||
}
|
||||
const store = this;
|
||||
this._selectedTabTargetPromise = (async function() {
|
||||
// If you connect to a tab, then detach from it, the root actor may have
|
||||
// de-listed the actors that belong to the tab. This breaks the toolbox
|
||||
// if you try to connect to the same tab again. To work around this
|
||||
// issue, we force a "listTabs" request before connecting to a tab.
|
||||
await store.listTabs();
|
||||
|
||||
const { outerWindowID } = store._selectedTab;
|
||||
return store._connection.client.mainRoot.getTab({ outerWindowID });
|
||||
})();
|
||||
this._selectedTabTargetPromise.then(target => {
|
||||
target.once("close", () => {
|
||||
this._selectedTabTargetPromise = null;
|
||||
});
|
||||
});
|
||||
return this._selectedTabTargetPromise;
|
||||
},
|
||||
};
|
|
@ -1,95 +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 { Cc, Ci } = require("chrome");
|
||||
const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
|
||||
const Services = require("Services");
|
||||
const Strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/webide.properties"
|
||||
);
|
||||
|
||||
function doesFileExist(location) {
|
||||
const file = new FileUtils.File(location);
|
||||
return file.exists();
|
||||
}
|
||||
exports.doesFileExist = doesFileExist;
|
||||
|
||||
function _getFile(location, ...pickerParams) {
|
||||
if (location) {
|
||||
return Promise.resolve(new FileUtils.File(location));
|
||||
}
|
||||
const fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
fp.init(...pickerParams);
|
||||
|
||||
return new Promise(resolve => {
|
||||
fp.open(res => {
|
||||
if (res == Ci.nsIFilePicker.returnCancel) {
|
||||
resolve(null);
|
||||
} else {
|
||||
resolve(fp.file);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getCustomBinary(window, location) {
|
||||
return _getFile(
|
||||
location,
|
||||
window,
|
||||
Strings.GetStringFromName("selectCustomBinary_title"),
|
||||
Ci.nsIFilePicker.modeOpen
|
||||
);
|
||||
}
|
||||
exports.getCustomBinary = getCustomBinary;
|
||||
|
||||
function getCustomProfile(window, location) {
|
||||
return _getFile(
|
||||
location,
|
||||
window,
|
||||
Strings.GetStringFromName("selectCustomProfile_title"),
|
||||
Ci.nsIFilePicker.modeGetFolder
|
||||
);
|
||||
}
|
||||
exports.getCustomProfile = getCustomProfile;
|
||||
|
||||
function getPackagedDirectory(window, location) {
|
||||
return _getFile(
|
||||
location,
|
||||
window,
|
||||
Strings.GetStringFromName("importPackagedApp_title"),
|
||||
Ci.nsIFilePicker.modeGetFolder
|
||||
);
|
||||
}
|
||||
exports.getPackagedDirectory = getPackagedDirectory;
|
||||
|
||||
function getHostedURL(window, location) {
|
||||
const ret = { value: null };
|
||||
|
||||
if (!location) {
|
||||
Services.prompt.prompt(
|
||||
window,
|
||||
Strings.GetStringFromName("importHostedApp_title"),
|
||||
Strings.GetStringFromName("importHostedApp_header"),
|
||||
ret,
|
||||
null,
|
||||
{}
|
||||
);
|
||||
location = ret.value;
|
||||
}
|
||||
|
||||
if (!location) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Clean location string and add "http://" if missing
|
||||
location = location.trim();
|
||||
try {
|
||||
// Will fail if no scheme
|
||||
Services.io.extractScheme(location);
|
||||
} catch (e) {
|
||||
location = "http://" + location;
|
||||
}
|
||||
return location;
|
||||
}
|
||||
exports.getHostedURL = getHostedURL;
|
|
@ -1,21 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DIRS += [
|
||||
'content',
|
||||
'modules',
|
||||
'themes',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/browser.ini'
|
||||
]
|
||||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'test/chrome.ini'
|
||||
]
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('DevTools', 'WebIDE')
|
|
@ -1,6 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
// Extend from the shared list of defined globals for mochitests.
|
||||
"extends": "../../../.eslintrc.mochitests.js"
|
||||
};
|
Двоичные данные
devtools/client/webide/test/addons/adb-extension-linux.xpi
Двоичные данные
devtools/client/webide/test/addons/adb-extension-linux.xpi
Двоичный файл не отображается.
Двоичные данные
devtools/client/webide/test/addons/adb-extension-linux64.xpi
Двоичные данные
devtools/client/webide/test/addons/adb-extension-linux64.xpi
Двоичный файл не отображается.
Двоичные данные
devtools/client/webide/test/addons/adb-extension-mac64.xpi
Двоичные данные
devtools/client/webide/test/addons/adb-extension-mac64.xpi
Двоичный файл не отображается.
Двоичные данные
devtools/client/webide/test/addons/adb-extension-win32.xpi
Двоичные данные
devtools/client/webide/test/addons/adb-extension-win32.xpi
Двоичный файл не отображается.
Двоичные данные
devtools/client/webide/test/app.zip
Двоичные данные
devtools/client/webide/test/app.zip
Двоичный файл не отображается.
|
@ -1,6 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head><title></title></head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"name": "A name (in app directory)",
|
||||
"description": "desc",
|
||||
"launch_path": "/index.html"
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
skip-if = asan || debug # bug 1078284 too many intermittents for these tests
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
doc_tabs.html
|
||||
head.js
|
||||
templates.json
|
||||
|
||||
[browser_tabs.js]
|
||||
skip-if = e10s # Bug 1072167 - browser_tabs.js test fails under e10s
|
|
@ -1,83 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const TEST_URI =
|
||||
"http://example.com/browser/devtools/client/webide/test/doc_tabs.html";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
(async function() {
|
||||
// Since we test the connections set below, destroy the server in case it
|
||||
// was left open.
|
||||
DebuggerServer.destroy();
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
let tab = await addTab(TEST_URI);
|
||||
|
||||
const win = await openWebIDE();
|
||||
const docProject = getProjectDocument(win);
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
|
||||
await connectToLocal(win, docRuntime);
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
|
||||
|
||||
await selectTabProject(win, docProject);
|
||||
|
||||
ok(win.UI.toolboxPromise, "Toolbox promise exists");
|
||||
await win.UI.toolboxPromise;
|
||||
|
||||
const 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
|
||||
const tabsNode = docProject.querySelector("#project-panel-tabs");
|
||||
is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
|
||||
await removeTab(tab);
|
||||
await waitForUpdate(win, "project");
|
||||
await waitForUpdate(win, "runtime-targets");
|
||||
is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available");
|
||||
|
||||
tab = await addTab(TEST_URI);
|
||||
|
||||
is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
|
||||
|
||||
await removeTab(tab);
|
||||
|
||||
is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
|
||||
|
||||
docProject.querySelector("#refresh-tabs").click();
|
||||
|
||||
await waitForUpdate(win, "runtime-targets");
|
||||
|
||||
is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available");
|
||||
|
||||
await win.Cmds.disconnectRuntime();
|
||||
await closeWebIDE(win);
|
||||
|
||||
DebuggerServer.destroy();
|
||||
})().then(finish, handleError);
|
||||
}
|
||||
|
||||
function connectToLocal(win, docRuntime) {
|
||||
return new Promise(resolve => {
|
||||
win.AppManager.connection.once(win.Connection.Events.CONNECTED, resolve);
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
});
|
||||
}
|
||||
|
||||
function selectTabProject(win, docProject) {
|
||||
return (async function() {
|
||||
await waitForUpdate(win, "runtime-targets");
|
||||
const tabsNode = docProject.querySelector("#project-panel-tabs");
|
||||
const tabNode = tabsNode.querySelectorAll(".panel-item")[1];
|
||||
const project = waitForUpdate(win, "project");
|
||||
tabNode.click();
|
||||
await project;
|
||||
})();
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"webide": {
|
||||
"prepackage": "echo \"{\\\"name\\\":\\\"hello\\\"}\" > manifest.webapp"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"webide": {
|
||||
"prepackage": {
|
||||
"command": "echo \"{\\\"name\\\":\\\"$NAME\\\"}\" > manifest.webapp",
|
||||
"cwd": "./stage",
|
||||
"env": ["NAME=world"]
|
||||
},
|
||||
"packageDir": "./stage"
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"webide": {
|
||||
"prepackage": "echo {\"name\":\"hello\"} > manifest.webapp"
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"webide": {
|
||||
"prepackage": {
|
||||
"command": "echo {\"name\":\"%NAME%\"} > manifest.webapp",
|
||||
"cwd": "./stage",
|
||||
"env": ["NAME=world"]
|
||||
},
|
||||
"packageDir": "./stage"
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
skip-if = asan || debug # bug 1078284 too many intermittents for these tests
|
||||
support-files =
|
||||
app/index.html
|
||||
app/manifest.webapp
|
||||
app.zip
|
||||
addons/adb-extension-linux.xpi
|
||||
addons/adb-extension-linux64.xpi
|
||||
addons/adb-extension-win32.xpi
|
||||
addons/adb-extension-mac64.xpi
|
||||
build_app1/package.json
|
||||
build_app2/manifest.webapp
|
||||
build_app2/package.json
|
||||
build_app2/stage/empty-directory
|
||||
build_app_windows1/package.json
|
||||
build_app_windows2/manifest.webapp
|
||||
build_app_windows2/package.json
|
||||
build_app_windows2/stage/empty-directory
|
||||
device_front_shared.js
|
||||
head.js
|
||||
hosted_app.manifest
|
||||
templates.json
|
||||
../../shared/test/browser_devices.json
|
||||
validator/*
|
||||
|
||||
[test_basic.html]
|
||||
[test_newapp.html]
|
||||
skip-if = (os == "win" && os_version == "10.0") # Bug 1197053
|
||||
[test_import.html]
|
||||
skip-if = (os == "linux") # Bug 1024734
|
||||
[test_duplicate_import.html]
|
||||
[test_runtime.html]
|
||||
[test_manifestUpdate.html]
|
||||
[test_addons.html]
|
||||
[test_deprecation_message.html]
|
||||
[test_device_runtime.html]
|
||||
[test_autoconnect_runtime.html]
|
||||
[test_autoselect_project.html]
|
||||
[test_device_preferences.html]
|
||||
[test_fullscreenToolbox.html]
|
||||
[test_zoom.html]
|
||||
[test_toolbox.html]
|
||||
[test_app_validator.html]
|
||||
[test_performance_panel.html]
|
|
@ -1,231 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* eslint no-unused-vars: ["error", {"args": "none", "vars": "local"}] */
|
||||
|
||||
"use strict";
|
||||
|
||||
var customName;
|
||||
var customValue;
|
||||
var customValueType;
|
||||
var customBtn;
|
||||
var newField;
|
||||
var change;
|
||||
var doc;
|
||||
var iframe;
|
||||
var resetBtn;
|
||||
var found = false;
|
||||
|
||||
function setDocument(frame) {
|
||||
iframe = frame;
|
||||
doc = iframe.contentWindow.document;
|
||||
}
|
||||
|
||||
function fieldChange(fields, id) {
|
||||
// Trigger existing field change
|
||||
for (const field of fields) {
|
||||
if (field.id == id) {
|
||||
const button = doc.getElementById("btn-" + id);
|
||||
found = true;
|
||||
ok(button.classList.contains("hide"), "Default field detected");
|
||||
field.value = "custom";
|
||||
field.click();
|
||||
ok(!button.classList.contains("hide"), "Custom field detected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(found, "Found " + id + " line");
|
||||
}
|
||||
|
||||
function addNewField() {
|
||||
found = false;
|
||||
customName = doc.querySelector("#custom-value-name");
|
||||
customValue = doc.querySelector("#custom-value-text");
|
||||
customValueType = doc.querySelector("#custom-value-type");
|
||||
customBtn = doc.querySelector("#custom-value");
|
||||
change = doc.createEvent("HTMLEvents");
|
||||
change.initEvent("change", false, true);
|
||||
|
||||
// Add a new custom string
|
||||
customValueType.value = "string";
|
||||
customValueType.dispatchEvent(change);
|
||||
customName.value = "new-string-field!";
|
||||
customValue.value = "test";
|
||||
customBtn.click();
|
||||
const newField = doc.querySelector("#new-string-field");
|
||||
if (newField) {
|
||||
found = true;
|
||||
is(newField.type, "text", "Custom type is a string");
|
||||
is(newField.value, "test", "Custom string new value is correct");
|
||||
}
|
||||
ok(found, "Found new string field line");
|
||||
is(customName.value, "", "Custom string name reset");
|
||||
is(customValue.value, "", "Custom string value reset");
|
||||
}
|
||||
|
||||
function addNewFieldWithEnter() {
|
||||
// Add a new custom value with the <enter> key
|
||||
found = false;
|
||||
customName.value = "new-string-field-two";
|
||||
customValue.value = "test";
|
||||
const newAddField = doc.querySelector("#add-custom-field");
|
||||
const enter = doc.createEvent("KeyboardEvent");
|
||||
enter.initKeyEvent(
|
||||
"keyup",
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
13,
|
||||
0
|
||||
);
|
||||
newAddField.dispatchEvent(enter);
|
||||
newField = doc.querySelector("#new-string-field-two");
|
||||
if (newField) {
|
||||
found = true;
|
||||
is(newField.type, "text", "Custom type is a string");
|
||||
is(newField.value, "test", "Custom string new value is correct");
|
||||
}
|
||||
ok(found, "Found new string field line");
|
||||
is(customName.value, "", "Custom string name reset");
|
||||
is(customValue.value, "", "Custom string value reset");
|
||||
}
|
||||
|
||||
function editExistingField() {
|
||||
// Edit existing custom string preference
|
||||
newField.value = "test2";
|
||||
newField.click();
|
||||
is(newField.value, "test2", "Custom string existing value is correct");
|
||||
}
|
||||
|
||||
function addNewFieldInteger() {
|
||||
// Add a new custom integer preference with a valid integer
|
||||
customValueType.value = "number";
|
||||
customValueType.dispatchEvent(change);
|
||||
customName.value = "new-integer-field";
|
||||
customValue.value = 1;
|
||||
found = false;
|
||||
|
||||
customBtn.click();
|
||||
newField = doc.querySelector("#new-integer-field");
|
||||
if (newField) {
|
||||
found = true;
|
||||
is(newField.type, "number", "Custom type is a number");
|
||||
is(newField.value, "1", "Custom integer value is correct");
|
||||
}
|
||||
ok(found, "Found new integer field line");
|
||||
is(customName.value, "", "Custom integer name reset");
|
||||
is(customValue.value, "", "Custom integer value reset");
|
||||
}
|
||||
|
||||
var editFieldInteger = async function() {
|
||||
// Edit existing custom integer preference
|
||||
newField.value = 3;
|
||||
newField.click();
|
||||
is(newField.value, "3", "Custom integer existing value is correct");
|
||||
|
||||
// Reset a custom field
|
||||
const resetBtn = doc.querySelector("#btn-new-integer-field");
|
||||
resetBtn.click();
|
||||
|
||||
try {
|
||||
await iframe.contentWindow.configView._defaultField;
|
||||
} catch (err) {
|
||||
const fieldRow = doc.querySelector("#row-new-integer-field");
|
||||
if (!fieldRow) {
|
||||
found = false;
|
||||
}
|
||||
ok(!found, "Custom field removed");
|
||||
}
|
||||
};
|
||||
|
||||
var resetExistingField = async function(id) {
|
||||
const existing = doc.getElementById(id);
|
||||
existing.click();
|
||||
is(existing.checked, true, "Existing boolean value is correct");
|
||||
resetBtn = doc.getElementById("btn-" + id);
|
||||
resetBtn.click();
|
||||
|
||||
await iframe.contentWindow.configView._defaultField;
|
||||
|
||||
ok(resetBtn.classList.contains("hide"), "Reset button hidden");
|
||||
is(existing.checked, true, "Existing field reset");
|
||||
};
|
||||
|
||||
var resetNewField = async function(id) {
|
||||
const custom = doc.getElementById(id);
|
||||
custom.click();
|
||||
is(custom.value, "test", "New string value is correct");
|
||||
resetBtn = doc.getElementById("btn-" + id);
|
||||
resetBtn.click();
|
||||
|
||||
await iframe.contentWindow.configView._defaultField;
|
||||
|
||||
ok(resetBtn.classList.contains("hide"), true, "Reset button hidden");
|
||||
};
|
||||
|
||||
function addNewFieldBoolean() {
|
||||
customValueType.value = "boolean";
|
||||
customValueType.dispatchEvent(change);
|
||||
customName.value = "new-boolean-field";
|
||||
customValue.checked = true;
|
||||
found = false;
|
||||
customBtn.click();
|
||||
newField = doc.querySelector("#new-boolean-field");
|
||||
if (newField) {
|
||||
found = true;
|
||||
is(newField.type, "checkbox", "Custom type is a checkbox");
|
||||
is(newField.checked, true, "Custom boolean value is correctly true");
|
||||
}
|
||||
ok(found, "Found new boolean field line");
|
||||
|
||||
// Mouse event trigger
|
||||
const mouseClick = new MouseEvent("click", {
|
||||
canBubble: true,
|
||||
cancelable: true,
|
||||
view: doc.parent,
|
||||
});
|
||||
|
||||
found = false;
|
||||
customValueType.value = "boolean";
|
||||
customValueType.dispatchEvent(change);
|
||||
customName.value = "new-boolean-field2";
|
||||
customValue.dispatchEvent(mouseClick);
|
||||
customBtn.dispatchEvent(mouseClick);
|
||||
newField = doc.querySelector("#new-boolean-field2");
|
||||
if (newField) {
|
||||
found = true;
|
||||
is(newField.checked, true, "Custom boolean value is correctly false");
|
||||
}
|
||||
ok(found, "Found new second boolean field line");
|
||||
|
||||
is(customName.value, "", "Custom boolean name reset");
|
||||
is(customValue.checked, false, "Custom boolean value reset");
|
||||
|
||||
newField.click();
|
||||
is(newField.checked, false, "Custom boolean existing value is correct");
|
||||
}
|
||||
|
||||
function searchFields(deck, keyword) {
|
||||
// Search for a non-existent field
|
||||
const searchField = doc.querySelector("#search-bar");
|
||||
searchField.value = "![o_O]!";
|
||||
searchField.click();
|
||||
|
||||
const fieldsTotal = doc.querySelectorAll("tr.edit-row").length;
|
||||
let hiddenFields = doc.querySelectorAll("tr.hide");
|
||||
is(hiddenFields.length, fieldsTotal, "Search keyword not found");
|
||||
|
||||
// Search for existing fields
|
||||
searchField.value = keyword;
|
||||
searchField.click();
|
||||
hiddenFields = doc.querySelectorAll("tr.hide");
|
||||
isnot(hiddenFields.length, fieldsTotal, "Search keyword found");
|
||||
|
||||
doc.querySelector("#close").click();
|
||||
|
||||
ok(!deck.selectedPanel, "No panel selected");
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test Tab</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Test Tab
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,276 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
var { AppConstants } = ChromeUtils.import(
|
||||
"resource://gre/modules/AppConstants.jsm"
|
||||
);
|
||||
const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
|
||||
const { gDevTools } = require("devtools/client/framework/devtools");
|
||||
var Services = require("Services");
|
||||
const { AppProjects } = require("devtools/client/webide/modules/app-projects");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const { DebuggerServer } = require("devtools/server/debugger-server");
|
||||
|
||||
var TEST_BASE;
|
||||
if (window.location === AppConstants.BROWSER_CHROME_URL) {
|
||||
TEST_BASE =
|
||||
"chrome://mochitests/content/browser/devtools/client/webide/test/";
|
||||
} else {
|
||||
TEST_BASE = "chrome://mochitests/content/chrome/devtools/client/webide/test/";
|
||||
}
|
||||
|
||||
Services.prefs.setBoolPref("devtools.webide.enabled", true);
|
||||
Services.prefs.setBoolPref("devtools.webide.enableLocalRuntime", true);
|
||||
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.remote.adb.extensionURL",
|
||||
TEST_BASE + "addons/adb-extension-#OS#.xpi"
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.webide.templatesURL",
|
||||
TEST_BASE + "templates.json"
|
||||
);
|
||||
Services.prefs.setCharPref(
|
||||
"devtools.devices.url",
|
||||
TEST_BASE + "browser_devices.json"
|
||||
);
|
||||
|
||||
var registerCleanupFunction =
|
||||
registerCleanupFunction || SimpleTest.registerCleanupFunction;
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("devtools.webide.enabled");
|
||||
Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
|
||||
Services.prefs.clearUserPref("devtools.webide.autoinstallADBExtension");
|
||||
Services.prefs.clearUserPref("devtools.webide.busyTimeout");
|
||||
Services.prefs.clearUserPref("devtools.webide.lastSelectedProject");
|
||||
Services.prefs.clearUserPref("devtools.webide.lastConnectedRuntime");
|
||||
});
|
||||
|
||||
var openWebIDE = async function({ autoInstallAddons } = {}) {
|
||||
info("opening WebIDE");
|
||||
|
||||
Services.prefs.setBoolPref(
|
||||
"devtools.webide.autoinstallADBExtension",
|
||||
!!autoInstallAddons
|
||||
);
|
||||
|
||||
const win = Services.ww.openWindow(
|
||||
null,
|
||||
"chrome://webide/content/",
|
||||
"webide",
|
||||
"chrome,centerscreen,resizable",
|
||||
null
|
||||
);
|
||||
|
||||
await new Promise(resolve => {
|
||||
win.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
SimpleTest.requestCompleteLog();
|
||||
SimpleTest.executeSoon(resolve);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
|
||||
info("WebIDE open");
|
||||
|
||||
return win;
|
||||
};
|
||||
|
||||
function closeWebIDE(win) {
|
||||
info("Closing WebIDE");
|
||||
|
||||
return new Promise(resolve => {
|
||||
win.addEventListener(
|
||||
"unload",
|
||||
function() {
|
||||
info("WebIDE closed");
|
||||
SimpleTest.executeSoon(resolve);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
win.close();
|
||||
});
|
||||
}
|
||||
|
||||
function removeAllProjects() {
|
||||
return (async function() {
|
||||
await AppProjects.load();
|
||||
// use a new array so we're not iterating over the same
|
||||
// underlying array that's being modified by AppProjects
|
||||
const projects = AppProjects.projects.map(p => p.location);
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
await AppProjects.remove(projects[i]);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
function nextTick() {
|
||||
return new Promise(resolve => {
|
||||
SimpleTest.executeSoon(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForUpdate(win, update) {
|
||||
info("Wait: " + update);
|
||||
return new Promise(resolve => {
|
||||
win.AppManager.on("app-manager-update", function onUpdate(what) {
|
||||
info("Got: " + what);
|
||||
if (what !== update) {
|
||||
return;
|
||||
}
|
||||
win.AppManager.off("app-manager-update", onUpdate);
|
||||
resolve(win.UI._updatePromise);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForTime(time) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
}
|
||||
|
||||
function documentIsLoaded(doc) {
|
||||
return new Promise(resolve => {
|
||||
if (doc.readyState == "complete") {
|
||||
resolve();
|
||||
} else {
|
||||
doc.addEventListener("readystatechange", function onChange() {
|
||||
if (doc.readyState == "complete") {
|
||||
doc.removeEventListener("readystatechange", onChange);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function lazyIframeIsLoaded(iframe) {
|
||||
return new Promise(resolve => {
|
||||
iframe.addEventListener(
|
||||
"load",
|
||||
function() {
|
||||
resolve(nextTick());
|
||||
},
|
||||
{ capture: true, once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function addTab(aUrl, aWindow) {
|
||||
info("Adding tab: " + aUrl);
|
||||
|
||||
return new Promise(resolve => {
|
||||
const targetWindow = aWindow || window;
|
||||
const targetBrowser = targetWindow.gBrowser;
|
||||
|
||||
targetWindow.focus();
|
||||
const tab = (targetBrowser.selectedTab = targetBrowser.addTab(aUrl));
|
||||
const linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function() {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
resolve(tab);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function removeTab(aTab, aWindow) {
|
||||
info("Removing tab.");
|
||||
|
||||
return new Promise(resolve => {
|
||||
const targetWindow = aWindow || window;
|
||||
const targetBrowser = targetWindow.gBrowser;
|
||||
const tabContainer = targetBrowser.tabContainer;
|
||||
|
||||
tabContainer.addEventListener(
|
||||
"TabClose",
|
||||
function(aEvent) {
|
||||
info("Tab removed and finished closing.");
|
||||
resolve();
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
|
||||
targetBrowser.removeTab(aTab);
|
||||
});
|
||||
}
|
||||
|
||||
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 getRuntimeWindow(win) {
|
||||
return win.document.querySelector("#runtime-listing-panel-details")
|
||||
.contentWindow;
|
||||
}
|
||||
|
||||
function getProjectWindow(win) {
|
||||
return win.document.querySelector("#project-listing-panel-details")
|
||||
.contentWindow;
|
||||
}
|
||||
|
||||
function getAddonsDocument(win) {
|
||||
return win.document.querySelector("#deck-panel-addons").contentDocument;
|
||||
}
|
||||
|
||||
function connectToLocalRuntime(win) {
|
||||
info("Loading local runtime.");
|
||||
|
||||
const runtimePanel = getRuntimeDocument(win);
|
||||
|
||||
const panelNode = runtimePanel.querySelector("#runtime-panel");
|
||||
const items = panelNode.querySelectorAll(".runtime-panel-item-other");
|
||||
is(items.length, 2, "Found 2 custom runtime buttons");
|
||||
|
||||
const updated = waitForUpdate(win, "runtime-global-actors");
|
||||
items[1].click();
|
||||
return updated;
|
||||
}
|
||||
|
||||
function handleError(aError) {
|
||||
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
|
||||
finish();
|
||||
}
|
||||
|
||||
function waitForConnectionChange(expectedState, count = 1) {
|
||||
return new Promise(resolve => {
|
||||
const onConnectionChange = state => {
|
||||
if (state != expectedState) {
|
||||
return;
|
||||
}
|
||||
if (--count != 0) {
|
||||
return;
|
||||
}
|
||||
DebuggerServer.off("connectionchange", onConnectionChange);
|
||||
resolve();
|
||||
};
|
||||
DebuggerServer.on("connectionchange", onConnectionChange);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from shared-head.js.
|
||||
*/
|
||||
function waitUntil(predicate, interval = 100) {
|
||||
if (predicate()) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
setTimeout(function() {
|
||||
waitUntil(predicate, interval).then(() => resolve(true));
|
||||
}, interval);
|
||||
});
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"name": "hosted manifest name property"
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
[
|
||||
{
|
||||
"file": "chrome://mochitests/content/chrome/devtools/client/webide/test/app.zip?1",
|
||||
"icon": "ximgx1",
|
||||
"name": "app name 1",
|
||||
"description": "app description 1"
|
||||
},
|
||||
{
|
||||
"file": "chrome://mochitests/content/chrome/devtools/client/webide/test/app.zip?2",
|
||||
"icon": "ximgx2",
|
||||
"name": "app name 2",
|
||||
"description": "app description 2"
|
||||
}
|
||||
]
|
|
@ -1,85 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
// XXX Bug 1072167 - When updating after migration, fix the no-undef issues.
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const { adbAddon, ADB_ADDON_STATES } = require("devtools/shared/adb/adb-addon");
|
||||
function isAdbAddonInstalled() {
|
||||
return adbAddon.status === ADB_ADDON_STATES.INSTALLED;
|
||||
}
|
||||
|
||||
function uninstallADBFromUI(doc) {
|
||||
return new Promise((resolve, reject) => {
|
||||
adbAddon.on("update", function onUpdate() {
|
||||
nextTick().then(() => {
|
||||
const li = doc.querySelector('[status="uninstalled"][addon="adb"]');
|
||||
if (li) {
|
||||
adbAddon.off("update", onUpdate);
|
||||
resolve();
|
||||
} else {
|
||||
reject("Can't find item");
|
||||
}
|
||||
});
|
||||
});
|
||||
const li = doc.querySelector('[status="installed"][addon="adb"]');
|
||||
li.querySelector(".uninstall-button").click();
|
||||
});
|
||||
}
|
||||
|
||||
(async function() {
|
||||
ok(!isAdbAddonInstalled(), "ADB extension not installed");
|
||||
|
||||
const win = await openWebIDE({
|
||||
autoInstallAddons: true,
|
||||
});
|
||||
|
||||
// ADB is installed asynchronously after starting WebIDE.
|
||||
while (!isAdbAddonInstalled()) {
|
||||
await adbAddon.once("update");
|
||||
}
|
||||
|
||||
ok(isAdbAddonInstalled(), "ADB extension has been auto-installed");
|
||||
|
||||
await nextTick();
|
||||
|
||||
const addonDoc = getAddonsDocument(win);
|
||||
const w = addonDoc.querySelector(".warning");
|
||||
let display = addonDoc.defaultView.getComputedStyle(w).display;
|
||||
is(display, "none", "Warning about missing ADB hidden");
|
||||
|
||||
await uninstallADBFromUI(addonDoc, "adb");
|
||||
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
const panelNode = docRuntime.querySelector("#runtime-panel");
|
||||
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");
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,199 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
const {HttpServer} = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
|
||||
|
||||
const {AppValidator} = require("devtools/client/webide/modules/app-validator");
|
||||
const nsFile = Components.Constructor("@mozilla.org/file/local;1",
|
||||
"nsIFile", "initWithPath");
|
||||
const strings = Services.strings.createBundle("chrome://devtools/locale/app-manager.properties");
|
||||
let httpserver, fakeOrigin;
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
httpserver = new HttpServer();
|
||||
httpserver.start(-1);
|
||||
fakeOrigin = "http://localhost:" + httpserver.identity.primaryPort + "/";
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
function createHosted(path, manifestFile = "/manifest.webapp") {
|
||||
const dirPath = getTestFilePath("validator/" + path);
|
||||
httpserver.registerDirectory("/", nsFile(dirPath));
|
||||
return new AppValidator({
|
||||
type: "hosted",
|
||||
location: fakeOrigin + manifestFile,
|
||||
});
|
||||
}
|
||||
|
||||
function createPackaged(path) {
|
||||
const dirPath = getTestFilePath("validator/" + path);
|
||||
return new AppValidator({
|
||||
type: "packaged",
|
||||
location: dirPath,
|
||||
});
|
||||
}
|
||||
|
||||
function next() {
|
||||
const test = tests.shift();
|
||||
if (test) {
|
||||
try {
|
||||
test();
|
||||
} catch (e) {
|
||||
console.error("exception", String(e), e, e.stack);
|
||||
}
|
||||
} else {
|
||||
httpserver.stop(function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const tests = [
|
||||
// Test a 100% valid example
|
||||
function() {
|
||||
const validator = createHosted("valid");
|
||||
validator.validate().then(() => {
|
||||
is(validator.errors.length, 0, "valid app got no error");
|
||||
is(validator.warnings.length, 0, "valid app got no warning");
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
function() {
|
||||
const validator = createPackaged("valid");
|
||||
validator.validate().then(() => {
|
||||
is(validator.errors.length, 0, "valid packaged app got no error");
|
||||
is(validator.warnings.length, 0, "valid packaged app got no warning");
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
// Test a launch path that returns a 404
|
||||
function() {
|
||||
const validator = createHosted("wrong-launch-path");
|
||||
validator.validate().then(() => {
|
||||
is(validator.errors.length, 1, "app with non-existant launch path got an error");
|
||||
is(validator.errors[0], strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [fakeOrigin + "wrong-path.html", 404]),
|
||||
"with the right error message");
|
||||
is(validator.warnings.length, 0, "but no warning");
|
||||
next();
|
||||
});
|
||||
},
|
||||
function() {
|
||||
const validator = createPackaged("wrong-launch-path");
|
||||
validator.validate().then(() => {
|
||||
is(validator.errors.length, 1, "app with wrong path got an error");
|
||||
const file = nsFile(validator.location);
|
||||
file.append("wrong-path.html");
|
||||
const url = Services.io.newFileURI(file);
|
||||
is(validator.errors[0], strings.formatStringFromName("validator.accessFailedLaunchPath", [url.spec]),
|
||||
"with the expected message");
|
||||
is(validator.warnings.length, 0, "but no warning");
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
// Test when using a non-absolute path for launch_path
|
||||
function() {
|
||||
const validator = createHosted("non-absolute-path");
|
||||
validator.validate().then(() => {
|
||||
is(validator.errors.length, 1, "app with non absolute path got an error");
|
||||
is(validator.errors[0], strings.formatStringFromName("validator.nonAbsoluteLaunchPath", ["non-absolute.html"]),
|
||||
"with expected message");
|
||||
is(validator.warnings.length, 0, "but no warning");
|
||||
next();
|
||||
});
|
||||
},
|
||||
function() {
|
||||
const validator = createPackaged("non-absolute-path");
|
||||
validator.validate().then(() => {
|
||||
is(validator.errors.length, 1, "app with non absolute path got an error");
|
||||
is(validator.errors[0], strings.formatStringFromName("validator.nonAbsoluteLaunchPath", ["non-absolute.html"]),
|
||||
"with expected message");
|
||||
is(validator.warnings.length, 0, "but no warning");
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
// Test multiple failures (missing name [error] and icon [warning])
|
||||
function() {
|
||||
const validator = createHosted("no-name-or-icon");
|
||||
validator.validate().then(() => {
|
||||
checkNoNameOrIcon(validator);
|
||||
});
|
||||
},
|
||||
function() {
|
||||
const validator = createPackaged("no-name-or-icon");
|
||||
validator.validate().then(() => {
|
||||
checkNoNameOrIcon(validator);
|
||||
});
|
||||
},
|
||||
|
||||
// Test a regular URL instead of a direct link to the manifest
|
||||
function() {
|
||||
const validator = createHosted("valid", "/");
|
||||
validator.validate().then(() => {
|
||||
is(validator.warnings.length, 0, "manifest found got no warning");
|
||||
is(validator.errors.length, 0, "manifest found got no error");
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
// Test finding a manifest at origin's root
|
||||
function() {
|
||||
const validator = createHosted("valid", "/unexisting-dir");
|
||||
validator.validate().then(() => {
|
||||
is(validator.warnings.length, 0, "manifest found at origin root got no warning");
|
||||
is(validator.errors.length, 0, "manifest found at origin root got no error");
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
// Test priorization of manifest.webapp at provided location instead of a manifest located at origin's root
|
||||
function() {
|
||||
const validator = createHosted("valid", "/alsoValid");
|
||||
validator.validate().then(() => {
|
||||
is(validator.manifest.name, "valid at subfolder", "manifest at subfolder was used");
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
];
|
||||
|
||||
function checkNoNameOrIcon(validator) {
|
||||
is(validator.errors.length, 1, "app with no name has an error");
|
||||
is(validator.errors[0],
|
||||
strings.GetStringFromName("validator.missNameManifestProperty"),
|
||||
"with expected message");
|
||||
is(validator.warnings.length, 1, "app with no icon has a warning");
|
||||
is(validator.warnings[0],
|
||||
strings.GetStringFromName("validator.missIconsManifestProperty"),
|
||||
"with expected message");
|
||||
next();
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,97 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
let win = await openWebIDE();
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
|
||||
const 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");
|
||||
|
||||
const panelNode = docRuntime.querySelector("#runtime-panel");
|
||||
const items = panelNode.querySelectorAll(".runtime-panel-item-usb");
|
||||
is(items.length, 1, "Found one runtime button");
|
||||
|
||||
let connectionsChanged = waitForConnectionChange("opened");
|
||||
items[0].click();
|
||||
|
||||
ok(win.document.querySelector("window").classList.contains("busy"),
|
||||
"UI is busy");
|
||||
await win.UI._busyPromise;
|
||||
|
||||
await connectionsChanged;
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
|
||||
|
||||
connectionsChanged = waitForConnectionChange("closed");
|
||||
|
||||
await nextTick();
|
||||
await closeWebIDE(win);
|
||||
|
||||
await connectionsChanged;
|
||||
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
|
||||
|
||||
// The DebuggerServer is destroyed when closing WebIDE, so re-initialize it.
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
connectionsChanged = waitForConnectionChange("opened");
|
||||
|
||||
win = await openWebIDE();
|
||||
|
||||
win.AppManager.runtimeList.usb.push(fakeRuntime);
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
await waitForUpdate(win, "runtime-targets");
|
||||
|
||||
await connectionsChanged;
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Automatically reconnected");
|
||||
|
||||
await win.Cmds.disconnectRuntime();
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
DebuggerServer.destroy();
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,112 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
let win = await openWebIDE();
|
||||
let docRuntime = getRuntimeDocument(win);
|
||||
const 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
|
||||
let connectionsChanged = waitForConnectionChange("opened");
|
||||
items[1].click();
|
||||
|
||||
await waitForUpdate(win, "runtime-targets");
|
||||
|
||||
await connectionsChanged;
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
|
||||
|
||||
ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
|
||||
|
||||
// Select main process
|
||||
await win.Cmds.showProjectPanel();
|
||||
await waitForUpdate(win, "runtime-targets");
|
||||
SimpleTest.executeSoon(() => {
|
||||
docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
|
||||
});
|
||||
|
||||
await waitForUpdate(win, "project");
|
||||
|
||||
const lastProject = Services.prefs.getCharPref("devtools.webide.lastSelectedProject");
|
||||
is(lastProject, "mainProcess:", "Last project is main process");
|
||||
|
||||
connectionsChanged = waitForConnectionChange("closed");
|
||||
|
||||
await nextTick();
|
||||
await closeWebIDE(win);
|
||||
|
||||
await connectionsChanged;
|
||||
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
|
||||
|
||||
// The DebuggerServer is destroyed when closing WebIDE, so re-initialize it.
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
connectionsChanged = waitForConnectionChange("opened");
|
||||
|
||||
// Re-open, should reselect main process after connection
|
||||
win = await 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();
|
||||
|
||||
await waitForUpdate(win, "runtime-targets");
|
||||
|
||||
await connectionsChanged;
|
||||
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");
|
||||
|
||||
// Wait for the toolbox to be fully loaded
|
||||
await win.UI.toolboxPromise;
|
||||
|
||||
// If we happen to pass a project object targeting the same context,
|
||||
// here, the main process, the `selectedProject` attribute shouldn't be updated
|
||||
// so that no `project` event would fire.
|
||||
const oldProject = win.AppManager.selectedProject;
|
||||
win.AppManager.selectedProject = {
|
||||
type: "mainProcess",
|
||||
};
|
||||
is(win.AppManager.selectedProject, oldProject, "AppManager.selectedProject shouldn't be updated if we selected the same project");
|
||||
|
||||
await win.Cmds.disconnectRuntime();
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
DebuggerServer.destroy();
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,56 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
const win = await openWebIDE();
|
||||
|
||||
const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
|
||||
await gDevToolsBrowser.isWebIDEInitialized.promise;
|
||||
ok(true, "WebIDE was initialized");
|
||||
|
||||
ok(win, "Found a window");
|
||||
ok(win.AppManager, "App Manager accessible");
|
||||
const appmgr = win.AppManager;
|
||||
ok(appmgr.connection, "App Manager connection ready");
|
||||
ok(appmgr.runtimeList, "Runtime list ready");
|
||||
|
||||
// test error reporting
|
||||
const nbox = win.UI.notificationBox;
|
||||
let notification = nbox.getNotificationWithValue("webide:errornotification");
|
||||
ok(!notification, "No notification yet");
|
||||
const deferred = new Promise((resolve, reject) => {
|
||||
nextTick().then(() => {
|
||||
reject("BOOM!");
|
||||
});
|
||||
});
|
||||
try {
|
||||
await win.UI.busyUntil(deferred, "xx");
|
||||
} catch (e) { /* This *will* fail */ }
|
||||
notification = nbox.getNotificationWithValue("webide:errornotification");
|
||||
ok(notification, "Error has been reported");
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,58 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
info("Open WebIDE");
|
||||
const win = await openWebIDE();
|
||||
|
||||
const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
|
||||
await gDevToolsBrowser.isWebIDEInitialized.promise;
|
||||
ok(true, "WebIDE was initialized");
|
||||
|
||||
info("Check if the deprecation message is displayed");
|
||||
const nbox = win.UI.deprecationBox;
|
||||
const deprecationMessage = nbox.getNotificationWithValue("webide:deprecationnotification");
|
||||
ok(!!deprecationMessage, "The deprecation message is displayed");
|
||||
|
||||
info("Check if a button is displayed in the notification box");
|
||||
// Note: `notification-button` is a hardcoded className added by the XUL
|
||||
// notificationbox widget and we cannot set custom classnames.
|
||||
const button = nbox.stack.querySelector(".notification-button");
|
||||
ok(!!button, "The button to open about:debugging is displayed");
|
||||
button.click();
|
||||
|
||||
info("Wait until the about:debugging tab is selected in the main window");
|
||||
const mainWindow = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
await waitUntil(() => {
|
||||
const contentWindow = mainWindow.gBrowser.selectedBrowser.contentWindow;
|
||||
return contentWindow.location.href.startsWith("about:debugging");
|
||||
});
|
||||
|
||||
info("Remove the about:debugging tab");
|
||||
await removeTab(mainWindow.gBrowser.selectedTab, mainWindow);
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,85 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<script type="application/javascript" 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">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
const win = await openWebIDE();
|
||||
|
||||
const prefIframe = win.document.querySelector("#deck-panel-devicepreferences");
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
await connectToLocalRuntime(win);
|
||||
|
||||
const prefs = docRuntime.querySelector("#runtime-preferences");
|
||||
|
||||
ok(!prefs.hasAttribute("disabled"), "device prefs cmd enabled");
|
||||
|
||||
const deck = win.document.querySelector("#deck");
|
||||
|
||||
win.Cmds.showDevicePrefs();
|
||||
is(deck.selectedPanel, prefIframe, "device preferences iframe selected");
|
||||
|
||||
await nextTick();
|
||||
|
||||
await lazyIframeIsLoaded(prefIframe);
|
||||
|
||||
await prefIframe.contentWindow.getAllPrefs;
|
||||
|
||||
setDocument(prefIframe);
|
||||
|
||||
const fields = doc.querySelectorAll(".editable");
|
||||
|
||||
addNewField();
|
||||
|
||||
const preference = "accessibility.accesskeycausesactivation";
|
||||
|
||||
fieldChange(fields, preference);
|
||||
|
||||
addNewFieldWithEnter();
|
||||
|
||||
editExistingField();
|
||||
|
||||
addNewFieldInteger();
|
||||
|
||||
await editFieldInteger();
|
||||
|
||||
await resetExistingField("accessibility.accesskeycausesactivation");
|
||||
|
||||
addNewFieldBoolean();
|
||||
|
||||
searchFields(deck, "debugger");
|
||||
|
||||
DebuggerServer.destroy();
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
SimpleTest.finish();
|
||||
})().catch(e => {
|
||||
ok(false, "Exception: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,79 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
const win = await openWebIDE();
|
||||
|
||||
const detailsIframe = win.document.querySelector("#deck-panel-runtimedetails");
|
||||
|
||||
await connectToLocalRuntime(win);
|
||||
|
||||
const details = win.document.querySelector("#cmd_showRuntimeDetails");
|
||||
|
||||
ok(!details.hasAttribute("disabled"), "info cmd enabled");
|
||||
|
||||
const deck = win.document.querySelector("#deck");
|
||||
|
||||
win.Cmds.showRuntimeDetails();
|
||||
is(deck.selectedPanel, detailsIframe, "info iframe selected");
|
||||
|
||||
await nextTick();
|
||||
|
||||
await lazyIframeIsLoaded(detailsIframe);
|
||||
|
||||
await detailsIframe.contentWindow.getDescriptionPromise;
|
||||
|
||||
// device info and permissions content is checked in other tests
|
||||
// We just test one value to make sure we get something
|
||||
|
||||
const doc = detailsIframe.contentWindow.document;
|
||||
const trs = doc.querySelectorAll("tr");
|
||||
let found = false;
|
||||
|
||||
for (const tr of trs) {
|
||||
const [name, val] = tr.querySelectorAll("td");
|
||||
if (name.textContent == "appid") {
|
||||
found = true;
|
||||
is(val.textContent, Services.appinfo.ID, "appid has the right value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok(found, "Found appid line");
|
||||
|
||||
doc.querySelector("#close").click();
|
||||
|
||||
ok(!deck.selectedPanel, "No panel selected");
|
||||
|
||||
DebuggerServer.destroy();
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
SimpleTest.finish();
|
||||
})().catch(e => {
|
||||
ok(false, "Exception: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,77 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
const win = await openWebIDE();
|
||||
const docProject = getProjectDocument(win);
|
||||
const winProject = getProjectWindow(win);
|
||||
const packagedAppLocation = getTestFilePath("app");
|
||||
const hostedAppManifest = TEST_BASE + "hosted_app.manifest";
|
||||
|
||||
await win.AppProjects.load();
|
||||
is(win.AppProjects.projects.length, 0, "IDB is empty");
|
||||
|
||||
let onValidated = waitForUpdate(win, "project-validated");
|
||||
let onDetails = waitForUpdate(win, "details");
|
||||
await winProject.projectList.importPackagedApp(packagedAppLocation);
|
||||
await onValidated;
|
||||
await onDetails;
|
||||
|
||||
await winProject.projectList.importHostedApp(hostedAppManifest);
|
||||
await waitForUpdate(win, "project-validated");
|
||||
await nextTick();
|
||||
|
||||
onValidated = waitForUpdate(win, "project-validated");
|
||||
onDetails = waitForUpdate(win, "details");
|
||||
await winProject.projectList.importPackagedApp(packagedAppLocation);
|
||||
await onValidated;
|
||||
await onDetails;
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
is(project.location, packagedAppLocation, "Correctly reselected existing packaged app.");
|
||||
await nextTick();
|
||||
|
||||
info("to call importHostedApp(" + hostedAppManifest + ") again");
|
||||
await winProject.projectList.importHostedApp(hostedAppManifest);
|
||||
await waitForUpdate(win, "project-validated");
|
||||
project = win.AppManager.selectedProject;
|
||||
is(project.location, hostedAppManifest, "Correctly reselected existing hosted app.");
|
||||
await nextTick();
|
||||
|
||||
const panelNode = docProject.querySelector("#project-panel");
|
||||
const items = panelNode.querySelectorAll(".panel-item");
|
||||
// 3 controls, + 2 projects
|
||||
is(items.length, 5, "5 projects in panel");
|
||||
is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct");
|
||||
is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct");
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
await removeAllProjects();
|
||||
|
||||
SimpleTest.finish();
|
||||
})().catch(e => {
|
||||
ok(false, "Exception: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
function connectToLocal(win, docRuntime) {
|
||||
return new Promise(resolve => {
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
resolve);
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
const win = await openWebIDE();
|
||||
const docProject = getProjectDocument(win);
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
const onGlobalActors = waitForUpdate(win, "runtime-global-actors");
|
||||
const onRuntimeTargets = waitForUpdate(win, "runtime-targets");
|
||||
connectToLocal(win, docRuntime);
|
||||
await onGlobalActors;
|
||||
await onRuntimeTargets;
|
||||
|
||||
// Select main process
|
||||
SimpleTest.executeSoon(() => {
|
||||
docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
|
||||
});
|
||||
|
||||
await waitForUpdate(win, "project");
|
||||
|
||||
ok(win.UI.toolboxPromise, "Toolbox promise exists");
|
||||
await win.UI.toolboxPromise;
|
||||
|
||||
const nbox = win.document.getElementById("containerbox");
|
||||
ok(!nbox.hasAttribute("toolboxfullscreen"), "Toolbox is not fullscreen");
|
||||
|
||||
win.Cmds.showRuntimeDetails();
|
||||
|
||||
ok(!nbox.hasAttribute("toolboxfullscreen"), "Toolbox is not fullscreen");
|
||||
|
||||
await win.Cmds.disconnectRuntime();
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
DebuggerServer.destroy();
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,82 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
const win = await openWebIDE();
|
||||
const docProject = getProjectDocument(win);
|
||||
const winProject = getProjectWindow(win);
|
||||
const packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
await win.AppProjects.load();
|
||||
is(win.AppProjects.projects.length, 0, "IDB is empty");
|
||||
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ")");
|
||||
ok(!win.UI._busyPromise, "UI is not busy");
|
||||
|
||||
const onValidated = waitForUpdate(win, "project-validated");
|
||||
const onDetails = waitForUpdate(win, "details");
|
||||
await winProject.projectList.importPackagedApp(packagedAppLocation);
|
||||
await onValidated;
|
||||
await onDetails;
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
is(project.location, packagedAppLocation, "Location is valid");
|
||||
is(project.name, "A name (in app directory)", "name field has been updated");
|
||||
is(project.manifest.launch_path, "/index.html", "manifest found. launch_path valid.");
|
||||
is(project.manifest.description, "desc", "manifest found. description valid");
|
||||
|
||||
await nextTick();
|
||||
|
||||
let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
|
||||
await winProject.projectList.importHostedApp(hostedAppManifest);
|
||||
await waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
is(project.location, hostedAppManifest, "Location is valid");
|
||||
is(project.name, "hosted manifest name property", "name field has been updated");
|
||||
|
||||
await nextTick();
|
||||
|
||||
hostedAppManifest = TEST_BASE + "/app";
|
||||
await winProject.projectList.importHostedApp(hostedAppManifest);
|
||||
await waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
ok(project.location.endsWith("manifest.webapp"), "The manifest was found and the project was updated");
|
||||
|
||||
const panelNode = docProject.querySelector("#project-panel");
|
||||
const items = panelNode.querySelectorAll(".panel-item");
|
||||
// 4 controls, + 2 projects
|
||||
is(items.length, 6, "6 projects in panel");
|
||||
is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct");
|
||||
is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct");
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
await removeAllProjects();
|
||||
|
||||
SimpleTest.finish();
|
||||
})().catch(e => {
|
||||
ok(false, "Exception: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,97 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
(async function() {
|
||||
const win = await openWebIDE();
|
||||
const winProject = getProjectWindow(win);
|
||||
const AppManager = win.AppManager;
|
||||
|
||||
function isProjectMarkedAsValid() {
|
||||
const details = win.frames[1];
|
||||
return !details.document.body.classList.contains("error");
|
||||
}
|
||||
|
||||
const packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
const onValidated = waitForUpdate(win, "project-validated");
|
||||
const onDetails = waitForUpdate(win, "details");
|
||||
await winProject.projectList.importPackagedApp(packagedAppLocation);
|
||||
await onValidated;
|
||||
await onDetails;
|
||||
|
||||
const 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
|
||||
const originalName = project.manifest.name;
|
||||
|
||||
project.manifest.name = "xxx";
|
||||
|
||||
// Write to disk
|
||||
await AppManager.writeManifest(project);
|
||||
|
||||
// Read file
|
||||
const manifestPath = OS.Path.join(packagedAppLocation, "manifest.webapp");
|
||||
let data = await OS.File.read(manifestPath);
|
||||
data = new TextDecoder().decode(data);
|
||||
const json = JSON.parse(data);
|
||||
is(json.name, "xxx", "manifest written on disc");
|
||||
|
||||
// Make the manifest invalid on disk
|
||||
delete json.name;
|
||||
const Encoder = new TextEncoder();
|
||||
data = Encoder.encode(JSON.stringify(json));
|
||||
await OS.File.writeAtomic(manifestPath, data, {tmpPath: manifestPath + ".tmp"});
|
||||
|
||||
// Trigger validation
|
||||
await AppManager.validateAndUpdateProject(AppManager.selectedProject);
|
||||
await 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;
|
||||
await AppManager.writeManifest(project);
|
||||
|
||||
// Trigger validation
|
||||
await AppManager.validateAndUpdateProject(AppManager.selectedProject);
|
||||
await 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");
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
await removeAllProjects();
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,46 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
const win = await openWebIDE();
|
||||
const winProject = getProjectWindow(win);
|
||||
let tmpDir = FileUtils.getDir("TmpD", []);
|
||||
await winProject.projectList.newApp({
|
||||
index: 0,
|
||||
name: "webideTmpApp",
|
||||
folder: tmpDir,
|
||||
});
|
||||
|
||||
const 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);
|
||||
await closeWebIDE(win);
|
||||
await removeAllProjects();
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,60 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
window.onload = async function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
try {
|
||||
Services.prefs.setBoolPref("devtools.performance.new-panel-enabled", true);
|
||||
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
const win = await openWebIDE();
|
||||
|
||||
const perfIframe = win.document.querySelector("#deck-panel-performance");
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
await connectToLocalRuntime(win);
|
||||
|
||||
const prefs = docRuntime.querySelector("#runtime-performance");
|
||||
|
||||
ok(!prefs.hidden, "performance button is displayed");
|
||||
ok(!prefs.hasAttribute("disabled"), "performance cmd enabled");
|
||||
|
||||
const deck = win.document.querySelector("#deck");
|
||||
|
||||
win.Cmds.showPerformancePanel();
|
||||
is(deck.selectedPanel, perfIframe, "performance iframe selected");
|
||||
|
||||
await nextTick();
|
||||
|
||||
await lazyIframeIsLoaded(perfIframe);
|
||||
|
||||
await SimpleTest.promiseWaitForCondition(
|
||||
() => perfIframe.contentDocument.querySelector(".perf"),
|
||||
"Waited for the react rendering that never came."
|
||||
);
|
||||
ok(true, "The perf interface was correctly rendered.");
|
||||
await closeWebIDE(win);
|
||||
} catch (e) {
|
||||
ok(false, "Exception: " + e + "\nStack: " + e.stack);
|
||||
} finally {
|
||||
Services.prefs.clearUserPref("devtools.performance.new-panel-enabled");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,207 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let win;
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
(async function() {
|
||||
if (win) {
|
||||
await closeWebIDE(win);
|
||||
}
|
||||
DebuggerServer.destroy();
|
||||
await removeAllProjects();
|
||||
})();
|
||||
});
|
||||
|
||||
(async function() {
|
||||
function isPlayActive() {
|
||||
return !win.document.querySelector("#cmd_play").hasAttribute("disabled");
|
||||
}
|
||||
|
||||
function isStopActive() {
|
||||
return !win.document.querySelector("#cmd_stop").hasAttribute("disabled");
|
||||
}
|
||||
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
win = await openWebIDE();
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
const docProject = getProjectDocument(win);
|
||||
const winProject = getProjectWindow(win);
|
||||
|
||||
const packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
const onValidated = waitForUpdate(win, "project-validated");
|
||||
const onDetails = waitForUpdate(win, "details");
|
||||
await winProject.projectList.importPackagedApp(packagedAppLocation);
|
||||
await onValidated;
|
||||
await onDetails;
|
||||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
is(connection, win.AppManager.connection, "connection is valid");
|
||||
connection.host = null; // force connectPipe
|
||||
connection.connect();
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
get name() {
|
||||
return "fakeRuntime";
|
||||
},
|
||||
});
|
||||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
return new Promise(() => {});
|
||||
},
|
||||
|
||||
get name() {
|
||||
return "infiniteRuntime";
|
||||
},
|
||||
});
|
||||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
return new Promise(() => {});
|
||||
},
|
||||
|
||||
prolongedConnection: true,
|
||||
|
||||
get name() {
|
||||
return "prolongedRuntime";
|
||||
},
|
||||
});
|
||||
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
const panelNode = docRuntime.querySelector("#runtime-panel");
|
||||
const items = panelNode.querySelectorAll(".runtime-panel-item-usb");
|
||||
is(items.length, 3, "Found 3 runtime buttons");
|
||||
|
||||
let onGlobalActors = waitForUpdate(win, "runtime-global-actors");
|
||||
|
||||
let connectionsChanged = waitForConnectionChange("opened");
|
||||
items[0].click();
|
||||
|
||||
ok(win.document.querySelector("window").classList.contains("busy"),
|
||||
"UI is busy");
|
||||
await win.UI._busyPromise;
|
||||
|
||||
await connectionsChanged;
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
|
||||
|
||||
await onGlobalActors;
|
||||
|
||||
// Play button always disabled now, webapps actor removed
|
||||
ok(!isPlayActive(), "play button is disabled");
|
||||
ok(!isStopActive(), "stop button is disabled");
|
||||
const oldProject = win.AppManager.selectedProject;
|
||||
win.AppManager.selectedProject = null;
|
||||
|
||||
await nextTick();
|
||||
|
||||
ok(!isPlayActive(), "play button is disabled");
|
||||
ok(!isStopActive(), "stop button is disabled");
|
||||
win.AppManager._selectedProject = oldProject;
|
||||
win.UI.updateCommands();
|
||||
|
||||
await nextTick();
|
||||
|
||||
ok(!isPlayActive(), "play button is enabled");
|
||||
ok(!isStopActive(), "stop button is disabled");
|
||||
|
||||
connectionsChanged = waitForConnectionChange("closed");
|
||||
await win.Cmds.disconnectRuntime();
|
||||
|
||||
await connectionsChanged;
|
||||
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
|
||||
|
||||
ok(win.AppManager.selectedProject, "A project is still selected");
|
||||
ok(!isPlayActive(), "play button is disabled");
|
||||
ok(!isStopActive(), "stop button is disabled");
|
||||
|
||||
connectionsChanged = waitForConnectionChange("opened");
|
||||
onGlobalActors = waitForUpdate(win, "runtime-global-actors");
|
||||
const onRuntimeTargets = waitForUpdate(win, "runtime-targets");
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
await connectionsChanged;
|
||||
await onGlobalActors;
|
||||
await onRuntimeTargets;
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
|
||||
|
||||
ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
|
||||
|
||||
// Select main process
|
||||
SimpleTest.executeSoon(() => {
|
||||
docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
|
||||
});
|
||||
|
||||
await waitForUpdate(win, "project");
|
||||
|
||||
// Toolbox opens automatically for main process / runtime apps
|
||||
ok(win.UI.toolboxPromise, "Toolbox promise exists");
|
||||
await win.UI.toolboxPromise;
|
||||
|
||||
await win.Cmds.disconnectRuntime();
|
||||
|
||||
Services.prefs.setIntPref("devtools.webide.busyTimeout", 100);
|
||||
|
||||
// Click the infinite runtime
|
||||
items[1].click();
|
||||
ok(win.document.querySelector("window").classList.contains("busy"),
|
||||
"UI is busy");
|
||||
|
||||
// Wait for error message since connection never completes
|
||||
await new Promise(resolve => {
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Click the prolonged runtime
|
||||
items[2].click();
|
||||
ok(win.document.querySelector("window").classList.contains("busy"),
|
||||
"UI is busy");
|
||||
|
||||
// Check for unexpected error message since this is prolonged
|
||||
const noErrorDeferred = new Promise((resolve, reject) => {
|
||||
win.UI.reportError = errorName => {
|
||||
if (errorName === "error_operationTimeout") {
|
||||
reject();
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
await noErrorDeferred;
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,95 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let win;
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
(async function() {
|
||||
if (win) {
|
||||
await closeWebIDE(win);
|
||||
}
|
||||
DebuggerServer.destroy();
|
||||
await removeAllProjects();
|
||||
})();
|
||||
});
|
||||
|
||||
(async function() {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
|
||||
win = await openWebIDE();
|
||||
const docRuntime = getRuntimeDocument(win);
|
||||
const docProject = getProjectDocument(win);
|
||||
|
||||
win.AppManager.update("runtime-list");
|
||||
|
||||
const deferred = new Promise(resolve => {
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
resolve);
|
||||
});
|
||||
|
||||
docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
|
||||
ok(win.document.querySelector("window").classList.contains("busy"),
|
||||
"UI is busy");
|
||||
await win.UI._busyPromise;
|
||||
|
||||
await deferred;
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
|
||||
|
||||
await waitForUpdate(win, "runtime-global-actors");
|
||||
|
||||
ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
|
||||
|
||||
// Select main process
|
||||
SimpleTest.executeSoon(() => {
|
||||
docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
|
||||
});
|
||||
|
||||
await waitForUpdate(win, "project");
|
||||
|
||||
// Toolbox opens automatically for main process / runtime apps
|
||||
ok(win.UI.toolboxPromise, "Toolbox promise exists");
|
||||
const toolbox = await win.UI.toolboxPromise;
|
||||
|
||||
await toolbox.destroy();
|
||||
|
||||
ok(!win.UI.toolboxPromise, "Toolbox promise should be unset once toolbox.destroy()'s promise resolves");
|
||||
|
||||
// Reopen the toolbox right after to check races and also
|
||||
// opening a toolbox more than just once against the same target
|
||||
await win.Cmds.toggleToolbox();
|
||||
|
||||
ok(win.UI.toolboxPromise, "Toolbox promise exists");
|
||||
|
||||
await win.UI.destroyToolbox();
|
||||
|
||||
ok(!win.UI.toolboxPromise, "Toolbox promise is also nullified the second times");
|
||||
|
||||
await win.Cmds.disconnectRuntime();
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,71 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
(async function() {
|
||||
let win = await openWebIDE();
|
||||
let viewer = win.docShell.contentViewer;
|
||||
|
||||
win.Cmds.zoomOut();
|
||||
win.Cmds.zoomOut();
|
||||
win.Cmds.zoomOut();
|
||||
win.Cmds.zoomOut();
|
||||
win.Cmds.zoomOut();
|
||||
win.Cmds.zoomOut();
|
||||
win.Cmds.zoomOut();
|
||||
|
||||
let roundZoom = Math.round(10 * viewer.fullZoom) / 10;
|
||||
is(roundZoom, 0.6, "Reach min zoom");
|
||||
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
win.Cmds.zoomIn();
|
||||
|
||||
roundZoom = Math.round(10 * viewer.fullZoom) / 10;
|
||||
is(roundZoom, 1.4, "Reach max zoom");
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
win = await openWebIDE();
|
||||
viewer = win.docShell.contentViewer;
|
||||
|
||||
roundZoom = Math.round(10 * viewer.fullZoom) / 10;
|
||||
is(roundZoom, 1.4, "Zoom restored");
|
||||
|
||||
win.Cmds.resetZoom();
|
||||
|
||||
is(viewer.fullZoom, 1, "Zoom reset");
|
||||
|
||||
await closeWebIDE(win);
|
||||
|
||||
SimpleTest.finish();
|
||||
})();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"launch_path": "/home.html"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"name": "non-absolute path",
|
||||
"icons": {
|
||||
"128": "/icon.png"
|
||||
},
|
||||
"launch_path": "non-absolute.html"
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче