mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge fx-team to mozilla-central a=merge
This commit is contained in:
commit
1f2744b05d
@ -80,10 +80,13 @@ WebappsStore.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_feedStore: function() {
|
_feedStore: function() {
|
||||||
|
if (!this._webAppsActor) {
|
||||||
|
return promise.resolve();
|
||||||
|
}
|
||||||
this._listenToApps();
|
this._listenToApps();
|
||||||
return this._getAllApps()
|
return this._getAllApps()
|
||||||
.then(this._getRunningApps.bind(this))
|
.then(this._getRunningApps.bind(this))
|
||||||
.then(this._getAppsIcons.bind(this))
|
.then(this._getAppsIcons.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
_listenToApps: function() {
|
_listenToApps: function() {
|
||||||
|
@ -32,30 +32,12 @@ function performTest() {
|
|||||||
info("process name: " + gProcess._dbgProcess.processName);
|
info("process name: " + gProcess._dbgProcess.processName);
|
||||||
info("process sig: " + gProcess._dbgProcess.processSignature);
|
info("process sig: " + gProcess._dbgProcess.processSignature);
|
||||||
|
|
||||||
ok(gProcess._dbgProfile,
|
ok(gProcess._dbgProfilePath,
|
||||||
"The remote debugger profile wasn't created properly!");
|
"The remote debugger profile wasn't created properly!");
|
||||||
ok(gProcess._dbgProfile.localDir,
|
is(gProcess._dbgProfilePath, OS.Path.join(OS.Constants.Path.profileDir, "chrome_debugger_profile"),
|
||||||
"The remote debugger profile doesn't have a localDir...");
|
"The remote debugger profile isn't where we expect it!");
|
||||||
ok(gProcess._dbgProfile.rootDir,
|
|
||||||
"The remote debugger profile doesn't have a rootDir...");
|
|
||||||
ok(gProcess._dbgProfile.name,
|
|
||||||
"The remote debugger profile doesn't have a name...");
|
|
||||||
|
|
||||||
info("profile localDir: " + gProcess._dbgProfile.localDir.path);
|
info("profile path: " + gProcess._dbgProfilePath);
|
||||||
info("profile rootDir: " + gProcess._dbgProfile.rootDir.path);
|
|
||||||
info("profile name: " + gProcess._dbgProfile.name);
|
|
||||||
|
|
||||||
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
|
|
||||||
.createInstance(Ci.nsIToolkitProfileService);
|
|
||||||
|
|
||||||
let profile = profileService.getProfileByName(gProcess._dbgProfile.name);
|
|
||||||
|
|
||||||
ok(profile,
|
|
||||||
"The remote debugger profile wasn't *actually* created properly!");
|
|
||||||
is(profile.localDir.path, gProcess._dbgProfile.localDir.path,
|
|
||||||
"The remote debugger profile doesn't have the correct localDir!");
|
|
||||||
is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path,
|
|
||||||
"The remote debugger profile doesn't have the correct rootDir!");
|
|
||||||
|
|
||||||
gProcess.close();
|
gProcess.close();
|
||||||
}
|
}
|
||||||
@ -68,9 +50,7 @@ function aOnClose() {
|
|||||||
|
|
||||||
info("process exit value: " + gProcess._dbgProcess.exitValue);
|
info("process exit value: " + gProcess._dbgProcess.exitValue);
|
||||||
|
|
||||||
info("profile localDir: " + gProcess._dbgProfile.localDir.path);
|
info("profile path: " + gProcess._dbgProfilePath);
|
||||||
info("profile rootDir: " + gProcess._dbgProfile.rootDir.path);
|
|
||||||
info("profile name: " + gProcess._dbgProfile.name);
|
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||||
|
|
||||||
const DBG_XUL = "chrome://browser/content/devtools/framework/toolbox-process-window.xul";
|
const DBG_XUL = "chrome://browser/content/devtools/framework/toolbox-process-window.xul";
|
||||||
const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger";
|
const CHROME_DEBUGGER_PROFILE_NAME = "chrome_debugger_profile";
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm")
|
||||||
@ -154,54 +154,33 @@ BrowserToolboxProcess.prototype = {
|
|||||||
_initProfile: function() {
|
_initProfile: function() {
|
||||||
dumpn("Initializing the chrome toolbox user profile.");
|
dumpn("Initializing the chrome toolbox user profile.");
|
||||||
|
|
||||||
let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]
|
let debuggingProfileDir = Services.dirsvc.get("ProfLD", Ci.nsIFile);
|
||||||
.createInstance(Ci.nsIToolkitProfileService);
|
debuggingProfileDir.append(CHROME_DEBUGGER_PROFILE_NAME);
|
||||||
|
|
||||||
let profileName;
|
|
||||||
try {
|
try {
|
||||||
// Attempt to get the required chrome debugging profile name string.
|
debuggingProfileDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
||||||
profileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME;
|
} catch (ex) {
|
||||||
dumpn("Using chrome toolbox profile name: " + profileName);
|
if (ex.result !== Cr.NS_ERROR_FILE_ALREADY_EXISTS) {
|
||||||
} catch (e) {
|
dumpn("Error trying to create a profile directory, failing.");
|
||||||
// Requested profile string could not be retrieved.
|
dumpn("Error: " + (ex.message || ex));
|
||||||
profileName = CHROME_DEBUGGER_PROFILE_NAME;
|
|
||||||
let msg = "Querying the current profile failed. " + e.name + ": " + e.message;
|
|
||||||
dumpn(msg);
|
|
||||||
Cu.reportError(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
let profileObject;
|
|
||||||
try {
|
|
||||||
// Attempt to get the required chrome debugging profile toolkit object.
|
|
||||||
profileObject = profileService.getProfileByName(profileName);
|
|
||||||
dumpn("Using chrome toolbox profile object: " + profileObject);
|
|
||||||
|
|
||||||
// The profile exists but the corresponding folder may have been deleted.
|
|
||||||
var enumerator = Services.dirsvc.get("ProfD", Ci.nsIFile).parent.directoryEntries;
|
|
||||||
while (enumerator.hasMoreElements()) {
|
|
||||||
let profileDir = enumerator.getNext().QueryInterface(Ci.nsIFile);
|
|
||||||
if (profileDir.leafName.contains(profileName)) {
|
|
||||||
// Requested profile was found and the folder exists.
|
|
||||||
this._dbgProfile = profileObject;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Requested profile was found but the folder was deleted. Cleanup needed.
|
|
||||||
profileObject.remove(true);
|
|
||||||
dumpn("The already existing chrome toolbox profile was invalid.");
|
|
||||||
} catch (e) {
|
|
||||||
// Requested profile object was not found.
|
|
||||||
let msg = "Creating a profile failed. " + e.name + ": " + e.message;
|
|
||||||
dumpn(msg);
|
|
||||||
Cu.reportError(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new chrome debugging profile.
|
this._dbgProfilePath = debuggingProfileDir.path;
|
||||||
this._dbgProfile = profileService.createProfile(null, profileName);
|
|
||||||
profileService.flush();
|
|
||||||
|
|
||||||
dumpn("Finished creating the chrome toolbox user profile.");
|
// We would like to copy prefs into this new profile...
|
||||||
dumpn("Flushed profile service with: " + profileName);
|
let prefsFile = debuggingProfileDir.clone();
|
||||||
|
prefsFile.append("prefs.js");
|
||||||
|
// ... but unfortunately, when we run tests, it seems the starting profile
|
||||||
|
// clears out the prefs file before re-writing it, and in practice the
|
||||||
|
// file is empty when we get here. So just copying doesn't work in that
|
||||||
|
// case.
|
||||||
|
// We could force a sync pref flush and then copy it... but if we're doing
|
||||||
|
// that, we might as well just flush directly to the new profile, which
|
||||||
|
// always works:
|
||||||
|
Services.prefs.savePrefFile(prefsFile);
|
||||||
|
|
||||||
|
dumpn("Finished creating the chrome toolbox user profile at: " + this._dbgProfilePath);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,7 +198,7 @@ BrowserToolboxProcess.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dumpn("Running chrome debugging process.");
|
dumpn("Running chrome debugging process.");
|
||||||
let args = ["-no-remote", "-foreground", "-P", this._dbgProfile.name, "-chrome", xulURI];
|
let args = ["-no-remote", "-foreground", "-profile", this._dbgProfilePath, "-chrome", xulURI];
|
||||||
|
|
||||||
process.runwAsync(args, args.length, { observe: () => this.close() });
|
process.runwAsync(args, args.length, { observe: () => this.close() });
|
||||||
|
|
||||||
|
@ -1419,7 +1419,7 @@ CssRuleView.prototype = {
|
|||||||
this.element.appendChild(editor.element);
|
this.element.appendChild(editor.element);
|
||||||
} else {
|
} else {
|
||||||
for (let rule of rules) {
|
for (let rule of rules) {
|
||||||
if (rule.selectorText === "element") {
|
if (rule.domRule.type === ELEMENT_STYLE) {
|
||||||
let referenceElement = rule.editor.element.nextSibling;
|
let referenceElement = rule.editor.element.nextSibling;
|
||||||
this.element.insertBefore(editor.element, referenceElement);
|
this.element.insertBefore(editor.element, referenceElement);
|
||||||
break;
|
break;
|
||||||
|
@ -84,7 +84,7 @@ function CheckLockState() {
|
|||||||
|
|
||||||
if (AppManager.connection &&
|
if (AppManager.connection &&
|
||||||
AppManager.connection.status == Connection.Status.CONNECTED &&
|
AppManager.connection.status == Connection.Status.CONNECTED &&
|
||||||
AppManager.deviceFront) {
|
AppManager.preferenceFront) {
|
||||||
|
|
||||||
// ADB check
|
// ADB check
|
||||||
if (AppManager.selectedRuntime instanceof USBRuntime) {
|
if (AppManager.selectedRuntime instanceof USBRuntime) {
|
||||||
|
@ -114,7 +114,8 @@ let UI = {
|
|||||||
// not focused.
|
// not focused.
|
||||||
if (AppManager.selectedProject &&
|
if (AppManager.selectedProject &&
|
||||||
AppManager.selectedProject.type != "mainProcess" &&
|
AppManager.selectedProject.type != "mainProcess" &&
|
||||||
AppManager.selectedProject.type != "runtimeApp") {
|
AppManager.selectedProject.type != "runtimeApp" &&
|
||||||
|
AppManager.selectedProject.type != "tab") {
|
||||||
AppManager.validateProject(AppManager.selectedProject);
|
AppManager.validateProject(AppManager.selectedProject);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -138,6 +139,7 @@ let UI = {
|
|||||||
break;
|
break;
|
||||||
case "project-is-not-running":
|
case "project-is-not-running":
|
||||||
case "project-is-running":
|
case "project-is-running":
|
||||||
|
case "list-tabs-response":
|
||||||
this.updateCommands();
|
this.updateCommands();
|
||||||
break;
|
break;
|
||||||
case "runtime":
|
case "runtime":
|
||||||
@ -562,6 +564,9 @@ let UI = {
|
|||||||
// If connected and a project is selected
|
// If connected and a project is selected
|
||||||
if (AppManager.selectedProject.type == "runtimeApp") {
|
if (AppManager.selectedProject.type == "runtimeApp") {
|
||||||
playCmd.removeAttribute("disabled");
|
playCmd.removeAttribute("disabled");
|
||||||
|
} else if (AppManager.selectedProject.type == "tab") {
|
||||||
|
playCmd.removeAttribute("disabled");
|
||||||
|
stopCmd.setAttribute("disabled", "true");
|
||||||
} else if (AppManager.selectedProject.type == "mainProcess") {
|
} else if (AppManager.selectedProject.type == "mainProcess") {
|
||||||
playCmd.setAttribute("disabled", "true");
|
playCmd.setAttribute("disabled", "true");
|
||||||
stopCmd.setAttribute("disabled", "true");
|
stopCmd.setAttribute("disabled", "true");
|
||||||
@ -592,16 +597,18 @@ let UI = {
|
|||||||
|
|
||||||
let runtimePanelButton = document.querySelector("#runtime-panel-button");
|
let runtimePanelButton = document.querySelector("#runtime-panel-button");
|
||||||
if (AppManager.connection.status == Connection.Status.CONNECTED) {
|
if (AppManager.connection.status == Connection.Status.CONNECTED) {
|
||||||
screenshotCmd.removeAttribute("disabled");
|
if (AppManager.deviceFront) {
|
||||||
permissionsCmd.removeAttribute("disabled");
|
|
||||||
disconnectCmd.removeAttribute("disabled");
|
|
||||||
detailsCmd.removeAttribute("disabled");
|
detailsCmd.removeAttribute("disabled");
|
||||||
|
permissionsCmd.removeAttribute("disabled");
|
||||||
|
screenshotCmd.removeAttribute("disabled");
|
||||||
|
}
|
||||||
|
disconnectCmd.removeAttribute("disabled");
|
||||||
runtimePanelButton.setAttribute("active", "true");
|
runtimePanelButton.setAttribute("active", "true");
|
||||||
} else {
|
} else {
|
||||||
screenshotCmd.setAttribute("disabled", "true");
|
|
||||||
permissionsCmd.setAttribute("disabled", "true");
|
|
||||||
disconnectCmd.setAttribute("disabled", "true");
|
|
||||||
detailsCmd.setAttribute("disabled", "true");
|
detailsCmd.setAttribute("disabled", "true");
|
||||||
|
permissionsCmd.setAttribute("disabled", "true");
|
||||||
|
screenshotCmd.setAttribute("disabled", "true");
|
||||||
|
disconnectCmd.setAttribute("disabled", "true");
|
||||||
runtimePanelButton.removeAttribute("active");
|
runtimePanelButton.removeAttribute("active");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -822,7 +829,13 @@ let Cmds = {
|
|||||||
|
|
||||||
|
|
||||||
let runtimeappsHeaderNode = document.querySelector("#panel-header-runtimeapps");
|
let runtimeappsHeaderNode = document.querySelector("#panel-header-runtimeapps");
|
||||||
if (AppManager.connection.status == Connection.Status.CONNECTED) {
|
let sortedApps = AppManager.webAppsStore.object.all;
|
||||||
|
sortedApps = sortedApps.sort((a, b) => {
|
||||||
|
return a.name > b.name;
|
||||||
|
});
|
||||||
|
let mainProcess = AppManager.isMainProcessDebuggable();
|
||||||
|
if (AppManager.connection.status == Connection.Status.CONNECTED &&
|
||||||
|
(sortedApps.length > 0 || mainProcess)) {
|
||||||
runtimeappsHeaderNode.removeAttribute("hidden");
|
runtimeappsHeaderNode.removeAttribute("hidden");
|
||||||
} else {
|
} else {
|
||||||
runtimeappsHeaderNode.setAttribute("hidden", "true");
|
runtimeappsHeaderNode.setAttribute("hidden", "true");
|
||||||
@ -833,7 +846,7 @@ let Cmds = {
|
|||||||
runtimeAppsNode.firstChild.remove();
|
runtimeAppsNode.firstChild.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AppManager.isMainProcessDebuggable()) {
|
if (mainProcess) {
|
||||||
let panelItemNode = document.createElement("toolbarbutton");
|
let panelItemNode = document.createElement("toolbarbutton");
|
||||||
panelItemNode.className = "panel-item";
|
panelItemNode.className = "panel-item";
|
||||||
panelItemNode.setAttribute("label", Strings.GetStringFromName("mainProcess_label"));
|
panelItemNode.setAttribute("label", Strings.GetStringFromName("mainProcess_label"));
|
||||||
@ -849,10 +862,6 @@ let Cmds = {
|
|||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sortedApps = AppManager.webAppsStore.object.all;
|
|
||||||
sortedApps = sortedApps.sort((a, b) => {
|
|
||||||
return a.name > b.name;
|
|
||||||
});
|
|
||||||
for (let i = 0; i < sortedApps.length; i++) {
|
for (let i = 0; i < sortedApps.length; i++) {
|
||||||
let app = sortedApps[i];
|
let app = sortedApps[i];
|
||||||
let panelItemNode = document.createElement("toolbarbutton");
|
let panelItemNode = document.createElement("toolbarbutton");
|
||||||
@ -871,9 +880,63 @@ let Cmds = {
|
|||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build the tab list right now, so it's fast...
|
||||||
|
this._buildProjectPanelTabs();
|
||||||
|
|
||||||
|
// But re-list them and rebuild, in case any tabs navigated since the last
|
||||||
|
// time they were listed.
|
||||||
|
AppManager.listTabs().then(() => {
|
||||||
|
this._buildProjectPanelTabs();
|
||||||
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_buildProjectPanelTabs: function() {
|
||||||
|
let tabs = AppManager.tabStore.tabs;
|
||||||
|
let tabsHeaderNode = document.querySelector("#panel-header-tabs");
|
||||||
|
if (AppManager.connection.status == Connection.Status.CONNECTED &&
|
||||||
|
tabs.length > 0) {
|
||||||
|
tabsHeaderNode.removeAttribute("hidden");
|
||||||
|
} else {
|
||||||
|
tabsHeaderNode.setAttribute("hidden", "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
let tabsNode = document.querySelector("#project-panel-tabs");
|
||||||
|
while (tabsNode.hasChildNodes()) {
|
||||||
|
tabsNode.firstChild.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < tabs.length; i++) {
|
||||||
|
let tab = tabs[i];
|
||||||
|
let url = new URL(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 = url.origin + "/favicon.ico";
|
||||||
|
tab.name = tab.title || Strings.GetStringFromName("project_tab_loading");
|
||||||
|
if (url.protocol.startsWith("http")) {
|
||||||
|
tab.name = url.hostname + ": " + tab.name;
|
||||||
|
}
|
||||||
|
let panelItemNode = document.createElement("toolbarbutton");
|
||||||
|
panelItemNode.className = "panel-item";
|
||||||
|
panelItemNode.setAttribute("label", tab.name);
|
||||||
|
panelItemNode.setAttribute("image", tab.favicon);
|
||||||
|
tabsNode.appendChild(panelItemNode);
|
||||||
|
panelItemNode.addEventListener("click", () => {
|
||||||
|
UI.hidePanels();
|
||||||
|
AppManager.selectedProject = {
|
||||||
|
type: "tab",
|
||||||
|
app: tab,
|
||||||
|
icon: tab.favicon,
|
||||||
|
location: tab.url,
|
||||||
|
name: tab.name
|
||||||
|
};
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
showRuntimePanel: function() {
|
showRuntimePanel: function() {
|
||||||
AppManager.scanForWiFiRuntimes();
|
AppManager.scanForWiFiRuntimes();
|
||||||
|
|
||||||
@ -924,6 +987,8 @@ let Cmds = {
|
|||||||
return UI.busyUntil(AppManager.installAndRunProject(), "installing and running app");
|
return UI.busyUntil(AppManager.installAndRunProject(), "installing and running app");
|
||||||
case "runtimeApp":
|
case "runtimeApp":
|
||||||
return UI.busyUntil(AppManager.runRuntimeApp(), "running app");
|
return UI.busyUntil(AppManager.runRuntimeApp(), "running app");
|
||||||
|
case "tab":
|
||||||
|
return UI.busyUntil(AppManager.reloadTab(), "reloading tab");
|
||||||
}
|
}
|
||||||
return promise.reject();
|
return promise.reject();
|
||||||
},
|
},
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
<hbox id="panel-buttons-container">
|
<hbox id="panel-buttons-container">
|
||||||
<toolbarbutton id="project-panel-button" class="panel-button no-project" command="cmd_showProjectPanel">
|
<toolbarbutton id="project-panel-button" class="panel-button no-project" command="cmd_showProjectPanel">
|
||||||
<image class="panel-button-image"/>
|
<image class="panel-button-image"/>
|
||||||
<label class="panel-button-label" value="&projectButton_label;"/>
|
<label class="panel-button-label" value="&projectButton_label;" crop="end"/>
|
||||||
<image class="panel-button-anchor"/>
|
<image class="panel-button-anchor"/>
|
||||||
</toolbarbutton>
|
</toolbarbutton>
|
||||||
<spacer flex="1"/>
|
<spacer flex="1"/>
|
||||||
@ -143,6 +143,8 @@
|
|||||||
<vbox id="project-panel-projects"></vbox>
|
<vbox id="project-panel-projects"></vbox>
|
||||||
<label class="panel-header" id="panel-header-runtimeapps" hidden="true">&projectPanel_runtimeApps;</label>
|
<label class="panel-header" id="panel-header-runtimeapps" hidden="true">&projectPanel_runtimeApps;</label>
|
||||||
<vbox flex="1" id="project-panel-runtimeapps"/>
|
<vbox flex="1" id="project-panel-runtimeapps"/>
|
||||||
|
<label class="panel-header" id="panel-header-tabs" hidden="true">&projectPanel_tabs;</label>
|
||||||
|
<vbox flex="1" id="project-panel-tabs"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
</panel>
|
</panel>
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.
|
|||||||
const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
|
||||||
const {AppProjects} = require("devtools/app-manager/app-projects");
|
const {AppProjects} = require("devtools/app-manager/app-projects");
|
||||||
const WebappsStore = require("devtools/app-manager/webapps-store");
|
const WebappsStore = require("devtools/app-manager/webapps-store");
|
||||||
|
const TabStore = require("devtools/webide/tab-store");
|
||||||
const {AppValidator} = require("devtools/app-manager/app-validator");
|
const {AppValidator} = require("devtools/app-manager/app-validator");
|
||||||
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
|
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
|
||||||
const AppActorFront = require("devtools/app-actor-front");
|
const AppActorFront = require("devtools/app-actor-front");
|
||||||
@ -25,6 +26,7 @@ const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
|||||||
const {USBRuntime, WiFiRuntime, SimulatorRuntime,
|
const {USBRuntime, WiFiRuntime, SimulatorRuntime,
|
||||||
gLocalRuntime, gRemoteRuntime} = require("devtools/webide/runtimes");
|
gLocalRuntime, gRemoteRuntime} = require("devtools/webide/runtimes");
|
||||||
const discovery = require("devtools/toolkit/discovery/discovery");
|
const discovery = require("devtools/toolkit/discovery/discovery");
|
||||||
|
const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
|
||||||
|
|
||||||
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
|
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
|
||||||
|
|
||||||
@ -47,6 +49,11 @@ exports.AppManager = AppManager = {
|
|||||||
this.onWebAppsStoreready = this.onWebAppsStoreready.bind(this);
|
this.onWebAppsStoreready = this.onWebAppsStoreready.bind(this);
|
||||||
this.webAppsStore = new WebappsStore(this.connection);
|
this.webAppsStore = new WebappsStore(this.connection);
|
||||||
this.webAppsStore.on("store-ready", this.onWebAppsStoreready);
|
this.webAppsStore.on("store-ready", this.onWebAppsStoreready);
|
||||||
|
this.tabStore = new TabStore(this.connection);
|
||||||
|
this.onTabNavigate = this.onTabNavigate.bind(this);
|
||||||
|
this.onTabClosed = this.onTabClosed.bind(this);
|
||||||
|
this.tabStore.on("navigate", this.onTabNavigate);
|
||||||
|
this.tabStore.on("closed", this.onTabClosed);
|
||||||
|
|
||||||
this.runtimeList = {
|
this.runtimeList = {
|
||||||
usb: [],
|
usb: [],
|
||||||
@ -81,6 +88,10 @@ exports.AppManager = AppManager = {
|
|||||||
this.webAppsStore.off("store-ready", this.onWebAppsStoreready);
|
this.webAppsStore.off("store-ready", this.onWebAppsStoreready);
|
||||||
this.webAppsStore.destroy();
|
this.webAppsStore.destroy();
|
||||||
this.webAppsStore = null;
|
this.webAppsStore = null;
|
||||||
|
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.connection.off(Connection.Events.STATUS_CHANGED, this.onConnectionChanged);
|
||||||
this._listTabsResponse = null;
|
this._listTabsResponse = null;
|
||||||
this.connection.disconnect();
|
this.connection.disconnect();
|
||||||
@ -192,7 +203,8 @@ exports.AppManager = AppManager = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
isProjectRunning: function() {
|
isProjectRunning: function() {
|
||||||
if (this.selectedProject.type == "mainProcess") {
|
if (this.selectedProject.type == "mainProcess" ||
|
||||||
|
this.selectedProject.type == "tab") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let manifest = this.getProjectManifestURL(this.selectedProject);
|
let manifest = this.getProjectManifestURL(this.selectedProject);
|
||||||
@ -209,7 +221,51 @@ exports.AppManager = AppManager = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
listTabs: function() {
|
||||||
|
return this.tabStore.listTabs();
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: Merge this into TabProject as part of project-agnostic work
|
||||||
|
onTabNavigate: function() {
|
||||||
|
if (this.selectedProject.type !== "tab") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let tab = this.selectedProject.app = this.tabStore.selectedTab;
|
||||||
|
let 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.activeTab.reload();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getTarget: function() {
|
getTarget: function() {
|
||||||
|
let client = this.connection.client;
|
||||||
|
|
||||||
if (this.selectedProject.type == "mainProcess") {
|
if (this.selectedProject.type == "mainProcess") {
|
||||||
return devtools.TargetFactory.forRemoteTab({
|
return devtools.TargetFactory.forRemoteTab({
|
||||||
form: this._listTabsResponse,
|
form: this._listTabsResponse,
|
||||||
@ -218,13 +274,16 @@ exports.AppManager = AppManager = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.selectedProject.type == "tab") {
|
||||||
|
return this.tabStore.getTargetForTab();
|
||||||
|
}
|
||||||
|
|
||||||
let manifest = this.getProjectManifestURL(this.selectedProject);
|
let manifest = this.getProjectManifestURL(this.selectedProject);
|
||||||
if (!manifest) {
|
if (!manifest) {
|
||||||
console.error("Can't find manifestURL for selected project");
|
console.error("Can't find manifestURL for selected project");
|
||||||
return promise.reject();
|
return promise.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
let client = this.connection.client;
|
|
||||||
let actor = this._listTabsResponse.webappsActor;
|
let actor = this._listTabsResponse.webappsActor;
|
||||||
return Task.spawn(function* () {
|
return Task.spawn(function* () {
|
||||||
// Once we asked the app to launch, the app isn't necessary completely loaded.
|
// Once we asked the app to launch, the app isn't necessary completely loaded.
|
||||||
@ -270,6 +329,9 @@ exports.AppManager = AppManager = {
|
|||||||
if (value != this.selectedProject) {
|
if (value != this.selectedProject) {
|
||||||
this._selectedProject = value;
|
this._selectedProject = value;
|
||||||
|
|
||||||
|
// Clear out tab store's selected state, if any
|
||||||
|
this.tabStore.selectedTab = null;
|
||||||
|
|
||||||
if (this.selectedProject) {
|
if (this.selectedProject) {
|
||||||
if (this.selectedProject.type == "runtimeApp") {
|
if (this.selectedProject.type == "runtimeApp") {
|
||||||
this.runRuntimeApp();
|
this.runRuntimeApp();
|
||||||
@ -278,6 +340,9 @@ exports.AppManager = AppManager = {
|
|||||||
this.selectedProject.type == "hosted") {
|
this.selectedProject.type == "hosted") {
|
||||||
this.validateProject(this.selectedProject);
|
this.validateProject(this.selectedProject);
|
||||||
}
|
}
|
||||||
|
if (this.selectedProject.type == "tab") {
|
||||||
|
this.tabStore.selectedTab = this.selectedProject.app;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.update("project");
|
this.update("project");
|
||||||
@ -300,7 +365,8 @@ exports.AppManager = AppManager = {
|
|||||||
this._selectedRuntime = value;
|
this._selectedRuntime = value;
|
||||||
if (!value && this.selectedProject &&
|
if (!value && this.selectedProject &&
|
||||||
(this.selectedProject.type == "mainProcess" ||
|
(this.selectedProject.type == "mainProcess" ||
|
||||||
this.selectedProject.type == "runtimeApp")) {
|
this.selectedProject.type == "runtimeApp" ||
|
||||||
|
this.selectedProject.type == "tab")) {
|
||||||
this.selectedProject = null;
|
this.selectedProject = null;
|
||||||
}
|
}
|
||||||
this.update("runtime");
|
this.update("runtime");
|
||||||
|
157
browser/devtools/webide/modules/tab-store.js
Normal file
157
browser/devtools/webide/modules/tab-store.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
const { Cu } = require("chrome");
|
||||||
|
|
||||||
|
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||||
|
const { Connection } = require("devtools/client/connection-manager");
|
||||||
|
const { Promise: promise } =
|
||||||
|
Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||||
|
const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||||
|
const { devtools } =
|
||||||
|
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||||
|
|
||||||
|
const _knownTabStores = new WeakMap();
|
||||||
|
|
||||||
|
let 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.response = null;
|
||||||
|
this.tabs = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
_onStatusChanged: function() {
|
||||||
|
if (this._connection.status == Connection.Status.CONNECTED) {
|
||||||
|
// Watch for changes to remote browser tabs
|
||||||
|
this._connection.client.addListener("tabListChanged",
|
||||||
|
this._onTabListChanged);
|
||||||
|
this._connection.client.addListener("tabNavigated",
|
||||||
|
this._onTabNavigated);
|
||||||
|
this.listTabs();
|
||||||
|
} else {
|
||||||
|
if (this._connection.client) {
|
||||||
|
this._connection.client.removeListener("tabListChanged",
|
||||||
|
this._onTabListChanged);
|
||||||
|
this._connection.client.removeListener("tabNavigated",
|
||||||
|
this._onTabNavigated);
|
||||||
|
}
|
||||||
|
this._resetStore();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onTabListChanged: function() {
|
||||||
|
this.listTabs();
|
||||||
|
},
|
||||||
|
|
||||||
|
_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();
|
||||||
|
}
|
||||||
|
let deferred = promise.defer();
|
||||||
|
this._connection.client.listTabs(response => {
|
||||||
|
if (response.error) {
|
||||||
|
this._connection.disconnect();
|
||||||
|
deferred.reject(response.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.response = response;
|
||||||
|
this.tabs = response.tabs;
|
||||||
|
this._checkSelectedTab();
|
||||||
|
deferred.resolve(response);
|
||||||
|
});
|
||||||
|
return deferred.promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
get selectedTab() {
|
||||||
|
return this._selectedTab;
|
||||||
|
},
|
||||||
|
set selectedTab(tab) {
|
||||||
|
this._selectedTab = tab;
|
||||||
|
// Attach to the tab to follow navigation events
|
||||||
|
if (this._selectedTab) {
|
||||||
|
this.getTargetForTab();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_checkSelectedTab: function() {
|
||||||
|
if (!this._selectedTab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let alive = this.tabs.some(tab => {
|
||||||
|
return tab.actor === this._selectedTab.actor;
|
||||||
|
});
|
||||||
|
if (!alive) {
|
||||||
|
this.emit("closed");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getTargetForTab: function() {
|
||||||
|
let store = this;
|
||||||
|
return Task.spawn(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.
|
||||||
|
yield store.listTabs();
|
||||||
|
return devtools.TargetFactory.forRemoteTab({
|
||||||
|
form: store._selectedTab,
|
||||||
|
client: store._connection.client,
|
||||||
|
chrome: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
@ -10,11 +10,13 @@ DIRS += [
|
|||||||
'themes',
|
'themes',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||||
|
|
||||||
EXTRA_JS_MODULES.devtools.webide += [
|
EXTRA_JS_MODULES.devtools.webide += [
|
||||||
'modules/addons.js',
|
'modules/addons.js',
|
||||||
'modules/app-manager.js',
|
'modules/app-manager.js',
|
||||||
'modules/remote-resources.js',
|
'modules/remote-resources.js',
|
||||||
'modules/runtimes.js'
|
'modules/runtimes.js',
|
||||||
|
'modules/tab-store.js',
|
||||||
]
|
]
|
||||||
|
9
browser/devtools/webide/test/browser.ini
Normal file
9
browser/devtools/webide/test/browser.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
subsuite = devtools
|
||||||
|
support-files =
|
||||||
|
addons/simulators.json
|
||||||
|
head.js
|
||||||
|
templates.json
|
||||||
|
|
||||||
|
[browser_tabs.js]
|
||||||
|
skip-if = true # Fails on TBPL, to be fixed in bug 1062611
|
55
browser/devtools/webide/test/browser_tabs.js
Normal file
55
browser/devtools/webide/test/browser_tabs.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
SimpleTest.requestCompleteLog();
|
||||||
|
|
||||||
|
Task.spawn(function() {
|
||||||
|
const { DebuggerServer } =
|
||||||
|
Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||||
|
DebuggerServer.init(function () { return true; });
|
||||||
|
DebuggerServer.addBrowserActors();
|
||||||
|
|
||||||
|
let tab = yield addTab("about:newtab");
|
||||||
|
|
||||||
|
let win = yield openWebIDE();
|
||||||
|
|
||||||
|
yield connectToLocal(win);
|
||||||
|
|
||||||
|
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
|
||||||
|
|
||||||
|
yield selectTabProject(win);
|
||||||
|
|
||||||
|
let project = win.AppManager.selectedProject;
|
||||||
|
is(project.location, "about:newtab", "Location is correct");
|
||||||
|
is(project.name, "New Tab", "Name is correct");
|
||||||
|
|
||||||
|
yield closeWebIDE(win);
|
||||||
|
DebuggerServer.destroy();
|
||||||
|
yield removeTab(tab);
|
||||||
|
|
||||||
|
finish();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectToLocal(win) {
|
||||||
|
let deferred = promise.defer();
|
||||||
|
win.AppManager.connection.once(
|
||||||
|
win.Connection.Events.CONNECTED,
|
||||||
|
() => deferred.resolve());
|
||||||
|
win.document.querySelectorAll(".runtime-panel-item-custom")[1].click();
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectTabProject(win) {
|
||||||
|
return Task.spawn(function() {
|
||||||
|
yield win.AppManager.listTabs();
|
||||||
|
win.Cmds.showProjectPanel();
|
||||||
|
yield nextTick();
|
||||||
|
let tabsNode = win.document.querySelector("#project-panel-tabs");
|
||||||
|
let tabNode = tabsNode.querySelectorAll(".panel-item")[1];
|
||||||
|
tabNode.click();
|
||||||
|
});
|
||||||
|
}
|
@ -14,7 +14,12 @@ const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
|||||||
const {require} = devtools;
|
const {require} = devtools;
|
||||||
const {AppProjects} = require("devtools/app-manager/app-projects");
|
const {AppProjects} = require("devtools/app-manager/app-projects");
|
||||||
|
|
||||||
const TEST_BASE = "chrome://mochitests/content/chrome/browser/devtools/webide/test/";
|
let TEST_BASE;
|
||||||
|
if (window.location === "chrome://browser/content/browser.xul") {
|
||||||
|
TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/webide/test/";
|
||||||
|
} else {
|
||||||
|
TEST_BASE = "chrome://mochitests/content/chrome/browser/devtools/webide/test/";
|
||||||
|
}
|
||||||
|
|
||||||
Services.prefs.setBoolPref("devtools.webide.enabled", true);
|
Services.prefs.setBoolPref("devtools.webide.enabled", true);
|
||||||
Services.prefs.setBoolPref("devtools.webide.enableLocalRuntime", true);
|
Services.prefs.setBoolPref("devtools.webide.enableLocalRuntime", true);
|
||||||
@ -110,3 +115,41 @@ function documentIsLoaded(doc) {
|
|||||||
}
|
}
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addTab(aUrl, aWindow) {
|
||||||
|
info("Adding tab: " + aUrl);
|
||||||
|
|
||||||
|
let deferred = promise.defer();
|
||||||
|
let targetWindow = aWindow || window;
|
||||||
|
let targetBrowser = targetWindow.gBrowser;
|
||||||
|
|
||||||
|
targetWindow.focus();
|
||||||
|
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||||
|
let linkedBrowser = tab.linkedBrowser;
|
||||||
|
|
||||||
|
linkedBrowser.addEventListener("load", function onLoad() {
|
||||||
|
linkedBrowser.removeEventListener("load", onLoad, true);
|
||||||
|
info("Tab added and finished loading: " + aUrl);
|
||||||
|
deferred.resolve(tab);
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeTab(aTab, aWindow) {
|
||||||
|
info("Removing tab.");
|
||||||
|
|
||||||
|
let deferred = promise.defer();
|
||||||
|
let targetWindow = aWindow || window;
|
||||||
|
let targetBrowser = targetWindow.gBrowser;
|
||||||
|
let tabContainer = targetBrowser.tabContainer;
|
||||||
|
|
||||||
|
tabContainer.addEventListener("TabClose", function onClose(aEvent) {
|
||||||
|
tabContainer.removeEventListener("TabClose", onClose, false);
|
||||||
|
info("Tab removed and finished closing.");
|
||||||
|
deferred.resolve();
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
targetBrowser.removeTab(aTab);
|
||||||
|
return deferred.promise;
|
||||||
|
}
|
||||||
|
@ -55,7 +55,8 @@ header {
|
|||||||
|
|
||||||
header > div {
|
header > div {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
display: inline-block;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#icon {
|
#icon {
|
||||||
@ -73,6 +74,9 @@ h1, #type {
|
|||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
#type {
|
#type {
|
||||||
|
@ -65,6 +65,10 @@ window.busy-determined #action-busy-undetermined {
|
|||||||
|
|
||||||
/* Panel buttons - projects */
|
/* Panel buttons - projects */
|
||||||
|
|
||||||
|
#project-panel-button {
|
||||||
|
-moz-box-pack: start;
|
||||||
|
}
|
||||||
|
|
||||||
#project-panel-button > .panel-button-image {
|
#project-panel-button > .panel-button-image {
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 13px;
|
height: 13px;
|
||||||
@ -81,6 +85,10 @@ window.busy-determined #action-busy-undetermined {
|
|||||||
-moz-image-region: rect(260px,338px,286px,312px);
|
-moz-image-region: rect(260px,338px,286px,312px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#project-panel-button > .panel-button-label {
|
||||||
|
max-width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Panel buttons - runtime */
|
/* Panel buttons - runtime */
|
||||||
|
|
||||||
#runtime-panel-button > .panel-button-image {
|
#runtime-panel-button > .panel-button-image {
|
||||||
@ -136,6 +144,7 @@ panel > vbox {
|
|||||||
panel > .panel-arrowcontainer > .panel-arrowcontent {
|
panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-item {
|
.panel-item {
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
|
|
||||||
<!ENTITY projectPanel_myProjects "My Projects">
|
<!ENTITY projectPanel_myProjects "My Projects">
|
||||||
<!ENTITY projectPanel_runtimeApps "Runtime Apps">
|
<!ENTITY projectPanel_runtimeApps "Runtime Apps">
|
||||||
|
<!ENTITY projectPanel_tabs "Tabs">
|
||||||
<!ENTITY runtimePanel_USBDevices "USB Devices">
|
<!ENTITY runtimePanel_USBDevices "USB Devices">
|
||||||
<!ENTITY runtimePanel_WiFiDevices "Wi-Fi Devices">
|
<!ENTITY runtimePanel_WiFiDevices "Wi-Fi Devices">
|
||||||
<!ENTITY runtimePanel_simulators "Simulators">
|
<!ENTITY runtimePanel_simulators "Simulators">
|
||||||
|
@ -22,6 +22,10 @@ importHostedApp_header=Enter Manifest URL
|
|||||||
notification_showTroubleShooting_label=troubleshooting
|
notification_showTroubleShooting_label=troubleshooting
|
||||||
notification_showTroubleShooting_accesskey=t
|
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.
|
# These messages appear in a notification box when an error occur.
|
||||||
|
|
||||||
error_cantInstallNotFullyConnected=Can't install project. Not fully connected.
|
error_cantInstallNotFullyConnected=Can't install project. Not fully connected.
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
background-image: linear-gradient(90deg, #a0dfff 0%, #ceeeff 100%);
|
background-image: linear-gradient(90deg, #a0dfff 0%, #ceeeff 100%);
|
||||||
border: 0px solid rgba(0,148,221,.5);
|
border: 0px solid rgba(0,148,221,.5);
|
||||||
box-shadow: 0 1px 5px 0 rgba(0,0,0,.5), inset 0 1px 1px 0 #fff;
|
box-shadow: 0 1px 5px 0 rgba(0,0,0,.5), inset 0 1px 1px 0 #fff;
|
||||||
|
color: rgb(51,51,51);
|
||||||
}
|
}
|
||||||
|
|
||||||
#customization-tipPanel > .panel-arrowcontainer > .panel-arrowcontent:-moz-locale-dir(rtl) {
|
#customization-tipPanel > .panel-arrowcontainer > .panel-arrowcontent:-moz-locale-dir(rtl) {
|
||||||
|
@ -224,10 +224,15 @@ let DeviceFront = protocol.FrontClass(DeviceActor, {
|
|||||||
const _knownDeviceFronts = new WeakMap();
|
const _knownDeviceFronts = new WeakMap();
|
||||||
|
|
||||||
exports.getDeviceFront = function(client, form) {
|
exports.getDeviceFront = function(client, form) {
|
||||||
if (_knownDeviceFronts.has(client))
|
if (!form.deviceActor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_knownDeviceFronts.has(client)) {
|
||||||
return _knownDeviceFronts.get(client);
|
return _knownDeviceFronts.get(client);
|
||||||
|
}
|
||||||
|
|
||||||
let front = new DeviceFront(client, form);
|
let front = new DeviceFront(client, form);
|
||||||
_knownDeviceFronts.set(client, front);
|
_knownDeviceFronts.set(client, front);
|
||||||
return front;
|
return front;
|
||||||
}
|
};
|
||||||
|
@ -116,8 +116,13 @@ let PreferenceFront = protocol.FrontClass(PreferenceActor, {
|
|||||||
const _knownPreferenceFronts = new WeakMap();
|
const _knownPreferenceFronts = new WeakMap();
|
||||||
|
|
||||||
exports.getPreferenceFront = function(client, form) {
|
exports.getPreferenceFront = function(client, form) {
|
||||||
if (_knownPreferenceFronts.has(client))
|
if (!form.preferenceActor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_knownPreferenceFronts.has(client)) {
|
||||||
return _knownPreferenceFronts.get(client);
|
return _knownPreferenceFronts.get(client);
|
||||||
|
}
|
||||||
|
|
||||||
let front = new PreferenceFront(client, form);
|
let front = new PreferenceFront(client, form);
|
||||||
_knownPreferenceFronts.set(client, front);
|
_knownPreferenceFronts.set(client, front);
|
||||||
|
Loading…
Reference in New Issue
Block a user