Merge fx-team to m-c a=merge
@ -194,14 +194,16 @@ function readURI(uri) {
|
||||
|
||||
// Combines all arguments into a resolved, normalized path
|
||||
function join (...paths) {
|
||||
let resolved = normalize(pathJoin(...paths))
|
||||
// OS.File `normalize` strips out the second slash in
|
||||
// `resource://` or `chrome://`, and third slash in
|
||||
// `file:///`, so we work around this
|
||||
resolved = resolved.replace(/^resource\:\/([^\/])/, 'resource://$1');
|
||||
resolved = resolved.replace(/^file\:\/([^\/])/, 'file:///$1');
|
||||
resolved = resolved.replace(/^chrome\:\/([^\/])/, 'chrome://$1');
|
||||
return resolved;
|
||||
let joined = pathJoin(...paths);
|
||||
let resolved = normalize(joined);
|
||||
|
||||
// OS.File `normalize` strips out any additional slashes breaking URIs like
|
||||
// `resource://`, `resource:///`, `chrome://` or `file:///`, so we work
|
||||
// around this putting back the slashes originally given, for such schemes.
|
||||
let re = /^(resource|file|chrome)(\:\/{1,3})([^\/])/;
|
||||
let matches = joined.match(re);
|
||||
|
||||
return resolved.replace(re, (...args) => args[1] + matches[2] + args[3]);
|
||||
}
|
||||
Loader.join = join;
|
||||
|
||||
@ -568,7 +570,8 @@ Loader.resolveURI = resolveURI;
|
||||
const Require = iced(function Require(loader, requirer) {
|
||||
let {
|
||||
modules, mapping, resolve: loaderResolve, load,
|
||||
manifest, rootURI, isNative, requireMap
|
||||
manifest, rootURI, isNative, requireMap,
|
||||
overrideRequire
|
||||
} = loader;
|
||||
|
||||
function require(id) {
|
||||
@ -576,6 +579,14 @@ const Require = iced(function Require(loader, requirer) {
|
||||
throw Error('You must provide a module name when calling require() from '
|
||||
+ requirer.id, requirer.uri);
|
||||
|
||||
if (overrideRequire) {
|
||||
return overrideRequire(id, _require);
|
||||
}
|
||||
|
||||
return _require(id);
|
||||
}
|
||||
|
||||
function _require(id) {
|
||||
let { uri, requirement } = getRequirements(id);
|
||||
let module = null;
|
||||
// If module is already cached by loader then just use it.
|
||||
@ -715,7 +726,7 @@ const Require = iced(function Require(loader, requirer) {
|
||||
}
|
||||
|
||||
// Expose the `resolve` function for this `Require` instance
|
||||
require.resolve = function resolve(id) {
|
||||
require.resolve = _require.resolve = function resolve(id) {
|
||||
let { uri } = getRequirements(id);
|
||||
return uri;
|
||||
}
|
||||
@ -901,6 +912,7 @@ function Loader(options) {
|
||||
value: options.invisibleToDebugger || false },
|
||||
load: { enumerable: false, value: options.load || load },
|
||||
checkCompatibility: { enumerable: false, value: checkCompatibility },
|
||||
overrideRequire: { enumerable: false, value: options.require },
|
||||
// Main (entry point) module, it can be set only once, since loader
|
||||
// instance can have only one main module.
|
||||
main: new function() {
|
||||
|
@ -14,7 +14,7 @@ const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { require: devtoolsRequire } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const { DebuggerServer } = devtoolsRequire("devtools/server/main");
|
||||
const { DebuggerClient } = Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {});
|
||||
const { DebuggerClient } = devtoolsRequire("devtools/toolkit/client/main");
|
||||
|
||||
let gClient;
|
||||
let ok;
|
||||
|
@ -14,7 +14,7 @@ const { set } = require('sdk/preferences/service');
|
||||
|
||||
const { require: devtoolsRequire } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const { DebuggerServer } = devtoolsRequire("devtools/server/main");
|
||||
const { DebuggerClient } = Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {});
|
||||
const { DebuggerClient } = devtoolsRequire("devtools/toolkit/client/main");
|
||||
|
||||
let gClient;
|
||||
let ok;
|
||||
|
1
addon-sdk/source/test/fixtures/loader/json/mutation.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ "value": 1 }
|
@ -57,6 +57,10 @@ exports['test join'] = function (assert) {
|
||||
'resource://my/path/yeah/whoa');
|
||||
assert.equal(join('resource://my/path/yeah/yuh', './whoa'),
|
||||
'resource://my/path/yeah/yuh/whoa');
|
||||
assert.equal(join('resource:///my/path/yeah/yuh', '../whoa'),
|
||||
'resource:///my/path/yeah/whoa');
|
||||
assert.equal(join('resource:///my/path/yeah/yuh', './whoa'),
|
||||
'resource:///my/path/yeah/yuh/whoa');
|
||||
assert.equal(join('file:///my/path/yeah/yuh', '../whoa'),
|
||||
'file:///my/path/yeah/whoa');
|
||||
assert.equal(join('file:///my/path/yeah/yuh', './whoa'),
|
||||
@ -552,4 +556,60 @@ exports['test user global'] = function(assert) {
|
||||
"user module returns expected `com` global");
|
||||
};
|
||||
|
||||
exports['test custom require caching'] = function(assert) {
|
||||
const loader = Loader({
|
||||
paths: { '': root + "/" },
|
||||
require: (id, require) => {
|
||||
// Just load it normally
|
||||
return require(id);
|
||||
}
|
||||
});
|
||||
const require = Require(loader, module);
|
||||
|
||||
let data = require('fixtures/loader/json/mutation.json');
|
||||
assert.equal(data.value, 1, 'has initial value');
|
||||
data.value = 2;
|
||||
let newdata = require('fixtures/loader/json/mutation.json');
|
||||
assert.equal(
|
||||
newdata.value,
|
||||
2,
|
||||
'JSON objects returned should be cached and the same instance'
|
||||
);
|
||||
};
|
||||
|
||||
exports['test caching when proxying a loader'] = function(assert) {
|
||||
const parentRequire = require;
|
||||
const loader = Loader({
|
||||
paths: { '': root + "/" },
|
||||
require: (id, childRequire) => {
|
||||
if(id === 'gimmejson') {
|
||||
return childRequire('fixtures/loader/json/mutation.json')
|
||||
}
|
||||
// Load it with the original (global) require
|
||||
return parentRequire(id);
|
||||
}
|
||||
});
|
||||
const childRequire = Require(loader, module);
|
||||
|
||||
let data = childRequire('./fixtures/loader/json/mutation.json');
|
||||
assert.equal(data.value, 1, 'data has initial value');
|
||||
data.value = 2;
|
||||
|
||||
let newdata = childRequire('./fixtures/loader/json/mutation.json');
|
||||
assert.equal(newdata.value, 2, 'data has changed');
|
||||
|
||||
let childData = childRequire('gimmejson');
|
||||
assert.equal(childData.value, 1, 'data from child loader has initial value');
|
||||
childData.value = 3;
|
||||
let newChildData = childRequire('gimmejson');
|
||||
assert.equal(newChildData.value, 3, 'data from child loader has changed');
|
||||
|
||||
data = childRequire('./fixtures/loader/json/mutation.json');
|
||||
assert.equal(data.value, 2, 'data from parent loader has not changed');
|
||||
|
||||
// Set it back to the original value just in case (this instance
|
||||
// will be shared across tests)
|
||||
data.value = 1;
|
||||
}
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
|
@ -14,7 +14,7 @@ XPCOMUtils.defineLazyGetter(this, 'devtools', function() {
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() {
|
||||
return Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {}).DebuggerClient;
|
||||
return devtools.require('devtools/toolkit/client/main').DebuggerClient;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() {
|
||||
|
@ -24,6 +24,8 @@ var FullScreen = {
|
||||
window.messageManager.addMessageListener(type, this);
|
||||
}
|
||||
|
||||
this._WarningBox.init();
|
||||
|
||||
if (window.fullScreen)
|
||||
this.toggle();
|
||||
},
|
||||
@ -103,16 +105,12 @@ var FullScreen = {
|
||||
switch (event.type) {
|
||||
case "activate":
|
||||
if (document.mozFullScreen) {
|
||||
this.showWarning(this.fullscreenOrigin);
|
||||
this._WarningBox.show();
|
||||
}
|
||||
break;
|
||||
case "fullscreen":
|
||||
this.toggle();
|
||||
break;
|
||||
case "transitionend":
|
||||
if (event.propertyName == "opacity")
|
||||
this.cancelWarning();
|
||||
break;
|
||||
case "MozDOMFullscreen:Entered": {
|
||||
// The event target is the element which requested the DOM
|
||||
// fullscreen. If we were entering DOM fullscreen for a remote
|
||||
@ -160,7 +158,7 @@ var FullScreen = {
|
||||
break;
|
||||
}
|
||||
case "DOMFullscreen:NewOrigin": {
|
||||
this.showWarning(aMessage.data.originNoSuffix);
|
||||
this._WarningBox.show(aMessage.data.originNoSuffix);
|
||||
break;
|
||||
}
|
||||
case "DOMFullscreen:Exit": {
|
||||
@ -221,7 +219,7 @@ var FullScreen = {
|
||||
},
|
||||
|
||||
cleanupDomFullscreen: function () {
|
||||
this.cancelWarning();
|
||||
this._WarningBox.close();
|
||||
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
|
||||
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
|
||||
@ -317,77 +315,195 @@ var FullScreen = {
|
||||
gPrefService.setBoolPref("browser.fullscreen.autohide", !gPrefService.getBoolPref("browser.fullscreen.autohide"));
|
||||
},
|
||||
|
||||
cancelWarning: function(event) {
|
||||
if (!this.warningBox)
|
||||
return;
|
||||
this.warningBox.removeEventListener("transitionend", this);
|
||||
if (this.warningFadeOutTimeout) {
|
||||
clearTimeout(this.warningFadeOutTimeout);
|
||||
this.warningFadeOutTimeout = null;
|
||||
}
|
||||
_WarningBox: {
|
||||
_element: null,
|
||||
_origin: null,
|
||||
|
||||
// Ensure focus switches away from the (now hidden) warning box. If the user
|
||||
// clicked buttons in the fullscreen key authorization UI, it would have been
|
||||
// focused, and any key events would be directed at the (now hidden) chrome
|
||||
// document instead of the target document.
|
||||
gBrowser.selectedBrowser.focus();
|
||||
/**
|
||||
* Timeout object for managing timeout request. If it is started when
|
||||
* the previous call hasn't finished, it would automatically cancelled
|
||||
* the previous one.
|
||||
*/
|
||||
Timeout: function(func, delay) {
|
||||
this._id = 0;
|
||||
this._func = func;
|
||||
this._delay = delay;
|
||||
},
|
||||
|
||||
this.warningBox.setAttribute("hidden", true);
|
||||
this.warningBox.removeAttribute("fade-warning-out");
|
||||
this.warningBox = null;
|
||||
},
|
||||
init: function() {
|
||||
this.Timeout.prototype = {
|
||||
start: function() {
|
||||
this.cancel();
|
||||
this._id = setTimeout(() => this._handle(), this._delay);
|
||||
},
|
||||
cancel: function() {
|
||||
if (this._id) {
|
||||
clearTimeout(this._id);
|
||||
this._id = 0;
|
||||
}
|
||||
},
|
||||
_handle: function() {
|
||||
this._id = 0;
|
||||
this._func();
|
||||
},
|
||||
get delay() {
|
||||
return this._delay;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
warningBox: null,
|
||||
warningFadeOutTimeout: null,
|
||||
|
||||
// Shows a warning that the site has entered fullscreen for a short duration.
|
||||
showWarning: function(aOrigin) {
|
||||
if (!document.mozFullScreen)
|
||||
return;
|
||||
|
||||
// Set the strings on the fullscreen warning UI.
|
||||
this.fullscreenOrigin = aOrigin;
|
||||
let uri = BrowserUtils.makeURI(aOrigin);
|
||||
let host = null;
|
||||
try {
|
||||
host = uri.host;
|
||||
} catch (e) { }
|
||||
let hostLabel = document.getElementById("full-screen-domain-text");
|
||||
if (host) {
|
||||
// Document's principal's URI has a host. Display a warning including the hostname and
|
||||
// show UI to enable the user to permanently grant this host permission to enter fullscreen.
|
||||
let utils = {};
|
||||
Cu.import("resource://gre/modules/DownloadUtils.jsm", utils);
|
||||
let displayHost = utils.DownloadUtils.getURIHost(uri.spec)[0];
|
||||
let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
|
||||
hostLabel.textContent = bundle.formatStringFromName("fullscreen.entered", [displayHost], 1);
|
||||
hostLabel.removeAttribute("hidden");
|
||||
} else {
|
||||
hostLabel.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
// Note: the warning box can be non-null if the warning box from the previous request
|
||||
// wasn't hidden before another request was made.
|
||||
if (!this.warningBox) {
|
||||
this.warningBox = document.getElementById("full-screen-warning-container");
|
||||
// Add a listener to clean up state after the warning is hidden.
|
||||
this.warningBox.addEventListener("transitionend", this);
|
||||
this.warningBox.removeAttribute("hidden");
|
||||
} else {
|
||||
if (this.warningFadeOutTimeout) {
|
||||
clearTimeout(this.warningFadeOutTimeout);
|
||||
this.warningFadeOutTimeout = null;
|
||||
// Shows a warning that the site has entered fullscreen for a short duration.
|
||||
show: function(aOrigin) {
|
||||
if (!document.mozFullScreen) {
|
||||
return;
|
||||
}
|
||||
this.warningBox.removeAttribute("fade-warning-out");
|
||||
}
|
||||
|
||||
// Set a timeout to fade the warning out after a few moments.
|
||||
this.warningFadeOutTimeout = setTimeout(() => {
|
||||
if (this.warningBox) {
|
||||
this.warningBox.setAttribute("fade-warning-out", "true");
|
||||
if (!this._element) {
|
||||
this._element = document.getElementById("fullscreen-warning");
|
||||
// Setup event listeners
|
||||
this._element.addEventListener("transitionend", this);
|
||||
window.addEventListener("mousemove", this, true);
|
||||
// The timeout to hide the warning box after a while.
|
||||
this._timeoutHide = new this.Timeout(() => {
|
||||
this._state = "hidden";
|
||||
}, gPrefService.getIntPref("full-screen-api.warning.timeout"));
|
||||
// The timeout to show the warning box when the pointer is at the top
|
||||
this._timeoutShow = new this.Timeout(() => {
|
||||
this._state = "ontop";
|
||||
this._timeoutHide.start();
|
||||
}, gPrefService.getIntPref("full-screen-api.warning.delay"));
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
// Set the strings on the fullscreen warning UI.
|
||||
if (aOrigin) {
|
||||
this._origin = aOrigin;
|
||||
}
|
||||
let uri = BrowserUtils.makeURI(this._origin);
|
||||
let host = null;
|
||||
try {
|
||||
host = uri.host;
|
||||
} catch (e) { }
|
||||
let textElem = document.getElementById("fullscreen-domain-text");
|
||||
if (!host) {
|
||||
textElem.setAttribute("hidden", true);
|
||||
} else {
|
||||
textElem.removeAttribute("hidden");
|
||||
let hostLabel = document.getElementById("fullscreen-domain");
|
||||
// Document's principal's URI has a host. Display a warning including it.
|
||||
let utils = {};
|
||||
Cu.import("resource://gre/modules/DownloadUtils.jsm", utils);
|
||||
hostLabel.value = utils.DownloadUtils.getURIHost(uri.spec)[0];
|
||||
}
|
||||
this._element.className = gIdentityHandler.getMode();
|
||||
|
||||
// User should be allowed to explicitly disable
|
||||
// the prompt if they really want.
|
||||
if (this._timeoutHide.delay <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Explicitly set the last state to hidden to avoid the warning
|
||||
// box being hidden immediately because of mousemove.
|
||||
this._state = "onscreen";
|
||||
this._lastState = "hidden";
|
||||
this._timeoutHide.start();
|
||||
},
|
||||
|
||||
close: function() {
|
||||
if (!this._element) {
|
||||
return;
|
||||
}
|
||||
// Cancel any pending timeout
|
||||
this._timeoutHide.cancel();
|
||||
this._timeoutShow.cancel();
|
||||
// Reset state of the warning box
|
||||
this._state = "hidden";
|
||||
this._element.setAttribute("hidden", true);
|
||||
// Remove all event listeners
|
||||
this._element.removeEventListener("transitionend", this);
|
||||
window.removeEventListener("mousemove", this, true);
|
||||
// Clear fields
|
||||
this._element = null;
|
||||
this._timeoutHide = null;
|
||||
this._timeoutShow = null;
|
||||
|
||||
// Ensure focus switches away from the (now hidden) warning box.
|
||||
// If the user clicked buttons in the warning box, it would have
|
||||
// been focused, and any key events would be directed at the (now
|
||||
// hidden) chrome document instead of the target document.
|
||||
gBrowser.selectedBrowser.focus();
|
||||
},
|
||||
|
||||
// State could be one of "onscreen", "ontop", "hiding", and
|
||||
// "hidden". Setting the state to "onscreen" and "ontop" takes
|
||||
// effect immediately, while setting it to "hidden" actually
|
||||
// turns the state to "hiding" before the transition finishes.
|
||||
_lastState: null,
|
||||
_STATES: ["hidden", "ontop", "onscreen"],
|
||||
get _state() {
|
||||
for (let state of this._STATES) {
|
||||
if (this._element.hasAttribute(state)) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return "hiding";
|
||||
},
|
||||
set _state(newState) {
|
||||
let currentState = this._state;
|
||||
if (currentState == newState) {
|
||||
return;
|
||||
}
|
||||
if (currentState != "hiding") {
|
||||
this._lastState = currentState;
|
||||
this._element.removeAttribute(currentState);
|
||||
}
|
||||
if (newState != "hidden") {
|
||||
this._element.setAttribute(newState, true);
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function(event) {
|
||||
switch (event.type) {
|
||||
case "mousemove": {
|
||||
let state = this._state;
|
||||
if (state == "hidden") {
|
||||
// If the warning box is currently hidden, show it after
|
||||
// a short delay if the pointer is at the top.
|
||||
if (event.clientY != 0) {
|
||||
this._timeoutShow.cancel();
|
||||
} else if (this._timeoutShow.delay >= 0) {
|
||||
this._timeoutShow.start();
|
||||
}
|
||||
} else {
|
||||
let elemRect = this._element.getBoundingClientRect();
|
||||
if (state == "hiding") {
|
||||
// If we are on the hiding transition, and the pointer
|
||||
// moved near the box, restore to the previous state.
|
||||
if (event.clientY <= elemRect.bottom + 50) {
|
||||
this._state = this._lastState;
|
||||
this._timeoutHide.start();
|
||||
}
|
||||
} else if (state == "ontop" || this._lastState != "hidden") {
|
||||
// State being "ontop" or the previous state not being
|
||||
// "hidden" indicates this current warning box is shown
|
||||
// in response to user's action. Hide it immediately when
|
||||
// the pointer leaves that area.
|
||||
if (event.clientY > elemRect.bottom + 50) {
|
||||
this._state = "hidden";
|
||||
this._timeoutHide.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "transitionend": {
|
||||
if (this._state == "hiding") {
|
||||
this._element.setAttribute("hidden", true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
showNavToolbox: function(trackMouse = true) {
|
||||
|
@ -476,10 +476,10 @@
|
||||
accesskey="&webapps.accesskey;"
|
||||
oncommand="BrowserOpenApps();"/>
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
<!-- only one of sync-setup or sync-menu will be showing at once -->
|
||||
<!-- only one of sync-setup, sync-syncnowitem or sync-reauthitem will be showing at once -->
|
||||
<menuitem id="sync-setup"
|
||||
label="&syncSetup.label;"
|
||||
accesskey="&syncSetup.accesskey;"
|
||||
label="&syncSignIn.label;"
|
||||
accesskey="&syncSignIn.accesskey;"
|
||||
observes="sync-setup-state"
|
||||
oncommand="gSyncUI.openSetup(null, 'menubar')"/>
|
||||
<menuitem id="sync-syncnowitem"
|
||||
|
@ -669,32 +669,49 @@ window[chromehidden~="toolbar"] toolbar:not(#nav-bar):not(#TabsToolbar):not(#pri
|
||||
background: black;
|
||||
}
|
||||
|
||||
#full-screen-warning-container {
|
||||
#fullscreen-warning {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2147483647 !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#full-screen-warning-container[fade-warning-out] {
|
||||
transition-property: opacity !important;
|
||||
transition-duration: 500ms !important;
|
||||
opacity: 0.0;
|
||||
}
|
||||
|
||||
#full-screen-warning-message {
|
||||
visibility: visible;
|
||||
transition: transform 300ms ease-in;
|
||||
/* To center the warning box horizontally,
|
||||
we use left: 50% with translateX(-50%). */
|
||||
top: 0; left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
/* We must specify a max-width, otherwise word-wrap:break-word doesn't
|
||||
work in descendant <description> and <label> elements. Bug 630864. */
|
||||
max-width: 800px;
|
||||
max-width: 95%;
|
||||
pointer-events: none;
|
||||
}
|
||||
#fullscreen-warning[hidden] {
|
||||
/* To ensure the transition always works fine, never change
|
||||
the value of display property. */
|
||||
display: flex;
|
||||
visibility: hidden !important;
|
||||
transition: initial;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
#fullscreen-warning[onscreen] {
|
||||
transform: translate(-50%, 50px);
|
||||
}
|
||||
#fullscreen-warning[ontop] {
|
||||
/* Use -10px to hide the border and border-radius on the top */
|
||||
transform: translate(-50%, -10px);
|
||||
}
|
||||
|
||||
#full-screen-domain-text {
|
||||
#fullscreen-domain-text,
|
||||
#fullscreen-generic-text {
|
||||
word-wrap: break-word;
|
||||
/* We must specify a min-width, otherwise word-wrap:break-word doesn't work. Bug 630864. */
|
||||
min-width: 1px;
|
||||
min-width: 1px
|
||||
}
|
||||
#fullscreen-domain-text:not([hidden]) + #fullscreen-generic-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fullscreen-exit-button {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* ::::: Ctrl-Tab Panel ::::: */
|
||||
|
@ -6937,6 +6937,13 @@ var gIdentityHandler = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current mode, which should be one of IDENTITY_MODE_*.
|
||||
*/
|
||||
getMode: function() {
|
||||
return this._mode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set up the messages for the primary identity UI based on the specified mode,
|
||||
* and the details of the SSL cert, where applicable
|
||||
|
@ -1173,13 +1173,22 @@
|
||||
#include ../../components/customizableui/content/customizeMode.inc.xul
|
||||
</deck>
|
||||
|
||||
<hbox id="full-screen-warning-container" hidden="true" fadeout="true">
|
||||
<hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
|
||||
<vbox id="full-screen-warning-message" align="center">
|
||||
<description id="full-screen-domain-text"/>
|
||||
<description class="full-screen-description" value="&fullscreenExitHint2.value;"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
<hbox id="fullscreen-warning" hidden="true">
|
||||
<description id="fullscreen-domain-text">
|
||||
&fullscreenWarning.beforeDomain.label;
|
||||
<label id="fullscreen-domain"/>
|
||||
&fullscreenWarning.afterDomain.label;
|
||||
</description>
|
||||
<description id="fullscreen-generic-text">
|
||||
&fullscreenWarning.generic.label;
|
||||
</description>
|
||||
<button id="fullscreen-exit-button"
|
||||
#ifdef XP_MACOSX
|
||||
label="&exitDOMFullscreenMac.button;"
|
||||
#else
|
||||
label="&exitDOMFullscreen.button;"
|
||||
#endif
|
||||
oncommand="FullScreen.exitDomFullScreen();"/>
|
||||
</hbox>
|
||||
|
||||
<vbox id="browser-bottombox" layer="true">
|
||||
|
@ -195,12 +195,8 @@ let gGrid = {
|
||||
parseFloat(getComputedStyle(refCell).marginBottom);
|
||||
this._cellWidth = refCell.offsetWidth + this._cellMargin;
|
||||
}
|
||||
|
||||
let availSpace = document.documentElement.clientHeight - this._cellMargin -
|
||||
document.querySelector("#newtab-search-container").offsetHeight;
|
||||
let visibleRows = Math.floor(availSpace / this._cellHeight);
|
||||
this._node.style.height = this._computeHeight() + "px";
|
||||
this._node.style.maxHeight = this._computeHeight(visibleRows) + "px";
|
||||
this._node.style.maxHeight = this._node.style.height;
|
||||
this._node.style.maxWidth = gGridPrefs.gridColumns * this._cellWidth +
|
||||
GRID_WIDTH_EXTRA + "px";
|
||||
}
|
||||
|
@ -340,6 +340,7 @@ input[type=button] {
|
||||
display: -moz-box;
|
||||
position: relative;
|
||||
-moz-box-pack: center;
|
||||
margin: 15px 0px;
|
||||
}
|
||||
|
||||
#newtab-search-container[page-disabled] {
|
||||
|
@ -5868,7 +5868,19 @@
|
||||
</property>
|
||||
|
||||
<field name="mOverCloseButton">false</field>
|
||||
<field name="_overPlayingIcon">false</field>
|
||||
<property name="_overPlayingIcon" readonly="true">
|
||||
<getter><![CDATA[
|
||||
let iconVisible = this.hasAttribute("soundplaying") ||
|
||||
this.hasAttribute("muted");
|
||||
let soundPlayingIcon =
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "soundplaying-icon");
|
||||
let overlayIcon =
|
||||
document.getAnonymousElementByAttribute(this, "anonid", "overlay-icon");
|
||||
|
||||
return soundPlayingIcon && soundPlayingIcon.mozMatchesSelector(":hover") ||
|
||||
(overlayIcon && overlayIcon.mozMatchesSelector(":hover") && iconVisible);
|
||||
]]></getter>
|
||||
</property>
|
||||
<field name="mCorrespondingMenuitem">null</field>
|
||||
|
||||
<!--
|
||||
@ -5947,25 +5959,15 @@
|
||||
<handlers>
|
||||
<handler event="mouseover"><![CDATA[
|
||||
let anonid = event.originalTarget.getAttribute("anonid");
|
||||
let iconVisible = this.hasAttribute("soundplaying") ||
|
||||
this.hasAttribute("muted");
|
||||
if (anonid == "close-button")
|
||||
this.mOverCloseButton = true;
|
||||
else if ((anonid == "soundplaying-icon") ||
|
||||
((anonid == "overlay-icon") && iconVisible))
|
||||
this._overPlayingIcon = true;
|
||||
|
||||
this._mouseenter();
|
||||
]]></handler>
|
||||
<handler event="mouseout"><![CDATA[
|
||||
let anonid = event.originalTarget.getAttribute("anonid");
|
||||
let iconVisible = this.hasAttribute("soundplaying") ||
|
||||
this.hasAttribute("muted");
|
||||
if (anonid == "close-button")
|
||||
this.mOverCloseButton = false;
|
||||
else if ((anonid == "soundplaying-icon") ||
|
||||
((anonid == "overlay-icon") && iconVisible))
|
||||
this._overPlayingIcon = false;
|
||||
|
||||
this._mouseleave();
|
||||
]]></handler>
|
||||
@ -5993,13 +5995,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
let anonid = event.originalTarget.getAttribute("anonid");
|
||||
let iconVisible = this.hasAttribute("soundplaying") ||
|
||||
this.hasAttribute("muted");
|
||||
if ((anonid == "soundplaying-icon") ||
|
||||
((anonid == "overlay-icon") && iconVisible)) {
|
||||
if (this._overPlayingIcon) {
|
||||
this.toggleMuteAudio();
|
||||
this._overPlayingIcon = false;
|
||||
}
|
||||
]]>
|
||||
</handler>
|
||||
|
@ -24,10 +24,19 @@ registerCleanupFunction(function() {
|
||||
}
|
||||
});
|
||||
|
||||
function hidden(el) {
|
||||
let win = el.ownerDocument.defaultView;
|
||||
let display = win.getComputedStyle(el).getPropertyValue("display", null);
|
||||
let opacity = win.getComputedStyle(el).getPropertyValue("opacity", null);
|
||||
|
||||
return display === "none" || opacity === "0";
|
||||
}
|
||||
|
||||
add_task(function* testNormalBrowsing() {
|
||||
yield UrlClassifierTestUtils.addTestTrackers();
|
||||
|
||||
tabbrowser = gBrowser;
|
||||
let {gIdentityHandler} = tabbrowser.ownerGlobal;
|
||||
let tab = tabbrowser.selectedTab = tabbrowser.addTab();
|
||||
|
||||
TrackingProtection = tabbrowser.ownerGlobal.TrackingProtection;
|
||||
@ -43,16 +52,21 @@ add_task(function* testNormalBrowsing() {
|
||||
|
||||
info("Load a test page containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
ok(TrackingProtection.container.hidden, "The container is hidden");
|
||||
gIdentityHandler._identityBox.click();
|
||||
ok(hidden(TrackingProtection.container), "The container is hidden");
|
||||
gIdentityHandler._identityPopup.hidden = true;
|
||||
|
||||
info("Load a test page not containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
|
||||
ok(TrackingProtection.container.hidden, "The container is hidden");
|
||||
gIdentityHandler._identityBox.click();
|
||||
ok(hidden(TrackingProtection.container), "The container is hidden");
|
||||
gIdentityHandler._identityPopup.hidden = true;
|
||||
});
|
||||
|
||||
add_task(function* testPrivateBrowsing() {
|
||||
let privateWin = yield promiseOpenAndLoadWindow({private: true}, true);
|
||||
tabbrowser = privateWin.gBrowser;
|
||||
let {gIdentityHandler} = tabbrowser.ownerGlobal;
|
||||
let tab = tabbrowser.selectedTab = tabbrowser.addTab();
|
||||
|
||||
TrackingProtection = tabbrowser.ownerGlobal.TrackingProtection;
|
||||
@ -68,11 +82,15 @@ add_task(function* testPrivateBrowsing() {
|
||||
|
||||
info("Load a test page containing tracking elements");
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
ok(TrackingProtection.container.hidden, "The container is hidden");
|
||||
gIdentityHandler._identityBox.click();
|
||||
ok(hidden(TrackingProtection.container), "The container is hidden");
|
||||
gIdentityHandler._identityPopup.hidden = true;
|
||||
|
||||
info("Load a test page not containing tracking elements");
|
||||
gIdentityHandler._identityBox.click();
|
||||
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
|
||||
ok(TrackingProtection.container.hidden, "The container is hidden");
|
||||
ok(hidden(TrackingProtection.container), "The container is hidden");
|
||||
gIdentityHandler._identityPopup.hidden = true;
|
||||
|
||||
privateWin.close();
|
||||
});
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
@ -9,7 +9,6 @@ loop.conversationViews = (function(mozL10n) {
|
||||
var CALL_STATES = loop.store.CALL_STATES;
|
||||
var CALL_TYPES = loop.shared.utils.CALL_TYPES;
|
||||
var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
|
||||
var REST_ERRNOS = loop.shared.utils.REST_ERRNOS;
|
||||
var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
@ -481,7 +480,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
switch (this.getStoreState().callStateReason) {
|
||||
case WEBSOCKET_REASONS.REJECT:
|
||||
case WEBSOCKET_REASONS.BUSY:
|
||||
case REST_ERRNOS.USER_UNAVAILABLE:
|
||||
case FAILURE_DETAILS.USER_UNAVAILABLE:
|
||||
var contactDisplayName = _getContactDisplayName(this.props.contact);
|
||||
if (contactDisplayName.length) {
|
||||
return mozL10n.get(
|
||||
@ -512,7 +511,6 @@ loop.conversationViews = (function(mozL10n) {
|
||||
});
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: navigator.mozLoop.userProfile.email,
|
||||
roomName: _getContactDisplayName(this.props.contact)
|
||||
}));
|
||||
},
|
||||
|
@ -9,7 +9,6 @@ loop.conversationViews = (function(mozL10n) {
|
||||
var CALL_STATES = loop.store.CALL_STATES;
|
||||
var CALL_TYPES = loop.shared.utils.CALL_TYPES;
|
||||
var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
|
||||
var REST_ERRNOS = loop.shared.utils.REST_ERRNOS;
|
||||
var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
@ -481,7 +480,7 @@ loop.conversationViews = (function(mozL10n) {
|
||||
switch (this.getStoreState().callStateReason) {
|
||||
case WEBSOCKET_REASONS.REJECT:
|
||||
case WEBSOCKET_REASONS.BUSY:
|
||||
case REST_ERRNOS.USER_UNAVAILABLE:
|
||||
case FAILURE_DETAILS.USER_UNAVAILABLE:
|
||||
var contactDisplayName = _getContactDisplayName(this.props.contact);
|
||||
if (contactDisplayName.length) {
|
||||
return mozL10n.get(
|
||||
@ -512,7 +511,6 @@ loop.conversationViews = (function(mozL10n) {
|
||||
});
|
||||
|
||||
this.props.dispatcher.dispatch(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: navigator.mozLoop.userProfile.email,
|
||||
roomName: _getContactDisplayName(this.props.contact)
|
||||
}));
|
||||
},
|
||||
|
@ -751,8 +751,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
handleCreateButtonClick: function() {
|
||||
var createRoomAction = new sharedActions.CreateRoom({
|
||||
nameTemplate: mozL10n.get("rooms_default_room_name_template"),
|
||||
roomOwner: this.props.userDisplayName
|
||||
nameTemplate: mozL10n.get("rooms_default_room_name_template")
|
||||
});
|
||||
|
||||
if (this.state.checked) {
|
||||
|
@ -751,8 +751,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
handleCreateButtonClick: function() {
|
||||
var createRoomAction = new sharedActions.CreateRoom({
|
||||
nameTemplate: mozL10n.get("rooms_default_room_name_template"),
|
||||
roomOwner: this.props.userDisplayName
|
||||
nameTemplate: mozL10n.get("rooms_default_room_name_template")
|
||||
});
|
||||
|
||||
if (this.state.checked) {
|
||||
|
@ -264,7 +264,6 @@ loop.store = loop.store || {};
|
||||
decryptedContext: {
|
||||
roomName: this._generateNewRoomName(actionData.nameTemplate)
|
||||
},
|
||||
roomOwner: actionData.roomOwner,
|
||||
maxSize: this.maxRoomCreationSize
|
||||
};
|
||||
|
||||
|
@ -80,7 +80,6 @@ loop.shared.actions = (function() {
|
||||
* a contact can't be reached.
|
||||
*/
|
||||
FetchRoomEmailLink: Action.define("fetchRoomEmailLink", {
|
||||
roomOwner: String,
|
||||
roomName: String
|
||||
}),
|
||||
|
||||
@ -307,8 +306,7 @@ loop.shared.actions = (function() {
|
||||
CreateRoom: Action.define("createRoom", {
|
||||
// The localized template to use to name the new room
|
||||
// (eg. "Conversation {{conversationLabel}}").
|
||||
nameTemplate: String,
|
||||
roomOwner: String
|
||||
nameTemplate: String
|
||||
// See https://wiki.mozilla.org/Loop/Architecture/Context#Format_of_context.value
|
||||
// urls: Object - Optional
|
||||
}),
|
||||
|
@ -421,8 +421,9 @@ loop.store = loop.store || {};
|
||||
*/
|
||||
fetchRoomEmailLink: function(actionData) {
|
||||
this.mozLoop.rooms.create({
|
||||
roomName: actionData.roomName,
|
||||
roomOwner: actionData.roomOwner,
|
||||
decryptedContext: {
|
||||
roomName: actionData.roomName
|
||||
},
|
||||
maxSize: loop.store.MAX_ROOM_CREATION_SIZE,
|
||||
expiresIn: loop.store.DEFAULT_EXPIRES_IN
|
||||
}, function(err, createdRoomData) {
|
||||
@ -532,9 +533,9 @@ loop.store = loop.store || {};
|
||||
function(err, result) {
|
||||
if (err) {
|
||||
console.error("Failed to get outgoing call data", err);
|
||||
var failureReason = "setup";
|
||||
var failureReason = FAILURE_DETAILS.UNKNOWN;
|
||||
if (err.errno === REST_ERRNOS.USER_UNAVAILABLE) {
|
||||
failureReason = REST_ERRNOS.USER_UNAVAILABLE;
|
||||
failureReason = FAILURE_DETAILS.USER_UNAVAILABLE;
|
||||
}
|
||||
this.dispatcher.dispatch(
|
||||
new sharedActions.ConnectionFailure({reason: failureReason}));
|
||||
|
@ -76,6 +76,7 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
||||
MEDIA_DENIED: "reason-media-denied",
|
||||
NO_MEDIA: "reason-no-media",
|
||||
UNABLE_TO_PUBLISH_MEDIA: "unable-to-publish-media",
|
||||
USER_UNAVAILABLE: "reason-user-unavailable",
|
||||
COULD_NOT_CONNECT: "reason-could-not-connect",
|
||||
NETWORK_DISCONNECTED: "reason-network-disconnected",
|
||||
EXPIRED_OR_INVALID: "reason-expired-or-invalid",
|
||||
|
@ -301,6 +301,21 @@ let LoopRoomsInternal = {
|
||||
return decryptedRoomKey;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Updates a roomUrl to add a new key onto the end of the url.
|
||||
*
|
||||
* @param {String} roomUrl The existing url that may or may not have a key
|
||||
* on the end.
|
||||
* @param {String} roomKey The new key to put on the url.
|
||||
* @return {String} The revised url.
|
||||
*/
|
||||
refreshRoomUrlWithNewKey: function(roomUrl, roomKey) {
|
||||
// Strip any existing key from the url.
|
||||
roomUrl = roomUrl.split("#")[0];
|
||||
// Now add the key to the url.
|
||||
return roomUrl + "#" + roomKey;
|
||||
},
|
||||
|
||||
/**
|
||||
* Encrypts room data in a format appropriate to sending to the loop
|
||||
* server.
|
||||
@ -404,10 +419,7 @@ let LoopRoomsInternal = {
|
||||
roomData.roomKey = key;
|
||||
roomData.decryptedContext = JSON.parse(decryptedData);
|
||||
|
||||
// Strip any existing key from the url.
|
||||
roomData.roomUrl = roomData.roomUrl.split("#")[0];
|
||||
// Now add the key to the url.
|
||||
roomData.roomUrl = roomData.roomUrl + "#" + roomData.roomKey;
|
||||
roomData.roomUrl = this.refreshRoomUrlWithNewKey(roomData.roomUrl, roomData.roomKey);
|
||||
|
||||
return roomData;
|
||||
}),
|
||||
@ -592,12 +604,15 @@ let LoopRoomsInternal = {
|
||||
* be the room, if it was created successfully.
|
||||
*/
|
||||
create: function(room, callback) {
|
||||
if (!("decryptedContext" in room) || !("roomOwner" in room) ||
|
||||
!("maxSize" in room)) {
|
||||
if (!("decryptedContext" in room) || !("maxSize" in room)) {
|
||||
callback(new Error("Missing required property to create a room"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!("roomOwner" in room)) {
|
||||
room.roomOwner = "-";
|
||||
}
|
||||
|
||||
Task.spawn(function* () {
|
||||
let {all, encrypted} = yield this.promiseEncryptRoomData(room);
|
||||
|
||||
@ -610,6 +625,8 @@ let LoopRoomsInternal = {
|
||||
extend(room, JSON.parse(response.body));
|
||||
// Do not keep this value - it is a request to the server.
|
||||
delete room.expiresIn;
|
||||
// Make sure the url has the key on it.
|
||||
room.roomUrl = this.refreshRoomUrlWithNewKey(room.roomUrl, room.roomKey);
|
||||
this.rooms.set(room.roomToken, room);
|
||||
|
||||
if (this.sessionType == LOOP_SESSION_TYPE.GUEST) {
|
||||
|
@ -321,8 +321,6 @@ describe("loop.conversationViews", function () {
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("name", "fetchRoomEmailLink"));
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("roomOwner", fakeMozLoop.userProfile.email));
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("roomName", "test@test.tld"));
|
||||
});
|
||||
@ -441,9 +439,9 @@ describe("loop.conversationViews", function () {
|
||||
"generic_failure_title");
|
||||
});
|
||||
|
||||
it("should show 'contact unavailable' when the reason is REST_ERRNOS.USER_UNAVAILABLE",
|
||||
it("should show 'contact unavailable' when the reason is FAILURE_DETAILS.USER_UNAVAILABLE",
|
||||
function () {
|
||||
conversationStore.setStoreState({callStateReason: REST_ERRNOS.USER_UNAVAILABLE});
|
||||
conversationStore.setStoreState({callStateReason: FAILURE_DETAILS.USER_UNAVAILABLE});
|
||||
|
||||
view = mountTestComponent({contact: fakeContact});
|
||||
|
||||
|
@ -838,8 +838,7 @@ describe("loop.panel", function() {
|
||||
TestUtils.Simulate.click(view.getDOMNode().querySelector(".new-room-button"));
|
||||
|
||||
sinon.assert.calledWith(dispatch, new sharedActions.CreateRoom({
|
||||
nameTemplate: "Fake title",
|
||||
roomOwner: fakeEmail
|
||||
nameTemplate: "Fake title"
|
||||
}));
|
||||
});
|
||||
|
||||
@ -870,7 +869,6 @@ describe("loop.panel", function() {
|
||||
|
||||
sinon.assert.calledWith(dispatch, new sharedActions.CreateRoom({
|
||||
nameTemplate: "Fake title",
|
||||
roomOwner: fakeEmail,
|
||||
urls: [{
|
||||
location: "http://invalid.com",
|
||||
description: "fakeSite",
|
||||
|
@ -243,8 +243,7 @@ describe("loop.store.RoomStore", function () {
|
||||
sandbox.stub(dispatcher, "dispatch");
|
||||
store.setStoreState({pendingCreation: false, rooms: []});
|
||||
fakeRoomCreationData = {
|
||||
nameTemplate: fakeNameTemplate,
|
||||
roomOwner: fakeOwner
|
||||
nameTemplate: fakeNameTemplate
|
||||
};
|
||||
});
|
||||
|
||||
@ -285,7 +284,6 @@ describe("loop.store.RoomStore", function () {
|
||||
decryptedContext: {
|
||||
roomName: "Conversation 1"
|
||||
},
|
||||
roomOwner: fakeOwner,
|
||||
maxSize: store.maxRoomCreationSize
|
||||
});
|
||||
});
|
||||
@ -310,7 +308,6 @@ describe("loop.store.RoomStore", function () {
|
||||
thumbnail: "fakeimage.png"
|
||||
}]
|
||||
},
|
||||
roomOwner: fakeOwner,
|
||||
maxSize: store.maxRoomCreationSize
|
||||
});
|
||||
});
|
||||
|
@ -9,6 +9,7 @@ describe("loop.store.ConversationStore", function () {
|
||||
var WS_STATES = loop.store.WS_STATES;
|
||||
var CALL_TYPES = loop.shared.utils.CALL_TYPES;
|
||||
var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
|
||||
var REST_ERRNOS = loop.shared.utils.REST_ERRNOS;
|
||||
var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
|
||||
var sharedActions = loop.shared.actions;
|
||||
var sharedUtils = loop.shared.utils;
|
||||
@ -535,7 +536,23 @@ describe("loop.store.ConversationStore", function () {
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("name", "connectionFailure"));
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("reason", "setup"));
|
||||
sinon.match.hasOwn("reason", FAILURE_DETAILS.UNKNOWN));
|
||||
});
|
||||
|
||||
it("should dispatch a connection failure action on failure with user unavailable", function() {
|
||||
client.setupOutgoingCall.callsArgWith(2, {
|
||||
errno: REST_ERRNOS.USER_UNAVAILABLE
|
||||
});
|
||||
|
||||
store.setupWindowData(
|
||||
new sharedActions.SetupWindowData(fakeSetupWindowData));
|
||||
|
||||
sinon.assert.calledOnce(dispatcher.dispatch);
|
||||
// Can't use instanceof here, as that matches any action
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("name", "connectionFailure"));
|
||||
sinon.assert.calledWithMatch(dispatcher.dispatch,
|
||||
sinon.match.hasOwn("reason", FAILURE_DETAILS.USER_UNAVAILABLE));
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1026,14 +1043,14 @@ describe("loop.store.ConversationStore", function () {
|
||||
describe("#fetchRoomEmailLink", function() {
|
||||
it("should request a new call url to the server", function() {
|
||||
store.fetchRoomEmailLink(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
}));
|
||||
|
||||
sinon.assert.calledOnce(fakeMozLoop.rooms.create);
|
||||
sinon.assert.calledWithMatch(fakeMozLoop.rooms.create, {
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
decryptedContext: {
|
||||
roomName: "FakeRoomName"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -1043,7 +1060,6 @@ describe("loop.store.ConversationStore", function () {
|
||||
cb(null, {roomUrl: "http://fake.invalid/"});
|
||||
};
|
||||
store.fetchRoomEmailLink(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
}));
|
||||
|
||||
@ -1059,7 +1075,6 @@ describe("loop.store.ConversationStore", function () {
|
||||
cb(new Error("error"));
|
||||
};
|
||||
store.fetchRoomEmailLink(new sharedActions.FetchRoomEmailLink({
|
||||
roomOwner: "bob@invalid.tld",
|
||||
roomName: "FakeRoomName"
|
||||
}));
|
||||
|
||||
|
@ -404,6 +404,13 @@ add_task(function* test_createRoom() {
|
||||
|
||||
gExpectedAdds.push(expectedRoom);
|
||||
let room = yield LoopRooms.promise("create", kCreateRoomProps);
|
||||
|
||||
// We can't check the value of the key, but check we've got a # which indicates
|
||||
// there should be one.
|
||||
Assert.ok(room.roomUrl.contains("#"), "Created room url should have a key");
|
||||
var key = room.roomUrl.split("#")[1];
|
||||
Assert.ok(key.length, "Created room url should have non-zero length key");
|
||||
|
||||
compareRooms(room, expectedRoom);
|
||||
});
|
||||
|
||||
|
@ -387,7 +387,7 @@
|
||||
roomOwner: "fake",
|
||||
roomUrl: "http://showcase",
|
||||
urls: [{
|
||||
description: "1171925 - Clicking the title or favicon for context (in the conversation/standalone windows) should appear to be part of the link and open the webpage",
|
||||
description: "A wonderful page!",
|
||||
location: "http://wonderful.invalid"
|
||||
// use the fallback thumbnail
|
||||
}]
|
||||
@ -601,45 +601,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
var Example = React.createClass({displayName: "Example",
|
||||
propTypes: {
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.element,
|
||||
React.PropTypes.arrayOf(React.PropTypes.element)
|
||||
]).isRequired,
|
||||
cssClass: React.PropTypes.string,
|
||||
dashed: React.PropTypes.bool,
|
||||
style: React.PropTypes.object,
|
||||
summary: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
makeId: function(prefix) {
|
||||
return (prefix || "") + this.props.summary.toLowerCase().replace(/\s/g, "-");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
var extraCSSClass = {
|
||||
"example": true
|
||||
};
|
||||
if (this.props.cssClass) {
|
||||
extraCSSClass[this.props.cssClass] = true;
|
||||
}
|
||||
return (
|
||||
React.createElement("div", {className: cx(extraCSSClass)},
|
||||
React.createElement("h3", {id: this.makeId()},
|
||||
this.props.summary,
|
||||
React.createElement("a", {href: this.makeId("#")}, " ¶")
|
||||
),
|
||||
React.createElement("div", {className: cx({comp: true, dashed: this.props.dashed}),
|
||||
style: this.props.style},
|
||||
this.props.children
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Section = React.createClass({displayName: "Section",
|
||||
propTypes: {
|
||||
children: React.PropTypes.oneOfType([
|
||||
@ -726,71 +687,130 @@
|
||||
React.createElement("p", {className: "note"},
|
||||
React.createElement("strong", null, "Note:"), " 332px wide."
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Re-sign-in view"},
|
||||
React.createElement(SignInRequestView, {mozLoop: mockMozLoopLoggedIn})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Re-sign-in view",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(SignInRequestView, {mozLoop: mockMozLoopLoggedIn})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Room list tab"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "rooms"})
|
||||
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Room list tab",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "rooms"})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact list tab"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Contact list tab",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact list tab long email"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedInLongEmail,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Contact list tab long email",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedInLongEmail,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact list tab (no contacts)"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mozLoopNoContacts,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Contact list tab (no contacts)",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mozLoopNoContacts,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Error Notification"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop,
|
||||
notifications: errNotifications,
|
||||
roomStore: roomStore})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Error Notification",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop,
|
||||
notifications: errNotifications,
|
||||
roomStore: roomStore})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Error Notification - authenticated"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: errNotifications,
|
||||
roomStore: roomStore})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Error Notification - authenticated",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: errNotifications,
|
||||
roomStore: roomStore})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact import success"},
|
||||
React.createElement(PanelView, {dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: new loop.shared.models.NotificationCollection([{level: "success", message: "Import success"}]),
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Contact import success",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: new loop.shared.models.NotificationCollection([{level: "success", message: "Import success"}]),
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact import error"},
|
||||
React.createElement(PanelView, {dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: new loop.shared.models.NotificationCollection([{level: "error", message: "Import error"}]),
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Contact import error",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: new loop.shared.models.NotificationCollection([{level: "error", message: "Import error"}]),
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts"})
|
||||
)
|
||||
),
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel", dashed: true, height: 400,
|
||||
summary: "Contact Form - Add", width: 332},
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 410,
|
||||
summary: "Contact Form - Add",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
@ -807,44 +827,70 @@
|
||||
React.createElement("p", {className: "note"},
|
||||
React.createElement("strong", null, "Note:"), " 332px wide."
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px", height: "200px"},
|
||||
summary: "AvailabilityDropdown"},
|
||||
React.createElement(AvailabilityDropdown, null)
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 200,
|
||||
summary: "AvailabilityDropdown",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(AvailabilityDropdown, null)
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {cssClass: "force-menu-show", dashed: true,
|
||||
style: {width: "332px", height: "200px"},
|
||||
summary: "AvailabilityDropdown Expanded"},
|
||||
React.createElement(AvailabilityDropdown, null)
|
||||
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 200,
|
||||
summary: "AvailabilityDropdown Expanded",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "panel force-menu-show", style: {"height": "100%", "paddingTop": "50px"}},
|
||||
React.createElement(AvailabilityDropdown, null)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "ContactDetail"},
|
||||
React.createElement(Example, {cssClass: "force-menu-show", dashed: true,
|
||||
style: {width: "300px", height: "272px"},
|
||||
summary: "ContactDetail"},
|
||||
React.createElement(ContactDetail, {contact: fakeContacts[0],
|
||||
handleContactAction: function() {}})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 272,
|
||||
summary: "ContactDetail",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "panel force-menu-show"},
|
||||
React.createElement(ContactDetail, {contact: fakeContacts[0],
|
||||
handleContactAction: function() {}})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "ContactDropdown"},
|
||||
React.createElement(Example, {dashed: true, style: {width: "300px", height: "272px"},
|
||||
summary: "ContactDropdown not blocked can edit"},
|
||||
React.createElement(ContactDropdown, {blocked: false,
|
||||
canEdit: true,
|
||||
handleAction: function () {}})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 272,
|
||||
summary: "ContactDropdown not blocked can edit",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(ContactDropdown, {blocked: false,
|
||||
canEdit: true,
|
||||
handleAction: function () {}})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "300px", height: "272px"},
|
||||
summary: "ContactDropdown blocked can't edit"},
|
||||
React.createElement(ContactDropdown, {blocked: true,
|
||||
canEdit: false,
|
||||
handleAction: function () {}})
|
||||
React.createElement(FramedExample, {cssClass: "fx-embedded-panel",
|
||||
dashed: true,
|
||||
height: 272,
|
||||
summary: "ContactDropdown blocked can't edit",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "panel"},
|
||||
React.createElement(ContactDropdown, {blocked: true,
|
||||
canEdit: false,
|
||||
handleAction: function () {}})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "AcceptCallView"},
|
||||
React.createElement(Example, {dashed: true, style: {width: "300px", height: "272px"},
|
||||
summary: "Default / incoming video call"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Default / incoming video call",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(AcceptCallView, {callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "Mr Smith",
|
||||
@ -853,8 +899,10 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Example, {dashed: true, style: {width: "300px", height: "272px"},
|
||||
summary: "Default / incoming audio only call"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Default / incoming audio only call",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(AcceptCallView, {callType: CALL_TYPES.AUDIO_ONLY,
|
||||
callerId: "Mr Smith",
|
||||
@ -865,8 +913,10 @@
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "AcceptCallView-ActiveState"},
|
||||
React.createElement(Example, {dashed: true, style: {width: "300px", height: "272px"},
|
||||
summary: "Default"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Default",
|
||||
width: 332},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(AcceptCallView, {callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "Mr Smith",
|
||||
@ -879,54 +929,85 @@
|
||||
|
||||
React.createElement(Section, {name: "ConversationToolbar"},
|
||||
React.createElement("h2", null, "Desktop Conversation Window"),
|
||||
React.createElement("div", {className: "fx-embedded override-position"},
|
||||
React.createElement(Example, {style: {width: "300px", height: "26px"}, summary: "Default"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
React.createElement("div", null,
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 26,
|
||||
summary: "Default",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {style: {width: "300px", height: "26px"}, summary: "Video muted"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: false}})
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 26,
|
||||
summary: "Video muted",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: false}})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {style: {width: "300px", height: "26px"}, summary: "Audio muted"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: false},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 26,
|
||||
summary: "Audio muted",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: false},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement("h2", null, "Standalone"),
|
||||
React.createElement("div", {className: "standalone override-position"},
|
||||
React.createElement(Example, {summary: "Default"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 26,
|
||||
summary: "Default",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {summary: "Video muted"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: false}})
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 26,
|
||||
summary: "Video muted",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: true},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: false}})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {summary: "Audio muted"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: false},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 26,
|
||||
summary: "Audio muted",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(ConversationToolbar, {audio: {enabled: false},
|
||||
hangup: noop,
|
||||
publishStream: noop,
|
||||
video: {enabled: true}})
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "PendingConversationView (Desktop)"},
|
||||
React.createElement(Example, {dashed: true,
|
||||
style: {width: "300px", height: "272px"},
|
||||
summary: "Connecting"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Connecting",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopPendingConversationView, {callState: "gather",
|
||||
contact: mockContact,
|
||||
@ -936,27 +1017,30 @@
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "CallFailedView"},
|
||||
React.createElement(Example, {dashed: true,
|
||||
style: {width: "300px", height: "272px"},
|
||||
summary: "Call Failed - Incoming"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Call Failed - Incoming",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
||||
outgoing: false,
|
||||
store: conversationStores[0]})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true,
|
||||
style: {width: "300px", height: "272px"},
|
||||
summary: "Call Failed - Outgoing"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Call Failed - Outgoing",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(CallFailedView, {dispatcher: dispatcher,
|
||||
outgoing: true,
|
||||
store: conversationStores[1]})
|
||||
)
|
||||
),
|
||||
React.createElement(Example, {dashed: true,
|
||||
style: {width: "300px", height: "272px"},
|
||||
summary: "Call Failed — with call URL error"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Call Failed — with call URL error",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(CallFailedView, {dispatcher: dispatcher, emailLinkError: true,
|
||||
outgoing: true,
|
||||
@ -966,12 +1050,11 @@
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "OngoingConversationView"},
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: conversationStores[0].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: conversationStores[0].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
@ -985,12 +1068,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 400,
|
||||
onContentsRendered: conversationStores[1].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window (medium)",
|
||||
width: 600},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 400,
|
||||
onContentsRendered: conversationStores[1].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window (medium)",
|
||||
width: 600},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
@ -1004,11 +1086,10 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
height: 600,
|
||||
onContentsRendered: conversationStores[2].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window (large)",
|
||||
width: 800},
|
||||
React.createElement(FramedExample, {height: 600,
|
||||
onContentsRendered: conversationStores[2].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window (large)",
|
||||
width: 800},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
@ -1022,12 +1103,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: conversationStores[3].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window - local face mute",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: conversationStores[3].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window - local face mute",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
@ -1041,11 +1121,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true, height: 394,
|
||||
onContentsRendered: conversationStores[4].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window - remote face mute",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: conversationStores[4].forcedUpdate,
|
||||
summary: "Desktop ongoing conversation window - remote face mute",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(OngoingConversationView, {
|
||||
audio: {enabled: true},
|
||||
@ -1064,34 +1144,45 @@
|
||||
React.createElement(Section, {name: "FeedbackView"},
|
||||
React.createElement("p", {className: "note"}
|
||||
),
|
||||
React.createElement(Example, {dashed: true,
|
||||
style: {width: "300px", height: "272px"},
|
||||
summary: "Default (useable demo)"},
|
||||
React.createElement(FeedbackView, {mozLoop: {},
|
||||
onAfterFeedbackReceived: function() {}})
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Default (useable demo)",
|
||||
width: 300},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(FeedbackView, {mozLoop: {},
|
||||
onAfterFeedbackReceived: function() {}})
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "AlertMessages"},
|
||||
React.createElement(Example, {summary: "Various alerts"},
|
||||
React.createElement("div", {className: "alert alert-warning"},
|
||||
React.createElement("button", {className: "close"}),
|
||||
React.createElement("p", {className: "message"},
|
||||
"The person you were calling has ended the conversation."
|
||||
)
|
||||
),
|
||||
React.createElement("br", null),
|
||||
React.createElement("div", {className: "alert alert-error"},
|
||||
React.createElement("button", {className: "close"}),
|
||||
React.createElement("p", {className: "message"},
|
||||
"The person you were calling has ended the conversation."
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 272,
|
||||
summary: "Various alerts",
|
||||
width: 300},
|
||||
React.createElement("div", null,
|
||||
React.createElement("div", {className: "alert alert-warning"},
|
||||
React.createElement("button", {className: "close"}),
|
||||
React.createElement("p", {className: "message"},
|
||||
"The person you were calling has ended the conversation."
|
||||
)
|
||||
),
|
||||
React.createElement("br", null),
|
||||
React.createElement("div", {className: "alert alert-error"},
|
||||
React.createElement("button", {className: "close"}),
|
||||
React.createElement("p", {className: "message"},
|
||||
"The person you were calling has ended the conversation."
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "UnsupportedBrowserView"},
|
||||
React.createElement(Example, {summary: "Standalone Unsupported Browser"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 430,
|
||||
summary: "Standalone Unsupported Browser",
|
||||
width: 480},
|
||||
React.createElement("div", {className: "standalone"},
|
||||
React.createElement(UnsupportedBrowserView, {isFirefox: false})
|
||||
)
|
||||
@ -1099,7 +1190,10 @@
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "UnsupportedDeviceView"},
|
||||
React.createElement(Example, {summary: "Standalone Unsupported Device"},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 430,
|
||||
summary: "Standalone Unsupported Device",
|
||||
width: 480},
|
||||
React.createElement("div", {className: "standalone"},
|
||||
React.createElement(UnsupportedDeviceView, {platform: "ios"})
|
||||
)
|
||||
@ -1107,11 +1201,10 @@
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "DesktopRoomConversationView"},
|
||||
React.createElement(FramedExample, {
|
||||
height: 398,
|
||||
onContentsRendered: invitationRoomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {height: 398,
|
||||
onContentsRendered: invitationRoomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (invitation, text-chat inclusion/scrollbars don't happen in real client)",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
@ -1123,12 +1216,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: desktopRoomStoreLoading.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (loading)",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: desktopRoomStoreLoading.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (loading)",
|
||||
width: 298},
|
||||
/* Hide scrollbars here. Rotating loading div overflows and causes
|
||||
scrollbars to appear */
|
||||
React.createElement("div", {className: "fx-embedded overflow-hidden"},
|
||||
@ -1143,12 +1235,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: roomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: roomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
@ -1161,12 +1252,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 482,
|
||||
onContentsRendered: desktopRoomStoreMedium.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (medium)",
|
||||
width: 602},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 482,
|
||||
onContentsRendered: desktopRoomStoreMedium.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (medium)",
|
||||
width: 602},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
@ -1179,12 +1269,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 485,
|
||||
onContentsRendered: desktopRoomStoreLarge.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (large)",
|
||||
width: 646},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 485,
|
||||
onContentsRendered: desktopRoomStoreLarge.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation (large)",
|
||||
width: 646},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
@ -1197,12 +1286,11 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation local face-mute",
|
||||
width: 298},
|
||||
React.createElement(FramedExample, {dashed: true,
|
||||
height: 394,
|
||||
onContentsRendered: desktopLocalFaceMuteRoomStore.activeRoomStore.forcedUpdate,
|
||||
summary: "Desktop room conversation local face-mute",
|
||||
width: 298},
|
||||
React.createElement("div", {className: "fx-embedded"},
|
||||
React.createElement(DesktopRoomConversationView, {
|
||||
dispatcher: dispatcher,
|
||||
@ -1292,13 +1380,12 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 483,
|
||||
onContentsRendered: localFaceMuteRoomStore.forcedUpdate,
|
||||
summary: "Standalone room conversation (local face mute, has-participants, 644x483)",
|
||||
width: 644},
|
||||
React.createElement(FramedExample, {cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 483,
|
||||
onContentsRendered: localFaceMuteRoomStore.forcedUpdate,
|
||||
summary: "Standalone room conversation (local face mute, has-participants, 644x483)",
|
||||
width: 644},
|
||||
React.createElement("div", {className: "standalone"},
|
||||
React.createElement(StandaloneRoomView, {
|
||||
activeRoomStore: localFaceMuteRoomStore,
|
||||
@ -1309,13 +1396,12 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 483,
|
||||
onContentsRendered: remoteFaceMuteRoomStore.forcedUpdate,
|
||||
summary: "Standalone room conversation (remote face mute, has-participants, 644x483)",
|
||||
width: 644},
|
||||
React.createElement(FramedExample, {cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 483,
|
||||
onContentsRendered: remoteFaceMuteRoomStore.forcedUpdate,
|
||||
summary: "Standalone room conversation (remote face mute, has-participants, 644x483)",
|
||||
width: 644},
|
||||
React.createElement("div", {className: "standalone"},
|
||||
React.createElement(StandaloneRoomView, {
|
||||
activeRoomStore: remoteFaceMuteRoomStore,
|
||||
@ -1326,13 +1412,12 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 660,
|
||||
onContentsRendered: loadingRemoteLoadingScreenStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, loading screen share, loading remote video, 800x660)",
|
||||
width: 800},
|
||||
React.createElement(FramedExample, {cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 660,
|
||||
onContentsRendered: loadingRemoteLoadingScreenStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, loading screen share, loading remote video, 800x660)",
|
||||
width: 800},
|
||||
/* Hide scrollbars here. Rotating loading div overflows and causes
|
||||
scrollbars to appear */
|
||||
React.createElement("div", {className: "standalone overflow-hidden"},
|
||||
@ -1346,13 +1431,12 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 660,
|
||||
onContentsRendered: loadingScreenSharingRoomStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, loading screen share, 800x660)",
|
||||
width: 800},
|
||||
React.createElement(FramedExample, {cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 660,
|
||||
onContentsRendered: loadingScreenSharingRoomStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, loading screen share, 800x660)",
|
||||
width: 800},
|
||||
/* Hide scrollbars here. Rotating loading div overflows and causes
|
||||
scrollbars to appear */
|
||||
React.createElement("div", {className: "standalone overflow-hidden"},
|
||||
@ -1366,13 +1450,12 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 660,
|
||||
onContentsRendered: updatingSharingRoomStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, receivingScreenShare, 800x660)",
|
||||
width: 800},
|
||||
React.createElement(FramedExample, {cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 660,
|
||||
onContentsRendered: updatingSharingRoomStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, receivingScreenShare, 800x660)",
|
||||
width: 800},
|
||||
React.createElement("div", {className: "standalone"},
|
||||
React.createElement(StandaloneRoomView, {
|
||||
activeRoomStore: updatingSharingRoomStore,
|
||||
@ -1426,13 +1509,12 @@
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "StandaloneRoomView (Mobile)"},
|
||||
React.createElement(FramedExample, {
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 480,
|
||||
onContentsRendered: updatingMobileActiveRoomStore.forcedUpdate,
|
||||
summary: "Standalone room conversation (has-participants, 600x480)",
|
||||
width: 600},
|
||||
React.createElement(FramedExample, {cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 480,
|
||||
onContentsRendered: updatingMobileActiveRoomStore.forcedUpdate,
|
||||
summary: "Standalone room conversation (has-participants, 600x480)",
|
||||
width: 600},
|
||||
React.createElement("div", {className: "standalone"},
|
||||
React.createElement(StandaloneRoomView, {
|
||||
activeRoomStore: updatingMobileActiveRoomStore,
|
||||
@ -1444,13 +1526,12 @@
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(FramedExample, {
|
||||
cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 480,
|
||||
onContentsRendered: updatingSharingRoomMobileStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, receivingScreenShare, 600x480)",
|
||||
width: 600},
|
||||
React.createElement(FramedExample, {cssClass: "standalone",
|
||||
dashed: true,
|
||||
height: 480,
|
||||
onContentsRendered: updatingSharingRoomMobileStore.forcedUpdate,
|
||||
summary: "Standalone room convo (has-participants, receivingScreenShare, 600x480)",
|
||||
width: 600},
|
||||
React.createElement("div", {className: "standalone", cssClass: "standalone"},
|
||||
React.createElement(StandaloneRoomView, {
|
||||
activeRoomStore: updatingSharingRoomMobileStore,
|
||||
@ -1493,13 +1574,19 @@
|
||||
),
|
||||
|
||||
React.createElement(Section, {className: "svg-icons", name: "SVG icons preview"},
|
||||
React.createElement(Example, {summary: "10x10"},
|
||||
React.createElement(FramedExample, {height: 240,
|
||||
summary: "10x10",
|
||||
width: 800},
|
||||
React.createElement(SVGIcons, {size: "10x10"})
|
||||
),
|
||||
React.createElement(Example, {summary: "14x14"},
|
||||
React.createElement(FramedExample, {height: 350,
|
||||
summary: "14x14",
|
||||
width: 800},
|
||||
React.createElement(SVGIcons, {size: "14x14"})
|
||||
),
|
||||
React.createElement(Example, {summary: "16x16"},
|
||||
React.createElement(FramedExample, {height: 480,
|
||||
summary: "16x16",
|
||||
width: 800},
|
||||
React.createElement(SVGIcons, {size: "16x16"})
|
||||
)
|
||||
)
|
||||
|
@ -18,6 +18,11 @@ component {3d2532e3-4932-4774-b7ba-968f5899d3a4} IEProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=ie {3d2532e3-4932-4774-b7ba-968f5899d3a4}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_EDGE_MIGRATOR
|
||||
component {62e8834b-2d17-49f5-96ff-56344903a2ae} EdgeProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=edge {62e8834b-2d17-49f5-96ff-56344903a2ae}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SAFARI_MIGRATOR
|
||||
component {4b609ecf-60b2-4655-9df4-dc149e474da1} SafariProfileMigrator.js
|
||||
contract @mozilla.org/profile/migrator;1?app=browser&type=safari {4b609ecf-60b2-4655-9df4-dc149e474da1}
|
||||
|
29
browser/components/migration/EdgeProfileMigrator.js
Normal file
@ -0,0 +1,29 @@
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
Cu.import("resource:///modules/MSMigrationUtils.jsm");
|
||||
|
||||
function EdgeProfileMigrator() {
|
||||
}
|
||||
|
||||
EdgeProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
EdgeProfileMigrator.prototype.getResources = function() {
|
||||
let resources = [
|
||||
MSMigrationUtils.getBookmarksMigrator(MSMigrationUtils.MIGRATION_TYPE_EDGE),
|
||||
];
|
||||
return resources.filter(r => r.exists);
|
||||
};
|
||||
|
||||
EdgeProfileMigrator.prototype.classDescription = "Edge Profile Migrator";
|
||||
EdgeProfileMigrator.prototype.contractID = "@mozilla.org/profile/migrator;1?app=browser&type=edge";
|
||||
EdgeProfileMigrator.prototype.classID = Components.ID("{62e8834b-2d17-49f5-96ff-56344903a2ae}");
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([EdgeProfileMigrator]);
|
@ -15,6 +15,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
Cu.import("resource:///modules/MSMigrationUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
@ -136,109 +137,6 @@ function hostIsIPAddress(aHost) {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Resources
|
||||
|
||||
function Bookmarks() {
|
||||
}
|
||||
|
||||
Bookmarks.prototype = {
|
||||
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||
|
||||
get exists() !!this._favoritesFolder,
|
||||
|
||||
__favoritesFolder: null,
|
||||
get _favoritesFolder() {
|
||||
if (!this.__favoritesFolder) {
|
||||
let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile);
|
||||
if (favoritesFolder.exists() && favoritesFolder.isReadable())
|
||||
this.__favoritesFolder = favoritesFolder;
|
||||
}
|
||||
return this.__favoritesFolder;
|
||||
},
|
||||
|
||||
__toolbarFolderName: null,
|
||||
get _toolbarFolderName() {
|
||||
if (!this.__toolbarFolderName) {
|
||||
// Retrieve the name of IE's favorites subfolder that holds the bookmarks
|
||||
// in the toolbar. This was previously stored in the registry and changed
|
||||
// in IE7 to always be called "Links".
|
||||
let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Internet Explorer\\Toolbar",
|
||||
"LinksFolderName");
|
||||
this.__toolbarFolderName = folderName || "Links";
|
||||
}
|
||||
return this.__toolbarFolderName;
|
||||
},
|
||||
|
||||
migrate: function B_migrate(aCallback) {
|
||||
return Task.spawn(function* () {
|
||||
// Import to the bookmarks menu.
|
||||
let folderGuid = PlacesUtils.bookmarks.menuGuid;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
folderGuid =
|
||||
yield MigrationUtils.createImportedBookmarksFolder("IE", folderGuid);
|
||||
}
|
||||
yield this._migrateFolder(this._favoritesFolder, folderGuid);
|
||||
}.bind(this)).then(() => aCallback(true),
|
||||
e => { Cu.reportError(e); aCallback(false) });
|
||||
},
|
||||
|
||||
_migrateFolder: Task.async(function* (aSourceFolder, aDestFolderGuid) {
|
||||
// TODO (bug 741993): the favorites order is stored in the Registry, at
|
||||
// HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
|
||||
// Until we support it, bookmarks are imported in alphabetical order.
|
||||
let entries = aSourceFolder.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
try {
|
||||
// Make sure that entry.path == entry.target to not follow .lnk folder
|
||||
// shortcuts which could lead to infinite cycles.
|
||||
// Don't use isSymlink(), since it would throw for invalid
|
||||
// lnk files pointing to URLs or to unresolvable paths.
|
||||
if (entry.path == entry.target && entry.isDirectory()) {
|
||||
let folderGuid;
|
||||
if (entry.leafName == this._toolbarFolderName &&
|
||||
entry.parent.equals(this._favoritesFolder)) {
|
||||
// Import to the bookmarks toolbar.
|
||||
folderGuid = PlacesUtils.bookmarks.toolbarGuid;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
folderGuid =
|
||||
yield MigrationUtils.createImportedBookmarksFolder("IE", folderGuid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Import to a new folder.
|
||||
folderGuid = (yield PlacesUtils.bookmarks.insert({
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
parentGuid: aDestFolderGuid,
|
||||
title: entry.leafName
|
||||
})).guid;
|
||||
}
|
||||
|
||||
if (entry.isReadable()) {
|
||||
// Recursively import the folder.
|
||||
yield this._migrateFolder(entry, folderGuid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Strip the .url extension, to both check this is a valid link file,
|
||||
// and get the associated title.
|
||||
let matches = entry.leafName.match(/(.+)\.url$/i);
|
||||
if (matches) {
|
||||
let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
let uri = fileHandler.readURLFile(entry);
|
||||
let title = matches[1];
|
||||
|
||||
yield PlacesUtils.bookmarks.insert({
|
||||
parentGuid: aDestFolderGuid, url: uri, title
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Unable to import IE favorite (" + entry.leafName + "): " + ex);
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
function History() {
|
||||
}
|
||||
@ -606,7 +504,7 @@ IEProfileMigrator.prototype = Object.create(MigratorPrototype);
|
||||
|
||||
IEProfileMigrator.prototype.getResources = function IE_getResources() {
|
||||
let resources = [
|
||||
new Bookmarks()
|
||||
MSMigrationUtils.getBookmarksMigrator()
|
||||
, new History()
|
||||
, new Cookies()
|
||||
, new Settings()
|
||||
|
172
browser/components/migration/MSMigrationUtils.jsm
Normal file
@ -0,0 +1,172 @@
|
||||
/* 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";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MSMigrationUtils"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
|
||||
"resource://gre/modules/WindowsRegistry.jsm");
|
||||
|
||||
const EDGE_FAVORITES = "AC\\MicrosoftEdge\\User\\Default\\Favorites";
|
||||
|
||||
function Bookmarks(migrationType) {
|
||||
this._migrationType = migrationType;
|
||||
}
|
||||
|
||||
Bookmarks.prototype = {
|
||||
type: MigrationUtils.resourceTypes.BOOKMARKS,
|
||||
|
||||
get exists() !!this._favoritesFolder,
|
||||
|
||||
get importedAppLabel() this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE ? "IE" : "Edge",
|
||||
|
||||
__favoritesFolder: null,
|
||||
get _favoritesFolder() {
|
||||
if (!this.__favoritesFolder) {
|
||||
if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE) {
|
||||
let favoritesFolder = Services.dirsvc.get("Favs", Ci.nsIFile);
|
||||
if (favoritesFolder.exists() && favoritesFolder.isReadable())
|
||||
return this.__favoritesFolder = favoritesFolder;
|
||||
}
|
||||
if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_EDGE) {
|
||||
let appData = Services.dirsvc.get("LocalAppData", Ci.nsIFile);
|
||||
appData.append("Packages");
|
||||
try {
|
||||
let edgeDir = appData.clone();
|
||||
edgeDir.append("Microsoft.MicrosoftEdge_8wekyb3d8bbwe");
|
||||
edgeDir.appendRelativePath(EDGE_FAVORITES);
|
||||
if (edgeDir.exists() && edgeDir.isDirectory()) {
|
||||
return this.__favoritesFolder = edgeDir;
|
||||
}
|
||||
} catch (ex) {} /* Ignore e.g. permissions errors here. */
|
||||
|
||||
// Let's try the long way:
|
||||
try {
|
||||
let dirEntries = appData.directoryEntries;
|
||||
while (dirEntries.hasMoreElements()) {
|
||||
let subDir = dirEntries.getNext();
|
||||
subDir.QueryInterface(Ci.nsIFile);
|
||||
if (subDir.leafName.startsWith("Microsoft.MicrosoftEdge")) {
|
||||
subDir.appendRelativePath(EDGE_FAVORITES);
|
||||
if (subDir.exists() && subDir.isDirectory()) {
|
||||
return this.__favoritesFolder = subDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError("Exception trying to find the Edge favorites directory: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.__favoritesFolder;
|
||||
},
|
||||
|
||||
__toolbarFolderName: null,
|
||||
get _toolbarFolderName() {
|
||||
if (!this.__toolbarFolderName) {
|
||||
if (this._migrationType == MSMigrationUtils.MIGRATION_TYPE_IE) {
|
||||
// Retrieve the name of IE's favorites subfolder that holds the bookmarks
|
||||
// in the toolbar. This was previously stored in the registry and changed
|
||||
// in IE7 to always be called "Links".
|
||||
let folderName = WindowsRegistry.readRegKey(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
|
||||
"Software\\Microsoft\\Internet Explorer\\Toolbar",
|
||||
"LinksFolderName");
|
||||
this.__toolbarFolderName = folderName || "Links";
|
||||
} else {
|
||||
this.__toolbarFolderName = "Links";
|
||||
}
|
||||
}
|
||||
return this.__toolbarFolderName;
|
||||
},
|
||||
|
||||
migrate: function B_migrate(aCallback) {
|
||||
return Task.spawn(function* () {
|
||||
// Import to the bookmarks menu.
|
||||
let folderGuid = PlacesUtils.bookmarks.menuGuid;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
folderGuid =
|
||||
yield MigrationUtils.createImportedBookmarksFolder(this.importedAppLabel, folderGuid);
|
||||
}
|
||||
yield this._migrateFolder(this._favoritesFolder, folderGuid);
|
||||
}.bind(this)).then(() => aCallback(true),
|
||||
e => { Cu.reportError(e); aCallback(false) });
|
||||
},
|
||||
|
||||
_migrateFolder: Task.async(function* (aSourceFolder, aDestFolderGuid) {
|
||||
// TODO (bug 741993): the favorites order is stored in the Registry, at
|
||||
// HCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Favorites
|
||||
// for IE, and in a similar location for Edge.
|
||||
// Until we support it, bookmarks are imported in alphabetical order.
|
||||
let entries = aSourceFolder.directoryEntries;
|
||||
while (entries.hasMoreElements()) {
|
||||
let entry = entries.getNext().QueryInterface(Ci.nsIFile);
|
||||
try {
|
||||
// Make sure that entry.path == entry.target to not follow .lnk folder
|
||||
// shortcuts which could lead to infinite cycles.
|
||||
// Don't use isSymlink(), since it would throw for invalid
|
||||
// lnk files pointing to URLs or to unresolvable paths.
|
||||
if (entry.path == entry.target && entry.isDirectory()) {
|
||||
let folderGuid;
|
||||
if (entry.leafName == this._toolbarFolderName &&
|
||||
entry.parent.equals(this._favoritesFolder)) {
|
||||
// Import to the bookmarks toolbar.
|
||||
folderGuid = PlacesUtils.bookmarks.toolbarGuid;
|
||||
if (!MigrationUtils.isStartupMigration) {
|
||||
folderGuid =
|
||||
yield MigrationUtils.createImportedBookmarksFolder(this.importedAppLabel, folderGuid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Import to a new folder.
|
||||
folderGuid = (yield PlacesUtils.bookmarks.insert({
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
parentGuid: aDestFolderGuid,
|
||||
title: entry.leafName
|
||||
})).guid;
|
||||
}
|
||||
|
||||
if (entry.isReadable()) {
|
||||
// Recursively import the folder.
|
||||
yield this._migrateFolder(entry, folderGuid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Strip the .url extension, to both check this is a valid link file,
|
||||
// and get the associated title.
|
||||
let matches = entry.leafName.match(/(.+)\.url$/i);
|
||||
if (matches) {
|
||||
let fileHandler = Cc["@mozilla.org/network/protocol;1?name=file"].
|
||||
getService(Ci.nsIFileProtocolHandler);
|
||||
let uri = fileHandler.readURLFile(entry);
|
||||
let title = matches[1];
|
||||
|
||||
yield PlacesUtils.bookmarks.insert({
|
||||
parentGuid: aDestFolderGuid, url: uri, title
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
Components.utils.reportError("Unable to import " + this.importedAppLabel + " favorite (" + entry.leafName + "): " + ex);
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
let MSMigrationUtils = {
|
||||
MIGRATION_TYPE_IE: 1,
|
||||
MIGRATION_TYPE_EDGE: 2,
|
||||
getBookmarksMigrator(migrationType = this.MIGRATION_TYPE_IE) {
|
||||
return new Bookmarks(migrationType);
|
||||
},
|
||||
};
|
@ -482,11 +482,13 @@ this.MigrationUtils = Object.freeze({
|
||||
migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=" +
|
||||
aKey].createInstance(Ci.nsIBrowserProfileMigrator);
|
||||
}
|
||||
catch(ex) { }
|
||||
catch(ex) { Cu.reportError(ex) }
|
||||
this._migrators.set(aKey, migrator);
|
||||
}
|
||||
|
||||
return migrator && migrator.sourceExists ? migrator : null;
|
||||
try {
|
||||
return migrator && migrator.sourceExists ? migrator : null;
|
||||
} catch (ex) { Cu.reportError(ex); return null }
|
||||
},
|
||||
|
||||
// Iterates the available migrators, in the most suitable
|
||||
@ -494,7 +496,7 @@ this.MigrationUtils = Object.freeze({
|
||||
get migrators() {
|
||||
let migratorKeysOrdered = [
|
||||
#ifdef XP_WIN
|
||||
"firefox", "ie", "chrome", "chromium", "safari", "360se", "canary"
|
||||
"firefox", "edge", "ie", "chrome", "chromium", "safari", "360se", "canary"
|
||||
#elifdef XP_MACOSX
|
||||
"firefox", "safari", "chrome", "chromium", "canary"
|
||||
#elifdef XP_UNIX
|
||||
|
@ -34,6 +34,7 @@
|
||||
<radiogroup id="importSourceGroup" align="start">
|
||||
<radio id="firefox" label="&importFromFirefox.label;" accesskey="&importFromFirefox.accesskey;"/>
|
||||
#ifdef XP_WIN
|
||||
<radio id="edge" label="&importFromEdge.label;" accesskey="&importFromEdge.accesskey;"/>
|
||||
<radio id="ie" label="&importFromIE.label;" accesskey="&importFromIE.accesskey;"/>
|
||||
<radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/>
|
||||
<radio id="chromium" label="&importFromChromium.label;" accesskey="&importFromChromium.accesskey;"/>
|
||||
|
@ -27,10 +27,12 @@ EXTRA_COMPONENTS += [
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
EXTRA_COMPONENTS += [
|
||||
'360seProfileMigrator.js',
|
||||
'EdgeProfileMigrator.js',
|
||||
'IEProfileMigrator.js',
|
||||
]
|
||||
DEFINES['HAS_360SE_MIGRATOR'] = True
|
||||
DEFINES['HAS_IE_MIGRATOR'] = True
|
||||
DEFINES['HAS_EDGE_MIGRATOR'] = True
|
||||
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'BrowserProfileMigrators.manifest',
|
||||
@ -53,6 +55,11 @@ EXTRA_PP_JS_MODULES += [
|
||||
'MigrationUtils.jsm',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
EXTRA_JS_MODULES += [
|
||||
'MSMigrationUtils.jsm',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'browsercomps'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -0,0 +1,7 @@
|
||||
add_task(function* () {
|
||||
let migrator = MigrationUtils.getMigrator("edge");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Assert.equal(!!(migrator && migrator.sourceExists), AppConstants.isPlatformAndVersionAtLeast("win", "10"),
|
||||
"Edge should be available for migration if and only if we're on Win 10+");
|
||||
});
|
||||
|
@ -11,6 +11,7 @@ support-files =
|
||||
skip-if = os != "mac" # Relies on ULibDir
|
||||
[test_Chrome_passwords.js]
|
||||
skip-if = os != "win"
|
||||
[test_Edge_availability.js]
|
||||
[test_fx_fhr.js]
|
||||
[test_IE_bookmarks.js]
|
||||
skip-if = os != "win"
|
||||
|
@ -12,7 +12,6 @@ body {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
let { devtools: loader, require } = Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
let { loader, require } = Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/Console.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
|
||||
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
|
@ -7,7 +7,6 @@ const promise = require("devtools/toolkit/deprecated-sync-thenables");
|
||||
const {Connection} = require("devtools/client/connection-manager");
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
const dbgClient = Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
const _knownWebappsStores = new WeakMap();
|
||||
|
||||
let WebappsStore;
|
||||
|
@ -16,8 +16,8 @@ let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
let { require } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
|
||||
let { DebuggerClient } = require("devtools/toolkit/client/main");
|
||||
let { DebuggerServer } = require("devtools/server/main");
|
||||
let { CallWatcherFront } = require("devtools/server/actors/call-watcher");
|
||||
let { CanvasFront } = require("devtools/server/actors/canvas");
|
||||
|
@ -28,7 +28,6 @@ function test() {
|
||||
// var helpers = require('./helpers');
|
||||
// var assert = require('../testharness/assert');
|
||||
|
||||
var Promise = require('gcli/util/promise').Promise;
|
||||
var util = require('gcli/util/util');
|
||||
var resource = require('gcli/types/resource');
|
||||
var Status = require('gcli/types/types').Status;
|
||||
|
@ -27,7 +27,6 @@ function test() {
|
||||
|
||||
// var assert = require('../testharness/assert');
|
||||
var util = require('gcli/util/util');
|
||||
var Promise = require('gcli/util/promise').Promise;
|
||||
|
||||
function forEachType(options, templateTypeSpec, callback) {
|
||||
var types = options.requisition.system.types;
|
||||
|
@ -27,7 +27,6 @@ var { TargetFactory } = require("devtools/framework/target");
|
||||
|
||||
var assert = { ok: ok, is: is, log: info };
|
||||
var util = require('gcli/util/util');
|
||||
var Promise = require('gcli/util/promise').Promise;
|
||||
var cli = require('gcli/cli');
|
||||
var KeyEvent = require('gcli/util/util').KeyEvent;
|
||||
|
||||
|
@ -19,8 +19,6 @@
|
||||
// THIS FILE IS GENERATED FROM SOURCE IN THE GCLI PROJECT
|
||||
// PLEASE TALK TO SOMEONE IN DEVELOPER TOOLS BEFORE EDITING IT
|
||||
|
||||
var Promise = require('gcli/util/promise').Promise;
|
||||
|
||||
var mockCommands;
|
||||
if (typeof exports !== 'undefined') {
|
||||
// If we're being loaded via require();
|
||||
|
@ -19,8 +19,7 @@ let { require } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
let { BrowserToolboxProcess } = Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", {});
|
||||
let { DebuggerServer } = require("devtools/server/main");
|
||||
let { DebuggerClient, ObjectClient } =
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { DebuggerClient, ObjectClient } = require("devtools/toolkit/client/main");
|
||||
let { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const { promiseInvoke } = require("devtools/async-utils");
|
||||
|
@ -10,12 +10,12 @@ const Cu = Components.utils;
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
let {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let {TargetFactory} = require("devtools/framework/target");
|
||||
let {Toolbox} = require("devtools/framework/toolbox")
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let {DebuggerClient} = require("devtools/toolkit/client/main");
|
||||
|
||||
let gClient;
|
||||
let gConnectionTimeout;
|
||||
|
@ -10,7 +10,7 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
const {require, devtools: loader} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const { require, loader } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
// Load target and toolbox lazily as they need gDevTools to be fully initialized
|
||||
loader.lazyRequireGetter(this, "TargetFactory", "devtools/framework/target", true);
|
||||
loader.lazyRequireGetter(this, "Toolbox", "devtools/framework/toolbox", true);
|
||||
@ -21,9 +21,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource://gre/modules/devtools/Console.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
|
||||
"resource://gre/modules/devtools/dbg-client.jsm");
|
||||
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
|
||||
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/toolkit/client/main", true);
|
||||
|
||||
const DefaultTools = require("definitions").defaultTools;
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
|
@ -10,7 +10,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
var {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||
var EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
var Telemetry = require("devtools/shared/telemetry");
|
||||
|
||||
|
@ -10,8 +10,7 @@ const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
|
||||
"resource://gre/modules/devtools/dbg-client.jsm");
|
||||
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/toolkit/client/main", true);
|
||||
|
||||
const targets = new WeakMap();
|
||||
const promiseTargets = new WeakMap();
|
||||
|
@ -9,8 +9,7 @@
|
||||
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is still waiting for a WebGL context to be created.");
|
||||
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { DebuggerClient } =
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
const { DebuggerClient } = require("devtools/toolkit/client/main");
|
||||
|
||||
/**
|
||||
* Bug 979536: Ensure fronts are destroyed after toolbox close.
|
||||
|
@ -2,7 +2,7 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { on, off } = require("sdk/event/core");
|
||||
const { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
const { DebuggerClient } = require("devtools/toolkit/client/main");
|
||||
|
||||
function test() {
|
||||
gDevTools.on("toolbox-created", onToolboxCreated);
|
||||
|
@ -6,8 +6,7 @@
|
||||
*/
|
||||
|
||||
let { DebuggerServer } = require("devtools/server/main");
|
||||
let { DebuggerClient } =
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { DebuggerClient } = require("devtools/toolkit/client/main");
|
||||
|
||||
const TAB_URL_1 = "data:text/html;charset=utf-8,foo";
|
||||
const TAB_URL_2 = "data:text/html;charset=utf-8,bar";
|
||||
|
@ -20,7 +20,7 @@ function toggleAllTools(state) {
|
||||
function getChromeActors(callback)
|
||||
{
|
||||
let { DebuggerServer } = require("devtools/server/main");
|
||||
let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { DebuggerClient } = require("devtools/toolkit/client/main");
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
|
@ -10,8 +10,7 @@ let { require } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let { TargetFactory } = require("devtools/framework/target");
|
||||
let { Toolbox } = require("devtools/framework/toolbox");
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
let { DebuggerClient } =
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
|
||||
let { DebuggerClient } = require("devtools/toolkit/client/main");
|
||||
let { ViewHelpers } =
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
|
||||
let { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* globals gDevTools, DOMHelpers, toolboxStrings, InspectorFront, Selection,
|
||||
CommandUtils, DevToolsUtils, Hosts, osString, showDoorhanger,
|
||||
getHighlighterUtils, getPerformanceFront */
|
||||
getHighlighterUtils, createPerformanceFront */
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -59,8 +59,8 @@ loader.lazyRequireGetter(this, "DevToolsUtils",
|
||||
"devtools/toolkit/DevToolsUtils");
|
||||
loader.lazyRequireGetter(this, "showDoorhanger",
|
||||
"devtools/shared/doorhanger", true);
|
||||
loader.lazyRequireGetter(this, "getPerformanceFront",
|
||||
"devtools/performance/front", true);
|
||||
loader.lazyRequireGetter(this, "createPerformanceFront",
|
||||
"devtools/server/actors/performance", true);
|
||||
loader.lazyRequireGetter(this, "system",
|
||||
"devtools/toolkit/shared/system");
|
||||
loader.lazyGetter(this, "osString", () => {
|
||||
@ -135,6 +135,7 @@ function Toolbox(target, selectedTool, hostType, hostOptions) {
|
||||
this._onBottomHostMinimized = this._onBottomHostMinimized.bind(this);
|
||||
this._onBottomHostMaximized = this._onBottomHostMaximized.bind(this);
|
||||
this._onToolSelectWhileMinimized = this._onToolSelectWhileMinimized.bind(this);
|
||||
this._onPerformanceFrontEvent = this._onPerformanceFrontEvent.bind(this);
|
||||
this._onBottomHostWillChange = this._onBottomHostWillChange.bind(this);
|
||||
this._toggleMinimizeMode = this._toggleMinimizeMode.bind(this);
|
||||
|
||||
@ -1989,14 +1990,13 @@ Toolbox.prototype = {
|
||||
}
|
||||
|
||||
this._performanceFrontConnection = promise.defer();
|
||||
|
||||
this._performance = getPerformanceFront(this._target);
|
||||
|
||||
yield this.performance.open();
|
||||
this._performance = createPerformanceFront(this._target);
|
||||
yield this.performance.connect();
|
||||
|
||||
// Emit an event when connected, but don't wait on startup for this.
|
||||
this.emit("profiler-connected");
|
||||
|
||||
this.performance.on("*", this._onPerformanceFrontEvent);
|
||||
this._performanceFrontConnection.resolve(this.performance);
|
||||
return this._performanceFrontConnection.promise;
|
||||
}),
|
||||
@ -2015,10 +2015,46 @@ Toolbox.prototype = {
|
||||
if (this._performanceFrontConnection) {
|
||||
yield this._performanceFrontConnection.promise;
|
||||
}
|
||||
this.performance.off("*", this._onPerformanceFrontEvent);
|
||||
yield this.performance.destroy();
|
||||
this._performance = null;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called when any event comes from the PerformanceFront. If the performance tool is already
|
||||
* loaded when the first event comes in, immediately unbind this handler, as this is
|
||||
* only used to queue up observed recordings before the performance tool can handle them,
|
||||
* which will only occur when `console.profile()` recordings are started before the tool loads.
|
||||
*/
|
||||
_onPerformanceFrontEvent: Task.async(function*(eventName, recording) {
|
||||
if (this.getPanel("performance")) {
|
||||
this.performance.off("*", this._onPerformanceFrontEvent);
|
||||
return;
|
||||
}
|
||||
|
||||
let recordings = this._performanceQueuedRecordings = this._performanceQueuedRecordings || [];
|
||||
|
||||
// Before any console recordings, we'll get a `console-profile-start` event
|
||||
// warning us that a recording will come later (via `recording-started`), so
|
||||
// start to boot up the tool and populate the tool with any other recordings
|
||||
// observed during that time.
|
||||
if (eventName === "console-profile-start" && !this._performanceToolOpenedViaConsole) {
|
||||
this._performanceToolOpenedViaConsole = this.loadTool("performance");
|
||||
let panel = yield this._performanceToolOpenedViaConsole;
|
||||
yield panel.open();
|
||||
|
||||
panel.panelWin.PerformanceController.populateWithRecordings(recordings);
|
||||
this.performance.off("*", this._onPerformanceFrontEvent);
|
||||
}
|
||||
|
||||
// Otherwise, if it's a recording-started event, we've already started loading
|
||||
// the tool, so just store this recording in our array to be later populated
|
||||
// once the tool loads.
|
||||
if (eventName === "recording-started") {
|
||||
recordings.push(recording);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Returns gViewSourceUtils for viewing source.
|
||||
*/
|
||||
|
@ -1,163 +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 { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
loader.lazyRequireGetter(this, "promise");
|
||||
loader.lazyRequireGetter(this, "RecordingUtils",
|
||||
"devtools/performance/recording-utils");
|
||||
|
||||
loader.lazyImporter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
loader.lazyImporter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
// This identifier string is used to tentatively ascertain whether or not
|
||||
// a JSON loaded from disk is actually something generated by this tool.
|
||||
// It isn't, of course, a definitive verification, but a Good Enough™
|
||||
// approximation before continuing the import. Don't localize this.
|
||||
const PERF_TOOL_SERIALIZER_IDENTIFIER = "Recorded Performance Data";
|
||||
const PERF_TOOL_SERIALIZER_LEGACY_VERSION = 1;
|
||||
const PERF_TOOL_SERIALIZER_CURRENT_VERSION = 2;
|
||||
|
||||
/**
|
||||
* Helpers for importing/exporting JSON.
|
||||
*/
|
||||
let PerformanceIO = {
|
||||
/**
|
||||
* Gets a nsIScriptableUnicodeConverter instance with a default UTF-8 charset.
|
||||
* @return object
|
||||
*/
|
||||
getUnicodeConverter: function() {
|
||||
let className = "@mozilla.org/intl/scriptableunicodeconverter";
|
||||
let converter = Cc[className].createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
converter.charset = "UTF-8";
|
||||
return converter;
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves a recording as JSON to a file. The provided data is assumed to be
|
||||
* acyclical, so that it can be properly serialized.
|
||||
*
|
||||
* @param object recordingData
|
||||
* The recording data to stream as JSON.
|
||||
* @param nsILocalFile file
|
||||
* The file to stream the data into.
|
||||
* @return object
|
||||
* A promise that is resolved once streaming finishes, or rejected
|
||||
* if there was an error.
|
||||
*/
|
||||
saveRecordingToFile: function(recordingData, file) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
recordingData.fileType = PERF_TOOL_SERIALIZER_IDENTIFIER;
|
||||
recordingData.version = PERF_TOOL_SERIALIZER_CURRENT_VERSION;
|
||||
|
||||
let string = JSON.stringify(recordingData);
|
||||
let inputStream = this.getUnicodeConverter().convertToInputStream(string);
|
||||
let outputStream = FileUtils.openSafeFileOutputStream(file);
|
||||
|
||||
NetUtil.asyncCopy(inputStream, outputStream, deferred.resolve);
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads a recording stored as JSON from a file.
|
||||
*
|
||||
* @param nsILocalFile file
|
||||
* The file to import the data from.
|
||||
* @return object
|
||||
* A promise that is resolved once importing finishes, or rejected
|
||||
* if there was an error.
|
||||
*/
|
||||
loadRecordingFromFile: function(file) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let channel = NetUtil.newChannel({
|
||||
uri: NetUtil.newURI(file),
|
||||
loadUsingSystemPrincipal: true});
|
||||
|
||||
channel.contentType = "text/plain";
|
||||
|
||||
NetUtil.asyncFetch(channel, (inputStream, status) => {
|
||||
try {
|
||||
let string = NetUtil.readInputStreamToString(inputStream, inputStream.available());
|
||||
var recordingData = JSON.parse(string);
|
||||
} catch (e) {
|
||||
deferred.reject(new Error("Could not read recording data file."));
|
||||
return;
|
||||
}
|
||||
if (recordingData.fileType != PERF_TOOL_SERIALIZER_IDENTIFIER) {
|
||||
deferred.reject(new Error("Unrecognized recording data file."));
|
||||
return;
|
||||
}
|
||||
if (!isValidSerializerVersion(recordingData.version)) {
|
||||
deferred.reject(new Error("Unsupported recording data file version."));
|
||||
return;
|
||||
}
|
||||
if (recordingData.version === PERF_TOOL_SERIALIZER_LEGACY_VERSION) {
|
||||
recordingData = convertLegacyData(recordingData);
|
||||
}
|
||||
if (recordingData.profile.meta.version === 2) {
|
||||
RecordingUtils.deflateProfile(recordingData.profile);
|
||||
}
|
||||
deferred.resolve(recordingData);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether or not the passed in `version`
|
||||
* is supported by this serializer.
|
||||
*
|
||||
* @param number version
|
||||
* @return boolean
|
||||
*/
|
||||
function isValidSerializerVersion (version) {
|
||||
return !!~[
|
||||
PERF_TOOL_SERIALIZER_LEGACY_VERSION,
|
||||
PERF_TOOL_SERIALIZER_CURRENT_VERSION
|
||||
].indexOf(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes recording data (with version `1`, from the original profiler tool), and
|
||||
* massages the data to be line with the current performance tool's property names
|
||||
* and values.
|
||||
*
|
||||
* @param object legacyData
|
||||
* @return object
|
||||
*/
|
||||
function convertLegacyData (legacyData) {
|
||||
let { profilerData, ticksData, recordingDuration } = legacyData;
|
||||
|
||||
// The `profilerData` and `ticksData` stay, but the previously unrecorded
|
||||
// fields just are empty arrays or objects.
|
||||
let data = {
|
||||
label: profilerData.profilerLabel,
|
||||
duration: recordingDuration,
|
||||
markers: [],
|
||||
frames: [],
|
||||
memory: [],
|
||||
ticks: ticksData,
|
||||
allocations: { sites: [], timestamps: [], frames: [] },
|
||||
profile: profilerData.profile,
|
||||
// Fake a configuration object here if there's tick data,
|
||||
// so that it can be rendered
|
||||
configuration: {
|
||||
withTicks: !!ticksData.length,
|
||||
withMarkers: false,
|
||||
withMemory: false,
|
||||
withAllocations: false
|
||||
}
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
exports.PerformanceIO = PerformanceIO;
|
@ -5,15 +5,9 @@
|
||||
|
||||
EXTRA_JS_MODULES.devtools.performance += [
|
||||
'modules/global.js',
|
||||
'modules/logic/actors.js',
|
||||
'modules/logic/compatibility.js',
|
||||
'modules/logic/frame-utils.js',
|
||||
'modules/logic/front.js',
|
||||
'modules/logic/io.js',
|
||||
'modules/logic/jit.js',
|
||||
'modules/logic/marker-utils.js',
|
||||
'modules/logic/recording-model.js',
|
||||
'modules/logic/recording-utils.js',
|
||||
'modules/logic/tree-model.js',
|
||||
'modules/logic/waterfall-utils.js',
|
||||
'modules/markers.js',
|
||||
|
@ -11,8 +11,6 @@ const { Task } = require("resource://gre/modules/Task.jsm");
|
||||
loader.lazyRequireGetter(this, "promise");
|
||||
loader.lazyRequireGetter(this, "EventEmitter",
|
||||
"devtools/toolkit/event-emitter");
|
||||
loader.lazyRequireGetter(this, "PerformanceFront",
|
||||
"devtools/performance/front", true);
|
||||
|
||||
function PerformancePanel(iframeWindow, toolbox) {
|
||||
this.panelWin = iframeWindow;
|
||||
@ -32,9 +30,15 @@ PerformancePanel.prototype = {
|
||||
* completes opening.
|
||||
*/
|
||||
open: Task.async(function*() {
|
||||
if (this._opening) {
|
||||
return this._opening;
|
||||
}
|
||||
let deferred = promise.defer();
|
||||
this._opening = deferred.promise;
|
||||
|
||||
this.panelWin.gToolbox = this._toolbox;
|
||||
this.panelWin.gTarget = this.target;
|
||||
this._onRecordingStartOrStop = this._onRecordingStartOrStop.bind(this);
|
||||
this._checkRecordingStatus = this._checkRecordingStatus.bind(this);
|
||||
|
||||
// Actor is already created in the toolbox; reuse
|
||||
// the same front, and the toolbox will also initialize the front,
|
||||
@ -50,14 +54,21 @@ PerformancePanel.prototype = {
|
||||
}
|
||||
|
||||
this.panelWin.gFront = front;
|
||||
this.panelWin.gFront.on("recording-started", this._onRecordingStartOrStop);
|
||||
this.panelWin.gFront.on("recording-stopped", this._onRecordingStartOrStop);
|
||||
|
||||
let { PerformanceController, EVENTS } = this.panelWin;
|
||||
PerformanceController.on(EVENTS.NEW_RECORDING, this._checkRecordingStatus);
|
||||
PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._checkRecordingStatus);
|
||||
yield this.panelWin.startupPerformance();
|
||||
|
||||
// Fire this once incase we have an in-progress recording (console profile)
|
||||
// that caused this start up, and no state change yet, so we can highlight the
|
||||
// tab if we need.
|
||||
this._checkRecordingStatus();
|
||||
|
||||
this.isReady = true;
|
||||
this.emit("ready");
|
||||
return this;
|
||||
|
||||
deferred.resolve(this);
|
||||
return this._opening;
|
||||
}),
|
||||
|
||||
// DevToolPanel API
|
||||
@ -72,16 +83,16 @@ PerformancePanel.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
this.panelWin.gFront.off("recording-started", this._onRecordingStartOrStop);
|
||||
this.panelWin.gFront.off("recording-stopped", this._onRecordingStartOrStop);
|
||||
let { PerformanceController, EVENTS } = this.panelWin;
|
||||
PerformanceController.off(EVENTS.NEW_RECORDING, this._checkRecordingStatus);
|
||||
PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._checkRecordingStatus);
|
||||
yield this.panelWin.shutdownPerformance();
|
||||
this.emit("destroyed");
|
||||
this._destroyed = true;
|
||||
}),
|
||||
|
||||
_onRecordingStartOrStop: function () {
|
||||
let front = this.panelWin.gFront;
|
||||
if (front.isRecording()) {
|
||||
_checkRecordingStatus: function () {
|
||||
if (this.panelWin.PerformanceController.isRecording()) {
|
||||
this._toolbox.highlightTool("performance");
|
||||
} else {
|
||||
this._toolbox.unhighlightTool("performance");
|
||||
|
@ -4,7 +4,7 @@
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
const { devtools: loader, require } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const { loader, require } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
|
||||
const { Task } = require("resource://gre/modules/Task.jsm");
|
||||
const { Heritage, ViewHelpers, WidgetMethods } = require("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
@ -25,9 +25,7 @@ loader.lazyRequireGetter(this, "L10N",
|
||||
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
|
||||
"devtools/performance/markers", true);
|
||||
loader.lazyRequireGetter(this, "RecordingUtils",
|
||||
"devtools/performance/recording-utils");
|
||||
loader.lazyRequireGetter(this, "RecordingModel",
|
||||
"devtools/performance/recording-model", true);
|
||||
"devtools/toolkit/performance/utils");
|
||||
loader.lazyRequireGetter(this, "GraphsController",
|
||||
"devtools/performance/graphs", true);
|
||||
loader.lazyRequireGetter(this, "WaterfallHeader",
|
||||
@ -92,15 +90,15 @@ const EVENTS = {
|
||||
UI_STOP_RECORDING: "Performance:UI:StopRecording",
|
||||
|
||||
// Emitted by the PerformanceView on import button click
|
||||
UI_IMPORT_RECORDING: "Performance:UI:ImportRecording",
|
||||
UI_RECORDING_IMPORTED: "Performance:UI:ImportRecording",
|
||||
// Emitted by the RecordingsView on export button click
|
||||
UI_EXPORT_RECORDING: "Performance:UI:ExportRecording",
|
||||
|
||||
// When a recording is started or stopped via the PerformanceController
|
||||
RECORDING_STARTED: "Performance:RecordingStarted",
|
||||
RECORDING_STOPPED: "Performance:RecordingStopped",
|
||||
RECORDING_WILL_START: "Performance:RecordingWillStart",
|
||||
RECORDING_WILL_STOP: "Performance:RecordingWillStop",
|
||||
// When a new recording is being tracked in the panel.
|
||||
NEW_RECORDING: "Performance:NewRecording",
|
||||
|
||||
// When a recording is started or stopped or stopping via the PerformanceController
|
||||
RECORDING_STATE_CHANGE: "Performance:RecordingStateChange",
|
||||
|
||||
// Emitted by the PerformanceController or RecordingView
|
||||
// when a recording model is selected
|
||||
@ -109,8 +107,7 @@ const EVENTS = {
|
||||
// When recordings have been cleared out
|
||||
RECORDINGS_CLEARED: "Performance:RecordingsCleared",
|
||||
|
||||
// When a recording is imported or exported via the PerformanceController
|
||||
RECORDING_IMPORTED: "Performance:RecordingImported",
|
||||
// When a recording is exported via the PerformanceController
|
||||
RECORDING_EXPORTED: "Performance:RecordingExported",
|
||||
|
||||
// When the front has updated information on the profiler's circular buffer
|
||||
@ -153,7 +150,25 @@ const EVENTS = {
|
||||
|
||||
// When a source is shown in the JavaScript Debugger at a specific location.
|
||||
SOURCE_SHOWN_IN_JS_DEBUGGER: "Performance:UI:SourceShownInJsDebugger",
|
||||
SOURCE_NOT_FOUND_IN_JS_DEBUGGER: "Performance:UI:SourceNotFoundInJsDebugger"
|
||||
SOURCE_NOT_FOUND_IN_JS_DEBUGGER: "Performance:UI:SourceNotFoundInJsDebugger",
|
||||
|
||||
// These are short hands for the RECORDING_STATE_CHANGE event to make refactoring
|
||||
// tests easier. UI components should use RECORDING_STATE_CHANGE, and these are
|
||||
// deprecated for test usage only.
|
||||
RECORDING_STARTED: "Performance:RecordingStarted",
|
||||
RECORDING_WILL_STOP: "Performance:RecordingWillStop",
|
||||
RECORDING_STOPPED: "Performance:RecordingStopped",
|
||||
|
||||
// Fired by the PerformanceController when `populateWithRecordings` is finished.
|
||||
RECORDINGS_SEEDED: "Performance:RecordingsSeeded",
|
||||
|
||||
// Emitted by the PerformanceController when `PerformanceController.stopRecording()`
|
||||
// is completed; used in tests, to know when a manual UI click is finished.
|
||||
CONTROLLER_STOPPED_RECORDING: "Performance:Controller:StoppedRecording",
|
||||
|
||||
// Emitted by the PerformanceController when a recording is imported. Used
|
||||
// only in tests. Should use the normal RECORDING_STATE_CHANGE in the UI.
|
||||
RECORDING_IMPORTED: "Performance:ImportedRecording",
|
||||
};
|
||||
|
||||
/**
|
||||
@ -165,20 +180,16 @@ let gToolbox, gTarget, gFront;
|
||||
* Initializes the profiler controller and views.
|
||||
*/
|
||||
let startupPerformance = Task.async(function*() {
|
||||
yield promise.all([
|
||||
PerformanceController.initialize(),
|
||||
PerformanceView.initialize()
|
||||
]);
|
||||
yield PerformanceController.initialize();
|
||||
yield PerformanceView.initialize();
|
||||
});
|
||||
|
||||
/**
|
||||
* Destroys the profiler controller and views.
|
||||
*/
|
||||
let shutdownPerformance = Task.async(function*() {
|
||||
yield promise.all([
|
||||
PerformanceController.destroy(),
|
||||
PerformanceView.destroy()
|
||||
]);
|
||||
yield PerformanceController.destroy();
|
||||
yield PerformanceView.destroy();
|
||||
});
|
||||
|
||||
/**
|
||||
@ -202,8 +213,7 @@ let PerformanceController = {
|
||||
this._onRecordingSelectFromView = this._onRecordingSelectFromView.bind(this);
|
||||
this._onPrefChanged = this._onPrefChanged.bind(this);
|
||||
this._onThemeChanged = this._onThemeChanged.bind(this);
|
||||
this._onRecordingStateChange = this._onRecordingStateChange.bind(this);
|
||||
this._onProfilerStatusUpdated = this._onProfilerStatusUpdated.bind(this);
|
||||
this._onFrontEvent = this._onFrontEvent.bind(this);
|
||||
|
||||
// Store data regarding if e10s is enabled.
|
||||
this._e10s = Services.appinfo.browserTabsRemoteAutostart;
|
||||
@ -212,15 +222,11 @@ let PerformanceController = {
|
||||
this._prefs = require("devtools/performance/global").PREFS;
|
||||
this._prefs.on("pref-changed", this._onPrefChanged);
|
||||
|
||||
gFront.on("recording-starting", this._onRecordingStateChange);
|
||||
gFront.on("recording-started", this._onRecordingStateChange);
|
||||
gFront.on("recording-stopping", this._onRecordingStateChange);
|
||||
gFront.on("recording-stopped", this._onRecordingStateChange);
|
||||
gFront.on("profiler-status", this._onProfilerStatusUpdated);
|
||||
gFront.on("*", this._onFrontEvent);
|
||||
ToolbarView.on(EVENTS.PREF_CHANGED, this._onPrefChanged);
|
||||
PerformanceView.on(EVENTS.UI_START_RECORDING, this.startRecording);
|
||||
PerformanceView.on(EVENTS.UI_STOP_RECORDING, this.stopRecording);
|
||||
PerformanceView.on(EVENTS.UI_IMPORT_RECORDING, this.importRecording);
|
||||
PerformanceView.on(EVENTS.UI_RECORDING_IMPORTED, this.importRecording);
|
||||
PerformanceView.on(EVENTS.UI_CLEAR_RECORDINGS, this.clearRecordings);
|
||||
RecordingsView.on(EVENTS.UI_EXPORT_RECORDING, this.exportRecording);
|
||||
RecordingsView.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelectFromView);
|
||||
@ -234,15 +240,11 @@ let PerformanceController = {
|
||||
destroy: function() {
|
||||
this._prefs.off("pref-changed", this._onPrefChanged);
|
||||
|
||||
gFront.off("recording-starting", this._onRecordingStateChange);
|
||||
gFront.off("recording-started", this._onRecordingStateChange);
|
||||
gFront.off("recording-stopping", this._onRecordingStateChange);
|
||||
gFront.off("recording-stopped", this._onRecordingStateChange);
|
||||
gFront.off("profiler-status", this._onProfilerStatusUpdated);
|
||||
gFront.off("*", this._onFrontEvent);
|
||||
ToolbarView.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
|
||||
PerformanceView.off(EVENTS.UI_START_RECORDING, this.startRecording);
|
||||
PerformanceView.off(EVENTS.UI_STOP_RECORDING, this.stopRecording);
|
||||
PerformanceView.off(EVENTS.UI_IMPORT_RECORDING, this.importRecording);
|
||||
PerformanceView.off(EVENTS.UI_RECORDING_IMPORTED, this.importRecording);
|
||||
PerformanceView.off(EVENTS.UI_CLEAR_RECORDINGS, this.clearRecordings);
|
||||
RecordingsView.off(EVENTS.UI_EXPORT_RECORDING, this.exportRecording);
|
||||
RecordingsView.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelectFromView);
|
||||
@ -292,8 +294,7 @@ let PerformanceController = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts recording with the PerformanceFront. Emits `EVENTS.RECORDING_STARTED`
|
||||
* when the front has started to record.
|
||||
* Starts recording with the PerformanceFront.
|
||||
*/
|
||||
startRecording: Task.async(function *() {
|
||||
let options = {
|
||||
@ -312,19 +313,25 @@ let PerformanceController = {
|
||||
}),
|
||||
|
||||
/**
|
||||
* Stops recording with the PerformanceFront. Emits `EVENTS.RECORDING_STOPPED`
|
||||
* when the front has stopped recording.
|
||||
* Stops recording with the PerformanceFront.
|
||||
*/
|
||||
stopRecording: Task.async(function *() {
|
||||
let recording = this.getLatestManualRecording();
|
||||
yield gFront.stopRecording(recording);
|
||||
|
||||
// Emit another stop event here, as a lot of tests use
|
||||
// the RECORDING_STOPPED event, but in the case of a UI click on a button,
|
||||
// the RECORDING_STOPPED event happens from the server, where this request may
|
||||
// not have yet finished, so listen to this in tests that fail because the `stopRecording`
|
||||
// request is not yet completed. Should only be used in that scenario.
|
||||
this.emit(EVENTS.CONTROLLER_STOPPED_RECORDING);
|
||||
}),
|
||||
|
||||
/**
|
||||
* Saves the given recording to a file. Emits `EVENTS.RECORDING_EXPORTED`
|
||||
* when the file was saved.
|
||||
*
|
||||
* @param RecordingModel recording
|
||||
* @param PerformanceRecording recording
|
||||
* The model that holds the recording data.
|
||||
* @param nsILocalFile file
|
||||
* The file to stream the data into.
|
||||
@ -346,7 +353,7 @@ let PerformanceController = {
|
||||
// If last recording is not recording, but finalizing itself,
|
||||
// wait for that to finish
|
||||
if (latest && !latest.isCompleted()) {
|
||||
yield this.once(EVENTS.RECORDING_STOPPED);
|
||||
yield this.waitForStateChangeOnRecording(latest, "recording-stopped");
|
||||
}
|
||||
|
||||
this._recordings.length = 0;
|
||||
@ -362,18 +369,22 @@ let PerformanceController = {
|
||||
* The file to import the data from.
|
||||
*/
|
||||
importRecording: Task.async(function*(_, file) {
|
||||
let recording = new RecordingModel();
|
||||
this._recordings.push(recording);
|
||||
yield recording.importRecording(file);
|
||||
let recording = yield gFront.importRecording(file);
|
||||
this._addNewRecording(recording);
|
||||
|
||||
this.emit(EVENTS.RECORDING_IMPORTED, recording);
|
||||
// Only emit in tests for legacy purposes for shorthand --
|
||||
// other things in UI should handle the generic NEW_RECORDING
|
||||
// event to handle lazy recordings.
|
||||
if (DevToolsUtils.testing) {
|
||||
this.emit(EVENTS.RECORDING_IMPORTED, recording);
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Sets the currently active RecordingModel. Should rarely be called directly,
|
||||
* Sets the currently active PerformanceRecording. Should rarely be called directly,
|
||||
* as RecordingsView handles this when manually selected a recording item. Exceptions
|
||||
* are when clearing the view.
|
||||
* @param RecordingModel recording
|
||||
* @param PerformanceRecording recording
|
||||
*/
|
||||
setCurrentRecording: function (recording) {
|
||||
if (this._currentRecording !== recording) {
|
||||
@ -383,8 +394,8 @@ let PerformanceController = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the currently active RecordingModel.
|
||||
* @return RecordingModel
|
||||
* Gets the currently active PerformanceRecording.
|
||||
* @return PerformanceRecording
|
||||
*/
|
||||
getCurrentRecording: function () {
|
||||
return this._currentRecording;
|
||||
@ -392,7 +403,7 @@ let PerformanceController = {
|
||||
|
||||
/**
|
||||
* Get most recently added recording that was triggered manually (via UI).
|
||||
* @return RecordingModel
|
||||
* @return PerformanceRecording
|
||||
*/
|
||||
getLatestManualRecording: function () {
|
||||
for (let i = this._recordings.length - 1; i >= 0; i--) {
|
||||
@ -434,48 +445,85 @@ let PerformanceController = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Emitted when the front updates RecordingModel's buffer status.
|
||||
* Fired from the front on any event. Propagates to other handlers from here.
|
||||
*/
|
||||
_onProfilerStatusUpdated: function (_, data) {
|
||||
_onFrontEvent: function (eventName, ...data) {
|
||||
if (eventName === "profiler-status") {
|
||||
this._onProfilerStatusUpdated(...data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (["recording-started", "recording-stopped", "recording-stopping"].indexOf(eventName) !== -1) {
|
||||
this._onRecordingStateChange(eventName, ...data);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Emitted when the front updates PerformanceRecording's buffer status.
|
||||
*/
|
||||
_onProfilerStatusUpdated: function (data) {
|
||||
this.emit(EVENTS.PROFILER_STATUS_UPDATED, data);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stores a recording internally.
|
||||
*
|
||||
* @param {PerformanceRecordingFront} recording
|
||||
*/
|
||||
_addNewRecording: function (recording) {
|
||||
if (this._recordings.indexOf(recording) === -1) {
|
||||
this._recordings.push(recording);
|
||||
this.emit(EVENTS.NEW_RECORDING, recording);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired when a recording model changes state.
|
||||
*
|
||||
* @param {string} state
|
||||
* @param {RecordingModel} model
|
||||
* Can be "recording-started", "recording-stopped" or "recording-stopping".
|
||||
* @param {PerformanceRecording} model
|
||||
*/
|
||||
_onRecordingStateChange: function (state, model) {
|
||||
// If we get a state change for a recording that isn't being tracked in the front,
|
||||
// just ignore it. This can occur when stopping a profile via console that was cleared.
|
||||
if (state !== "recording-starting" && this.getRecordings().indexOf(model) === -1) {
|
||||
return;
|
||||
}
|
||||
this._addNewRecording(model);
|
||||
|
||||
switch (state) {
|
||||
// Fired when a RecordingModel was just created from the front
|
||||
case "recording-starting":
|
||||
// When a recording is just starting, store it internally
|
||||
this._recordings.push(model);
|
||||
this.emit(EVENTS.RECORDING_WILL_START, model);
|
||||
break;
|
||||
// Fired when a RecordingModel has started recording
|
||||
case "recording-started":
|
||||
this.emit(EVENTS.RECORDING_STARTED, model);
|
||||
break;
|
||||
// Fired when a RecordingModel is no longer recording, and
|
||||
// starting to fetch all the profiler data
|
||||
case "recording-stopping":
|
||||
this.emit(EVENTS.RECORDING_WILL_STOP, model);
|
||||
break;
|
||||
// Fired when a RecordingModel is finished fetching all of its data
|
||||
case "recording-stopped":
|
||||
this.emit(EVENTS.RECORDING_STOPPED, model);
|
||||
break;
|
||||
this.emit(EVENTS.RECORDING_STATE_CHANGE, state, model);
|
||||
|
||||
// Emit the state specific events for tests that I'm too
|
||||
// lazy and frusterated to change right now. These events
|
||||
// should only be used in tests, as the rest of the UI should
|
||||
// react to general RECORDING_STATE_CHANGE events and NEW_RECORDING
|
||||
// events to handle lazy recordings.
|
||||
if (DevToolsUtils.testing) {
|
||||
switch (state) {
|
||||
case "recording-started":
|
||||
this.emit(EVENTS.RECORDING_STARTED, model);
|
||||
break;
|
||||
case "recording-stopping":
|
||||
this.emit(EVENTS.RECORDING_WILL_STOP, model);
|
||||
break;
|
||||
case "recording-stopped":
|
||||
this.emit(EVENTS.RECORDING_STOPPED, model);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes a recording and returns a value between 0 and 1 indicating how much
|
||||
* of the buffer is used.
|
||||
*/
|
||||
getBufferUsageForRecording: function (recording) {
|
||||
return gFront.getBufferUsageForRecording(recording);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating if any recordings are currently in progress or not.
|
||||
*/
|
||||
isRecording: function () {
|
||||
return this._recordings.some(r => r.isRecording());
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the internal store of recording models.
|
||||
*/
|
||||
@ -483,6 +531,13 @@ let PerformanceController = {
|
||||
return this._recordings;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns traits from the front.
|
||||
*/
|
||||
getTraits: function () {
|
||||
return gFront.traits;
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility method taking a string or an array of strings of feature names (like
|
||||
* "withAllocations" or "withMarkers"), and returns whether or not the current
|
||||
@ -508,6 +563,21 @@ let PerformanceController = {
|
||||
return [].concat(features).every(f => config[f]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes an array of PerformanceRecordingFronts and adds them to the internal
|
||||
* store of the UI. Used by the toolbox to lazily seed recordings that
|
||||
* were observed before the panel was loaded in the scenario where `console.profile()`
|
||||
* is used before the tool is loaded.
|
||||
*
|
||||
* @param {Array<PerformanceRecordingFront>} recordings
|
||||
*/
|
||||
populateWithRecordings: function (recordings=[]) {
|
||||
for (let recording of recordings) {
|
||||
PerformanceController._addNewRecording(recording);
|
||||
}
|
||||
this.emit(EVENTS.RECORDINGS_SEEDED);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns an object with `supported` and `enabled` properties indicating
|
||||
* whether or not the platform is capable of turning on e10s and whether or not
|
||||
@ -530,6 +600,25 @@ let PerformanceController = {
|
||||
return { supported, enabled };
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes a PerformanceRecording and a state, and waits for
|
||||
* the event to be emitted from the front for that recording.
|
||||
*
|
||||
* @param {PerformanceRecordingFront} recording
|
||||
* @param {string} expectedState
|
||||
* @return {Promise}
|
||||
*/
|
||||
waitForStateChangeOnRecording: Task.async(function *(recording, expectedState) {
|
||||
let deferred = promise.defer();
|
||||
this.on(EVENTS.RECORDING_STATE_CHANGE, function handler (state, model) {
|
||||
if (state === expectedState && model === recording) {
|
||||
this.off(EVENTS.RECORDING_STATE_CHANGE, handler);
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
yield deferred.promise;
|
||||
}),
|
||||
|
||||
/**
|
||||
* Called on init, sets an `e10s` attribute on the main view container with
|
||||
* "disabled" if e10s is possible on the platform and just not on, or "unsupported"
|
||||
|
@ -51,10 +51,7 @@ let PerformanceView = {
|
||||
this._onClearButtonClick = this._onClearButtonClick.bind(this);
|
||||
this._onRecordingSelected = this._onRecordingSelected.bind(this);
|
||||
this._onProfilerStatusUpdated = this._onProfilerStatusUpdated.bind(this);
|
||||
this._onRecordingWillStart = this._onRecordingWillStart.bind(this);
|
||||
this._onRecordingStarted = this._onRecordingStarted.bind(this);
|
||||
this._onRecordingWillStop = this._onRecordingWillStop.bind(this);
|
||||
this._onRecordingStopped = this._onRecordingStopped.bind(this);
|
||||
this._onRecordingStateChange = this._onRecordingStateChange.bind(this);
|
||||
|
||||
for (let button of $$(".record-button")) {
|
||||
button.addEventListener("click", this._onRecordButtonClick);
|
||||
@ -65,10 +62,8 @@ let PerformanceView = {
|
||||
// Bind to controller events to unlock the record button
|
||||
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
|
||||
PerformanceController.on(EVENTS.PROFILER_STATUS_UPDATED, this._onProfilerStatusUpdated);
|
||||
PerformanceController.on(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
|
||||
PerformanceController.on(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
|
||||
PerformanceController.on(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
|
||||
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
|
||||
PerformanceController.on(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
|
||||
PerformanceController.on(EVENTS.NEW_RECORDING, this._onRecordingStateChange);
|
||||
|
||||
this.setState("empty");
|
||||
|
||||
@ -92,10 +87,8 @@ let PerformanceView = {
|
||||
|
||||
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
|
||||
PerformanceController.off(EVENTS.PROFILER_STATUS_UPDATED, this._onProfilerStatusUpdated);
|
||||
PerformanceController.off(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
|
||||
PerformanceController.off(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
|
||||
PerformanceController.off(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
|
||||
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
|
||||
PerformanceController.off(EVENTS.RECORDING_STATE_CHANGE, this._onRecordingStateChange);
|
||||
PerformanceController.off(EVENTS.NEW_RECORDING, this._onRecordingStateChange);
|
||||
|
||||
yield ToolbarView.destroy();
|
||||
yield RecordingsView.destroy();
|
||||
@ -157,7 +150,7 @@ let PerformanceView = {
|
||||
return;
|
||||
}
|
||||
|
||||
let bufferUsage = recording.getBufferUsage();
|
||||
let bufferUsage = PerformanceController.getBufferUsageForRecording(recording) || 0;
|
||||
|
||||
// Normalize to a percentage value
|
||||
let percent = Math.floor(bufferUsage * 100);
|
||||
@ -174,7 +167,7 @@ let PerformanceView = {
|
||||
}
|
||||
|
||||
$bufferLabel.value = L10N.getFormatStr("profiler.bufferFull", percent);
|
||||
this.emit(EVENTS.UI_BUFFER_UPDATED, percent);
|
||||
this.emit(EVENTS.UI_BUFFER_STATUS_UPDATED, percent);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -209,61 +202,25 @@ let PerformanceView = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired when a recording is just starting, but actors may not have
|
||||
* yet started actually recording.
|
||||
*/
|
||||
_onRecordingWillStart: function (_, recording) {
|
||||
if (!recording.isConsole()) {
|
||||
this._lockRecordButtons(true);
|
||||
this._activateRecordButtons(true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When a recording has started.
|
||||
*/
|
||||
_onRecordingStarted: function (_, recording) {
|
||||
// A stopped recording can be from `console.profileEnd` -- only unlock
|
||||
// the button if it's the main recording that was started via UI.
|
||||
if (!recording.isConsole()) {
|
||||
this._lockRecordButtons(false);
|
||||
}
|
||||
if (recording.isRecording()) {
|
||||
this.updateBufferStatus();
|
||||
}
|
||||
},
|
||||
_onRecordingStateChange: function () {
|
||||
let currentRecording = PerformanceController.getCurrentRecording();
|
||||
let recordings = PerformanceController.getRecordings();
|
||||
|
||||
/**
|
||||
* Fired when a recording is stopping, but not yet completed
|
||||
*/
|
||||
_onRecordingWillStop: function (_, recording) {
|
||||
if (!recording.isConsole()) {
|
||||
this._lockRecordButtons(true);
|
||||
this._activateRecordButtons(false);
|
||||
}
|
||||
// Lock the details view while the recording is being loaded in the UI.
|
||||
// Only do this if this is the current recording.
|
||||
if (recording === PerformanceController.getCurrentRecording()) {
|
||||
this._activateRecordButtons(recordings.find(r => !r.isConsole() && r.isRecording()));
|
||||
this._lockRecordButtons(recordings.find(r => !r.isConsole() && r.isFinalizing()));
|
||||
|
||||
if (currentRecording && currentRecording.isFinalizing()) {
|
||||
this.setState("loading");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When a recording is complete.
|
||||
*/
|
||||
_onRecordingStopped: function (_, recording) {
|
||||
// A stopped recording can be from `console.profileEnd` -- only unlock
|
||||
// the button if it's the main recording that was started via UI.
|
||||
if (!recording.isConsole()) {
|
||||
this._lockRecordButtons(false);
|
||||
}
|
||||
|
||||
// If the currently selected recording is the one that just stopped,
|
||||
// switch state to "recorded".
|
||||
if (recording === PerformanceController.getCurrentRecording()) {
|
||||
if (currentRecording && currentRecording.isCompleted()) {
|
||||
this.setState("recorded");
|
||||
}
|
||||
if (currentRecording && currentRecording.isRecording()) {
|
||||
this.updateBufferStatus();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -280,6 +237,8 @@ let PerformanceView = {
|
||||
if (this._recordButton.hasAttribute("checked")) {
|
||||
this.emit(EVENTS.UI_STOP_RECORDING);
|
||||
} else {
|
||||
this._lockRecordButtons(true);
|
||||
this._activateRecordButtons(true);
|
||||
this.emit(EVENTS.UI_START_RECORDING);
|
||||
}
|
||||
},
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
<popupset id="performance-options-popupset">
|
||||
<menupopup id="performance-filter-menupopup"/>
|
||||
<menupopup id="performance-options-menupopup">
|
||||
<menupopup id="performance-options-menupopup" position="before_end">
|
||||
<menuitem id="option-show-platform-data"
|
||||
type="checkbox"
|
||||
data-pref="show-platform-data"
|
||||
@ -45,7 +45,6 @@
|
||||
label="&performanceUI.enableMemory;"
|
||||
tooltiptext="&performanceUI.enableMemory.tooltiptext;"/>
|
||||
<menuitem id="option-enable-allocations"
|
||||
class="experimental-option"
|
||||
type="checkbox"
|
||||
data-pref="enable-allocations"
|
||||
label="&performanceUI.enableAllocations;"
|
||||
@ -120,22 +119,26 @@
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="&performanceUI.toolbar.waterfall;"
|
||||
hidden="true"
|
||||
data-view="waterfall" />
|
||||
data-view="waterfall"
|
||||
tooltiptext="&performanceUI.toolbar.waterfall.tooltiptext;" />
|
||||
<toolbarbutton id="select-js-calltree-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="&performanceUI.toolbar.js-calltree;"
|
||||
hidden="true"
|
||||
data-view="js-calltree" />
|
||||
data-view="js-calltree"
|
||||
tooltiptext="&performanceUI.toolbar.js-calltree.tooltiptext;" />
|
||||
<toolbarbutton id="select-js-flamegraph-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="&performanceUI.toolbar.js-flamegraph;"
|
||||
hidden="true"
|
||||
data-view="js-flamegraph" />
|
||||
data-view="js-flamegraph"
|
||||
tooltiptext="&performanceUI.toolbar.js-flamegraph.tooltiptext;" />
|
||||
<toolbarbutton id="select-memory-calltree-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="&performanceUI.toolbar.memory-calltree;"
|
||||
hidden="true"
|
||||
data-view="memory-calltree" />
|
||||
data-view="memory-calltree"
|
||||
tooltiptext="&performanceUI.toolbar.allocations.tooltiptext;" />
|
||||
<toolbarbutton id="select-memory-flamegraph-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="&performanceUI.toolbar.memory-flamegraph;"
|
||||
|
@ -21,14 +21,6 @@ support-files =
|
||||
[browser_markers-timestamp.js]
|
||||
[browser_perf-allocations-to-samples.js]
|
||||
[browser_perf-categories-js-calltree.js]
|
||||
[browser_perf-compatibility-01.js]
|
||||
[browser_perf-compatibility-02.js]
|
||||
[browser_perf-compatibility-03.js]
|
||||
[browser_perf-compatibility-04.js]
|
||||
[browser_perf-compatibility-05.js]
|
||||
[browser_perf-compatibility-06.js]
|
||||
[browser_perf-compatibility-07.js]
|
||||
[browser_perf-compatibility-08.js]
|
||||
[browser_perf-clear-01.js]
|
||||
[browser_perf-clear-02.js]
|
||||
[browser_perf-columns-js-calltree.js]
|
||||
@ -42,8 +34,6 @@ support-files =
|
||||
[browser_perf-console-record-07.js]
|
||||
[browser_perf-console-record-08.js]
|
||||
[browser_perf-console-record-09.js]
|
||||
[browser_perf-data-massaging-01.js]
|
||||
[browser_perf-data-samples.js]
|
||||
[browser_perf-details-calltree-render.js]
|
||||
[browser_perf-details-flamegraph-render.js]
|
||||
[browser_perf-details-memory-calltree-render.js]
|
||||
@ -57,19 +47,15 @@ support-files =
|
||||
[browser_perf-details-06.js]
|
||||
[browser_perf-details-07.js]
|
||||
[browser_perf-events-calltree.js]
|
||||
[browser_perf-front-basic-profiler-01.js]
|
||||
[browser_perf-front-basic-timeline-01.js]
|
||||
#[browser_perf-front-profiler-01.js] bug 1077464
|
||||
[browser_perf-front-profiler-02.js]
|
||||
[browser_perf-front-profiler-03.js]
|
||||
[browser_perf-front-profiler-04.js]
|
||||
#[browser_perf-front-profiler-05.js] bug 1077464
|
||||
#[browser_perf-front-profiler-06.js]
|
||||
[browser_perf-front-01.js]
|
||||
[browser_perf-front-02.js]
|
||||
[browser_perf-highlighted.js]
|
||||
#[browser_perf-jit-view-01.js] bug 1176056
|
||||
#[browser_perf-jit-view-02.js] bug 1176056
|
||||
[browser_perf-legacy-front-01.js]
|
||||
[browser_perf-legacy-front-02.js]
|
||||
[browser_perf-legacy-front-03.js]
|
||||
[browser_perf-legacy-front-04.js]
|
||||
[browser_perf-legacy-front-05.js]
|
||||
[browser_perf-legacy-front-06.js]
|
||||
[browser_perf-loading-01.js]
|
||||
[browser_perf-loading-02.js]
|
||||
[browser_perf-marker-details-01.js]
|
||||
@ -101,13 +87,9 @@ skip-if = os == 'linux' # Bug 1172120
|
||||
[browser_perf-overview-selection-02.js]
|
||||
[browser_perf-overview-selection-03.js]
|
||||
[browser_perf-overview-time-interval.js]
|
||||
[browser_perf-shared-connection-02.js]
|
||||
[browser_perf-shared-connection-03.js]
|
||||
[browser_perf-states.js]
|
||||
[browser_perf-refresh.js]
|
||||
[browser_perf-ui-recording.js]
|
||||
[browser_perf-recording-model-01.js]
|
||||
[browser_perf-recording-model-02.js]
|
||||
[browser_perf-recording-notices-01.js]
|
||||
[browser_perf-recording-notices-02.js]
|
||||
[browser_perf-recording-notices-03.js]
|
||||
|
@ -12,13 +12,13 @@ function waitForMarkerType(front, type) {
|
||||
info("Waiting for marker of type = " + type);
|
||||
const { promise, resolve } = Promise.defer();
|
||||
|
||||
const handler = (_, name, markers) => {
|
||||
const handler = (name, data) => {
|
||||
if (name !== "markers") {
|
||||
return;
|
||||
}
|
||||
|
||||
let markers = data.markers;
|
||||
info("Got markers: " + JSON.stringify(markers, null, 2));
|
||||
|
||||
if (markers.some(m => m.name === type)) {
|
||||
ok(true, "Found marker of type = " + type);
|
||||
front.off("timeline-data", handler);
|
||||
@ -36,7 +36,7 @@ function* spawnTest () {
|
||||
|
||||
let { target, front } = yield initBackend(TEST_URL);
|
||||
|
||||
yield front.startRecording({ withMarkers: true, withTicks: true });
|
||||
let rec = yield front.startRecording({ withMarkers: true, withTicks: true });
|
||||
|
||||
yield Promise.all([
|
||||
waitForMarkerType(front, "nsCycleCollector::Collect"),
|
||||
@ -44,7 +44,7 @@ function* spawnTest () {
|
||||
]);
|
||||
ok(true, "Got expected cycle collection events");
|
||||
|
||||
yield front.stopRecording();
|
||||
yield front.stopRecording(rec);
|
||||
|
||||
// Destroy the front before removing tab to ensure no
|
||||
// lingering requests
|
||||
|
@ -24,13 +24,11 @@ function* spawnTest () {
|
||||
|
||||
info(`Got ${markers.length} markers.`);
|
||||
|
||||
let maxMarkerTime = model._timelineStartTime + model.getDuration() + TIME_CLOSE_TO;
|
||||
|
||||
ok(markers.every(({name}) => name === "GarbageCollection"), "All markers found are GC markers");
|
||||
ok(markers.length > 0, "found atleast one GC marker");
|
||||
ok(markers.every(({start}) => typeof start === "number" && start > 0 && start < maxMarkerTime),
|
||||
ok(markers.every(({start, end}) => typeof start === "number" && start > 0 && start < end),
|
||||
"All markers have a start time between the valid range.");
|
||||
ok(markers.every(({end}) => typeof end === "number" && end > 0 && end < maxMarkerTime),
|
||||
ok(markers.every(({end}) => typeof end === "number"),
|
||||
"All markers have an end time between the valid range.");
|
||||
ok(markers.every(({causeName}) => typeof causeName === "string"),
|
||||
"All markers have a causeName.");
|
||||
@ -41,7 +39,8 @@ function* spawnTest () {
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
function handler (_, name, m) {
|
||||
function handler (name, m) {
|
||||
m = m.markers;
|
||||
if (name === "markers" && m[0].name === "GarbageCollection") {
|
||||
markers = m;
|
||||
}
|
||||
|
@ -31,12 +31,12 @@ function* spawnTest () {
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
function handler (_, name, _markers) {
|
||||
function handler (name, data) {
|
||||
if (name !== "markers") {
|
||||
return;
|
||||
}
|
||||
|
||||
_markers.forEach(marker => {
|
||||
data.markers.forEach(marker => {
|
||||
info(marker.name);
|
||||
if (marker.name === "Parse HTML") {
|
||||
markers.push(marker);
|
||||
|
@ -33,9 +33,9 @@ function* spawnTest () {
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
function handler (_, name, m) {
|
||||
function handler (name, data) {
|
||||
if (name === "markers") {
|
||||
markers = markers.concat(m.filter(marker => marker.name === "Styles"));
|
||||
markers = markers.concat(data.markers.filter(marker => marker.name === "Styles"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,8 @@ function* spawnTest () {
|
||||
ok(markers.every(({stack}) => typeof stack === "number"), "All markers have stack references.");
|
||||
ok(markers.every(({name}) => name === "TimeStamp"), "All markers found are TimeStamp markers");
|
||||
ok(markers.length === 2, "found 2 TimeStamp markers");
|
||||
ok(markers.every(({start}) => typeof start === "number" && start > 0 && start < maxMarkerTime),
|
||||
"All markers have a start time between the valid range.");
|
||||
ok(markers.every(({end}) => typeof end === "number" && end > 0 && end < maxMarkerTime),
|
||||
"All markers have an end time between the valid range.");
|
||||
ok(markers.every(({start, end}) => typeof start === "number" && start === end),
|
||||
"All markers have equal start and end times");
|
||||
is(markers[0].causeName, void 0, "Unlabeled timestamps have an empty causeName");
|
||||
is(markers[1].causeName, "myLabel", "Labeled timestamps have correct causeName");
|
||||
|
||||
@ -42,9 +40,9 @@ function* spawnTest () {
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
function handler (_, name, m) {
|
||||
function handler (name, data) {
|
||||
if (name === "markers") {
|
||||
markers = markers.concat(m.filter(marker => marker.name === "TimeStamp"));
|
||||
markers = markers.concat(data.markers.filter(marker => marker.name === "TimeStamp"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,6 @@
|
||||
*/
|
||||
|
||||
function test() {
|
||||
let RecordingUtils = require("devtools/performance/recording-utils");
|
||||
|
||||
let output = RecordingUtils.getProfileThreadFromAllocations(TEST_DATA);
|
||||
is(output.toSource(), EXPECTED_OUTPUT.toSource(), "The output is correct.");
|
||||
|
||||
|
@ -1,53 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test basic functionality of PerformanceFront with mock memory and timeline actors.
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 100;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL, {
|
||||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_MOCK_TIMELINE_ACTOR: true
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
|
||||
|
||||
let { memory, timeline } = front.getActorSupport();
|
||||
ok(!memory, "memory should be mocked.");
|
||||
ok(!timeline, "timeline should be mocked.");
|
||||
|
||||
let recording = yield front.startRecording({
|
||||
withTicks: true,
|
||||
withMarkers: true,
|
||||
withMemory: true,
|
||||
withAllocations: true,
|
||||
allocationsSampleProbability: +Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF),
|
||||
allocationsMaxLogLength: Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF)
|
||||
});
|
||||
|
||||
ok(typeof recording._profilerStartTime === "number",
|
||||
"The front.startRecording() returns a recording with a profiler start time");
|
||||
ok(typeof recording._timelineStartTime === "number",
|
||||
"The front.startRecording() returns a recording with a timeline start time");
|
||||
ok(typeof recording._memoryStartTime === "number",
|
||||
"The front.startRecording() returns a recording with a memory start time");
|
||||
|
||||
yield busyWait(WAIT_TIME);
|
||||
|
||||
yield front.stopRecording(recording);
|
||||
|
||||
ok(typeof recording.getDuration() === "number",
|
||||
"The front.stopRecording() allows recording to get a duration.");
|
||||
|
||||
ok(recording.getDuration() >= 0,
|
||||
"The profilerEndTime is after profilerStartTime.");
|
||||
|
||||
// Destroy the front before removing tab to ensure no
|
||||
// lingering requests
|
||||
yield front.destroy();
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test basic functionality of PerformanceFront with only mock memory.
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 100;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL, {
|
||||
TEST_MOCK_MEMORY_ACTOR: true
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
|
||||
|
||||
let { memory, timeline } = front.getActorSupport();
|
||||
ok(!memory, "memory should be mocked.");
|
||||
ok(timeline, "timeline should not be mocked.");
|
||||
|
||||
let recording = yield front.startRecording({
|
||||
withTicks: true,
|
||||
withMarkers: true,
|
||||
withMemory: true,
|
||||
withAllocations: true,
|
||||
allocationsSampleProbability: +Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF),
|
||||
allocationsMaxLogLength: Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF)
|
||||
});
|
||||
|
||||
ok(typeof recording._profilerStartTime === "number",
|
||||
"The front.startRecording() returns a recording with a profiler start time");
|
||||
ok(typeof recording._timelineStartTime === "number",
|
||||
"The front.startRecording() returns a recording with a timeline start time");
|
||||
ok(typeof recording._memoryStartTime === "number",
|
||||
"The front.startRecording() returns a recording with a memory start time");
|
||||
|
||||
yield busyWait(WAIT_TIME);
|
||||
|
||||
yield front.stopRecording(recording);
|
||||
|
||||
ok(typeof recording.getDuration() === "number",
|
||||
"The front.stopRecording() allows recording to get a duration.");
|
||||
|
||||
ok(recording.getDuration() >= 0,
|
||||
"The profilerEndTime is after profilerStartTime.");
|
||||
|
||||
// Destroy the front before removing tab to ensure no
|
||||
// lingering requests
|
||||
yield front.destroy();
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that when using an older server (< Fx40) where the profiler actor does not
|
||||
* have the `getBufferInfo` method that nothing breaks and RecordingModels have null
|
||||
* `getBufferUsage()` values.
|
||||
*/
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL, {
|
||||
TEST_MOCK_PROFILER_CHECK_TIMER: 10,
|
||||
TEST_PROFILER_FILTER_STATUS: ["position", "totalSize", "generation"]
|
||||
});
|
||||
|
||||
let model = yield front.startRecording();
|
||||
let count = 0;
|
||||
while (count < 5) {
|
||||
let [_, stats] = yield onceSpread(front._profiler, "profiler-status");
|
||||
is(stats.generation, void 0, "profiler-status has void `generation`");
|
||||
is(stats.totalSize, void 0, "profiler-status has void `totalSize`");
|
||||
is(stats.position, void 0, "profiler-status has void `position`");
|
||||
count++;
|
||||
}
|
||||
|
||||
is(model.getBufferUsage(), null, "model should have `null` for its buffer usage");
|
||||
yield front.stopRecording(model);
|
||||
is(model.getBufferUsage(), null, "after recording, model should still have `null` for its buffer usage");
|
||||
|
||||
// Destroy the front before removing tab to ensure no
|
||||
// lingering requests
|
||||
yield front.destroy();
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -6,14 +6,11 @@
|
||||
* before it was opened.
|
||||
*/
|
||||
|
||||
let { getPerformanceFront } = require("devtools/performance/front");
|
||||
let WAIT_TIME = 10;
|
||||
|
||||
function* spawnTest() {
|
||||
let profilerConnected = waitForProfilerConnection();
|
||||
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
|
||||
yield profilerConnected;
|
||||
let front = getPerformanceFront(target);
|
||||
let front = toolbox.performance;
|
||||
|
||||
let profileStart = once(front, "recording-started");
|
||||
console.profile("rust");
|
||||
@ -29,6 +26,7 @@ function* spawnTest() {
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
let recordings = PerformanceController.getRecordings();
|
||||
yield waitUntil(() => PerformanceController.getRecordings().length === 1);
|
||||
is(recordings.length, 1, "one recording found in the performance panel.");
|
||||
is(recordings[0].isConsole(), true, "recording came from console.profile.");
|
||||
is(recordings[0].getLabel(), "rust", "correct label in the recording model.");
|
||||
|
@ -6,14 +6,11 @@
|
||||
* when it is opened.
|
||||
*/
|
||||
|
||||
let { getPerformanceFront } = require("devtools/performance/front");
|
||||
let WAIT_TIME = 10;
|
||||
|
||||
function* spawnTest() {
|
||||
let profilerConnected = waitForProfilerConnection();
|
||||
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
|
||||
yield profilerConnected;
|
||||
let front = getPerformanceFront(target);
|
||||
let front = toolbox.performance;
|
||||
|
||||
let profileStart = once(front, "recording-started");
|
||||
console.profile("rust");
|
||||
@ -26,6 +23,7 @@ function* spawnTest() {
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
yield waitUntil(() => PerformanceController.getRecordings().length === 2);
|
||||
let recordings = PerformanceController.getRecordings();
|
||||
is(recordings.length, 2, "two recordings found in the performance panel.");
|
||||
is(recordings[0].isConsole(), true, "recording came from console.profile (1).");
|
||||
|
@ -6,14 +6,11 @@
|
||||
* also console recordings that have finished before it was opened.
|
||||
*/
|
||||
|
||||
let { getPerformanceFront } = require("devtools/performance/front");
|
||||
let WAIT_TIME = 10;
|
||||
|
||||
function* spawnTest() {
|
||||
let profilerConnected = waitForProfilerConnection();
|
||||
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
|
||||
yield profilerConnected;
|
||||
let front = getPerformanceFront(target);
|
||||
let front = toolbox.performance;
|
||||
|
||||
let profileStart = once(front, "recording-started");
|
||||
console.profile("rust");
|
||||
@ -31,6 +28,7 @@ function* spawnTest() {
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
yield waitUntil(() => PerformanceController.getRecordings().length === 2);
|
||||
let recordings = PerformanceController.getRecordings();
|
||||
is(recordings.length, 2, "two recordings found in the performance panel.");
|
||||
is(recordings[0].isConsole(), true, "recording came from console.profile (1).");
|
||||
|
@ -1,41 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if the retrieved profiler data samples always have a (root) node.
|
||||
* If this ever changes, the |ThreadNode.prototype.insert| function in
|
||||
* browser/devtools/performance/modules/logic/tree-model.js will have to be changed.
|
||||
*/
|
||||
|
||||
const WAIT_TIME = 1000; // ms
|
||||
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let front = panel.panelWin.gFront;
|
||||
|
||||
let rec = yield front.startRecording();
|
||||
busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
|
||||
|
||||
yield front.stopRecording(rec);
|
||||
let profile = rec.getProfile();
|
||||
let sampleCount = 0;
|
||||
|
||||
for (let thread of profile.threads) {
|
||||
info("Checking thread: " + thread.name);
|
||||
|
||||
for (let sample of thread.samples.data) {
|
||||
sampleCount++;
|
||||
|
||||
let stack = getInflatedStackLocations(thread, sample);
|
||||
if (stack[0] != "(root)") {
|
||||
ok(false, "The sample " + stack.toSource() + " doesn't have a root node.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ok(sampleCount > 0,
|
||||
"At least some samples have been iterated over, checking for root nodes.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the waterfall view renders content after recording.
|
||||
*/
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, PerformanceController, DetailsView, WaterfallView } = panel.panelWin;
|
||||
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, false);
|
||||
yield startRecording(panel);
|
||||
yield waitUntil(hasGCMarkers(PerformanceController));
|
||||
|
||||
let rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
|
||||
yield stopRecording(panel);
|
||||
ok(DetailsView.isViewSelected(WaterfallView),
|
||||
"The waterfall view is selected by default in the details view.");
|
||||
yield rendered;
|
||||
|
||||
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, false);
|
||||
yield startRecording(panel);
|
||||
yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
|
||||
|
||||
rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
|
||||
yield stopRecording(panel);
|
||||
yield rendered;
|
||||
|
||||
ok(true, "WaterfallView rendered again after recording completed a second time.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
||||
function hasGCMarkers (controller) {
|
||||
return function () {
|
||||
controller.getCurrentRecording().getMarkers().filter(m => m.name === "GarbageCollection").length >== 2;
|
||||
};
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
* Tests that the call tree up/down events work for js calltree and memory calltree.
|
||||
*/
|
||||
const { ThreadNode } = require("devtools/performance/tree-model");
|
||||
const RecordingUtils = require("devtools/performance/recording-utils")
|
||||
|
||||
function* spawnTest() {
|
||||
let focus = 0;
|
||||
|
@ -1,55 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test basic functionality of PerformanceFront, emitting start and endtime values
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 1000;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL);
|
||||
|
||||
let recording = yield front.startRecording({
|
||||
withAllocations: true,
|
||||
allocationsSampleProbability: +Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF),
|
||||
allocationsMaxLogLength: Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF)
|
||||
});
|
||||
|
||||
let allocationsCount = 0;
|
||||
let allocationsCounter = (_, type) => type === "allocations" && allocationsCount++;
|
||||
|
||||
// Record allocation events to ensure it's called more than once
|
||||
// so we know it's polling
|
||||
front.on("timeline-data", allocationsCounter);
|
||||
|
||||
ok(typeof recording._profilerStartTime === "number",
|
||||
"The front.startRecording() returns a recording model with a profiler start time.");
|
||||
ok(typeof recording._timelineStartTime === "number",
|
||||
"The front.startRecording() returns a recording model with a timeline start time.");
|
||||
ok(typeof recording._memoryStartTime === "number",
|
||||
"The front.startRecording() returns a recording model with a memory start time.");
|
||||
|
||||
yield Promise.all([
|
||||
busyWait(WAIT_TIME),
|
||||
waitUntil(() => allocationsCount > 1)
|
||||
]);
|
||||
|
||||
yield front.stopRecording(recording);
|
||||
|
||||
front.off("timeline-data", allocationsCounter);
|
||||
|
||||
ok(typeof recording.getDuration() === "number",
|
||||
"The front.stopRecording() gives the recording model a stop time and duration.");
|
||||
ok(recording.getDuration() > 0,
|
||||
"The front.stopRecording() gives a positive duration amount.");
|
||||
|
||||
is((yield front._request("memory", "getState")), "detached",
|
||||
"Memory actor is detached when stopping recording with allocations.");
|
||||
|
||||
// Destroy the front before removing tab to ensure no
|
||||
// lingering requests
|
||||
yield front.destroy();
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that timeline and memory actors can be started multiple times to get
|
||||
* different start times for different recording sessions.
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 1000;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL);
|
||||
let config = { withMarkers: true, withAllocations: true, withTicks: true };
|
||||
|
||||
yield front._request("memory", "attach");
|
||||
|
||||
let timelineStart1 = yield front._request("timeline", "start", config);
|
||||
let memoryStart1 = yield front._request("memory", "startRecordingAllocations");
|
||||
let timelineStart2 = yield front._request("timeline", "start", config);
|
||||
let memoryStart2 = yield front._request("memory", "startRecordingAllocations");
|
||||
let timelineStop = yield front._request("timeline", "stop");
|
||||
let memoryStop = yield front._request("memory", "stopRecordingAllocations");
|
||||
|
||||
info(timelineStart1);
|
||||
info(timelineStart2);
|
||||
ok(typeof timelineStart1 === "number", "first timeline start returned a number");
|
||||
ok(typeof timelineStart2 === "number", "second timeline start returned a number");
|
||||
ok(typeof memoryStart1 === "number", "first memory start returned a number");
|
||||
ok(typeof memoryStart2 === "number", "second memory start returned a number");
|
||||
ok(timelineStart1 < timelineStart2, "can start timeline actor twice and get different start times");
|
||||
ok(memoryStart1 < memoryStart2, "can start memory actor twice and get different start times");
|
||||
|
||||
// Destroy the front before removing tab to ensure no
|
||||
// lingering requests
|
||||
yield front.destroy();
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test basic functionality of PerformanceFront
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 1000;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, front } = yield initBackend(SIMPLE_URL);
|
||||
|
||||
let startModel = yield front.startRecording();
|
||||
let { profilerStartTime, timelineStartTime, memoryStartTime } = startModel;
|
||||
|
||||
ok(startModel._profilerStartTime !== undefined,
|
||||
"A `_profilerStartTime` property exists in the recording model.");
|
||||
ok(startModel._timelineStartTime !== undefined,
|
||||
"A `_timelineStartTime` property exists in the recording model.");
|
||||
is(startModel._memoryStartTime, 0,
|
||||
"A `_memoryStartTime` property exists in the recording model, but it's 0.");
|
||||
|
||||
yield busyWait(WAIT_TIME);
|
||||
|
||||
let stopModel = yield front.stopRecording(startModel);
|
||||
|
||||
ok(stopModel.getProfile(), "recording model has a profile after stopping.");
|
||||
ok(stopModel.getDuration(), "recording model has a duration after stopping.");
|
||||
|
||||
// Destroy the front before removing tab to ensure no
|
||||
// lingering requests
|
||||
yield front.destroy();
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if the built-in profiler module doesn't deactivate when the toolbox
|
||||
* is destroyed if there are other consumers using it.
|
||||
*/
|
||||
|
||||
let test = Task.async(function*() {
|
||||
let { panel: firstPanel } = yield initPerformance(SIMPLE_URL);
|
||||
let firstFront = firstPanel.panelWin.gFront;
|
||||
|
||||
let activated = firstFront.once("profiler-activated");
|
||||
yield firstFront.startRecording();
|
||||
yield activated;
|
||||
|
||||
let { panel: secondPanel } = yield initPerformance(SIMPLE_URL);
|
||||
let secondFront = secondPanel.panelWin.gFront;
|
||||
loadFrameScripts();
|
||||
|
||||
let alreadyActive = secondFront.once("profiler-already-active");
|
||||
yield secondFront.startRecording();
|
||||
yield alreadyActive;
|
||||
|
||||
// Manually teardown the tabs so we can check profiler status
|
||||
let tab1 = firstPanel.target.tab;
|
||||
let tab2 = secondPanel.target.tab;
|
||||
yield firstPanel._toolbox.destroy();
|
||||
yield removeTab(tab1);
|
||||
ok((yield PMM_isProfilerActive()),
|
||||
"The built-in profiler module should still be active.");
|
||||
|
||||
yield secondPanel._toolbox.destroy();
|
||||
ok(!(yield PMM_isProfilerActive()),
|
||||
"The built-in profiler module should no longer be active.");
|
||||
yield removeTab(tab2);
|
||||
tab1 = tab2 = null;
|
||||
|
||||
finish();
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if the built-in profiler module is not reactivated if no other
|
||||
* consumer was using it over the remote debugger protocol, and ensures
|
||||
* that the actor will work properly even in such cases (e.g. the Gecko Profiler
|
||||
* addon was installed and automatically activated the profiler module).
|
||||
*/
|
||||
|
||||
let test = Task.async(function*() {
|
||||
// Ensure the profiler is already running when the test starts.
|
||||
loadFrameScripts();
|
||||
let ENTRIES = 1000000;
|
||||
let INTERVAL = 1;
|
||||
let FEATURES = ["js"];
|
||||
yield sendProfilerCommand("StartProfiler", [ENTRIES, INTERVAL, FEATURES, FEATURES.length]);
|
||||
|
||||
let { panel: firstPanel } = yield initPerformance(SIMPLE_URL);
|
||||
let firstFront = firstPanel.panelWin.gFront;
|
||||
|
||||
let firstAlreadyActive = firstFront.once("profiler-already-active");
|
||||
let recording = yield firstFront.startRecording();
|
||||
yield firstAlreadyActive;
|
||||
ok(recording._profilerStartTime > 0, "The profiler was not restarted.");
|
||||
|
||||
let { panel: secondPanel } = yield initPerformance(SIMPLE_URL);
|
||||
let secondFront = secondPanel.panelWin.gFront;
|
||||
|
||||
let secondAlreadyActive = secondFront.once("profiler-already-active");
|
||||
let secondRecording = yield secondFront.startRecording();
|
||||
yield secondAlreadyActive;
|
||||
ok(secondRecording._profilerStartTime > 0, "The profiler was not restarted.");
|
||||
|
||||
yield teardown(firstPanel);
|
||||
ok((yield PMM_isProfilerActive()),
|
||||
"The built-in profiler module should still be active.");
|
||||
|
||||
yield teardown(secondPanel);
|
||||
ok(!(yield PMM_isProfilerActive()),
|
||||
"The built-in profiler module should have been automatically stoped.");
|
||||
|
||||
finish();
|
||||
});
|
@ -6,19 +6,17 @@
|
||||
* whether already loaded, or via console.profile with an unloaded performance tools.
|
||||
*/
|
||||
|
||||
let { getPerformanceFront } = require("devtools/performance/front");
|
||||
|
||||
function* spawnTest() {
|
||||
let profilerConnected = waitForProfilerConnection();
|
||||
let { target, toolbox, console } = yield initConsole(SIMPLE_URL);
|
||||
yield profilerConnected;
|
||||
let front = getPerformanceFront(target);
|
||||
let front = toolbox.performance;
|
||||
let tab = toolbox.doc.getElementById("toolbox-tab-performance");
|
||||
|
||||
let profileStart = once(front, "recording-started");
|
||||
console.profile("rust");
|
||||
yield profileStart;
|
||||
|
||||
yield waitUntil(() => tab.hasAttribute("highlighted"));
|
||||
|
||||
ok(tab.hasAttribute("highlighted"),
|
||||
"performance tab is highlighted during recording from console.profile when unloaded");
|
||||
|
||||
|
@ -6,8 +6,6 @@
|
||||
* if on, and displays selected frames on focus.
|
||||
*/
|
||||
|
||||
const RecordingUtils = require("devtools/performance/recording-utils");
|
||||
|
||||
Services.prefs.setBoolPref(INVERT_PREF, false);
|
||||
|
||||
function* spawnTest() {
|
||||
|
@ -6,9 +6,6 @@
|
||||
* for meta nodes when viewing "content only".
|
||||
*/
|
||||
|
||||
const { CATEGORY_MASK } = require("devtools/performance/global");
|
||||
const RecordingUtils = require("devtools/performance/recording-utils");
|
||||
|
||||
Services.prefs.setBoolPref(INVERT_PREF, false);
|
||||
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
|
||||
|
||||
|
@ -18,19 +18,20 @@ let test = Task.async(function*() {
|
||||
// Test mock memory
|
||||
function *testMockMemory () {
|
||||
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
|
||||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_PERFORMANCE_LEGACY_FRONT: true,
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
Services.prefs.setBoolPref(FRAMERATE_PREF, true);
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
|
||||
let { EVENTS, $, gFront, PerformanceController, PerformanceView, DetailsView, WaterfallView } = panel.panelWin;
|
||||
|
||||
let { memory: memorySupport, timeline: timelineSupport } = gFront.getActorSupport();
|
||||
yield startRecording(panel, { waitForOverview: false });
|
||||
yield waitUntil(() => PerformanceController.getCurrentRecording().getTicks().length);
|
||||
yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length);
|
||||
yield stopRecording(panel, { waitForOverview: false });
|
||||
|
||||
ok(gFront.LEGACY_FRONT, "using legacy front");
|
||||
|
||||
let config = PerformanceController.getCurrentRecording().getConfiguration();
|
||||
let {
|
||||
markers, allocations, memory, ticks
|
||||
@ -75,7 +76,7 @@ function *testMockMemory () {
|
||||
// Test mock memory and timeline actor
|
||||
function *testMockMemoryAndTimeline() {
|
||||
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
|
||||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_PERFORMANCE_LEGACY_FRONT: true,
|
||||
TEST_MOCK_TIMELINE_ACTOR: true,
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
@ -83,7 +84,6 @@ function *testMockMemoryAndTimeline() {
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
|
||||
let { EVENTS, $, gFront, PerformanceController, PerformanceView, DetailsView, WaterfallView } = panel.panelWin;
|
||||
|
||||
let { memory: memorySupport, timeline: timelineSupport } = gFront.getActorSupport();
|
||||
yield startRecording(panel, { waitForOverview: false });
|
||||
yield busyWait(WAIT_TIME);
|
||||
yield stopRecording(panel, { waitForOverview: false });
|
@ -10,15 +10,17 @@ const WAIT_TIME = 1000;
|
||||
|
||||
let test = Task.async(function*() {
|
||||
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
|
||||
TEST_MOCK_MEMORY_ACTOR: true,
|
||||
TEST_MOCK_TIMELINE_ACTOR: true
|
||||
TEST_MOCK_TIMELINE_ACTOR: true,
|
||||
TEST_PERFORMANCE_LEGACY_FRONT: true,
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
let { EVENTS, $, gFront, PerformanceController, PerformanceView, DetailsView, JsCallTreeView } = panel.panelWin;
|
||||
let { EVENTS, $, gFront: front, PerformanceController, PerformanceView, DetailsView, JsCallTreeView } = panel.panelWin;
|
||||
|
||||
let { memory: memorySupport, timeline: timelineSupport } = gFront.getActorSupport();
|
||||
ok(!memorySupport, "memory should be mocked.");
|
||||
ok(!timelineSupport, "timeline should be mocked.");
|
||||
ok(front.LEGACY_FRONT, true, "Using legacy front");
|
||||
is(front.traits.features.withMarkers, false, "traits.features.withMarkers is false.");
|
||||
is(front.traits.features.withTicks, false, "traits.features.withTicks is false.");
|
||||
is(front.traits.features.withMemory, false, "traits.features.withMemory is false.");
|
||||
is(front.traits.features.withAllocations, false, "traits.features.withAllocations is false.");
|
||||
|
||||
yield startRecording(panel, { waitForOverview: false });
|
||||
busyWait(WAIT_TIME); // allow the profiler module to sample some cpu activity
|
@ -7,18 +7,21 @@
|
||||
*/
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL, void 0, {
|
||||
TEST_MOCK_PROFILER_CHECK_TIMER: 10,
|
||||
TEST_PERFORMANCE_LEGACY_FRONT: true,
|
||||
TEST_PROFILER_FILTER_STATUS: ["position", "totalSize", "generation"]
|
||||
});
|
||||
let { gFront: front, EVENTS, $, PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
|
||||
|
||||
let { gFront: front, EVENTS, $, PerformanceController, PerformanceView } = panel.panelWin;
|
||||
front.setProfilerStatusInterval(10);
|
||||
yield startRecording(panel);
|
||||
|
||||
yield once(front._profiler, "profiler-status");
|
||||
front.on("profiler-status", () => ok(false, "profiler-status should not be emitted when not supported"));
|
||||
|
||||
yield busyWait(100);
|
||||
ok(!$("#details-pane-container").getAttribute("buffer-status"),
|
||||
"container does not have [buffer-status] attribute when not supported");
|
||||
|
||||
yield once(front._profiler, "profiler-status");
|
||||
yield busyWait(100);
|
||||
ok(!$("#details-pane-container").getAttribute("buffer-status"),
|
||||
"container does not have [buffer-status] attribute when not supported");
|
||||
|
@ -10,15 +10,16 @@ const WAIT_TIME = 1000;
|
||||
|
||||
let test = Task.async(function*() {
|
||||
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL, "performance", {
|
||||
TEST_MOCK_MEMORY_ACTOR: true
|
||||
TEST_PERFORMANCE_LEGACY_FRONT: true
|
||||
});
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
let { EVENTS, $, gFront, PerformanceController, PerformanceView, DetailsView, WaterfallView } = panel.panelWin;
|
||||
let { EVENTS, $, gFront: front, PerformanceController, PerformanceView, DetailsView, WaterfallView } = panel.panelWin;
|
||||
|
||||
|
||||
let { memory: memorySupport, timeline: timelineSupport } = gFront.getActorSupport();
|
||||
ok(!memorySupport, "memory should be mocked.");
|
||||
ok(timelineSupport, "timeline should not be mocked.");
|
||||
ok(front.LEGACY_FRONT, true, "Using legacy front");
|
||||
is(front.traits.features.withMarkers, true, "traits.features.withMarkers is true.");
|
||||
is(front.traits.features.withTicks, true, "traits.features.withTicks is true.");
|
||||
is(front.traits.features.withMemory, false, "traits.features.withMemory is false.");
|
||||
is(front.traits.features.withAllocations, false, "traits.features.withAllocations is false.");
|
||||
|
||||
yield startRecording(panel);
|
||||
yield busyWait(100);
|
@ -10,7 +10,9 @@
|
||||
const WAIT_TIME = 1000; // ms
|
||||
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { panel } = yield initPerformance(SIMPLE_URL, void 0, {
|
||||
TEST_PERFORMANCE_LEGACY_FRONT: true,
|
||||
});
|
||||
let { gFront: front, gTarget: target } = panel.panelWin;
|
||||
|
||||
// Explicitly override the profiler's trait `filterable`
|
@ -0,0 +1,48 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if the profiler is populated by in-progress console recordings
|
||||
* when it is opened with the legacy front.
|
||||
*/
|
||||
|
||||
let WAIT_TIME = 10;
|
||||
|
||||
function* spawnTest() {
|
||||
let { target, toolbox, console } = yield initConsole(SIMPLE_URL, { TEST_PERFORMANCE_LEGACY_FRONT: true });
|
||||
let front = toolbox.performance;
|
||||
|
||||
let profileStart = once(front, "recording-started");
|
||||
console.profile("rust");
|
||||
yield profileStart;
|
||||
profileStart = once(front, "recording-started");
|
||||
console.profile("rust2");
|
||||
yield profileStart;
|
||||
|
||||
yield gDevTools.showToolbox(target, "performance");
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
let { panelWin: { PerformanceController, RecordingsView }} = panel;
|
||||
|
||||
yield waitUntil(() => PerformanceController.getRecordings().length === 2);
|
||||
let recordings = PerformanceController.getRecordings();
|
||||
is(recordings.length, 2, "two recordings found in the performance panel.");
|
||||
is(recordings[0].isConsole(), true, "recording came from console.profile (1).");
|
||||
is(recordings[0].getLabel(), "rust", "correct label in the recording model (1).");
|
||||
is(recordings[0].isRecording(), true, "recording is still recording (1).");
|
||||
is(recordings[1].isConsole(), true, "recording came from console.profile (2).");
|
||||
is(recordings[1].getLabel(), "rust2", "correct label in the recording model (2).");
|
||||
is(recordings[1].isRecording(), true, "recording is still recording (2).");
|
||||
|
||||
is(RecordingsView.selectedItem.attachment, recordings[0],
|
||||
"The first console recording should be selected.");
|
||||
|
||||
let profileEnd = once(front, "recording-stopped");
|
||||
console.profileEnd("rust");
|
||||
yield profileEnd;
|
||||
profileEnd = once(front, "recording-stopped");
|
||||
console.profileEnd("rust2");
|
||||
yield profileEnd;
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|