This commit is contained in:
Wes Kocher 2015-08-13 16:30:54 -07:00
Родитель 0ecd79f7c8 792263b5e1
Коммит 6b7a0b75b5
513 изменённых файлов: 8026 добавлений и 6533 удалений

Просмотреть файл

@ -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 поставляемый 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();
});

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 10 KiB

После

Ширина:  |  Высота:  |  Размер: 9.9 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 38 KiB

После

Ширина:  |  Высота:  |  Размер: 38 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 10 KiB

После

Ширина:  |  Высота:  |  Размер: 9.9 KiB

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

До

Ширина:  |  Высота:  |  Размер: 38 KiB

После

Ширина:  |  Высота:  |  Размер: 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}

Просмотреть файл

@ -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()

Просмотреть файл

@ -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();
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше