mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
9e4356a394
@ -1167,3 +1167,7 @@ pref("dom.audiochannel.mutedByDefault", true);
|
||||
|
||||
// Default device name for Presentation API
|
||||
pref("dom.presentation.device.name", "Firefox OS");
|
||||
|
||||
// Enable notification of performance timing
|
||||
pref("dom.performance.enable_notify_performance_timing", true);
|
||||
|
||||
|
@ -25,6 +25,10 @@ XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() {
|
||||
return devtools.require('devtools/server/actors/eventlooplag').EventLoopLagFront;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'PerformanceEntriesFront', function() {
|
||||
return devtools.require('devtools/server/actors/performance-entries').PerformanceEntriesFront;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() {
|
||||
return devtools.require('devtools/server/actors/memory').MemoryFront;
|
||||
});
|
||||
@ -588,6 +592,76 @@ let eventLoopLagWatcher = {
|
||||
};
|
||||
developerHUD.registerWatcher(eventLoopLagWatcher);
|
||||
|
||||
/*
|
||||
* The performanceEntriesWatcher determines the delta between the epoch
|
||||
* of an app's launch time and the app's performance entry marks.
|
||||
* When it receives an "appLaunch" performance entry mark it records the
|
||||
* name of the app being launched and the epoch of when the launch ocurred.
|
||||
* When it receives subsequent performance entry events for the app being
|
||||
* launched, it records the delta of the performance entry opoch compared
|
||||
* to the app-launch epoch and emits an "app-start-time-<performance mark name>"
|
||||
* event containing the delta.
|
||||
*/
|
||||
let performanceEntriesWatcher = {
|
||||
_client: null,
|
||||
_fronts: new Map(),
|
||||
_appLaunchName: null,
|
||||
_appLaunchStartTime: null,
|
||||
|
||||
init(client) {
|
||||
this._client = client;
|
||||
},
|
||||
|
||||
trackTarget(target) {
|
||||
// The performanceEntries watcher doesn't register a metric because
|
||||
// currently the metrics generated are not displayed in
|
||||
// in the front-end.
|
||||
|
||||
let front = new PerformanceEntriesFront(this._client, target.actor);
|
||||
this._fronts.set(target, front);
|
||||
|
||||
// User timings are always gathered; there is no setting to enable/
|
||||
// disable.
|
||||
front.start();
|
||||
|
||||
front.on('entry', detail => {
|
||||
if (detail.type === 'mark') {
|
||||
let name = detail.name;
|
||||
let epoch = detail.epoch;
|
||||
let CHARS_UNTIL_APP_NAME = 7; // '@app://'
|
||||
|
||||
// FIXME There is a potential race condition that can result
|
||||
// in some performance entries being disregarded. See bug 1189942.
|
||||
if (name.indexOf('appLaunch') != -1) {
|
||||
let appStartPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME;
|
||||
let length = (name.indexOf('.') - appStartPos);
|
||||
this._appLaunchName = name.substr(appStartPos, length);
|
||||
this._appLaunchStartTime = epoch;
|
||||
} else {
|
||||
let origin = detail.origin;
|
||||
origin = origin.substr(0, origin.indexOf('.'));
|
||||
if (this._appLaunchName === origin) {
|
||||
let time = epoch - this._appLaunchStartTime;
|
||||
let eventName = 'app-startup-time-' + name;
|
||||
|
||||
// Events based on performance marks are for telemetry only, they are
|
||||
// not displayed in the HUD front end.
|
||||
target._sendTelemetryEvent({name: eventName, value: time});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
untrackTarget(target) {
|
||||
let fronts = this._fronts;
|
||||
if (fronts.has(target)) {
|
||||
fronts.get(target).destroy();
|
||||
fronts.delete(target);
|
||||
}
|
||||
}
|
||||
};
|
||||
developerHUD.registerWatcher(performanceEntriesWatcher);
|
||||
|
||||
/**
|
||||
* The Memory Watcher uses devtools actors to track memory usage.
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,11 +19,11 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8bc59310552179f9a8bc6cdd0188e2475df52fb7"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ddfd98cdafefaa1b60273d5568b8dbd13730dae"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="07c383a786f188904311a37f6062c2cb84c9b61d">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,11 +19,11 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8bc59310552179f9a8bc6cdd0188e2475df52fb7"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -139,7 +139,7 @@
|
||||
<project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/>
|
||||
<project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="8d7676dfb68ee0cd069affedd5d1e97316a184ba"/>
|
||||
<project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
|
||||
<project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="a74adcf8d88320d936daa8d20ce88ca0107fb916"/>
|
||||
<project name="hardware_qcom_display" path="hardware/qcom/display" remote="b2g" revision="0eb5fd21d8697136ee4a0166f5e06bff25cc1e8a"/>
|
||||
<project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
|
||||
<project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/>
|
||||
<project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "c5425d9f1f5184731a59ed4bc99295acbde30390",
|
||||
"git_revision": "581de383687dc441a878d2c91a0167c6ec688fef",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "68ce99a4e1761c06e5f31f6674ee46fef1bbf44b",
|
||||
"revision": "a0015e0f59bdec57f732c805238172bd49406ab5",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ddfd98cdafefaa1b60273d5568b8dbd13730dae"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="07c383a786f188904311a37f6062c2cb84c9b61d">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="c5425d9f1f5184731a59ed4bc99295acbde30390"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="581de383687dc441a878d2c91a0167c6ec688fef"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4d9fbc08e87731447c19e96e13d8c7444baafcca"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -358,6 +358,8 @@ function init() {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}).catch(err => {
|
||||
error("Failed to get the signed in user: " + err);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ let gFxAccounts = {
|
||||
"weave:service:setup-complete",
|
||||
"weave:ui:login:error",
|
||||
"fxa-migration:state-changed",
|
||||
this.FxAccountsCommon.ONLOGIN_NOTIFICATION,
|
||||
this.FxAccountsCommon.ONVERIFIED_NOTIFICATION,
|
||||
this.FxAccountsCommon.ONLOGOUT_NOTIFICATION,
|
||||
"weave:notification:removed",
|
||||
@ -222,10 +223,11 @@ let gFxAccounts = {
|
||||
this.updateMigrationNotification();
|
||||
},
|
||||
|
||||
// Note that updateAppMenuItem() returns a Promise that's only used by tests.
|
||||
updateAppMenuItem: function () {
|
||||
if (this._migrationInfo) {
|
||||
this.updateAppMenuItemForMigration();
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let profileInfoEnabled = false;
|
||||
@ -241,7 +243,7 @@ let gFxAccounts = {
|
||||
// state once migration is complete.
|
||||
this.panelUIFooter.hidden = true;
|
||||
this.panelUIFooter.removeAttribute("fxastatus");
|
||||
return;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.panelUIFooter.hidden = false;
|
||||
@ -311,12 +313,18 @@ let gFxAccounts = {
|
||||
}
|
||||
}
|
||||
|
||||
// Calling getSignedInUserProfile() without a user logged in causes log
|
||||
// noise that looks like an actual error...
|
||||
fxAccounts.getSignedInUser().then(userData => {
|
||||
return fxAccounts.getSignedInUser().then(userData => {
|
||||
// userData may be null here when the user is not signed-in, but that's expected
|
||||
updateWithUserData(userData);
|
||||
return userData ? fxAccounts.getSignedInUserProfile() : null;
|
||||
// unverified users cause us to spew log errors fetching an OAuth token
|
||||
// to fetch the profile, so don't even try in that case.
|
||||
if (!userData || !userData.verified || !profileInfoEnabled) {
|
||||
return null; // don't even try to grab the profile.
|
||||
}
|
||||
return fxAccounts.getSignedInUserProfile().catch(err => {
|
||||
// Not fetching the profile is sad but the FxA logs will already have noise.
|
||||
return null;
|
||||
});
|
||||
}).then(profile => {
|
||||
if (!profile) {
|
||||
return;
|
||||
@ -327,7 +335,7 @@ let gFxAccounts = {
|
||||
// The most likely scenario is a user logged out, so reflect that.
|
||||
// Bug 995134 calls for better errors so we could retry if we were
|
||||
// sure this was the failure reason.
|
||||
this.FxAccountsCommon.log.error("Error updating FxA profile", error);
|
||||
this.FxAccountsCommon.log.error("Error updating FxA account info", error);
|
||||
updateWithUserData(null);
|
||||
});
|
||||
},
|
||||
|
@ -29,7 +29,7 @@ let TrackingProtection = {
|
||||
this.disabledTooltipText =
|
||||
gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip");
|
||||
|
||||
this.enabledHistogram.add(this.enabledGlobally);
|
||||
this.enabledHistogramAdd(this.enabledGlobally);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
@ -55,12 +55,25 @@ let TrackingProtection = {
|
||||
this.container.hidden = !this.enabled;
|
||||
},
|
||||
|
||||
get enabledHistogram() {
|
||||
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED");
|
||||
enabledHistogramAdd(value) {
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
return;
|
||||
}
|
||||
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").add(value);
|
||||
},
|
||||
|
||||
get eventsHistogram() {
|
||||
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
|
||||
eventsHistogramAdd(value) {
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
return;
|
||||
}
|
||||
Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS").add(value);
|
||||
},
|
||||
|
||||
shieldHistogramAdd(value) {
|
||||
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
return;
|
||||
}
|
||||
Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD").add(value);
|
||||
},
|
||||
|
||||
onSecurityChange(state, isSimulated) {
|
||||
@ -91,18 +104,25 @@ let TrackingProtection = {
|
||||
gPrefService.savePrefFile(null);
|
||||
this.showIntroPanel();
|
||||
}
|
||||
|
||||
this.shieldHistogramAdd(2);
|
||||
} else if (isAllowing) {
|
||||
this.icon.setAttribute("tooltiptext", this.disabledTooltipText);
|
||||
this.icon.setAttribute("state", "loaded-tracking-content");
|
||||
this.content.setAttribute("state", "loaded-tracking-content");
|
||||
|
||||
this.shieldHistogramAdd(1);
|
||||
} else {
|
||||
this.icon.removeAttribute("tooltiptext");
|
||||
this.icon.removeAttribute("state");
|
||||
this.content.removeAttribute("state");
|
||||
|
||||
// We didn't show the shield
|
||||
this.shieldHistogramAdd(0);
|
||||
}
|
||||
|
||||
// Telemetry for state change.
|
||||
this.eventsHistogram.add(0);
|
||||
this.eventsHistogramAdd(0);
|
||||
},
|
||||
|
||||
disableForCurrentPage() {
|
||||
@ -124,7 +144,7 @@ let TrackingProtection = {
|
||||
}
|
||||
|
||||
// Telemetry for disable protection.
|
||||
this.eventsHistogram.add(1);
|
||||
this.eventsHistogramAdd(1);
|
||||
|
||||
// Hide the control center.
|
||||
document.getElementById("identity-popup").hidePopup();
|
||||
@ -147,7 +167,7 @@ let TrackingProtection = {
|
||||
}
|
||||
|
||||
// Telemetry for enable protection.
|
||||
this.eventsHistogram.add(2);
|
||||
this.eventsHistogramAdd(2);
|
||||
|
||||
// Hide the control center.
|
||||
document.getElementById("identity-popup").hidePopup();
|
||||
|
@ -6869,10 +6869,6 @@ var gIdentityHandler = {
|
||||
nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT |
|
||||
nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT)) {
|
||||
this.showBadContentDoorhanger(state);
|
||||
} else if (TrackingProtection.enabled) {
|
||||
// We didn't show the shield
|
||||
Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD")
|
||||
.add(0);
|
||||
}
|
||||
},
|
||||
|
||||
@ -6894,19 +6890,6 @@ var gIdentityHandler = {
|
||||
// default
|
||||
let iconState = "bad-content-blocked-notification-icon";
|
||||
|
||||
// Telemetry for whether the shield was due to tracking protection or not
|
||||
let histogram = Services.telemetry.getHistogramById
|
||||
("TRACKING_PROTECTION_SHIELD");
|
||||
if (state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) {
|
||||
histogram.add(1);
|
||||
} else if (state &
|
||||
Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) {
|
||||
histogram.add(2);
|
||||
} else if (gPrefService.getBoolPref("privacy.trackingprotection.enabled")) {
|
||||
// Tracking protection is enabled but no tracking elements are loaded,
|
||||
// the shield is due to mixed content.
|
||||
histogram.add(3);
|
||||
}
|
||||
if (state &
|
||||
(Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT |
|
||||
Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT)) {
|
||||
|
@ -303,6 +303,8 @@ skip-if = true # browser_drag.js is disabled, as it needs to be updated for the
|
||||
[browser_focusonkeydown.js]
|
||||
[browser_fullscreen-window-open.js]
|
||||
skip-if = buildapp == 'mulet' || e10s || os == "linux" # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly. Linux: Intermittent failures - bug 941575.
|
||||
[browser_fxaccounts.js]
|
||||
support-files = fxa_profile_handler.sjs
|
||||
[browser_fxa_migrate.js]
|
||||
[browser_fxa_oauth.js]
|
||||
[browser_fxa_web_channel.js]
|
||||
@ -436,6 +438,10 @@ support-files =
|
||||
benignPage.html
|
||||
[browser_trackingUI_5.js]
|
||||
tags = trackingprotection
|
||||
support-files =
|
||||
trackingPage.html
|
||||
[browser_trackingUI_telemetry.js]
|
||||
tags = trackingprotection
|
||||
support-files =
|
||||
trackingPage.html
|
||||
[browser_typeAheadFind.js]
|
||||
|
258
browser/base/content/test/general/browser_fxaccounts.js
Normal file
258
browser/base/content/test/general/browser_fxaccounts.js
Normal file
@ -0,0 +1,258 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let {Log} = Cu.import("resource://gre/modules/Log.jsm", {});
|
||||
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
let {fxAccounts} = Cu.import("resource://gre/modules/FxAccounts.jsm", {});
|
||||
let FxAccountsCommon = {};
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js", FxAccountsCommon);
|
||||
|
||||
const TEST_ROOT = "http://example.com/browser/browser/base/content/test/general/";
|
||||
|
||||
// instrument gFxAccounts to send observer notifications when it's done
|
||||
// what it does.
|
||||
(function() {
|
||||
let unstubs = {}; // The original functions we stub out.
|
||||
|
||||
// The stub functions.
|
||||
let stubs = {
|
||||
updateAppMenuItem: function() {
|
||||
return unstubs['updateAppMenuItem'].call(gFxAccounts).then(() => {
|
||||
Services.obs.notifyObservers(null, "test:browser_fxaccounts:updateAppMenuItem", null);
|
||||
});
|
||||
},
|
||||
// Opening preferences is trickier than it should be as leaks are reported
|
||||
// due to the promises it fires off at load time and there's no clear way to
|
||||
// know when they are done.
|
||||
// So just ensure openPreferences is called rather than whether it opens.
|
||||
openPreferences: function() {
|
||||
Services.obs.notifyObservers(null, "test:browser_fxaccounts:openPreferences", null);
|
||||
}
|
||||
};
|
||||
|
||||
for (let name in stubs) {
|
||||
unstubs[name] = gFxAccounts[name];
|
||||
gFxAccounts[name] = stubs[name];
|
||||
}
|
||||
// and undo our damage at the end.
|
||||
registerCleanupFunction(() => {
|
||||
for (let name in unstubs) {
|
||||
gFxAccounts[name] = unstubs[name];
|
||||
}
|
||||
stubs = unstubs = null;
|
||||
});
|
||||
})();
|
||||
|
||||
// Other setup/cleanup
|
||||
let newTab;
|
||||
|
||||
Services.prefs.setCharPref("identity.fxaccounts.remote.signup.uri",
|
||||
TEST_ROOT + "accounts_testRemoteCommands.html");
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("identity.fxaccounts.remote.signup.uri");
|
||||
Services.prefs.clearUserPref("identity.fxaccounts.remote.profile.uri");
|
||||
gBrowser.removeTab(newTab);
|
||||
});
|
||||
|
||||
add_task(function* initialize() {
|
||||
// Set a new tab with something other than about:blank, so it doesn't get reused.
|
||||
// We must wait for it to load or the promiseTabOpen() call in the next test
|
||||
// gets confused.
|
||||
newTab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla", {animate: false});
|
||||
yield promiseTabLoaded(newTab);
|
||||
});
|
||||
|
||||
// The elements we care about.
|
||||
let panelUILabel = document.getElementById("PanelUI-fxa-label");
|
||||
let panelUIStatus = document.getElementById("PanelUI-fxa-status");
|
||||
let panelUIFooter = document.getElementById("PanelUI-footer-fxa");
|
||||
|
||||
// The tests
|
||||
add_task(function* test_nouser() {
|
||||
let user = yield fxAccounts.getSignedInUser();
|
||||
Assert.strictEqual(user, null, "start with no user signed in");
|
||||
let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem");
|
||||
Services.obs.notifyObservers(null, this.FxAccountsCommon.ONLOGOUT_NOTIFICATION, null);
|
||||
yield promiseUpdateDone;
|
||||
|
||||
// Check the world - the FxA footer area is visible as it is offering a signin.
|
||||
Assert.ok(isFooterVisible())
|
||||
|
||||
Assert.equal(panelUILabel.getAttribute("label"), panelUIStatus.getAttribute("defaultlabel"));
|
||||
Assert.ok(!panelUIStatus.hasAttribute("tooltiptext"), "no tooltip when signed out");
|
||||
Assert.ok(!panelUIFooter.hasAttribute("fxastatus"), "no fxsstatus when signed out");
|
||||
Assert.ok(!panelUIFooter.hasAttribute("fxaprofileimage"), "no fxaprofileimage when signed out");
|
||||
|
||||
let promiseOpen = promiseTabOpen("about:accounts?entryPoint=menupanel");
|
||||
panelUIStatus.click();
|
||||
yield promiseOpen;
|
||||
});
|
||||
|
||||
/*
|
||||
XXX - Bug 1191162 - need a better hawk mock story or this will leak in debug builds.
|
||||
|
||||
add_task(function* test_unverifiedUser() {
|
||||
let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem");
|
||||
yield setSignedInUser(false); // this will fire the observer that does the update.
|
||||
yield promiseUpdateDone;
|
||||
|
||||
// Check the world.
|
||||
Assert.ok(isFooterVisible())
|
||||
|
||||
Assert.equal(panelUILabel.getAttribute("label"), "foo@example.com");
|
||||
Assert.equal(panelUIStatus.getAttribute("tooltiptext"),
|
||||
panelUIStatus.getAttribute("signedinTooltiptext"));
|
||||
Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin");
|
||||
let promisePreferencesOpened = promiseObserver("test:browser_fxaccounts:openPreferences");
|
||||
panelUIStatus.click();
|
||||
yield promisePreferencesOpened
|
||||
yield signOut();
|
||||
});
|
||||
*/
|
||||
|
||||
add_task(function* test_verifiedUserEmptyProfile() {
|
||||
// We see 2 updateAppMenuItem() calls - one for the signedInUser and one after
|
||||
// we first fetch the profile. We want them both to fire or we aren't testing
|
||||
// the state we think we are testing.
|
||||
let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem", 2);
|
||||
configureProfileURL({}); // successful but empty profile.
|
||||
yield setSignedInUser(true); // this will fire the observer that does the update.
|
||||
yield promiseUpdateDone;
|
||||
|
||||
// Check the world.
|
||||
Assert.ok(isFooterVisible())
|
||||
Assert.equal(panelUILabel.getAttribute("label"), "foo@example.com");
|
||||
Assert.equal(panelUIStatus.getAttribute("tooltiptext"),
|
||||
panelUIStatus.getAttribute("signedinTooltiptext"));
|
||||
Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin");
|
||||
|
||||
let promisePreferencesOpened = promiseObserver("test:browser_fxaccounts:openPreferences");
|
||||
panelUIStatus.click();
|
||||
yield promisePreferencesOpened;
|
||||
yield signOut();
|
||||
});
|
||||
|
||||
add_task(function* test_verifiedUserDisplayName() {
|
||||
let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem", 2);
|
||||
configureProfileURL({ displayName: "Test User Display Name" });
|
||||
yield setSignedInUser(true); // this will fire the observer that does the update.
|
||||
yield promiseUpdateDone;
|
||||
|
||||
Assert.ok(isFooterVisible())
|
||||
Assert.equal(panelUILabel.getAttribute("label"), "Test User Display Name");
|
||||
Assert.equal(panelUIStatus.getAttribute("tooltiptext"),
|
||||
panelUIStatus.getAttribute("signedinTooltiptext"));
|
||||
Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin");
|
||||
yield signOut();
|
||||
});
|
||||
|
||||
add_task(function* test_verifiedUserProfileFailure() {
|
||||
// profile failure means only one observer fires.
|
||||
let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem", 1);
|
||||
configureProfileURL(null, 500);
|
||||
yield setSignedInUser(true); // this will fire the observer that does the update.
|
||||
yield promiseUpdateDone;
|
||||
|
||||
Assert.ok(isFooterVisible())
|
||||
Assert.equal(panelUILabel.getAttribute("label"), "foo@example.com");
|
||||
Assert.equal(panelUIStatus.getAttribute("tooltiptext"),
|
||||
panelUIStatus.getAttribute("signedinTooltiptext"));
|
||||
Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin");
|
||||
yield signOut();
|
||||
});
|
||||
|
||||
// Helpers.
|
||||
function isFooterVisible() {
|
||||
let style = window.getComputedStyle(panelUIFooter);
|
||||
return style.getPropertyValue("display") == "flex";
|
||||
}
|
||||
|
||||
function configureProfileURL(profile, responseStatus = 200) {
|
||||
let responseBody = profile ? JSON.stringify(profile) : "";
|
||||
let url = TEST_ROOT + "fxa_profile_handler.sjs?" +
|
||||
"responseStatus=" + responseStatus +
|
||||
"responseBody=" + responseBody +
|
||||
// This is a bit cheeky - the FxA code will just append "/profile"
|
||||
// to the preference value. We arrange for this to be seen by our
|
||||
//.sjs as part of the query string.
|
||||
"&path=";
|
||||
|
||||
Services.prefs.setCharPref("identity.fxaccounts.remote.profile.uri", url);
|
||||
}
|
||||
|
||||
function promiseObserver(topic, count = 1) {
|
||||
return new Promise(resolve => {
|
||||
let obs = (subject, topic, data) => {
|
||||
if (--count == 0) {
|
||||
Services.obs.removeObserver(obs, topic);
|
||||
resolve(subject);
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(obs, topic, false);
|
||||
});
|
||||
}
|
||||
|
||||
// Stolen from browser_aboutHome.js
|
||||
function promiseWaitForEvent(node, type, capturing) {
|
||||
return new Promise((resolve) => {
|
||||
node.addEventListener(type, function listener(event) {
|
||||
node.removeEventListener(type, listener, capturing);
|
||||
resolve(event);
|
||||
}, capturing);
|
||||
});
|
||||
}
|
||||
|
||||
let promiseTabOpen = Task.async(function*(urlBase) {
|
||||
info("Waiting for tab to open...");
|
||||
let event = yield promiseWaitForEvent(gBrowser.tabContainer, "TabOpen", true);
|
||||
let tab = event.target;
|
||||
yield promiseTabLoadEvent(tab);
|
||||
ok(tab.linkedBrowser.currentURI.spec.startsWith(urlBase),
|
||||
"Got " + tab.linkedBrowser.currentURI.spec + ", expecting " + urlBase);
|
||||
let whenUnloaded = promiseTabUnloaded(tab);
|
||||
gBrowser.removeTab(tab);
|
||||
yield whenUnloaded;
|
||||
});
|
||||
|
||||
function promiseTabUnloaded(tab)
|
||||
{
|
||||
return new Promise(resolve => {
|
||||
info("Wait for tab to unload");
|
||||
function handle(event) {
|
||||
tab.linkedBrowser.removeEventListener("unload", handle, true);
|
||||
info("Got unload event");
|
||||
resolve(event);
|
||||
}
|
||||
tab.linkedBrowser.addEventListener("unload", handle, true, true);
|
||||
});
|
||||
}
|
||||
|
||||
// FxAccounts helpers.
|
||||
function setSignedInUser(verified) {
|
||||
let data = {
|
||||
email: "foo@example.com",
|
||||
uid: "1234@lcip.org",
|
||||
assertion: "foobar",
|
||||
sessionToken: "dead",
|
||||
kA: "beef",
|
||||
kB: "cafe",
|
||||
verified: verified,
|
||||
|
||||
oauthTokens: {
|
||||
// a token for the profile server.
|
||||
profile: "key value",
|
||||
}
|
||||
}
|
||||
return fxAccounts.setSignedInUser(data);
|
||||
}
|
||||
|
||||
let signOut = Task.async(function* () {
|
||||
// This test needs to make sure that any updates for the logout have
|
||||
// completed before starting the next test, or we see the observer
|
||||
// notifications get out of sync.
|
||||
let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateAppMenuItem");
|
||||
// we always want a "localOnly" signout here...
|
||||
yield fxAccounts.signOut(true);
|
||||
yield promiseUpdateDone;
|
||||
});
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Test telemetry for Tracking Protection
|
||||
*/
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
const PREF = "privacy.trackingprotection.enabled";
|
||||
const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
|
||||
const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
|
||||
const {UrlClassifierTestUtils} = Cu.import("resource://testing-common/UrlClassifierTestUtils.jsm", {});
|
||||
|
||||
/**
|
||||
* Enable local telemetry recording for the duration of the tests.
|
||||
*/
|
||||
let oldCanRecord = Services.telemetry.canRecordExtended;
|
||||
Services.telemetry.canRecordExtended = true;
|
||||
Services.prefs.setBoolPref(PREF, false);
|
||||
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").clear();
|
||||
registerCleanupFunction(function () {
|
||||
UrlClassifierTestUtils.cleanupTestTrackers();
|
||||
Services.telemetry.canRecordExtended = oldCanRecord;
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
});
|
||||
|
||||
function getShieldHistogram() {
|
||||
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD");
|
||||
}
|
||||
|
||||
function getEnabledHistogram() {
|
||||
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED");
|
||||
}
|
||||
|
||||
function getEventsHistogram() {
|
||||
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
|
||||
}
|
||||
|
||||
function getShieldCounts() {
|
||||
return getShieldHistogram().snapshot().counts;
|
||||
}
|
||||
|
||||
function getEnabledCounts() {
|
||||
return getEnabledHistogram().snapshot().counts;
|
||||
}
|
||||
|
||||
function getEventCounts() {
|
||||
return getEventsHistogram().snapshot().counts;
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
yield UrlClassifierTestUtils.addTestTrackers();
|
||||
|
||||
let TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
|
||||
ok(TrackingProtection, "TP is attached to the browser window");
|
||||
ok(!TrackingProtection.enabled, "TP is not enabled");
|
||||
|
||||
// Open a window with TP disabled to make sure 'enabled' is logged correctly.
|
||||
let newWin = yield promiseOpenAndLoadWindow({}, true);
|
||||
yield promiseWindowClosed(newWin);
|
||||
|
||||
is(getEnabledCounts()[0], 1, "TP was disabled once on start up");
|
||||
is(getEnabledCounts()[1], 0, "TP was not enabled on start up");
|
||||
|
||||
// Enable TP so the next browser to open will log 'enabled'
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* testNewWindow() {
|
||||
let newWin = yield promiseOpenAndLoadWindow({}, true);
|
||||
let tab = newWin.gBrowser.selectedTab = newWin.gBrowser.addTab();
|
||||
let TrackingProtection = newWin.TrackingProtection;
|
||||
ok(TrackingProtection, "TP is attached to the browser window");
|
||||
|
||||
is(getEnabledCounts()[0], 1, "TP was disabled once on start up");
|
||||
is(getEnabledCounts()[1], 1, "TP was enabled once on start up");
|
||||
|
||||
// Reset these to make counting easier
|
||||
getEventsHistogram().clear();
|
||||
getShieldHistogram().clear();
|
||||
|
||||
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
|
||||
is(getEventCounts()[0], 1, "Total page loads");
|
||||
is(getEventCounts()[1], 0, "Disable actions");
|
||||
is(getEventCounts()[2], 0, "Enable actions");
|
||||
is(getShieldCounts()[0], 1, "Page loads without tracking");
|
||||
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
// Note that right now the events and shield histogram is not measuring what
|
||||
// you might think. Since onSecurityChange fires twice for a tracking page,
|
||||
// the total page loads count is double counting, and the shield count
|
||||
// (which is meant to measure times when the shield wasn't shown) fires even
|
||||
// when tracking elements exist on the page.
|
||||
todo_is(getEventCounts()[0], 2, "FIXME: TOTAL PAGE LOADS IS DOUBLE COUNTING");
|
||||
is(getEventCounts()[1], 0, "Disable actions");
|
||||
is(getEventCounts()[2], 0, "Enable actions");
|
||||
todo_is(getShieldCounts()[0], 1, "FIXME: TOTAL PAGE LOADS WITHOUT TRACKING IS DOUBLE COUNTING");
|
||||
|
||||
info("Disable TP for the page (which reloads the page)");
|
||||
let tabReloadPromise = promiseTabLoadEvent(tab);
|
||||
newWin.document.querySelector("#tracking-action-unblock").doCommand();
|
||||
yield tabReloadPromise;
|
||||
todo_is(getEventCounts()[0], 3, "FIXME: TOTAL PAGE LOADS IS DOUBLE COUNTING");
|
||||
is(getEventCounts()[1], 1, "Disable actions");
|
||||
is(getEventCounts()[2], 0, "Enable actions");
|
||||
todo_is(getShieldCounts()[0], 1, "FIXME: TOTAL PAGE LOADS WITHOUT TRACKING IS DOUBLE COUNTING");
|
||||
|
||||
info("Re-enable TP for the page (which reloads the page)");
|
||||
tabReloadPromise = promiseTabLoadEvent(tab);
|
||||
newWin.document.querySelector("#tracking-action-block").doCommand();
|
||||
yield tabReloadPromise;
|
||||
todo_is(getEventCounts()[0], 4, "FIXME: TOTAL PAGE LOADS IS DOUBLE COUNTING");
|
||||
is(getEventCounts()[1], 1, "Disable actions");
|
||||
is(getEventCounts()[2], 1, "Enable actions");
|
||||
todo_is(getShieldCounts()[0], 1, "FIXME: TOTAL PAGE LOADS WITHOUT TRACKING IS DOUBLE COUNTING");
|
||||
|
||||
yield promiseWindowClosed(newWin);
|
||||
|
||||
// Reset these to make counting easier for the next test
|
||||
getEventsHistogram().clear();
|
||||
getShieldHistogram().clear();
|
||||
getEnabledHistogram().clear();
|
||||
});
|
||||
|
||||
add_task(function* testPrivateBrowsing() {
|
||||
let privateWin = yield promiseOpenAndLoadWindow({private: true}, true);
|
||||
let tab = privateWin.gBrowser.selectedTab = privateWin.gBrowser.addTab();
|
||||
let TrackingProtection = privateWin.TrackingProtection;
|
||||
ok(TrackingProtection, "TP is attached to the browser window");
|
||||
|
||||
// Do a bunch of actions and make sure that no telemetry data is gathered
|
||||
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
|
||||
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
|
||||
let tabReloadPromise = promiseTabLoadEvent(tab);
|
||||
privateWin.document.querySelector("#tracking-action-unblock").doCommand();
|
||||
yield tabReloadPromise;
|
||||
tabReloadPromise = promiseTabLoadEvent(tab);
|
||||
privateWin.document.querySelector("#tracking-action-block").doCommand();
|
||||
yield tabReloadPromise;
|
||||
|
||||
// Sum up all the counts to make sure that nothing got logged
|
||||
is(getEnabledCounts().reduce((p,c)=>p+c), 0, "Telemetry logging off in PB mode");
|
||||
is(getEventCounts().reduce((p,c)=>p+c), 0, "Telemetry logging off in PB mode");
|
||||
is(getShieldCounts().reduce((p,c)=>p+c), 0, "Telemetry logging off in PB mode");
|
||||
|
||||
yield promiseWindowClosed(privateWin);
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Dummy test page</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
|
||||
</head>
|
||||
<body>
|
||||
<p>Dummy test page</p>
|
||||
|
34
browser/base/content/test/general/fxa_profile_handler.sjs
Normal file
34
browser/base/content/test/general/fxa_profile_handler.sjs
Normal file
@ -0,0 +1,34 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This is basically an echo server!
|
||||
// We just grab responseStatus and responseBody query params!
|
||||
|
||||
function reallyHandleRequest(request, response) {
|
||||
var query = "?" + request.queryString;
|
||||
|
||||
var responseStatus = 200;
|
||||
var match = /responseStatus=([^&]*)/.exec(query);
|
||||
if (match) {
|
||||
responseStatus = parseInt(match[1]);
|
||||
}
|
||||
|
||||
var responseBody = "";
|
||||
match = /responseBody=([^&]*)/.exec(query);
|
||||
if (match) {
|
||||
responseBody = decodeURIComponent(match[1]);
|
||||
}
|
||||
|
||||
response.setStatusLine("1.0", responseStatus, "OK");
|
||||
response.write(responseBody);
|
||||
}
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
try {
|
||||
reallyHandleRequest(request, response);
|
||||
} catch (e) {
|
||||
response.setStatusLine("1.0", 500, "NotOK");
|
||||
response.write("Error handling request: " + e);
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
"browser": true,
|
||||
"mocha": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"globals": {
|
||||
"_": false,
|
||||
"$": false,
|
||||
@ -35,31 +36,75 @@
|
||||
// problems they find, one at a time.
|
||||
|
||||
// Eslint built-in rules are documented at <http://eslint.org/docs/rules/>
|
||||
"camelcase": 0, // TODO: Remove (use default)
|
||||
"callback-return": 0, // TBD
|
||||
"camelcase": 0, // TODO: set to 2
|
||||
"comma-spacing": 2,
|
||||
"computed-property-spacing": [2, "never"],
|
||||
"consistent-return": 0, // TODO: Remove (use default)
|
||||
"consistent-return": 0, // TODO: set to 2
|
||||
"curly": [2, "all"],
|
||||
dot-location: 0, // [2, property],
|
||||
"eol-last": 2,
|
||||
"eqeqeq": 0, // TBD. Might need to be separate for content & chrome
|
||||
"global-strict": 0, // Leave as zero (this will be unsupported in eslint 1.0.0)
|
||||
"key-spacing": [2, {"beforeColon": false, "afterColon": true }],
|
||||
"linebreak-style": [2, "unix"],
|
||||
"new-cap": 0, // TODO: Remove (use default)
|
||||
"no-catch-shadow": 0, // TODO: Remove (use default)
|
||||
"new-cap": 0, // TODO: set to 2
|
||||
"new-parens": 2,
|
||||
"no-alert": 2,
|
||||
"no-array-constructor": 2,
|
||||
"no-caller": 2,
|
||||
"no-catch-shadow": 0, // TODO: set to 2
|
||||
"no-class-assign": 2,
|
||||
"no-const-assign": 2,
|
||||
"no-console": 0, // Leave as 0. We use console logging in content code.
|
||||
"no-empty": 0, // TODO: Remove (use default)
|
||||
"no-empty": 0, // TODO: set to 2
|
||||
"no-empty-label": 2,
|
||||
"no-eval": 2,
|
||||
"no-extend-native": 2, // XXX
|
||||
"no-extra-bind": 0, // Leave as 0
|
||||
"no-extra-parens": 0, // TODO: (bug?) [2, "functions"],
|
||||
"no-implied-eval": 2,
|
||||
"no-invalid-this": 0, // TBD
|
||||
"no-iterator": 2,
|
||||
"no-label-var": 2,
|
||||
"no-labels": 2,
|
||||
"no-lone-blocks": 2,
|
||||
"no-loop-func": 2,
|
||||
"no-multi-spaces": 0, // TBD.
|
||||
"no-new": 0, // TODO: Remove (use default)
|
||||
"no-return-assign": 0, // TODO: Remove (use default)
|
||||
"no-multi-str": 2,
|
||||
"no-native-reassign": 2,
|
||||
"no-new": 2,
|
||||
"no-new-func": 2,
|
||||
"no-new-object": 2,
|
||||
"no-new-wrappers": 2,
|
||||
"no-octal-escape": 2,
|
||||
"no-process-exit": 2,
|
||||
"no-proto": 2,
|
||||
"no-return-assign": 2,
|
||||
"no-script-url": 2,
|
||||
"no-sequences": 2,
|
||||
"no-shadow": 2,
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-spaced-func": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-underscore-dangle": 0, // Leave as 0. Commonly used for private variables.
|
||||
"no-unexpected-multiline": 2,
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unused-expressions": 0, // TODO: Remove (use default)
|
||||
"no-unused-vars": 0, // TODO: Remove (use default)
|
||||
"no-use-before-define": 0, // TODO: Remove (use default)
|
||||
"no-unused-expressions": 0, // TODO: Set to 2
|
||||
"no-unused-vars": 0, // TODO: Set to 2
|
||||
"no-use-before-define": 0, // TODO: Set to 2
|
||||
"no-useless-call": 2,
|
||||
"no-with": 2,
|
||||
"object-curly-spacing": 0, // [2, "always"],
|
||||
"quotes": [2, "double", "avoid-escape"],
|
||||
"semi": 2,
|
||||
"semi-spacing": [2, {"before": false, "after": true}],
|
||||
"space-infix-ops": 2,
|
||||
"space-return-throw-case": 2,
|
||||
"space-unary-ops": [2, {"words": true, "nonwords": false}],
|
||||
"spaced-comment": [2, "always"],
|
||||
"strict": [2, "function"],
|
||||
"yoda": [2, "never"],
|
||||
// eslint-plugin-react rules. These are documented at
|
||||
// <https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules>
|
||||
"react/jsx-quotes": [2, "double", "avoid-escape"],
|
||||
@ -67,6 +112,7 @@
|
||||
"react/jsx-sort-props": 2,
|
||||
"react/jsx-sort-prop-types": 2,
|
||||
"react/jsx-uses-vars": 2,
|
||||
"react/jsx-no-duplicate-props": 2,
|
||||
// Need to fix the couple of instances which don't
|
||||
// currently pass this rule.
|
||||
"react/no-did-mount-set-state": 0,
|
||||
|
@ -56,9 +56,12 @@
|
||||
"Assert": false,
|
||||
},
|
||||
"rules": {
|
||||
"arrow-parens": 0, // TBD
|
||||
"arrow-spacing": 2,
|
||||
"generator-star-spacing": [2, "after"],
|
||||
// We should fix the errors and enable this (set to 2)
|
||||
"no-var": 0,
|
||||
"require-yield": 0, // TODO: Set to 2.
|
||||
"strict": [2, "global"]
|
||||
}
|
||||
}
|
||||
|
@ -283,3 +283,31 @@ html[dir="rtl"] .contacts-gravatar-promo > .button-close {
|
||||
right: auto;
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.contact-controls {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.contact-controls > .button {
|
||||
padding: .5em;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.button.primary {
|
||||
background: #00A9DC;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.button.secondary {
|
||||
background: #EBEBEB;
|
||||
color: #4D4D4D;
|
||||
}
|
||||
|
||||
.contact-controls > .primary {
|
||||
flex: 5;
|
||||
}
|
||||
|
||||
.contact-controls > .secondary {
|
||||
flex: 3;
|
||||
}
|
||||
|
@ -435,10 +435,7 @@ body {
|
||||
border-radius: 2px;
|
||||
min-height: 26px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.button > .button-caption {
|
||||
vertical-align: middle;
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
@ -641,7 +638,6 @@ html[dir="rtl"] .generate-url-spinner {
|
||||
/* Undo the start border + padding so that unhovered dnd-status is aligned
|
||||
as if there was no additional spacing. */
|
||||
-moz-margin-start: calc(-1px + -4px);
|
||||
font-size: .9em;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
}
|
||||
@ -651,8 +647,33 @@ html[dir="rtl"] .generate-url-spinner {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
/* Status badges -- Available/Unavailable */
|
||||
.status-available:before,
|
||||
.status-unavailable:before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: bottom;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
-moz-margin-end: .2rem;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .dropdown-menu-item.status-available:before,
|
||||
html[dir="rtl"] .dropdown-menu-item.status-unavailable:before {
|
||||
margin-right: -3px;
|
||||
}
|
||||
|
||||
.status-available:before {
|
||||
background-image: url("../shared/img/icons-16x16.svg#status-available");
|
||||
}
|
||||
|
||||
.status-unavailable:before {
|
||||
background-image: url("../shared/img/icons-16x16.svg#status-unavailable");
|
||||
}
|
||||
|
||||
/* Status badges -- Available/Unavailable */
|
||||
.status {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
@ -661,14 +682,6 @@ html[dir="rtl"] .generate-url-spinner {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.status-available {
|
||||
background-color: #6cb23e;
|
||||
}
|
||||
|
||||
.status-dnd {
|
||||
border: 1px solid #888;
|
||||
}
|
||||
|
||||
/* Sign in/up link */
|
||||
|
||||
.signin-link {
|
||||
@ -677,42 +690,36 @@ html[dir="rtl"] .generate-url-spinner {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.signin-link a {
|
||||
font-size: .9em;
|
||||
.signin-link > a {
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.footer-signin-separator {
|
||||
border-right: 1px solid #aaa;
|
||||
height: 16px;
|
||||
margin: 0 1em;
|
||||
color: #00A9DC;
|
||||
}
|
||||
|
||||
/* Settings (gear) menu */
|
||||
|
||||
.button-settings {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background-color: #a5a;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: .9em;
|
||||
cursor: pointer;
|
||||
background: transparent url(../shared/img/svg/glyph-settings-16x16.svg) no-repeat center center;
|
||||
background-size: contain;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
vertical-align: middle;
|
||||
background: transparent url("../shared/img/icons-10x10.svg#settings-cog");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
-moz-margin-start: .5em;
|
||||
}
|
||||
|
||||
.footer .button-settings {
|
||||
opacity: .6; /* used to "grey" the icon a little */
|
||||
.user-details .dropdown-menu {
|
||||
bottom: 1.3rem; /* Just above the text. */
|
||||
left: -5px; /* Compensate for button padding. */
|
||||
}
|
||||
|
||||
html[dir="rtl"] .user-details .dropdown-menu {
|
||||
right: -5px;
|
||||
}
|
||||
|
||||
.settings-menu .dropdown-menu {
|
||||
@ -721,7 +728,7 @@ html[dir="rtl"] .generate-url-spinner {
|
||||
set by .dropdown-menu */
|
||||
top: auto;
|
||||
left: auto;
|
||||
bottom: -8px;
|
||||
bottom: 1.1em;
|
||||
right: 14px;
|
||||
}
|
||||
|
||||
@ -735,34 +742,32 @@ html[dir="rtl"] .settings-menu .dropdown-menu {
|
||||
|
||||
.settings-menu .icon {
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
-moz-margin-end: 1em;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.settings-menu .icon-settings {
|
||||
background: transparent url(../shared/img/svg/glyph-settings-16x16.svg) no-repeat center center;
|
||||
}
|
||||
|
||||
.settings-menu .icon-tour {
|
||||
background: transparent url("../shared/img/icons-16x16.svg#tour") no-repeat center center;
|
||||
background-image: url("../shared/img/icons-16x16.svg#tour");
|
||||
}
|
||||
|
||||
.settings-menu .icon-account {
|
||||
background: transparent url(../shared/img/svg/glyph-account-16x16.svg) no-repeat center center;
|
||||
background-image: url(../shared/img/svg/glyph-account-16x16.svg);
|
||||
}
|
||||
|
||||
.settings-menu .icon-signin {
|
||||
background: transparent url(../shared/img/svg/glyph-signin-16x16.svg) no-repeat center center;
|
||||
background-image: url(../shared/img/svg/glyph-signin-16x16.svg);
|
||||
}
|
||||
|
||||
.settings-menu .icon-signout {
|
||||
background: transparent url(../shared/img/svg/glyph-signout-16x16.svg) no-repeat center center;
|
||||
background-image: url(../shared/img/svg/glyph-signout-16x16.svg);
|
||||
}
|
||||
|
||||
.settings-menu .icon-help {
|
||||
background: transparent url(../shared/img/svg/glyph-help-16x16.svg) no-repeat center center;
|
||||
background-image: url(../shared/img/svg/glyph-help-16x16.svg);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
@ -774,11 +779,10 @@ html[dir="rtl"] .settings-menu .dropdown-menu {
|
||||
justify-content: space-between;
|
||||
align-content: stretch;
|
||||
align-items: center;
|
||||
font-size: 1em;
|
||||
border-top: 1px solid #D1D1D1;
|
||||
background-color: #eaeaea;
|
||||
color: #7f7f7f;
|
||||
padding: .5rem 1rem;
|
||||
font-size: 1rem;
|
||||
background-color: #fff;
|
||||
color: #666666;
|
||||
padding: .5rem 15px;
|
||||
}
|
||||
|
||||
.footer .signin-details {
|
||||
|
@ -590,19 +590,6 @@ loop.contacts = (function(_, mozL10n) {
|
||||
return (
|
||||
React.createElement("div", null,
|
||||
React.createElement("div", {className: "content-area"},
|
||||
React.createElement(ButtonGroup, null,
|
||||
React.createElement(Button, {caption: this.state.importBusy
|
||||
? mozL10n.get("importing_contacts_progress_button")
|
||||
: mozL10n.get("import_contacts_button2"),
|
||||
disabled: this.state.importBusy,
|
||||
onClick: this.handleImportButtonClick},
|
||||
React.createElement("div", {className: cx({"contact-import-spinner": true,
|
||||
spinner: true,
|
||||
busy: this.state.importBusy})})
|
||||
),
|
||||
React.createElement(Button, {caption: mozL10n.get("new_contact_button"),
|
||||
onClick: this.handleAddContactButtonClick})
|
||||
),
|
||||
showFilter ?
|
||||
React.createElement("input", {className: "contact-filter",
|
||||
placeholder: mozL10n.get("contacts_search_placesholder"),
|
||||
@ -620,6 +607,21 @@ loop.contacts = (function(_, mozL10n) {
|
||||
shownContacts.blocked ?
|
||||
shownContacts.blocked.sort(this.sortContacts).map(viewForItem) :
|
||||
null
|
||||
),
|
||||
React.createElement(ButtonGroup, {additionalClass: "contact-controls"},
|
||||
React.createElement(Button, {additionalClass: "secondary",
|
||||
caption: this.state.importBusy
|
||||
? mozL10n.get("importing_contacts_progress_button")
|
||||
: mozL10n.get("import_contacts_button3"),
|
||||
disabled: this.state.importBusy,
|
||||
onClick: this.handleImportButtonClick},
|
||||
React.createElement("div", {className: cx({"contact-import-spinner": true,
|
||||
spinner: true,
|
||||
busy: this.state.importBusy})})
|
||||
),
|
||||
React.createElement(Button, {additionalClass: "primary",
|
||||
caption: mozL10n.get("new_contact_button"),
|
||||
onClick: this.handleAddContactButtonClick})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -590,19 +590,6 @@ loop.contacts = (function(_, mozL10n) {
|
||||
return (
|
||||
<div>
|
||||
<div className="content-area">
|
||||
<ButtonGroup>
|
||||
<Button caption={this.state.importBusy
|
||||
? mozL10n.get("importing_contacts_progress_button")
|
||||
: mozL10n.get("import_contacts_button2")}
|
||||
disabled={this.state.importBusy}
|
||||
onClick={this.handleImportButtonClick}>
|
||||
<div className={cx({"contact-import-spinner": true,
|
||||
spinner: true,
|
||||
busy: this.state.importBusy})} />
|
||||
</Button>
|
||||
<Button caption={mozL10n.get("new_contact_button")}
|
||||
onClick={this.handleAddContactButtonClick} />
|
||||
</ButtonGroup>
|
||||
{showFilter ?
|
||||
<input className="contact-filter"
|
||||
placeholder={mozL10n.get("contacts_search_placesholder")}
|
||||
@ -621,6 +608,21 @@ loop.contacts = (function(_, mozL10n) {
|
||||
shownContacts.blocked.sort(this.sortContacts).map(viewForItem) :
|
||||
null}
|
||||
</ul>
|
||||
<ButtonGroup additionalClass="contact-controls">
|
||||
<Button additionalClass="secondary"
|
||||
caption={this.state.importBusy
|
||||
? mozL10n.get("importing_contacts_progress_button")
|
||||
: mozL10n.get("import_contacts_button3")}
|
||||
disabled={this.state.importBusy}
|
||||
onClick={this.handleImportButtonClick} >
|
||||
<div className={cx({"contact-import-spinner": true,
|
||||
spinner: true,
|
||||
busy: this.state.importBusy})} />
|
||||
</Button>
|
||||
<Button additionalClass="primary"
|
||||
caption={mozL10n.get("new_contact_button")}
|
||||
onClick={this.handleAddContactButtonClick} />
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -143,36 +143,35 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// XXX https://github.com/facebook/react/issues/310 for === htmlFor
|
||||
var cx = React.addons.classSet;
|
||||
var availabilityStatus = cx({
|
||||
"status": true,
|
||||
"status-dnd": this.state.doNotDisturb,
|
||||
"status-available": !this.state.doNotDisturb
|
||||
});
|
||||
var availabilityDropdown = cx({
|
||||
"dropdown-menu": true,
|
||||
"hide": !this.state.showMenu
|
||||
});
|
||||
var statusIcon = cx({
|
||||
"status-unavailable": this.state.doNotDisturb,
|
||||
"status-available": !this.state.doNotDisturb
|
||||
});
|
||||
var availabilityText = this.state.doNotDisturb ?
|
||||
mozL10n.get("display_name_dnd_status") :
|
||||
mozL10n.get("display_name_available_status");
|
||||
mozL10n.get("display_name_dnd_status") :
|
||||
mozL10n.get("display_name_available_status");
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "dropdown"},
|
||||
React.createElement("p", {className: "dnd-status", onClick: this.toggleDropdownMenu, ref: "menu-button"},
|
||||
React.createElement("span", null, availabilityText),
|
||||
React.createElement("i", {className: availabilityStatus})
|
||||
React.createElement("p", {className: "dnd-status"},
|
||||
React.createElement("span", {className: statusIcon,
|
||||
onClick: this.toggleDropdownMenu,
|
||||
ref: "menu-button"},
|
||||
availabilityText
|
||||
)
|
||||
),
|
||||
React.createElement("ul", {className: availabilityDropdown},
|
||||
React.createElement("li", {className: "dropdown-menu-item dnd-make-available",
|
||||
React.createElement("li", {className: "dropdown-menu-item status-available",
|
||||
onClick: this.changeAvailability("available")},
|
||||
React.createElement("i", {className: "status status-available"}),
|
||||
React.createElement("span", null, mozL10n.get("display_name_available_status"))
|
||||
),
|
||||
React.createElement("li", {className: "dropdown-menu-item dnd-make-unavailable",
|
||||
React.createElement("li", {className: "dropdown-menu-item status-unavailable",
|
||||
onClick: this.changeAvailability("do-not-disturb")},
|
||||
React.createElement("i", {className: "status status-dnd"}),
|
||||
React.createElement("span", null, mozL10n.get("display_name_dnd_status"))
|
||||
)
|
||||
)
|
||||
@ -409,7 +408,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "settings-menu dropdown"},
|
||||
React.createElement("a", {className: "button-settings",
|
||||
React.createElement("button", {className: "button-settings",
|
||||
onClick: this.toggleDropdownMenu,
|
||||
ref: "menu-button",
|
||||
title: mozL10n.get("settings_menu_button_tooltip")}),
|
||||
@ -443,21 +442,35 @@ loop.panel = (function(_, mozL10n) {
|
||||
/**
|
||||
* FxA sign in/up link component.
|
||||
*/
|
||||
var AuthLink = React.createClass({displayName: "AuthLink",
|
||||
var AccountLink = React.createClass({displayName: "AccountLink",
|
||||
mixins: [sharedMixins.WindowCloseMixin],
|
||||
|
||||
handleSignUpLinkClick: function() {
|
||||
propTypes: {
|
||||
fxAEnabled: React.PropTypes.bool.isRequired,
|
||||
userProfile: userProfileValidator
|
||||
},
|
||||
|
||||
handleSignInLinkClick: function() {
|
||||
navigator.mozLoop.logInToFxA();
|
||||
this.closeWindow();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!navigator.mozLoop.fxAEnabled || navigator.mozLoop.userProfile) {
|
||||
if (!this.props.fxAEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.props.userProfile && this.props.userProfile.email) {
|
||||
return (
|
||||
React.createElement("div", {className: "user-identity"},
|
||||
loop.shared.utils.truncate(this.props.userProfile.email, 24)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
React.createElement("p", {className: "signin-link"},
|
||||
React.createElement("a", {href: "#", onClick: this.handleSignUpLinkClick},
|
||||
React.createElement("a", {href: "#", onClick: this.handleSignInLinkClick},
|
||||
mozL10n.get("panel_footer_signin_or_signup_link")
|
||||
)
|
||||
)
|
||||
@ -465,23 +478,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* FxA user identity (guest/authenticated) component.
|
||||
*/
|
||||
var UserIdentity = React.createClass({displayName: "UserIdentity",
|
||||
propTypes: {
|
||||
displayName: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
React.createElement("p", {className: "user-identity"},
|
||||
this.props.displayName
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var RoomEntryContextItem = React.createClass({displayName: "RoomEntryContextItem",
|
||||
mixins: [loop.shared.mixins.WindowCloseMixin],
|
||||
|
||||
@ -612,6 +608,18 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* User profile prop can be either an object or null as per mozLoopAPI
|
||||
* and there is no way to express this with React 0.12.2
|
||||
*/
|
||||
function userProfileValidator(props, propName, componentName) {
|
||||
if (Object.prototype.toString.call(props[propName]) !== "[object Object]" &&
|
||||
!_.isNull(props[propName])) {
|
||||
return new Error("Required prop `" + propName +
|
||||
"` was not correctly specified in `" + componentName + "`.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Room list.
|
||||
*/
|
||||
@ -622,7 +630,8 @@ loop.panel = (function(_, mozL10n) {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
||||
// Used for room creation, associated with room owner.
|
||||
userProfile: userProfileValidator
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -663,6 +672,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
return mozL10n.get("rooms_list_current_conversations", {num: numRooms});
|
||||
},
|
||||
|
||||
_getUserDisplayName: function() {
|
||||
return this.props.userProfile && this.props.userProfile.email ||
|
||||
mozL10n.get("display_name_guest");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.error) {
|
||||
// XXX Better end user reporting of errors.
|
||||
@ -687,7 +701,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
mozLoop: this.props.mozLoop,
|
||||
pendingOperation: this.state.pendingCreation ||
|
||||
this.state.pendingInitialRetrieval,
|
||||
userDisplayName: this.props.userDisplayName})
|
||||
userDisplayName: this._getUserDisplayName()})
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -815,15 +829,13 @@ loop.panel = (function(_, mozL10n) {
|
||||
React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
selectedTab: React.PropTypes.string,
|
||||
// Used only for unit tests.
|
||||
showTabButtons: React.PropTypes.bool,
|
||||
// Mostly used for UI components showcase and unit tests
|
||||
userProfile: React.PropTypes.object
|
||||
showTabButtons: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
hasEncryptionKey: this.props.mozLoop.hasEncryptionKey,
|
||||
userProfile: this.props.userProfile || this.props.mozLoop.userProfile,
|
||||
userProfile: this.props.mozLoop.userProfile,
|
||||
gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen")
|
||||
};
|
||||
},
|
||||
@ -918,11 +930,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
window.removeEventListener("UIAction", this._UIActionHandler);
|
||||
},
|
||||
|
||||
_getUserDisplayName: function() {
|
||||
return this.state.userProfile && this.state.userProfile.email ||
|
||||
mozL10n.get("display_name_guest");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var NotificationListView = sharedViews.NotificationListView;
|
||||
|
||||
@ -962,7 +969,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
React.createElement(RoomList, {dispatcher: this.props.dispatcher,
|
||||
mozLoop: this.props.mozLoop,
|
||||
store: this.props.roomStore,
|
||||
userDisplayName: this._getUserDisplayName()}),
|
||||
userProfile: this.state.userProfile}),
|
||||
React.createElement(ToSView, null)
|
||||
),
|
||||
React.createElement(Tab, {name: "contacts"},
|
||||
@ -992,12 +999,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
),
|
||||
React.createElement("div", {className: "footer"},
|
||||
React.createElement("div", {className: "user-details"},
|
||||
React.createElement(UserIdentity, {displayName: this._getUserDisplayName()}),
|
||||
React.createElement(AvailabilityDropdown, null)
|
||||
),
|
||||
React.createElement("div", {className: "signin-details"},
|
||||
React.createElement(AuthLink, null),
|
||||
React.createElement("div", {className: "footer-signin-separator"}),
|
||||
React.createElement(AccountLink, {fxAEnabled: this.props.mozLoop.fxAEnabled,
|
||||
userProfile: this.state.userProfile}),
|
||||
React.createElement(SettingsDropdown, {mozLoop: this.props.mozLoop})
|
||||
)
|
||||
)
|
||||
@ -1038,18 +1044,17 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
AuthLink: AuthLink,
|
||||
AccountLink: AccountLink,
|
||||
AvailabilityDropdown: AvailabilityDropdown,
|
||||
GettingStartedView: GettingStartedView,
|
||||
init: init,
|
||||
NewRoomView: NewRoomView,
|
||||
PanelView: PanelView,
|
||||
RoomEntry: RoomEntry,
|
||||
RoomList: RoomList,
|
||||
SettingsDropdown: SettingsDropdown,
|
||||
SignInRequestView: SignInRequestView,
|
||||
ToSView: ToSView,
|
||||
UserIdentity: UserIdentity
|
||||
ToSView: ToSView
|
||||
};
|
||||
})(_, document.mozL10n);
|
||||
|
||||
|
@ -143,36 +143,35 @@ loop.panel = (function(_, mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// XXX https://github.com/facebook/react/issues/310 for === htmlFor
|
||||
var cx = React.addons.classSet;
|
||||
var availabilityStatus = cx({
|
||||
"status": true,
|
||||
"status-dnd": this.state.doNotDisturb,
|
||||
"status-available": !this.state.doNotDisturb
|
||||
});
|
||||
var availabilityDropdown = cx({
|
||||
"dropdown-menu": true,
|
||||
"hide": !this.state.showMenu
|
||||
});
|
||||
var statusIcon = cx({
|
||||
"status-unavailable": this.state.doNotDisturb,
|
||||
"status-available": !this.state.doNotDisturb
|
||||
});
|
||||
var availabilityText = this.state.doNotDisturb ?
|
||||
mozL10n.get("display_name_dnd_status") :
|
||||
mozL10n.get("display_name_available_status");
|
||||
mozL10n.get("display_name_dnd_status") :
|
||||
mozL10n.get("display_name_available_status");
|
||||
|
||||
return (
|
||||
<div className="dropdown">
|
||||
<p className="dnd-status" onClick={this.toggleDropdownMenu} ref="menu-button">
|
||||
<span>{availabilityText}</span>
|
||||
<i className={availabilityStatus}></i>
|
||||
<p className="dnd-status">
|
||||
<span className={statusIcon}
|
||||
onClick={this.toggleDropdownMenu}
|
||||
ref="menu-button">
|
||||
{availabilityText}
|
||||
</span>
|
||||
</p>
|
||||
<ul className={availabilityDropdown}>
|
||||
<li className="dropdown-menu-item dnd-make-available"
|
||||
<li className="dropdown-menu-item status-available"
|
||||
onClick={this.changeAvailability("available")}>
|
||||
<i className="status status-available"></i>
|
||||
<span>{mozL10n.get("display_name_available_status")}</span>
|
||||
</li>
|
||||
<li className="dropdown-menu-item dnd-make-unavailable"
|
||||
<li className="dropdown-menu-item status-unavailable"
|
||||
onClick={this.changeAvailability("do-not-disturb")}>
|
||||
<i className="status status-dnd"></i>
|
||||
<span>{mozL10n.get("display_name_dnd_status")}</span>
|
||||
</li>
|
||||
</ul>
|
||||
@ -409,7 +408,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
|
||||
return (
|
||||
<div className="settings-menu dropdown">
|
||||
<a className="button-settings"
|
||||
<button className="button-settings"
|
||||
onClick={this.toggleDropdownMenu}
|
||||
ref="menu-button"
|
||||
title={mozL10n.get("settings_menu_button_tooltip")} />
|
||||
@ -443,21 +442,35 @@ loop.panel = (function(_, mozL10n) {
|
||||
/**
|
||||
* FxA sign in/up link component.
|
||||
*/
|
||||
var AuthLink = React.createClass({
|
||||
var AccountLink = React.createClass({
|
||||
mixins: [sharedMixins.WindowCloseMixin],
|
||||
|
||||
handleSignUpLinkClick: function() {
|
||||
propTypes: {
|
||||
fxAEnabled: React.PropTypes.bool.isRequired,
|
||||
userProfile: userProfileValidator
|
||||
},
|
||||
|
||||
handleSignInLinkClick: function() {
|
||||
navigator.mozLoop.logInToFxA();
|
||||
this.closeWindow();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!navigator.mozLoop.fxAEnabled || navigator.mozLoop.userProfile) {
|
||||
if (!this.props.fxAEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.props.userProfile && this.props.userProfile.email) {
|
||||
return (
|
||||
<div className="user-identity">
|
||||
{loop.shared.utils.truncate(this.props.userProfile.email, 24)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<p className="signin-link">
|
||||
<a href="#" onClick={this.handleSignUpLinkClick}>
|
||||
<a href="#" onClick={this.handleSignInLinkClick}>
|
||||
{mozL10n.get("panel_footer_signin_or_signup_link")}
|
||||
</a>
|
||||
</p>
|
||||
@ -465,23 +478,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* FxA user identity (guest/authenticated) component.
|
||||
*/
|
||||
var UserIdentity = React.createClass({
|
||||
propTypes: {
|
||||
displayName: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<p className="user-identity">
|
||||
{this.props.displayName}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var RoomEntryContextItem = React.createClass({
|
||||
mixins: [loop.shared.mixins.WindowCloseMixin],
|
||||
|
||||
@ -612,6 +608,18 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* User profile prop can be either an object or null as per mozLoopAPI
|
||||
* and there is no way to express this with React 0.12.2
|
||||
*/
|
||||
function userProfileValidator(props, propName, componentName) {
|
||||
if (Object.prototype.toString.call(props[propName]) !== "[object Object]" &&
|
||||
!_.isNull(props[propName])) {
|
||||
return new Error("Required prop `" + propName +
|
||||
"` was not correctly specified in `" + componentName + "`.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Room list.
|
||||
*/
|
||||
@ -622,7 +630,8 @@ loop.panel = (function(_, mozL10n) {
|
||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
|
||||
mozLoop: React.PropTypes.object.isRequired,
|
||||
store: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
userDisplayName: React.PropTypes.string.isRequired // for room creation
|
||||
// Used for room creation, associated with room owner.
|
||||
userProfile: userProfileValidator
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
@ -663,6 +672,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
return mozL10n.get("rooms_list_current_conversations", {num: numRooms});
|
||||
},
|
||||
|
||||
_getUserDisplayName: function() {
|
||||
return this.props.userProfile && this.props.userProfile.email ||
|
||||
mozL10n.get("display_name_guest");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.error) {
|
||||
// XXX Better end user reporting of errors.
|
||||
@ -687,7 +701,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
mozLoop={this.props.mozLoop}
|
||||
pendingOperation={this.state.pendingCreation ||
|
||||
this.state.pendingInitialRetrieval}
|
||||
userDisplayName={this.props.userDisplayName} />
|
||||
userDisplayName={this._getUserDisplayName()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -815,15 +829,13 @@ loop.panel = (function(_, mozL10n) {
|
||||
React.PropTypes.instanceOf(loop.store.RoomStore).isRequired,
|
||||
selectedTab: React.PropTypes.string,
|
||||
// Used only for unit tests.
|
||||
showTabButtons: React.PropTypes.bool,
|
||||
// Mostly used for UI components showcase and unit tests
|
||||
userProfile: React.PropTypes.object
|
||||
showTabButtons: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
hasEncryptionKey: this.props.mozLoop.hasEncryptionKey,
|
||||
userProfile: this.props.userProfile || this.props.mozLoop.userProfile,
|
||||
userProfile: this.props.mozLoop.userProfile,
|
||||
gettingStartedSeen: this.props.mozLoop.getLoopPref("gettingStarted.seen")
|
||||
};
|
||||
},
|
||||
@ -918,11 +930,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
window.removeEventListener("UIAction", this._UIActionHandler);
|
||||
},
|
||||
|
||||
_getUserDisplayName: function() {
|
||||
return this.state.userProfile && this.state.userProfile.email ||
|
||||
mozL10n.get("display_name_guest");
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var NotificationListView = sharedViews.NotificationListView;
|
||||
|
||||
@ -962,7 +969,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
<RoomList dispatcher={this.props.dispatcher}
|
||||
mozLoop={this.props.mozLoop}
|
||||
store={this.props.roomStore}
|
||||
userDisplayName={this._getUserDisplayName()} />
|
||||
userProfile={this.state.userProfile} />
|
||||
<ToSView />
|
||||
</Tab>
|
||||
<Tab name="contacts">
|
||||
@ -992,12 +999,11 @@ loop.panel = (function(_, mozL10n) {
|
||||
</TabView>
|
||||
<div className="footer">
|
||||
<div className="user-details">
|
||||
<UserIdentity displayName={this._getUserDisplayName()} />
|
||||
<AvailabilityDropdown />
|
||||
</div>
|
||||
<div className="signin-details">
|
||||
<AuthLink />
|
||||
<div className="footer-signin-separator" />
|
||||
<AccountLink fxAEnabled={this.props.mozLoop.fxAEnabled}
|
||||
userProfile={this.state.userProfile}/>
|
||||
<SettingsDropdown mozLoop={this.props.mozLoop}/>
|
||||
</div>
|
||||
</div>
|
||||
@ -1038,18 +1044,17 @@ loop.panel = (function(_, mozL10n) {
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
AuthLink: AuthLink,
|
||||
AccountLink: AccountLink,
|
||||
AvailabilityDropdown: AvailabilityDropdown,
|
||||
GettingStartedView: GettingStartedView,
|
||||
init: init,
|
||||
NewRoomView: NewRoomView,
|
||||
PanelView: PanelView,
|
||||
RoomEntry: RoomEntry,
|
||||
RoomList: RoomList,
|
||||
SettingsDropdown: SettingsDropdown,
|
||||
SignInRequestView: SignInRequestView,
|
||||
ToSView: ToSView,
|
||||
UserIdentity: UserIdentity
|
||||
ToSView: ToSView
|
||||
};
|
||||
})(_, document.mozL10n);
|
||||
|
||||
|
@ -460,23 +460,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
this.props.roomData.roomContextUrls[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Truncate a string if it exceeds the length as defined in `maxLen`, which
|
||||
* is defined as '72' characters by default. If the string needs trimming,
|
||||
* it'll be suffixed with the unicode ellipsis char, \u2026.
|
||||
*
|
||||
* @param {String} str The string to truncate, if needed.
|
||||
* @param {Number} maxLen Maximum number of characters that the string is
|
||||
* allowed to contain. Optional, defaults to 72.
|
||||
* @return {String} Truncated version of `str`.
|
||||
*/
|
||||
_truncate: function(str, maxLen) {
|
||||
if (!maxLen) {
|
||||
maxLen = 72;
|
||||
}
|
||||
return (str.length > maxLen) ? str.substr(0, maxLen) + "…" : str;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.show) {
|
||||
return null;
|
||||
|
@ -460,23 +460,6 @@ loop.roomViews = (function(mozL10n) {
|
||||
this.props.roomData.roomContextUrls[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Truncate a string if it exceeds the length as defined in `maxLen`, which
|
||||
* is defined as '72' characters by default. If the string needs trimming,
|
||||
* it'll be suffixed with the unicode ellipsis char, \u2026.
|
||||
*
|
||||
* @param {String} str The string to truncate, if needed.
|
||||
* @param {Number} maxLen Maximum number of characters that the string is
|
||||
* allowed to contain. Optional, defaults to 72.
|
||||
* @return {String} Truncated version of `str`.
|
||||
*/
|
||||
_truncate: function(str, maxLen) {
|
||||
if (!maxLen) {
|
||||
maxLen = 72;
|
||||
}
|
||||
return (str.length > maxLen) ? str.substr(0, maxLen) + "…" : str;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (!this.state.show) {
|
||||
return null;
|
||||
|
@ -422,7 +422,6 @@ p {
|
||||
background-color: #fdfdfd;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,.3);
|
||||
list-style: none;
|
||||
padding: 5px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
@ -432,19 +431,17 @@ html[dir="rtl"] .dropdown-menu {
|
||||
}
|
||||
|
||||
.dropdown-menu-item {
|
||||
width: 100%;
|
||||
text-align: start;
|
||||
margin: .3em 0;
|
||||
padding: .2em .5em;
|
||||
padding: .5em 15px;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
font-size: 1em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dropdown-menu-item:hover {
|
||||
border: 1px solid #ccc;
|
||||
background-color: #eee;
|
||||
background-color: #dbf7ff;
|
||||
}
|
||||
|
||||
.dropdown-menu-item > .icon {
|
||||
|
@ -1072,6 +1072,7 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
}
|
||||
|
||||
.media-wrapper > .focus-stream {
|
||||
display: flex;
|
||||
/* We want this to be the width, minus 200px which is for the right-side text
|
||||
chat and video displays. */
|
||||
width: calc(100% - 200px);
|
||||
@ -1347,21 +1348,10 @@ html[dir="rtl"] .room-context-btn-close {
|
||||
}
|
||||
|
||||
.standalone .room-conversation-wrapper .room-inner-info-area {
|
||||
position: absolute;
|
||||
/* `top` is chosen to vertically position the area near the center
|
||||
of the media element. */
|
||||
top: calc(50% - 140px);
|
||||
left: 25%;
|
||||
z-index: 1000;
|
||||
/* `width` here is specified by the design spec. */
|
||||
width: 250px;
|
||||
color: #fff;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .standalone .room-conversation-wrapper .room-inner-info-area {
|
||||
right: 25%;
|
||||
left: auto;
|
||||
margin: auto;
|
||||
/* 290px is the width of the widest info child, i.e., a tile */
|
||||
width: 290px;
|
||||
}
|
||||
|
||||
.standalone .prompt-media-message {
|
||||
|
@ -29,6 +29,7 @@
|
||||
<polygon id="expand-shape" points="10,0 4.838,0 6.506,1.669 0,8.175 1.825,10 8.331,3.494 10,5.162"/>
|
||||
<path id="edit-shape" d="M5.493,1.762l2.745,2.745L2.745,10H0V7.255L5.493,1.762z M2.397,9.155l0.601-0.601L1.446,7.002L0.845,7.603 V8.31H1.69v0.845H2.397z M5.849,3.028c0-0.096-0.048-0.144-0.146-0.144c-0.044,0-0.081,0.015-0.112,0.046L2.014,6.508 C1.983,6.538,1.968,6.577,1.968,6.619c0,0.098,0.048,0.146,0.144,0.146c0.044,0,0.081-0.015,0.112-0.046l3.579-3.577 C5.834,3.111,5.849,3.073,5.849,3.028z M10,2.395c0,0.233-0.081,0.431-0.245,0.595L8.66,4.085L5.915,1.34L7.01,0.25 C7.168,0.083,7.366,0,7.605,0c0.233,0,0.433,0.083,0.601,0.25l1.55,1.544C9.919,1.966,10,2.166,10,2.395z"/>
|
||||
<rect id="minimize-shape" y="3.6" width="10" height="2.8"/>
|
||||
<path id="cog-shape" d="M122.285722,122.071424 C122.285722,122.936938 121.579806,123.642854 120.714291,123.642854 C119.848777,123.642854 119.142861,122.936938 119.142861,122.071424 C119.142861,121.205909 119.848777,120.499993 120.714291,120.499993 C121.579806,120.499993 122.285722,121.205909 122.285722,122.071424 L122.285722,122.071424 Z M125.428583,121.402338 C125.428583,121.297985 125.354922,121.199771 125.250569,121.181356 L124.127242,121.009481 C124.065858,120.806913 123.97992,120.604346 123.875567,120.407917 C124.084273,120.119413 124.311394,119.849323 124.520099,119.566957 C124.550791,119.523988 124.569207,119.481019 124.569207,119.425773 C124.569207,119.376666 124.55693,119.327559 124.526238,119.290729 C124.268425,118.928563 123.838737,118.547982 123.513402,118.247201 C123.470433,118.21037 123.415187,118.185817 123.359942,118.185817 C123.304696,118.185817 123.249451,118.204232 123.21262,118.241062 L122.340967,118.897871 C122.162954,118.805795 121.978802,118.732134 121.788511,118.67075 L121.616636,117.541285 C121.604359,117.436932 121.506145,117.357133 121.395654,117.357133 L120.032929,117.357133 C119.922438,117.357133 119.8365,117.430793 119.811947,117.529008 C119.713732,117.897312 119.676902,118.296308 119.633933,118.67075 C119.443642,118.732134 119.253352,118.811933 119.075338,118.904009 L118.228239,118.247201 C118.179132,118.21037 118.123886,118.185817 118.068641,118.185817 C117.859935,118.185817 117.031251,119.082023 116.88393,119.28459 C116.853238,119.327559 116.828684,119.370528 116.828684,119.425773 C116.828684,119.481019 116.853238,119.530126 116.890068,119.573095 C117.117189,119.849323 117.338171,120.125551 117.546877,120.420194 C117.448662,120.604346 117.368863,120.788498 117.307479,120.984927 L116.165737,121.156802 C116.073661,121.175217 116,121.285709 116,121.377785 L116,122.74051 C116,122.844862 116.073661,122.943077 116.178014,122.961492 L117.301341,123.127229 C117.362725,123.335934 117.448662,123.538502 117.553015,123.73493 C117.34431,124.023435 117.117189,124.293525 116.908483,124.575891 C116.877791,124.61886 116.859376,124.661829 116.859376,124.717074 C116.859376,124.766182 116.871653,124.815289 116.902345,124.858258 C117.160158,125.214285 117.589846,125.594866 117.915181,125.889509 C117.95815,125.932478 118.013395,125.957031 118.068641,125.957031 C118.123886,125.957031 118.179132,125.938616 118.222101,125.901786 L119.087615,125.244977 C119.265629,125.337053 119.449781,125.410714 119.640071,125.472098 L119.811947,126.601563 C119.824223,126.705916 119.922438,126.785715 120.032929,126.785715 L121.395654,126.785715 C121.506145,126.785715 121.592083,126.712054 121.616636,126.61384 C121.714851,126.245536 121.751681,125.84654 121.79465,125.472098 C121.98494,125.410714 122.175231,125.330914 122.353244,125.238838 L123.200343,125.901786 C123.249451,125.932478 123.304696,125.957031 123.359942,125.957031 C123.568647,125.957031 124.397331,125.054686 124.544653,124.858258 C124.581483,124.815289 124.599899,124.77232 124.599899,124.717074 C124.599899,124.661829 124.575345,124.606583 124.538515,124.563614 C124.311394,124.287386 124.090411,124.017297 123.881706,123.716515 C123.97992,123.538502 124.053581,123.35435 124.121103,123.157921 L125.256707,122.986046 C125.354922,122.96763 125.428583,122.857139 125.428583,122.765063 L125.428583,121.402338 Z" transform="translate(-116 -117)" fill="#666" fill-rule="evenodd"/>
|
||||
</defs>
|
||||
<use id="close" xlink:href="#close-shape"/>
|
||||
<use id="close-active" xlink:href="#close-shape"/>
|
||||
@ -48,4 +49,5 @@
|
||||
<use id="minimize" xlink:href="#minimize-shape"/>
|
||||
<use id="minimize-active" xlink:href="#minimize-shape"/>
|
||||
<use id="minimize-disabled" xlink:href="#minimize-shape"/>
|
||||
<use id="settings-cog" xlink:href="#cog-shape"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 5.9 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 74 KiB |
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" fill="#131311" d="M14.77,8c0,0.804,0.262,1.548,0.634,1.678L16,9.887 c-0.205,0.874-0.553,1.692-1.011,2.434l-0.567-0.272c-0.355-0.171-1.066,0.17-1.635,0.738c-0.569,0.569-0.909,1.279-0.738,1.635 l0.273,0.568c-0.741,0.46-1.566,0.79-2.438,0.998l-0.205-0.584c-0.13-0.372-0.874-0.634-1.678-0.634s-1.548,0.262-1.678,0.634 l-0.209,0.596c-0.874-0.205-1.692-0.553-2.434-1.011l0.272-0.567c0.171-0.355-0.17-1.066-0.739-1.635 c-0.568-0.568-1.279-0.909-1.635-0.738l-0.568,0.273c-0.46-0.741-0.79-1.566-0.998-2.439l0.584-0.205 C0.969,9.547,1.231,8.804,1.231,8c0-0.804-0.262-1.548-0.634-1.678L0,6.112c0.206-0.874,0.565-1.685,1.025-2.427l0.554,0.266 c0.355,0.171,1.066-0.17,1.635-0.738c0.569-0.568,0.909-1.28,0.739-1.635L3.686,1.025c0.742-0.46,1.553-0.818,2.427-1.024 l0.209,0.596C6.453,0.969,7.197,1.23,8.001,1.23s1.548-0.262,1.678-0.634l0.209-0.596c0.874,0.205,1.692,0.553,2.434,1.011 l-0.272,0.567c-0.171,0.355,0.17,1.066,0.738,1.635c0.569,0.568,1.279,0.909,1.635,0.738l0.568-0.273 c0.46,0.741,0.79,1.566,0.998,2.438l-0.584,0.205C15.032,6.452,14.77,7.196,14.77,8z M8.001,3.661C5.604,3.661,3.661,5.603,3.661,8 c0,2.397,1.943,4.34,4.339,4.34c2.397,0,4.339-1.943,4.339-4.34C12.34,5.603,10.397,3.661,8.001,3.661z"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -446,7 +446,11 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
||||
// We can alias `subarray` to `slice` when the latter is not available, because
|
||||
// they're semantically identical.
|
||||
if (!Uint8Array.prototype.slice) {
|
||||
/* eslint-disable */
|
||||
// Eslint disabled for no-extend-native; Specific override needed for Firefox 37
|
||||
// and earlier, also for other browsers.
|
||||
Uint8Array.prototype.slice = Uint8Array.prototype.subarray;
|
||||
/* eslint-enable */
|
||||
}
|
||||
|
||||
/**
|
||||
@ -736,6 +740,34 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a string if it exceeds the length as defined in `maxLen`, which
|
||||
* is defined as '72' characters by default. If the string needs trimming,
|
||||
* it'll be suffixed with the unicode ellipsis char, \u2026.
|
||||
*
|
||||
* @param {String} str The string to truncate, if needed.
|
||||
* @param {Number} maxLen Maximum number of characters that the string is
|
||||
* allowed to contain. Optional, defaults to 72.
|
||||
* @return {String} Truncated version of `str`.
|
||||
*/
|
||||
function truncate(str, maxLen) {
|
||||
maxLen = maxLen || 72;
|
||||
|
||||
if (str.length > maxLen) {
|
||||
var substring = str.substr(0, maxLen);
|
||||
// XXX Due to the fact that we have two different l10n libraries.
|
||||
var direction = mozL10n.getDirection ? mozL10n.getDirection() :
|
||||
mozL10n.language.direction;
|
||||
if (direction === "rtl") {
|
||||
return "…" + substring;
|
||||
}
|
||||
|
||||
return substring + "…";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
this.utils = {
|
||||
CALL_TYPES: CALL_TYPES,
|
||||
FAILURE_DETAILS: FAILURE_DETAILS,
|
||||
@ -764,6 +796,7 @@ var inChrome = typeof Components != "undefined" && "utils" in Components;
|
||||
strToUint8Array: strToUint8Array,
|
||||
Uint8ArrayToStr: Uint8ArrayToStr,
|
||||
objectDiff: objectDiff,
|
||||
stripFalsyValues: stripFalsyValues
|
||||
stripFalsyValues: stripFalsyValues,
|
||||
truncate: truncate
|
||||
};
|
||||
}).call(inChrome ? this : loop.shared);
|
||||
|
@ -54,7 +54,6 @@ browser.jar:
|
||||
content/browser/loop/shared/img/video-inverse-14x14@2x.png (content/shared/img/video-inverse-14x14@2x.png)
|
||||
content/browser/loop/shared/img/dropdown-inverse.png (content/shared/img/dropdown-inverse.png)
|
||||
content/browser/loop/shared/img/dropdown-inverse@2x.png (content/shared/img/dropdown-inverse@2x.png)
|
||||
content/browser/loop/shared/img/svg/glyph-settings-16x16.svg (content/shared/img/svg/glyph-settings-16x16.svg)
|
||||
content/browser/loop/shared/img/svg/glyph-account-16x16.svg (content/shared/img/svg/glyph-account-16x16.svg)
|
||||
content/browser/loop/shared/img/svg/glyph-signin-16x16.svg (content/shared/img/svg/glyph-signin-16x16.svg)
|
||||
content/browser/loop/shared/img/svg/glyph-signout-16x16.svg (content/shared/img/svg/glyph-signout-16x16.svg)
|
||||
|
@ -75,4 +75,6 @@ config:
|
||||
@echo "loop.config.roomsSupportUrl = 'https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc';" >> content/config.js
|
||||
@echo "loop.config.guestSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';" >> content/config.js
|
||||
@echo "loop.config.generalSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';" >> content/config.js
|
||||
@echo "loop.config.tilesIframeUrl = 'https://tiles.cdn.mozilla.net/iframe.html';" >> content/config.js
|
||||
@echo "loop.config.tilesSupportUrl = 'https://support.mozilla.org/tiles-firefox-hello';" >> content/config.js
|
||||
@echo "loop.config.unsupportedPlatformUrl = 'https://support.mozilla.org/en-US/kb/which-browsers-will-work-firefox-hello-video-chat';" >> content/config.js
|
||||
|
@ -51,6 +51,37 @@ body,
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
/* Waiting info offer */
|
||||
|
||||
.standalone .empty-room-message {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.standalone .room-waiting-area {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 3em auto 1em;
|
||||
}
|
||||
|
||||
.standalone .room-waiting-help {
|
||||
background: transparent url("../shared/img/svg/glyph-help-16x16.svg") no-repeat;
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.standalone .room-waiting-tile {
|
||||
border: 0;
|
||||
border-radius: 5px;
|
||||
/* These sizes are the size of the tile image and title */
|
||||
height: 204px;
|
||||
/* Override the default iframe 300px width with the inherited width */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Top/Bottom spacing
|
||||
**/
|
||||
|
@ -151,7 +151,17 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
React.createElement("div", {className: "room-inner-info-area"},
|
||||
React.createElement("p", {className: "empty-room-message"},
|
||||
mozL10n.get("rooms_only_occupant_label")
|
||||
)
|
||||
),
|
||||
React.createElement("p", {className: "room-waiting-area"},
|
||||
mozL10n.get("rooms_read_while_wait_offer"),
|
||||
React.createElement("a", {href: loop.config.tilesSupportUrl,
|
||||
onClick: this.recordClick,
|
||||
rel: "noreferrer",
|
||||
target: "_blank"},
|
||||
React.createElement("i", {className: "room-waiting-help"})
|
||||
)
|
||||
),
|
||||
React.createElement("iframe", {className: "room-waiting-tile", src: loop.config.tilesIframeUrl})
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -461,13 +471,6 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
React.createElement("div", {className: "room-conversation-wrapper standalone-room-wrapper"},
|
||||
React.createElement("div", {className: "beta-logo"}),
|
||||
React.createElement(StandaloneRoomHeader, {dispatcher: this.props.dispatcher}),
|
||||
React.createElement(StandaloneRoomInfoArea, {activeRoomStore: this.props.activeRoomStore,
|
||||
dispatcher: this.props.dispatcher,
|
||||
failureReason: this.state.failureReason,
|
||||
isFirefox: this.props.isFirefox,
|
||||
joinRoom: this.joinRoom,
|
||||
roomState: this.state.roomState,
|
||||
roomUsed: this.state.used}),
|
||||
React.createElement(sharedViews.MediaLayoutView, {
|
||||
dispatcher: this.props.dispatcher,
|
||||
displayScreenShare: displayScreenShare,
|
||||
@ -484,7 +487,15 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
screenSharePosterUrl: this.props.screenSharePosterUrl,
|
||||
screenShareVideoObject: this.state.screenShareVideoObject,
|
||||
showContextRoomName: true,
|
||||
useDesktopPaths: false}),
|
||||
useDesktopPaths: false},
|
||||
React.createElement(StandaloneRoomInfoArea, {activeRoomStore: this.props.activeRoomStore,
|
||||
dispatcher: this.props.dispatcher,
|
||||
failureReason: this.state.failureReason,
|
||||
isFirefox: this.props.isFirefox,
|
||||
joinRoom: this.joinRoom,
|
||||
roomState: this.state.roomState,
|
||||
roomUsed: this.state.used})
|
||||
),
|
||||
React.createElement(sharedViews.ConversationToolbar, {
|
||||
audio: {enabled: !this.state.audioMuted,
|
||||
visible: this._roomIsActive()},
|
||||
|
@ -152,6 +152,16 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
<p className="empty-room-message">
|
||||
{mozL10n.get("rooms_only_occupant_label")}
|
||||
</p>
|
||||
<p className="room-waiting-area">
|
||||
{mozL10n.get("rooms_read_while_wait_offer")}
|
||||
<a href={loop.config.tilesSupportUrl}
|
||||
onClick={this.recordClick}
|
||||
rel="noreferrer"
|
||||
target="_blank">
|
||||
<i className="room-waiting-help"></i>
|
||||
</a>
|
||||
</p>
|
||||
<iframe className="room-waiting-tile" src={loop.config.tilesIframeUrl} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -461,13 +471,6 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
<div className="room-conversation-wrapper standalone-room-wrapper">
|
||||
<div className="beta-logo" />
|
||||
<StandaloneRoomHeader dispatcher={this.props.dispatcher} />
|
||||
<StandaloneRoomInfoArea activeRoomStore={this.props.activeRoomStore}
|
||||
dispatcher={this.props.dispatcher}
|
||||
failureReason={this.state.failureReason}
|
||||
isFirefox={this.props.isFirefox}
|
||||
joinRoom={this.joinRoom}
|
||||
roomState={this.state.roomState}
|
||||
roomUsed={this.state.used} />
|
||||
<sharedViews.MediaLayoutView
|
||||
dispatcher={this.props.dispatcher}
|
||||
displayScreenShare={displayScreenShare}
|
||||
@ -484,7 +487,15 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
screenSharePosterUrl={this.props.screenSharePosterUrl}
|
||||
screenShareVideoObject={this.state.screenShareVideoObject}
|
||||
showContextRoomName={true}
|
||||
useDesktopPaths={false} />
|
||||
useDesktopPaths={false}>
|
||||
<StandaloneRoomInfoArea activeRoomStore={this.props.activeRoomStore}
|
||||
dispatcher={this.props.dispatcher}
|
||||
failureReason={this.state.failureReason}
|
||||
isFirefox={this.props.isFirefox}
|
||||
joinRoom={this.joinRoom}
|
||||
roomState={this.state.roomState}
|
||||
roomUsed={this.state.used} />
|
||||
</sharedViews.MediaLayoutView>
|
||||
<sharedViews.ConversationToolbar
|
||||
audio={{enabled: !this.state.audioMuted,
|
||||
visible: this._roomIsActive()}}
|
||||
|
@ -111,6 +111,11 @@ rooms_media_denied_message=We could not get access to your microphone or camera.
|
||||
room_information_failure_not_available=No information about this conversation is available. Please request a new link from the person who sent it to you.
|
||||
room_information_failure_unsupported_browser=Your browser cannot access any information about this conversation. Please make sure you're using the latest version.
|
||||
|
||||
## LOCALIZATION_NOTE(rooms_read_while_wait_offer): This string is followed by a
|
||||
# tile/offer image and title that are provided by a separate service that has
|
||||
# localized content.
|
||||
rooms_read_while_wait_offer=Want something to read while you wait?
|
||||
|
||||
## LOCALIZATION_NOTE(standalone_title_with_status): {{clientShortname}} will be
|
||||
## replaced by the brand name and {{currentStatus}} will be replaced
|
||||
## by the current call status (Connecting, Ringing, etc.)
|
||||
|
@ -12,8 +12,8 @@
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"eslint": "0.24.x",
|
||||
"eslint-plugin-react": "2.7.x",
|
||||
"eslint": "1.0.x",
|
||||
"eslint-plugin-react": "3.2.x",
|
||||
"express": "4.x"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -12,6 +12,8 @@
|
||||
var express = require("express");
|
||||
var app = express();
|
||||
|
||||
var path = require("path");
|
||||
|
||||
var port = process.env.PORT || 3000;
|
||||
var feedbackApiUrl = process.env.LOOP_FEEDBACK_API_URL ||
|
||||
"https://input.allizom.org/api/v1/feedback";
|
||||
@ -46,6 +48,8 @@ function getConfigFile(req, res) {
|
||||
"loop.config.fxosApp.rooms = true;",
|
||||
"loop.config.fxosApp.manifestUrl = 'http://fake-market.herokuapp.com/apps/packagedApp/manifest.webapp';",
|
||||
"loop.config.roomsSupportUrl = 'https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc';",
|
||||
"loop.config.tilesIframeUrl = 'https://tiles.cdn.mozilla.net/iframe.html';",
|
||||
"loop.config.tilesSupportUrl = 'https://support.mozilla.org/tiles-firefox-hello';",
|
||||
"loop.config.guestSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';",
|
||||
"loop.config.generalSupportUrl = 'https://support.mozilla.org/kb/respond-firefox-hello-invitation-guest-mode';",
|
||||
"loop.config.unsupportedPlatformUrl = 'https://support.mozilla.org/en-US/kb/which-browsers-will-work-firefox-hello-video-chat'"
|
||||
@ -60,32 +64,35 @@ app.get("/content/c/config.js", getConfigFile);
|
||||
// /ui - for the ui showcase
|
||||
// /content - for the standalone files.
|
||||
|
||||
app.use("/ui", express.static(__dirname + "/../ui"));
|
||||
app.use("/ui", express.static(path.join(__dirname, "..", "ui")));
|
||||
app.use("/ui/loop/", express.static(path.join(__dirname, "..", "content")));
|
||||
app.use("/ui/shared/", express.static(path.join(__dirname, "..", "content",
|
||||
"shared")));
|
||||
|
||||
// This exists exclusively for the unit tests. They are served the
|
||||
// whole loop/ directory structure and expect some files in the standalone directory.
|
||||
app.use("/standalone/content", express.static(__dirname + "/content"));
|
||||
app.use("/standalone/content", express.static(path.join(__dirname, "content")));
|
||||
|
||||
// We load /content this from both /content *and* /../content. The first one
|
||||
// does what we need for running in the github loop-client context, the second one
|
||||
// handles running in the hg repo under mozilla-central and is used so that the shared
|
||||
// files are in the right location.
|
||||
app.use("/content", express.static(__dirname + "/content"));
|
||||
app.use("/content", express.static(__dirname + "/../content"));
|
||||
app.use("/content", express.static(path.join(__dirname, "content")));
|
||||
app.use("/content", express.static(path.join(__dirname, "..", "content")));
|
||||
// These two are based on the above, but handle call urls, that have a /c/ in them.
|
||||
app.use("/content/c", express.static(__dirname + "/content"));
|
||||
app.use("/content/c", express.static(__dirname + "/../content"));
|
||||
app.use("/content/c", express.static(path.join(__dirname, "content")));
|
||||
app.use("/content/c", express.static(path.join(__dirname, "..", "content")));
|
||||
|
||||
// Two lines for the same reason as /content above.
|
||||
app.use("/test", express.static(__dirname + "/test"));
|
||||
app.use("/test", express.static(__dirname + "/../test"));
|
||||
app.use("/test", express.static(path.join(__dirname, "test")));
|
||||
app.use("/test", express.static(path.join(__dirname, "..", "test")));
|
||||
|
||||
// As we don't have hashes on the urls, the best way to serve the index files
|
||||
// appears to be to be to closely filter the url and match appropriately.
|
||||
function serveIndex(req, res) {
|
||||
"use strict";
|
||||
|
||||
return res.sendfile(__dirname + "/content/index.html");
|
||||
return res.sendfile(path.join(__dirname, "content", "index.html"));
|
||||
}
|
||||
|
||||
app.get(/^\/content\/[\w\-]+$/, serveIndex);
|
||||
|
@ -72,7 +72,8 @@ describe("loop.panel", function() {
|
||||
logOutFromFxA: sandbox.stub(),
|
||||
notifyUITour: sandbox.stub(),
|
||||
openURL: sandbox.stub(),
|
||||
getSelectedTabMetadata: sandbox.stub()
|
||||
getSelectedTabMetadata: sandbox.stub(),
|
||||
userProfile: null
|
||||
};
|
||||
|
||||
document.mozL10n.initialize(navigator.mozLoop);
|
||||
@ -136,9 +137,9 @@ describe("loop.panel", function() {
|
||||
navigator.mozLoop.doNotDisturb = true;
|
||||
});
|
||||
|
||||
it("should toggle the value of mozLoop.doNotDisturb", function() {
|
||||
it("should toggle mozLoop.doNotDisturb to false", function() {
|
||||
var availableMenuOption = view.getDOMNode()
|
||||
.querySelector(".dnd-make-available");
|
||||
.querySelector(".status-available");
|
||||
|
||||
TestUtils.Simulate.click(availableMenuOption);
|
||||
|
||||
@ -147,7 +148,7 @@ describe("loop.panel", function() {
|
||||
|
||||
it("should toggle the dropdown menu", function() {
|
||||
var availableMenuOption = view.getDOMNode()
|
||||
.querySelector(".dnd-status span");
|
||||
.querySelector(".dnd-status span");
|
||||
|
||||
TestUtils.Simulate.click(availableMenuOption);
|
||||
|
||||
@ -235,8 +236,7 @@ describe("loop.panel", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("AuthLink", function() {
|
||||
|
||||
describe("AccountLink", function() {
|
||||
beforeEach(function() {
|
||||
navigator.mozLoop.calls = { clearCallInProgress: function() {} };
|
||||
});
|
||||
@ -249,13 +249,12 @@ describe("loop.panel", function() {
|
||||
|
||||
it("should trigger the FxA sign in/up process when clicking the link",
|
||||
function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
navigator.mozLoop.logInToFxA = sandbox.stub();
|
||||
|
||||
var view = createTestPanelView();
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".signin-link a"));
|
||||
view.getDOMNode().querySelector(".signin-link > a"));
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.logInToFxA);
|
||||
});
|
||||
@ -268,7 +267,7 @@ describe("loop.panel", function() {
|
||||
var view = createTestPanelView();
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".signin-link a"));
|
||||
view.getDOMNode().querySelector(".signin-link > a"));
|
||||
|
||||
sinon.assert.calledOnce(fakeWindow.close);
|
||||
});
|
||||
@ -277,9 +276,50 @@ describe("loop.panel", function() {
|
||||
function() {
|
||||
navigator.mozLoop.fxAEnabled = false;
|
||||
var view = TestUtils.renderIntoDocument(
|
||||
React.createElement(loop.panel.AuthLink));
|
||||
React.createElement(loop.panel.AccountLink, {
|
||||
fxAEnabled: false,
|
||||
userProfile: null
|
||||
}));
|
||||
expect(view.getDOMNode()).to.be.null;
|
||||
});
|
||||
|
||||
it("should add ellipsis to text over 24chars", function() {
|
||||
navigator.mozLoop.userProfile = {
|
||||
email: "reallyreallylongtext@example.com"
|
||||
};
|
||||
var view = createTestPanelView();
|
||||
var node = view.getDOMNode().querySelector(".user-identity");
|
||||
|
||||
expect(node.textContent).to.eql("reallyreallylongtext@exa…");
|
||||
});
|
||||
|
||||
it("should throw an error when user profile is different from {} or null",
|
||||
function() {
|
||||
var warnstub = sandbox.stub(console, "warn");
|
||||
var view = TestUtils.renderIntoDocument(React.createElement(
|
||||
loop.panel.AccountLink, {
|
||||
fxAEnabled: false,
|
||||
userProfile: []
|
||||
}
|
||||
));
|
||||
|
||||
sinon.assert.calledOnce(warnstub);
|
||||
sinon.assert.calledWithExactly(warnstub, "Warning: Required prop `userProfile` was not correctly specified in `AccountLink`.");
|
||||
});
|
||||
|
||||
it("should throw an error when user profile is different from {} or null",
|
||||
function() {
|
||||
var warnstub = sandbox.stub(console, "warn");
|
||||
var view = TestUtils.renderIntoDocument(React.createElement(
|
||||
loop.panel.AccountLink, {
|
||||
fxAEnabled: false,
|
||||
userProfile: function() {}
|
||||
}
|
||||
));
|
||||
|
||||
sinon.assert.calledOnce(warnstub);
|
||||
sinon.assert.calledWithExactly(warnstub, "Warning: Required prop `userProfile` was not correctly specified in `AccountLink`.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("SettingsDropdown", function() {
|
||||
@ -300,17 +340,39 @@ describe("loop.panel", function() {
|
||||
navigator.mozLoop.fxAEnabled = true;
|
||||
});
|
||||
|
||||
it("should show a signin entry when user is not authenticated",
|
||||
function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
describe("UserLoggedOut", function() {
|
||||
beforeEach(function() {
|
||||
fakeMozLoop.userProfile = null;
|
||||
});
|
||||
|
||||
it("should show a signin entry when user is not authenticated",
|
||||
function() {
|
||||
var view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode().querySelectorAll(".icon-signout"))
|
||||
.to.have.length.of(0);
|
||||
expect(view.getDOMNode().querySelectorAll(".icon-signin"))
|
||||
.to.have.length.of(1);
|
||||
});
|
||||
|
||||
it("should hide any account entry when user is not authenticated",
|
||||
function() {
|
||||
var view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode().querySelectorAll(".icon-account"))
|
||||
.to.have.length.of(0);
|
||||
});
|
||||
|
||||
it("should sign in the user on click when unauthenticated", function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
var view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode().querySelectorAll(".icon-signout"))
|
||||
.to.have.length.of(0);
|
||||
expect(view.getDOMNode().querySelectorAll(".icon-signin"))
|
||||
.to.have.length.of(1);
|
||||
TestUtils.Simulate.click(view.getDOMNode()
|
||||
.querySelector(".icon-signin"));
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.logInToFxA);
|
||||
});
|
||||
});
|
||||
|
||||
it("should show a signout entry when user is authenticated", function() {
|
||||
navigator.mozLoop.userProfile = {email: "test@example.com"};
|
||||
@ -332,43 +394,24 @@ describe("loop.panel", function() {
|
||||
.to.have.length.of(1);
|
||||
});
|
||||
|
||||
it("should open the FxA settings when the account entry is clicked", function() {
|
||||
navigator.mozLoop.userProfile = {email: "test@example.com"};
|
||||
it("should open the FxA settings when the account entry is clicked",
|
||||
function() {
|
||||
navigator.mozLoop.userProfile = {email: "test@example.com"};
|
||||
|
||||
var view = mountTestComponent();
|
||||
var view = mountTestComponent();
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".icon-account"));
|
||||
TestUtils.Simulate.click(view.getDOMNode()
|
||||
.querySelector(".icon-account"));
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.openFxASettings);
|
||||
});
|
||||
|
||||
it("should hide any account entry when user is not authenticated",
|
||||
function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
|
||||
var view = mountTestComponent();
|
||||
|
||||
expect(view.getDOMNode().querySelectorAll(".icon-account"))
|
||||
.to.have.length.of(0);
|
||||
});
|
||||
|
||||
it("should sign in the user on click when unauthenticated", function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
var view = mountTestComponent();
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".icon-signin"));
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.logInToFxA);
|
||||
});
|
||||
sinon.assert.calledOnce(navigator.mozLoop.openFxASettings);
|
||||
});
|
||||
|
||||
it("should sign out the user on click when authenticated", function() {
|
||||
navigator.mozLoop.userProfile = {email: "test@example.com"};
|
||||
var view = mountTestComponent();
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".icon-signout"));
|
||||
TestUtils.Simulate.click(view.getDOMNode()
|
||||
.querySelector(".icon-signout"));
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.logOutFromFxA);
|
||||
});
|
||||
@ -724,7 +767,8 @@ describe("loop.panel", function() {
|
||||
store: roomStore,
|
||||
dispatcher: dispatcher,
|
||||
userDisplayName: fakeEmail,
|
||||
mozLoop: fakeMozLoop
|
||||
mozLoop: fakeMozLoop,
|
||||
userProfile: null
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ describe("loop.store.RoomStore", function () {
|
||||
|
||||
expect(store.getStoreState().rooms).to.have.length.of(3);
|
||||
expect(store.getStoreState().rooms.reduce(function(count, room) {
|
||||
return count += room.roomToken === sampleRoom.roomToken ? 1 : 0;
|
||||
return count + (room.roomToken === sampleRoom.roomToken ? 1 : 0);
|
||||
}, 0)).eql(1);
|
||||
});
|
||||
});
|
||||
|
@ -289,8 +289,10 @@ add_task(function* basicAuthorizationAndRegistration() {
|
||||
yield loadLoopPanel({stayOnline: true});
|
||||
yield statusChangedPromise;
|
||||
let loopDoc = document.getElementById("loop-panel-iframe").contentDocument;
|
||||
let visibleEmail = loopDoc.getElementsByClassName("user-identity")[0];
|
||||
is(visibleEmail.textContent, "Guest", "Guest should be displayed on the panel when not logged in");
|
||||
let accountLogin = loopDoc.getElementsByClassName("signin-link")[0];
|
||||
let visibleEmail = loopDoc.getElementsByClassName("user-identity");
|
||||
is(visibleEmail.length, 0, "No email should be displayed when logged out");
|
||||
is(accountLogin.textContent, "Sign In or Sign Up", "Login/Signup links when logged out");
|
||||
is(MozLoopService.userProfile, null, "profile should be null before log-in");
|
||||
let loopButton = document.getElementById("loop-button");
|
||||
is(loopButton.getAttribute("state"), "", "state of loop button should be empty when not logged in");
|
||||
@ -303,6 +305,8 @@ add_task(function* basicAuthorizationAndRegistration() {
|
||||
is(tokenData.scope, "profile", "Check scope");
|
||||
is(tokenData.token_type, "bearer", "Check token_type");
|
||||
|
||||
visibleEmail = loopDoc.getElementsByClassName("user-identity")[0];
|
||||
|
||||
is(MozLoopService.userProfile.email, "test@example.com", "email should exist in the profile data");
|
||||
is(MozLoopService.userProfile.uid, "1234abcd", "uid should exist in the profile data");
|
||||
is(visibleEmail.textContent, "test@example.com", "the email should be correct on the panel");
|
||||
@ -328,7 +332,7 @@ add_task(function* basicAuthorizationAndRegistration() {
|
||||
registrationResponse = yield promiseOAuthGetRegistration(BASE_URL);
|
||||
is(registrationResponse.response, null,
|
||||
"Check registration was deleted on the server");
|
||||
is(visibleEmail.textContent, "Guest", "Guest should be displayed on the panel again after logout");
|
||||
is(accountLogin.textContent, "Sign In or Sign Up", "Login/Signup links when logged out");
|
||||
is(MozLoopService.userProfile, null, "userProfile should be null after logout");
|
||||
});
|
||||
|
||||
|
@ -665,4 +665,45 @@ describe("loop.shared.utils", function() {
|
||||
expect(obj).to.eql({ prop1: "null", prop3: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe("#truncate", function() {
|
||||
describe("ltr support", function() {
|
||||
it("should default to 72 chars", function() {
|
||||
var output = sharedUtils.truncate(new Array(75).join());
|
||||
|
||||
expect(output.length).to.eql(73); // 72 + …
|
||||
});
|
||||
|
||||
it("should take a max size argument", function() {
|
||||
var output = sharedUtils.truncate(new Array(73).join(), 20);
|
||||
|
||||
expect(output.length).to.eql(21); // 20 + …
|
||||
});
|
||||
});
|
||||
|
||||
describe("rtl support", function() {
|
||||
var directionStub;
|
||||
|
||||
beforeEach(function() {
|
||||
// XXX should use sandbox
|
||||
// https://github.com/cjohansen/Sinon.JS/issues/781
|
||||
directionStub = sinon.stub(navigator.mozL10n.language, "direction", {
|
||||
get: function() {
|
||||
return "rtl";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
directionStub.restore();
|
||||
});
|
||||
|
||||
it("should support RTL", function() {
|
||||
var output = sharedUtils.truncate(new Array(73).join(), 20);
|
||||
|
||||
expect(output.length).to.eql(21); // 20 + …
|
||||
expect(output.substr(0, 1)).to.eql("…");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -181,6 +181,20 @@ describe("loop.standaloneRoomViews", function() {
|
||||
.not.eql(null);
|
||||
});
|
||||
|
||||
it("should display a waiting room message and tile iframe on JOINED",
|
||||
function() {
|
||||
var DUMMY_TILE_URL = "http://tile/";
|
||||
loop.config.tilesIframeUrl = DUMMY_TILE_URL;
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.JOINED});
|
||||
|
||||
expect(view.getDOMNode().querySelector(".room-waiting-area"))
|
||||
.not.eql(null);
|
||||
|
||||
var tile = view.getDOMNode().querySelector(".room-waiting-tile");
|
||||
expect(tile).not.eql(null);
|
||||
expect(tile.src).eql(DUMMY_TILE_URL);
|
||||
});
|
||||
|
||||
it("should display an empty room message on SESSION_CONNECTED",
|
||||
function() {
|
||||
activeRoomStore.setStoreState({roomState: ROOM_STATES.SESSION_CONNECTED});
|
||||
|
@ -14,7 +14,13 @@
|
||||
navigator.mozL10n = document.mozL10n = {
|
||||
initialize: function(){},
|
||||
|
||||
getDirection: function(){},
|
||||
getDirection: function(){
|
||||
if (document.location.search === "?rtl=1") {
|
||||
return "rtl";
|
||||
}
|
||||
|
||||
return "ltr";
|
||||
},
|
||||
|
||||
get: function(stringId, vars) {
|
||||
|
||||
|
@ -164,6 +164,7 @@ var fakeContacts = [{
|
||||
},
|
||||
fxAEnabled: true,
|
||||
startAlerting: function() {},
|
||||
stopAlerting: function() {}
|
||||
stopAlerting: function() {},
|
||||
userProfile: null
|
||||
};
|
||||
})();
|
||||
|
@ -129,6 +129,9 @@ body {
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.room-waiting-tile {
|
||||
background-color: grey;
|
||||
}
|
||||
/* SVG icons showcase */
|
||||
|
||||
.svg-icons h3 {
|
||||
@ -162,3 +165,9 @@ body {
|
||||
.standalone.text-chat-example .text-chat-view {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
/* Force dropdown menus to display. */
|
||||
.force-menu-show * {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
// 1. Desktop components
|
||||
// 1.1 Panel
|
||||
var AvailabilityDropdown = loop.panel.AvailabilityDropdown;
|
||||
var PanelView = loop.panel.PanelView;
|
||||
var SignInRequestView = loop.panel.SignInRequestView;
|
||||
// 1.2. Conversation Window
|
||||
@ -438,7 +439,17 @@
|
||||
|
||||
// Local mocks
|
||||
|
||||
var mockMozLoopRooms = _.extend({}, navigator.mozLoop);
|
||||
var mockMozLoopLoggedIn = _.cloneDeep(navigator.mozLoop);
|
||||
mockMozLoopLoggedIn.userProfile = {
|
||||
email: "text@example.com",
|
||||
uid: "0354b278a381d3cb408bb46ffc01266"
|
||||
};
|
||||
|
||||
var mockMozLoopLoggedInLongEmail = _.cloneDeep(navigator.mozLoop);
|
||||
mockMozLoopLoggedInLongEmail.userProfile = {
|
||||
email: "reallyreallylongtext@example.com",
|
||||
uid: "0354b278a381d3cb408bb46ffc01266"
|
||||
};
|
||||
|
||||
var mockContact = {
|
||||
name: ["Mr Smith"],
|
||||
@ -492,7 +503,8 @@
|
||||
"10x10": ["close", "close-active", "close-disabled", "dropdown",
|
||||
"dropdown-white", "dropdown-active", "dropdown-disabled", "edit",
|
||||
"edit-active", "edit-disabled", "edit-white", "expand", "expand-active",
|
||||
"expand-disabled", "minimize", "minimize-active", "minimize-disabled"
|
||||
"expand-disabled", "minimize", "minimize-active", "minimize-disabled",
|
||||
"settings-cog"
|
||||
],
|
||||
"14x14": ["audio", "audio-active", "audio-disabled", "facemute",
|
||||
"facemute-active", "facemute-disabled", "hangup", "hangup-active",
|
||||
@ -509,7 +521,8 @@
|
||||
"precall", "precall-hover", "precall-active", "screen-white", "screenmute-white",
|
||||
"settings", "settings-hover", "settings-active", "share-darkgrey", "tag",
|
||||
"tag-hover", "tag-active", "trash", "unblock", "unblock-hover", "unblock-active",
|
||||
"video", "video-hover", "video-active", "tour"
|
||||
"video", "video-hover", "video-active", "tour", "status-available",
|
||||
"status-unavailable"
|
||||
]
|
||||
},
|
||||
|
||||
@ -580,6 +593,7 @@
|
||||
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
|
||||
@ -591,8 +605,14 @@
|
||||
|
||||
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: "example"},
|
||||
React.createElement("div", {className: cx(extraCSSClass)},
|
||||
React.createElement("h3", {id: this.makeId()},
|
||||
this.props.summary,
|
||||
React.createElement("a", {href: this.makeId("#")}, " ¶")
|
||||
@ -693,25 +713,31 @@
|
||||
React.createElement("strong", null, "Note:"), " 332px wide."
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Re-sign-in view"},
|
||||
React.createElement(SignInRequestView, {mozLoop: mockMozLoopRooms})
|
||||
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: mockMozLoopRooms,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "rooms",
|
||||
userProfile: {email: "test@example.com"}})
|
||||
selectedTab: "rooms"})
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact list tab"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopRooms,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: notifications,
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts",
|
||||
userProfile: {email: "test@example.com"}})
|
||||
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(Example, {dashed: true, style: {width: "332px"}, summary: "Error Notification"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
@ -723,26 +749,38 @@
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Error Notification - authenticated"},
|
||||
React.createElement(PanelView, {client: mockClient,
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: navigator.mozLoop,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: errNotifications,
|
||||
roomStore: roomStore,
|
||||
userProfile: {email: "test@example.com"}})
|
||||
roomStore: roomStore})
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact import success"},
|
||||
React.createElement(PanelView, {dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopRooms,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: new loop.shared.models.NotificationCollection([{level: "success", message: "Import success"}]),
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts",
|
||||
userProfile: {email: "test@example.com"}})
|
||||
selectedTab: "contacts"})
|
||||
),
|
||||
React.createElement(Example, {dashed: true, style: {width: "332px"}, summary: "Contact import error"},
|
||||
React.createElement(PanelView, {dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopRooms,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
notifications: new loop.shared.models.NotificationCollection([{level: "error", message: "Import error"}]),
|
||||
roomStore: roomStore,
|
||||
selectedTab: "contacts",
|
||||
userProfile: {email: "test@example.com"}})
|
||||
selectedTab: "contacts"})
|
||||
)
|
||||
),
|
||||
|
||||
React.createElement(Section, {name: "Availability Dropdown"},
|
||||
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(Example, {cssClass: "force-menu-show", dashed: true,
|
||||
style: {width: "332px", height: "200px"},
|
||||
summary: "AvailabilityDropdown Expanded"},
|
||||
React.createElement(AvailabilityDropdown, null)
|
||||
)
|
||||
),
|
||||
|
||||
@ -753,7 +791,7 @@
|
||||
React.createElement(AcceptCallView, {callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "Mr Smith",
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopRooms})
|
||||
mozLoop: mockMozLoopLoggedIn})
|
||||
)
|
||||
),
|
||||
|
||||
@ -763,7 +801,7 @@
|
||||
React.createElement(AcceptCallView, {callType: CALL_TYPES.AUDIO_ONLY,
|
||||
callerId: "Mr Smith",
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopRooms})
|
||||
mozLoop: mockMozLoopLoggedIn})
|
||||
)
|
||||
)
|
||||
),
|
||||
@ -775,7 +813,7 @@
|
||||
React.createElement(AcceptCallView, {callType: CALL_TYPES.AUDIO_VIDEO,
|
||||
callerId: "Mr Smith",
|
||||
dispatcher: dispatcher,
|
||||
mozLoop: mockMozLoopRooms,
|
||||
mozLoop: mockMozLoopLoggedIn,
|
||||
showMenu: true})
|
||||
)
|
||||
)
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
// 1. Desktop components
|
||||
// 1.1 Panel
|
||||
var AvailabilityDropdown = loop.panel.AvailabilityDropdown;
|
||||
var PanelView = loop.panel.PanelView;
|
||||
var SignInRequestView = loop.panel.SignInRequestView;
|
||||
// 1.2. Conversation Window
|
||||
@ -438,7 +439,17 @@
|
||||
|
||||
// Local mocks
|
||||
|
||||
var mockMozLoopRooms = _.extend({}, navigator.mozLoop);
|
||||
var mockMozLoopLoggedIn = _.cloneDeep(navigator.mozLoop);
|
||||
mockMozLoopLoggedIn.userProfile = {
|
||||
email: "text@example.com",
|
||||
uid: "0354b278a381d3cb408bb46ffc01266"
|
||||
};
|
||||
|
||||
var mockMozLoopLoggedInLongEmail = _.cloneDeep(navigator.mozLoop);
|
||||
mockMozLoopLoggedInLongEmail.userProfile = {
|
||||
email: "reallyreallylongtext@example.com",
|
||||
uid: "0354b278a381d3cb408bb46ffc01266"
|
||||
};
|
||||
|
||||
var mockContact = {
|
||||
name: ["Mr Smith"],
|
||||
@ -492,7 +503,8 @@
|
||||
"10x10": ["close", "close-active", "close-disabled", "dropdown",
|
||||
"dropdown-white", "dropdown-active", "dropdown-disabled", "edit",
|
||||
"edit-active", "edit-disabled", "edit-white", "expand", "expand-active",
|
||||
"expand-disabled", "minimize", "minimize-active", "minimize-disabled"
|
||||
"expand-disabled", "minimize", "minimize-active", "minimize-disabled",
|
||||
"settings-cog"
|
||||
],
|
||||
"14x14": ["audio", "audio-active", "audio-disabled", "facemute",
|
||||
"facemute-active", "facemute-disabled", "hangup", "hangup-active",
|
||||
@ -509,7 +521,8 @@
|
||||
"precall", "precall-hover", "precall-active", "screen-white", "screenmute-white",
|
||||
"settings", "settings-hover", "settings-active", "share-darkgrey", "tag",
|
||||
"tag-hover", "tag-active", "trash", "unblock", "unblock-hover", "unblock-active",
|
||||
"video", "video-hover", "video-active", "tour"
|
||||
"video", "video-hover", "video-active", "tour", "status-available",
|
||||
"status-unavailable"
|
||||
]
|
||||
},
|
||||
|
||||
@ -580,6 +593,7 @@
|
||||
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
|
||||
@ -591,8 +605,14 @@
|
||||
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
var extraCSSClass = {
|
||||
"example": true
|
||||
};
|
||||
if (this.props.cssClass) {
|
||||
extraCSSClass[this.props.cssClass] = true;
|
||||
}
|
||||
return (
|
||||
<div className="example">
|
||||
<div className={cx(extraCSSClass)}>
|
||||
<h3 id={this.makeId()}>
|
||||
{this.props.summary}
|
||||
<a href={this.makeId("#")}> ¶</a>
|
||||
@ -693,25 +713,31 @@
|
||||
<strong>Note:</strong> 332px wide.
|
||||
</p>
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Re-sign-in view">
|
||||
<SignInRequestView mozLoop={mockMozLoopRooms} />
|
||||
<SignInRequestView mozLoop={mockMozLoopLoggedIn} />
|
||||
</Example>
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Room list tab">
|
||||
<PanelView client={mockClient}
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopRooms}
|
||||
mozLoop={mockMozLoopLoggedIn}
|
||||
notifications={notifications}
|
||||
roomStore={roomStore}
|
||||
selectedTab="rooms"
|
||||
userProfile={{email: "test@example.com"}} />
|
||||
selectedTab="rooms" />
|
||||
</Example>
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Contact list tab">
|
||||
<PanelView client={mockClient}
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopRooms}
|
||||
mozLoop={mockMozLoopLoggedIn}
|
||||
notifications={notifications}
|
||||
roomStore={roomStore}
|
||||
selectedTab="contacts"
|
||||
userProfile={{email: "test@example.com"}} />
|
||||
selectedTab="contacts" />
|
||||
</Example>
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Contact list tab long email">
|
||||
<PanelView client={mockClient}
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopLoggedInLongEmail}
|
||||
notifications={notifications}
|
||||
roomStore={roomStore}
|
||||
selectedTab="contacts" />
|
||||
</Example>
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Error Notification">
|
||||
<PanelView client={mockClient}
|
||||
@ -723,26 +749,38 @@
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Error Notification - authenticated">
|
||||
<PanelView client={mockClient}
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={navigator.mozLoop}
|
||||
mozLoop={mockMozLoopLoggedIn}
|
||||
notifications={errNotifications}
|
||||
roomStore={roomStore}
|
||||
userProfile={{email: "test@example.com"}} />
|
||||
roomStore={roomStore} />
|
||||
</Example>
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Contact import success">
|
||||
<PanelView dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopRooms}
|
||||
mozLoop={mockMozLoopLoggedIn}
|
||||
notifications={new loop.shared.models.NotificationCollection([{level: "success", message: "Import success"}])}
|
||||
roomStore={roomStore}
|
||||
selectedTab="contacts"
|
||||
userProfile={{email: "test@example.com"}} />
|
||||
selectedTab="contacts" />
|
||||
</Example>
|
||||
<Example dashed={true} style={{width: "332px"}} summary="Contact import error">
|
||||
<PanelView dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopRooms}
|
||||
mozLoop={mockMozLoopLoggedIn}
|
||||
notifications={new loop.shared.models.NotificationCollection([{level: "error", message: "Import error"}])}
|
||||
roomStore={roomStore}
|
||||
selectedTab="contacts"
|
||||
userProfile={{email: "test@example.com"}} />
|
||||
selectedTab="contacts" />
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
<Section name="Availability Dropdown">
|
||||
<p className="note">
|
||||
<strong>Note:</strong> 332px wide.
|
||||
</p>
|
||||
<Example dashed={true} style={{width: "332px", height: "200px"}}
|
||||
summary="AvailabilityDropdown">
|
||||
<AvailabilityDropdown />
|
||||
</Example>
|
||||
<Example cssClass="force-menu-show" dashed={true}
|
||||
style={{width: "332px", height: "200px"}}
|
||||
summary="AvailabilityDropdown Expanded">
|
||||
<AvailabilityDropdown />
|
||||
</Example>
|
||||
</Section>
|
||||
|
||||
@ -753,7 +791,7 @@
|
||||
<AcceptCallView callType={CALL_TYPES.AUDIO_VIDEO}
|
||||
callerId="Mr Smith"
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopRooms} />
|
||||
mozLoop={mockMozLoopLoggedIn} />
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
@ -763,7 +801,7 @@
|
||||
<AcceptCallView callType={CALL_TYPES.AUDIO_ONLY}
|
||||
callerId="Mr Smith"
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopRooms} />
|
||||
mozLoop={mockMozLoopLoggedIn} />
|
||||
</div>
|
||||
</Example>
|
||||
</Section>
|
||||
@ -775,7 +813,7 @@
|
||||
<AcceptCallView callType={CALL_TYPES.AUDIO_VIDEO}
|
||||
callerId="Mr Smith"
|
||||
dispatcher={dispatcher}
|
||||
mozLoop={mockMozLoopRooms}
|
||||
mozLoop={mockMozLoopLoggedIn}
|
||||
showMenu={true} />
|
||||
</div>
|
||||
</Example>
|
||||
|
@ -119,6 +119,7 @@ let gSyncPane = {
|
||||
"weave:service:setup-complete",
|
||||
"weave:service:logout:finish",
|
||||
FxAccountsCommon.ONVERIFIED_NOTIFICATION,
|
||||
FxAccountsCommon.ONLOGIN_NOTIFICATION,
|
||||
FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION,
|
||||
];
|
||||
let migrateTopic = "fxa-migration:state-changed";
|
||||
|
@ -33,13 +33,13 @@ const styleEditorProps = "chrome://browser/locale/devtools/styleeditor.propertie
|
||||
const shaderEditorProps = "chrome://browser/locale/devtools/shadereditor.properties";
|
||||
const canvasDebuggerProps = "chrome://browser/locale/devtools/canvasdebugger.properties";
|
||||
const webAudioEditorProps = "chrome://browser/locale/devtools/webaudioeditor.properties";
|
||||
const profilerProps = "chrome://browser/locale/devtools/profiler.properties";
|
||||
const performanceProps = "chrome://browser/locale/devtools/performance.properties";
|
||||
const netMonitorProps = "chrome://browser/locale/devtools/netmonitor.properties";
|
||||
const storageProps = "chrome://browser/locale/devtools/storage.properties";
|
||||
const scratchpadProps = "chrome://browser/locale/devtools/scratchpad.properties";
|
||||
|
||||
loader.lazyGetter(this, "toolboxStrings", () => Services.strings.createBundle(toolboxProps));
|
||||
loader.lazyGetter(this, "profilerStrings",() => Services.strings.createBundle(profilerProps));
|
||||
loader.lazyGetter(this, "performanceStrings",() => Services.strings.createBundle(performanceProps));
|
||||
loader.lazyGetter(this, "webConsoleStrings", () => Services.strings.createBundle(webConsoleProps));
|
||||
loader.lazyGetter(this, "debuggerStrings", () => Services.strings.createBundle(debuggerProps));
|
||||
loader.lazyGetter(this, "styleEditorStrings", () => Services.strings.createBundle(styleEditorProps));
|
||||
@ -254,14 +254,14 @@ Tools.performance = {
|
||||
highlightedicon: "chrome://browser/skin/devtools/tool-profiler-active.svg",
|
||||
url: "chrome://browser/content/devtools/performance.xul",
|
||||
visibilityswitch: "devtools.performance.enabled",
|
||||
label: l10n("profiler.label2", profilerStrings),
|
||||
panelLabel: l10n("profiler.panelLabel2", profilerStrings),
|
||||
label: l10n("performance.label", performanceStrings),
|
||||
panelLabel: l10n("performance.panelLabel", performanceStrings),
|
||||
get tooltip() {
|
||||
return l10n("profiler.tooltip3", profilerStrings,
|
||||
return l10n("performance.tooltip", performanceStrings,
|
||||
"Shift+" + functionkey(this.key));
|
||||
},
|
||||
accesskey: l10n("profiler.accesskey", profilerStrings),
|
||||
key: l10n("profiler.commandkey2", profilerStrings),
|
||||
accesskey: l10n("performance.accesskey", performanceStrings),
|
||||
key: l10n("performance.commandkey", performanceStrings),
|
||||
modifiers: "shift",
|
||||
inMenu: true,
|
||||
|
||||
|
@ -7,11 +7,10 @@ const { ViewHelpers } = require("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
||||
/**
|
||||
* Localization convenience methods.
|
||||
+ TODO: merge these into a single file: Bug 1082695.
|
||||
*/
|
||||
const L10N = new ViewHelpers.MultiL10N([
|
||||
"chrome://browser/locale/devtools/timeline.properties",
|
||||
"chrome://browser/locale/devtools/profiler.properties"
|
||||
"chrome://browser/locale/devtools/markers.properties",
|
||||
"chrome://browser/locale/devtools/performance.properties"
|
||||
]);
|
||||
|
||||
/**
|
||||
|
@ -93,12 +93,8 @@ function getMarkerFields (marker) {
|
||||
// If blueprint.fields is a function, use that
|
||||
if (typeof blueprint.fields === "function") {
|
||||
let fields = blueprint.fields(marker);
|
||||
// Add a ":" to the label since the localization files contain the ":"
|
||||
// if not present. This should be changed, ugh.
|
||||
return Object.keys(fields || []).map(label => {
|
||||
// TODO revisit localization strings for markers bug 1163763
|
||||
let normalizedLabel = label.indexOf(":") !== -1 ? label : (label + ":");
|
||||
return { label: normalizedLabel, value: fields[label] };
|
||||
return { label, value: fields[label] };
|
||||
});
|
||||
}
|
||||
|
||||
@ -168,7 +164,7 @@ const DOM = {
|
||||
* @return {Element}
|
||||
*/
|
||||
buildDuration: function (doc, marker) {
|
||||
let label = L10N.getStr("timeline.markerDetail.duration");
|
||||
let label = L10N.getStr("marker.field.duration");
|
||||
let start = L10N.getFormatStrWithNumbers("timeline.tick", marker.start);
|
||||
let end = L10N.getFormatStrWithNumbers("timeline.tick", marker.end);
|
||||
let duration = L10N.getFormatStrWithNumbers("timeline.tick", marker.end - marker.start);
|
||||
@ -217,7 +213,7 @@ const DOM = {
|
||||
let container = doc.createElement("vbox");
|
||||
let labelName = doc.createElement("label");
|
||||
labelName.className = "plain marker-details-labelname";
|
||||
labelName.setAttribute("value", L10N.getStr(`timeline.markerDetail.${type}`));
|
||||
labelName.setAttribute("value", L10N.getStr(`marker.field.${type}`));
|
||||
container.setAttribute("type", type);
|
||||
container.className = "marker-details-stack";
|
||||
container.appendChild(labelName);
|
||||
@ -235,7 +231,7 @@ const DOM = {
|
||||
let asyncBox = doc.createElement("hbox");
|
||||
let asyncLabel = doc.createElement("label");
|
||||
asyncLabel.className = "devtools-monospace";
|
||||
asyncLabel.setAttribute("value", L10N.getFormatStr("timeline.markerDetail.asyncStack",
|
||||
asyncLabel.setAttribute("value", L10N.getFormatStr("marker.field.asyncStack",
|
||||
frame.asyncCause));
|
||||
asyncBox.appendChild(asyncLabel);
|
||||
container.appendChild(asyncBox);
|
||||
@ -278,7 +274,7 @@ const DOM = {
|
||||
|
||||
if (!displayName && !url) {
|
||||
let label = doc.createElement("label");
|
||||
label.setAttribute("value", L10N.getStr("timeline.markerDetail.unknownFrame"));
|
||||
label.setAttribute("value", L10N.getStr("marker.value.unknownFrame"));
|
||||
hbox.appendChild(label);
|
||||
}
|
||||
|
||||
@ -301,18 +297,19 @@ const DOM = {
|
||||
* markers that are considered "from content" should be labeled here.
|
||||
*/
|
||||
const JS_MARKER_MAP = {
|
||||
"<script> element": "Script Tag",
|
||||
"<script> element": L10N.getStr("marker.label.javascript.scriptElement"),
|
||||
"promise callback": L10N.getStr("marker.label.javascript.promiseCallback"),
|
||||
"promise initializer": L10N.getStr("marker.label.javascript.promiseInit"),
|
||||
"Worker runnable": L10N.getStr("marker.label.javascript.workerRunnable"),
|
||||
"javascript: URI": L10N.getStr("marker.label.javascript.jsURI"),
|
||||
// The difference between these two event handler markers are differences
|
||||
// in their WebIDL implementation, so distinguishing them is not necessary.
|
||||
"EventHandlerNonNull": L10N.getStr("marker.label.javascript.eventHandler"),
|
||||
"EventListener.handleEvent": L10N.getStr("marker.label.javascript.eventHandler"),
|
||||
// These markers do not get L10N'd because they're JS names.
|
||||
"setInterval handler": "setInterval",
|
||||
"setTimeout handler": "setTimeout",
|
||||
"FrameRequestCallback": "requestAnimationFrame",
|
||||
"promise callback": "Promise Callback",
|
||||
"promise initializer": "Promise Init",
|
||||
"Worker runnable": "Worker",
|
||||
"javascript: URI": "JavaScript URI",
|
||||
// The difference between these two event handler markers are differences
|
||||
// in their WebIDL implementation, so distinguishing them is not necessary.
|
||||
"EventHandlerNonNull": "Event Handler",
|
||||
"EventListener.handleEvent": "Event Handler",
|
||||
};
|
||||
|
||||
/**
|
||||
@ -324,21 +321,20 @@ const Formatters = {
|
||||
* a blueprint entry. Uses "Other" in the marker filter menu.
|
||||
*/
|
||||
UnknownLabel: function (marker={}) {
|
||||
return marker.name || L10N.getStr("timeline.label.unknown");
|
||||
return marker.name || L10N.getStr("marker.label.unknown");
|
||||
},
|
||||
|
||||
GCLabel: function (marker={}) {
|
||||
let label = L10N.getStr("timeline.label.garbageCollection");
|
||||
// Only if a `nonincrementalReason` exists, do we want to label
|
||||
// this as a non incremental GC event.
|
||||
if ("nonincrementalReason" in marker) {
|
||||
label = `${label} (Non-incremental)`;
|
||||
return L10N.getStr("marker.label.garbageCollection.nonIncremental");
|
||||
}
|
||||
return label;
|
||||
return L10N.getStr("marker.label.garbageCollection");
|
||||
},
|
||||
|
||||
JSLabel: function (marker={}) {
|
||||
let generic = L10N.getStr("timeline.label.javascript2");
|
||||
let generic = L10N.getStr("marker.label.javascript");
|
||||
if ("causeName" in marker) {
|
||||
return JS_MARKER_MAP[marker.causeName] || generic;
|
||||
}
|
||||
@ -357,40 +353,44 @@ const Formatters = {
|
||||
*/
|
||||
JSFields: function (marker) {
|
||||
if ("causeName" in marker && !JS_MARKER_MAP[marker.causeName]) {
|
||||
return { Reason: PREFS["show-platform-data"] ? marker.causeName : GECKO_SYMBOL };
|
||||
let cause = PREFS["show-platform-data"] ? marker.causeName : GECKO_SYMBOL;
|
||||
return {
|
||||
[L10N.getStr("marker.field.causeName")]: cause
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
DOMEventFields: function (marker) {
|
||||
let fields = Object.create(null);
|
||||
if ("type" in marker) {
|
||||
fields[L10N.getStr("timeline.markerDetail.DOMEventType")] = marker.type;
|
||||
fields[L10N.getStr("marker.field.DOMEventType")] = marker.type;
|
||||
}
|
||||
if ("eventPhase" in marker) {
|
||||
let phase;
|
||||
if (marker.eventPhase === Ci.nsIDOMEvent.AT_TARGET) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventTargetPhase");
|
||||
phase = L10N.getStr("marker.value.DOMEventTargetPhase");
|
||||
} else if (marker.eventPhase === Ci.nsIDOMEvent.CAPTURING_PHASE) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventCapturingPhase");
|
||||
phase = L10N.getStr("marker.value.DOMEventCapturingPhase");
|
||||
} else if (marker.eventPhase === Ci.nsIDOMEvent.BUBBLING_PHASE) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventBubblingPhase");
|
||||
phase = L10N.getStr("marker.value.DOMEventBubblingPhase");
|
||||
}
|
||||
fields[L10N.getStr("timeline.markerDetail.DOMEventPhase")] = phase;
|
||||
fields[L10N.getStr("marker.field.DOMEventPhase")] = phase;
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
|
||||
StylesFields: function (marker) {
|
||||
if ("restyleHint" in marker) {
|
||||
return { "Restyle Hint": marker.restyleHint.replace(/eRestyle_/g, "") };
|
||||
return {
|
||||
[L10N.getStr("marker.field.restyleHint")]: marker.restyleHint.replace(/eRestyle_/g, "")
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
CycleCollectionFields: function (marker) {
|
||||
let Type = PREFS["show-platform-data"]
|
||||
? marker.name
|
||||
: marker.name.replace(/nsCycleCollector::/g, "");
|
||||
return { Type };
|
||||
return {
|
||||
[L10N.getStr("marker.field.type")]: marker.name.replace(/nsCycleCollector::/g, "")
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -371,9 +371,8 @@ RecordingModel.prototype = {
|
||||
case "allocations": {
|
||||
if (!config.withAllocations) { break; }
|
||||
let [{ sites, timestamps, frames, counts }] = data;
|
||||
let timeOffset = this._memoryStartTime * 1000;
|
||||
let timeScale = 1000;
|
||||
RecordingUtils.offsetAndScaleTimestamps(timestamps, timeOffset, timeScale);
|
||||
let timeOffset = this._memoryStartTime;
|
||||
RecordingUtils.offsetAndScaleTimestamps(timestamps, timeOffset);
|
||||
pushAll(this._allocations.sites, sites);
|
||||
pushAll(this._allocations.timestamps, timestamps);
|
||||
pushAll(this._allocations.frames, frames);
|
||||
|
@ -106,7 +106,9 @@ function offsetMarkerTimes(markers, timeOffset) {
|
||||
function offsetAndScaleTimestamps(timestamps, timeOffset, timeScale) {
|
||||
for (let i = 0, len = timestamps.length; i < len; i++) {
|
||||
timestamps[i] -= timeOffset;
|
||||
timestamps[i] /= timeScale;
|
||||
if (timeScale) {
|
||||
timestamps[i] /= timeScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ const { Formatters } = require("devtools/performance/marker-utils");
|
||||
* A simple schema for mapping markers to the timeline UI. The keys correspond
|
||||
* to marker names, while the values are objects with the following format:
|
||||
*
|
||||
* - group: The row index in the timeline overview graph; multiple markers
|
||||
* - group: The row index in the overview graph; multiple markers
|
||||
* can be added on the same row. @see <overview.js/buildGraphImage>
|
||||
* - label: The label used in the waterfall to identify the marker. Can be a
|
||||
* string or just a function that accepts the marker and returns a
|
||||
@ -60,25 +60,25 @@ const TIMELINE_BLUEPRINT = {
|
||||
"Styles": {
|
||||
group: 0,
|
||||
colorName: "graphs-purple",
|
||||
label: L10N.getStr("timeline.label.styles2"),
|
||||
label: L10N.getStr("marker.label.styles"),
|
||||
fields: Formatters.StylesFields,
|
||||
},
|
||||
"Reflow": {
|
||||
group: 0,
|
||||
colorName: "graphs-purple",
|
||||
label: L10N.getStr("timeline.label.reflow2"),
|
||||
label: L10N.getStr("marker.label.reflow"),
|
||||
},
|
||||
"Paint": {
|
||||
group: 0,
|
||||
colorName: "graphs-green",
|
||||
label: L10N.getStr("timeline.label.paint"),
|
||||
label: L10N.getStr("marker.label.paint"),
|
||||
},
|
||||
|
||||
/* Group 1 - JS */
|
||||
"DOMEvent": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.domevent"),
|
||||
label: L10N.getStr("marker.label.domevent"),
|
||||
fields: Formatters.DOMEventFields,
|
||||
},
|
||||
"Javascript": {
|
||||
@ -90,32 +90,32 @@ const TIMELINE_BLUEPRINT = {
|
||||
"Parse HTML": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.parseHTML"),
|
||||
label: L10N.getStr("marker.label.parseHTML"),
|
||||
},
|
||||
"Parse XML": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.parseXML"),
|
||||
label: L10N.getStr("marker.label.parseXML"),
|
||||
},
|
||||
"GarbageCollection": {
|
||||
group: 1,
|
||||
colorName: "graphs-red",
|
||||
label: Formatters.GCLabel,
|
||||
fields: [
|
||||
{ property: "causeName", label: "Reason:" },
|
||||
{ property: "nonincrementalReason", label: "Non-incremental Reason:" }
|
||||
{ property: "causeName", label: L10N.getStr("marker.field.causeName") },
|
||||
{ property: "nonincrementalReason", label: L10N.getStr("marker.field.nonIncrementalCause") }
|
||||
],
|
||||
},
|
||||
"nsCycleCollector::Collect": {
|
||||
group: 1,
|
||||
colorName: "graphs-red",
|
||||
label: "Cycle Collection",
|
||||
label: L10N.getStr("marker.label.cycleCollection"),
|
||||
fields: Formatters.CycleCollectionFields,
|
||||
},
|
||||
"nsCycleCollector::ForgetSkippable": {
|
||||
group: 1,
|
||||
colorName: "graphs-red",
|
||||
label: "Cycle Collection",
|
||||
label: L10N.getStr("marker.label.cycleCollection.forgetSkippable"),
|
||||
fields: Formatters.CycleCollectionFields,
|
||||
},
|
||||
|
||||
@ -123,10 +123,10 @@ const TIMELINE_BLUEPRINT = {
|
||||
"ConsoleTime": {
|
||||
group: 2,
|
||||
colorName: "graphs-blue",
|
||||
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
|
||||
label: sublabelForProperty(L10N.getStr("marker.label.consoleTime"), "causeName"),
|
||||
fields: [{
|
||||
property: "causeName",
|
||||
label: L10N.getStr("timeline.markerDetail.consoleTimerName")
|
||||
label: L10N.getStr("marker.field.consoleTimerName")
|
||||
}],
|
||||
nestable: false,
|
||||
collapsible: false,
|
||||
@ -134,7 +134,7 @@ const TIMELINE_BLUEPRINT = {
|
||||
"TimeStamp": {
|
||||
group: 2,
|
||||
colorName: "graphs-blue",
|
||||
label: sublabelForProperty(L10N.getStr("timeline.label.timestamp"), "causeName"),
|
||||
label: sublabelForProperty(L10N.getStr("marker.label.timestamp"), "causeName"),
|
||||
fields: [{
|
||||
property: "causeName",
|
||||
label: "Label:"
|
||||
|
@ -24,8 +24,8 @@ loader.lazyRequireGetter(this, "getColor",
|
||||
"devtools/shared/theme", true);
|
||||
loader.lazyRequireGetter(this, "ProfilerGlobal",
|
||||
"devtools/performance/global");
|
||||
loader.lazyRequireGetter(this, "TimelineGlobal",
|
||||
"devtools/performance/global");
|
||||
loader.lazyRequireGetter(this, "L10N",
|
||||
"devtools/performance/global", true);
|
||||
loader.lazyRequireGetter(this, "MarkersOverview",
|
||||
"devtools/performance/markers-overview", true);
|
||||
|
||||
@ -124,7 +124,7 @@ FramerateGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
|
||||
* The parent node holding the overview.
|
||||
*/
|
||||
function MemoryGraph(parent) {
|
||||
PerformanceGraph.call(this, parent, TimelineGlobal.L10N.getStr("graphs.memory"));
|
||||
PerformanceGraph.call(this, parent, L10N.getStr("graphs.memory"));
|
||||
}
|
||||
|
||||
MemoryGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
|
||||
|
@ -11,8 +11,6 @@ const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
|
||||
loader.lazyRequireGetter(this, "EventEmitter",
|
||||
"devtools/toolkit/event-emitter");
|
||||
loader.lazyRequireGetter(this, "L10N",
|
||||
"devtools/performance/global", true);
|
||||
loader.lazyRequireGetter(this, "MarkerUtils",
|
||||
"devtools/performance/marker-utils");
|
||||
|
||||
|
@ -173,7 +173,7 @@ let PerformanceView = {
|
||||
$container.setAttribute("buffer-status", "in-progress");
|
||||
}
|
||||
|
||||
$bufferLabel.value = `Buffer ${percent}% full`;
|
||||
$bufferLabel.value = L10N.getFormatStr("profiler.bufferFull", percent);
|
||||
this.emit(EVENTS.UI_BUFFER_UPDATED, percent);
|
||||
},
|
||||
|
||||
@ -289,8 +289,7 @@ let PerformanceView = {
|
||||
*/
|
||||
_onImportButtonClick: function(e) {
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
// TODO localize? in bug 1163763
|
||||
fp.init(window, "Import recording…", Ci.nsIFilePicker.modeOpen);
|
||||
fp.init(window, L10N.getStr("recordingsList.importDialogTitle"), Ci.nsIFilePicker.modeOpen);
|
||||
fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
|
||||
fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
|
||||
|
||||
|
@ -8,8 +8,8 @@
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/performance.css" type="text/css"?>
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % profilerDTD SYSTEM "chrome://browser/locale/devtools/profiler.dtd">
|
||||
%profilerDTD;
|
||||
<!ENTITY % performanceDTD SYSTEM "chrome://browser/locale/devtools/performance.dtd">
|
||||
%performanceDTD;
|
||||
]>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
@ -36,46 +36,46 @@
|
||||
<menuitem id="option-show-platform-data"
|
||||
type="checkbox"
|
||||
data-pref="show-platform-data"
|
||||
label="&profilerUI.showPlatformData;"
|
||||
tooltiptext="&profilerUI.showPlatformData.tooltiptext;"/>
|
||||
label="&performanceUI.showPlatformData;"
|
||||
tooltiptext="&performanceUI.showPlatformData.tooltiptext;"/>
|
||||
<menuitem id="option-enable-memory"
|
||||
class="experimental-option"
|
||||
type="checkbox"
|
||||
data-pref="enable-memory"
|
||||
label="&profilerUI.enableMemory;"
|
||||
tooltiptext="&profilerUI.enableMemory.tooltiptext;"/>
|
||||
label="&performanceUI.enableMemory;"
|
||||
tooltiptext="&performanceUI.enableMemory.tooltiptext;"/>
|
||||
<menuitem id="option-enable-allocations"
|
||||
class="experimental-option"
|
||||
type="checkbox"
|
||||
data-pref="enable-allocations"
|
||||
label="&profilerUI.enableAllocations;"
|
||||
tooltiptext="&profilerUI.enableAllocations.tooltiptext;"/>
|
||||
label="&performanceUI.enableAllocations;"
|
||||
tooltiptext="&performanceUI.enableAllocations.tooltiptext;"/>
|
||||
<menuitem id="option-enable-framerate"
|
||||
type="checkbox"
|
||||
data-pref="enable-framerate"
|
||||
label="&profilerUI.enableFramerate;"
|
||||
tooltiptext="&profilerUI.enableFramerate.tooltiptext;"/>
|
||||
label="&performanceUI.enableFramerate;"
|
||||
tooltiptext="&performanceUI.enableFramerate.tooltiptext;"/>
|
||||
<menuitem id="option-invert-call-tree"
|
||||
type="checkbox"
|
||||
data-pref="invert-call-tree"
|
||||
label="&profilerUI.invertTree;"
|
||||
tooltiptext="&profilerUI.invertTree.tooltiptext;"/>
|
||||
label="&performanceUI.invertTree;"
|
||||
tooltiptext="&performanceUI.invertTree.tooltiptext;"/>
|
||||
<menuitem id="option-invert-flame-graph"
|
||||
type="checkbox"
|
||||
data-pref="invert-flame-graph"
|
||||
label="&profilerUI.invertFlameGraph;"
|
||||
tooltiptext="&profilerUI.invertFlameGraph.tooltiptext;"/>
|
||||
label="&performanceUI.invertFlameGraph;"
|
||||
tooltiptext="&performanceUI.invertFlameGraph.tooltiptext;"/>
|
||||
<menuitem id="option-flatten-tree-recursion"
|
||||
type="checkbox"
|
||||
data-pref="flatten-tree-recursion"
|
||||
label="&profilerUI.flattenTreeRecursion;"
|
||||
tooltiptext="&profilerUI.flattenTreeRecursion.tooltiptext;"/>
|
||||
label="&performanceUI.flattenTreeRecursion;"
|
||||
tooltiptext="&performanceUI.flattenTreeRecursion.tooltiptext;"/>
|
||||
<menuitem id="option-enable-jit-optimizations"
|
||||
class="experimental-option"
|
||||
type="checkbox"
|
||||
data-pref="enable-jit-optimizations"
|
||||
label="&profilerUI.enableJITOptimizations;"
|
||||
tooltiptext="&profilerUI.enableJITOptimizations.tooltiptext;"/>
|
||||
label="&performanceUI.enableJITOptimizations;"
|
||||
tooltiptext="&performanceUI.enableJITOptimizations.tooltiptext;"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
@ -89,13 +89,13 @@
|
||||
class="devtools-toolbarbutton-group">
|
||||
<toolbarbutton id="main-record-button"
|
||||
class="devtools-toolbarbutton record-button"
|
||||
tooltiptext="&profilerUI.recordButton2.tooltip;"/>
|
||||
tooltiptext="&performanceUI.recordButton.tooltip;"/>
|
||||
<toolbarbutton id="import-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&profilerUI.importButton;"/>
|
||||
label="&performanceUI.importButton;"/>
|
||||
<toolbarbutton id="clear-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&profilerUI.clearButton;"/>
|
||||
label="&performanceUI.clearButton;"/>
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<vbox id="recordings-list" flex="1"/>
|
||||
@ -112,33 +112,33 @@
|
||||
<toolbarbutton id="filter-button"
|
||||
class="devtools-toolbarbutton"
|
||||
popup="performance-filter-menupopup"
|
||||
tooltiptext="&profilerUI.options.filter.tooltiptext;"/>
|
||||
tooltiptext="&performanceUI.options.filter.tooltiptext;"/>
|
||||
</hbox>
|
||||
<hbox id="performance-toolbar-controls-detail-views"
|
||||
class="devtools-toolbarbutton-group">
|
||||
<toolbarbutton id="select-waterfall-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="Waterfall"
|
||||
label="&performanceUI.toolbar.waterfall;"
|
||||
hidden="true"
|
||||
data-view="waterfall" />
|
||||
<toolbarbutton id="select-js-calltree-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="Call Tree"
|
||||
label="&performanceUI.toolbar.js-calltree;"
|
||||
hidden="true"
|
||||
data-view="js-calltree" />
|
||||
<toolbarbutton id="select-js-flamegraph-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="Flame Chart"
|
||||
label="&performanceUI.toolbar.js-flamegraph;"
|
||||
hidden="true"
|
||||
data-view="js-flamegraph" />
|
||||
<toolbarbutton id="select-memory-calltree-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="Allocations Tree"
|
||||
label="&performanceUI.toolbar.memory-calltree;"
|
||||
hidden="true"
|
||||
data-view="memory-calltree" />
|
||||
<toolbarbutton id="select-memory-flamegraph-view"
|
||||
class="devtools-toolbarbutton devtools-button"
|
||||
label="Allocations Chart"
|
||||
label="&performanceUI.toolbar.memory-flamegraph;"
|
||||
hidden="true"
|
||||
data-view="memory-flamegraph" />
|
||||
<toolbarbutton id="select-optimizations-view"
|
||||
@ -153,7 +153,7 @@
|
||||
<toolbarbutton id="performance-options-button"
|
||||
class="devtools-toolbarbutton devtools-option-toolbarbutton"
|
||||
popup="performance-options-menupopup"
|
||||
tooltiptext="&profilerUI.options.gear.tooltiptext;"/>
|
||||
tooltiptext="&performanceUI.options.gear.tooltiptext;"/>
|
||||
</hbox>
|
||||
</toolbar>
|
||||
|
||||
@ -169,7 +169,7 @@
|
||||
<hbox class="devtools-toolbarbutton-group"
|
||||
pack="center">
|
||||
<toolbarbutton class="devtools-toolbarbutton record-button"
|
||||
label="&profilerUI.startRecording;"
|
||||
label="&performanceUI.startRecording;"
|
||||
standalone="true"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
@ -193,7 +193,7 @@
|
||||
align="center"
|
||||
pack="center"
|
||||
flex="1">
|
||||
<label value="&profilerUI.loadingNotice;"/>
|
||||
<label value="&performanceUI.loadingNotice;"/>
|
||||
</hbox>
|
||||
|
||||
<!-- "Recording" notice, shown when a recording is in progress -->
|
||||
@ -205,19 +205,17 @@
|
||||
<hbox class="devtools-toolbarbutton-group"
|
||||
pack="center">
|
||||
<toolbarbutton class="devtools-toolbarbutton record-button"
|
||||
label="&profilerUI.stopRecording;"
|
||||
label="&performanceUI.stopRecording;"
|
||||
standalone="true"/>
|
||||
</hbox>
|
||||
<label class="realtime-disabled-message">
|
||||
Realtime recording data disabled on non-multiprocess Firefox.
|
||||
</label>
|
||||
<label class="realtime-disabled-on-e10s-message">
|
||||
Enable multiprocess Firefox in preferences for rendering recording data in realtime.
|
||||
</label>
|
||||
<label class="realtime-disabled-message"
|
||||
value="&performanceUI.disabledRealTime.nonE10SBuild;"/>
|
||||
<label class="realtime-disabled-on-e10s-message"
|
||||
value="&performanceUI.disabledRealTime.disabledE10S;"/>
|
||||
<label class="buffer-status-message"
|
||||
tooltiptext="&profilerUI.bufferStatusTooltip;"/>
|
||||
tooltiptext="&performanceUI.bufferStatusTooltip;"/>
|
||||
<label class="buffer-status-message-full"
|
||||
value="&profilerUI.bufferStatusFull;"/>
|
||||
value="&performanceUI.bufferStatusFull;"/>
|
||||
</vbox>
|
||||
|
||||
<!-- "Console" notice, shown when a console recording is in progress -->
|
||||
@ -227,25 +225,23 @@
|
||||
pack="center"
|
||||
flex="1">
|
||||
<hbox class="console-profile-recording-notice">
|
||||
<label value="&profilerUI.console.recordingNoticeStart;" />
|
||||
<label value="&performanceUI.console.recordingNoticeStart;" />
|
||||
<label class="console-profile-command" />
|
||||
<label value="&profilerUI.console.recordingNoticeEnd;" />
|
||||
<label value="&performanceUI.console.recordingNoticeEnd;" />
|
||||
</hbox>
|
||||
<hbox class="console-profile-stop-notice">
|
||||
<label value="&profilerUI.console.stopCommandStart;" />
|
||||
<label value="&performanceUI.console.stopCommandStart;" />
|
||||
<label class="console-profile-command" />
|
||||
<label value="&profilerUI.console.stopCommandEnd;" />
|
||||
<label value="&performanceUI.console.stopCommandEnd;" />
|
||||
</hbox>
|
||||
<label class="realtime-disabled-message">
|
||||
Realtime recording data disabled on non-multiprocess Firefox.
|
||||
</label>
|
||||
<label class="realtime-disabled-on-e10s-message">
|
||||
Enable multiprocess Firefox in preferences for rendering recording data in realtime.
|
||||
</label>
|
||||
<label class="realtime-disabled-message"
|
||||
value="&performanceUI.disabledRealTime.nonE10SBuild;"/>
|
||||
<label class="realtime-disabled-on-e10s-message"
|
||||
value="&performanceUI.disabledRealTime.disabledE10S;"/>
|
||||
<label class="buffer-status-message"
|
||||
tooltiptext="&profilerUI.bufferStatusTooltip;"/>
|
||||
tooltiptext="&performanceUI.bufferStatusTooltip;"/>
|
||||
<label class="buffer-status-message-full"
|
||||
value="&profilerUI.bufferStatusFull;"/>
|
||||
value="&performanceUI.bufferStatusFull;"/>
|
||||
</vbox>
|
||||
|
||||
<!-- Detail views -->
|
||||
@ -269,33 +265,33 @@
|
||||
<label class="plain call-tree-header"
|
||||
type="duration"
|
||||
crop="end"
|
||||
value="&profilerUI.table.totalDuration2;"
|
||||
tooltiptext="&profilerUI.table.totalDuration.tooltip;"/>
|
||||
value="&performanceUI.table.totalDuration;"
|
||||
tooltiptext="&performanceUI.table.totalDuration.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="percentage"
|
||||
crop="end"
|
||||
value="&profilerUI.table.totalPercentage;"
|
||||
tooltiptext="&profilerUI.table.totalPercentage.tooltip;"/>
|
||||
value="&performanceUI.table.totalPercentage;"
|
||||
tooltiptext="&performanceUI.table.totalPercentage.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-duration"
|
||||
crop="end"
|
||||
value="&profilerUI.table.selfDuration2;"
|
||||
tooltiptext="&profilerUI.table.selfDuration.tooltip;"/>
|
||||
value="&performanceUI.table.selfDuration;"
|
||||
tooltiptext="&performanceUI.table.selfDuration.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-percentage"
|
||||
crop="end"
|
||||
value="&profilerUI.table.selfPercentage;"
|
||||
tooltiptext="&profilerUI.table.selfPercentage.tooltip;"/>
|
||||
value="&performanceUI.table.selfPercentage;"
|
||||
tooltiptext="&performanceUI.table.selfPercentage.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="samples"
|
||||
crop="end"
|
||||
value="&profilerUI.table.samples;"
|
||||
tooltiptext="&profilerUI.table.samples.tooltip;"/>
|
||||
value="&performanceUI.table.samples;"
|
||||
tooltiptext="&performanceUI.table.samples.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="function"
|
||||
crop="end"
|
||||
value="&profilerUI.table.function;"
|
||||
tooltiptext="&profilerUI.table.function.tooltip;"/>
|
||||
value="&performanceUI.table.function;"
|
||||
tooltiptext="&performanceUI.table.function.tooltip;"/>
|
||||
</hbox>
|
||||
<vbox class="call-tree-cells-container" flex="1"/>
|
||||
</vbox>
|
||||
@ -311,17 +307,17 @@
|
||||
<label class="plain call-tree-header"
|
||||
type="allocations"
|
||||
crop="end"
|
||||
value="&profilerUI.table.totalAlloc1;"
|
||||
tooltiptext="&profilerUI.table.totalAlloc.tooltip;"/>
|
||||
value="&performanceUI.table.totalAlloc;"
|
||||
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="self-allocations"
|
||||
crop="end"
|
||||
value="&profilerUI.table.selfAlloc1;"
|
||||
tooltiptext="&profilerUI.table.selfAlloc.tooltip;"/>
|
||||
value="&performanceUI.table.selfAlloc;"
|
||||
tooltiptext="&performanceUI.table.selfAlloc.tooltip;"/>
|
||||
<label class="plain call-tree-header"
|
||||
type="function"
|
||||
crop="end"
|
||||
value="&profilerUI.table.function;"/>
|
||||
value="&performanceUI.table.function;"/>
|
||||
</hbox>
|
||||
<vbox class="call-tree-cells-container" flex="1"/>
|
||||
</vbox>
|
||||
@ -352,7 +348,7 @@
|
||||
<vbox id="jit-optimizations-view">
|
||||
<toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
|
||||
<hbox id="jit-optimizations-header">
|
||||
<span class="jit-optimizations-title">&profilerUI.JITOptimizationsTitle;</span>
|
||||
<span class="jit-optimizations-title">&performanceUI.JITOptimizationsTitle;</span>
|
||||
<span class="header-function-name" />
|
||||
<span class="header-file opt-url debugger-link" />
|
||||
<span class="header-line opt-line" />
|
||||
|
@ -2,6 +2,7 @@
|
||||
tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
doc_allocs.html
|
||||
doc_force_cc.html
|
||||
doc_force_gc.html
|
||||
doc_innerHTML.html
|
||||
|
@ -5,14 +5,14 @@
|
||||
* Tests that the memory call tree view renders content after recording.
|
||||
*/
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
|
||||
let { panel } = yield initPerformance(ALLOCS_URL);
|
||||
let { EVENTS, $$, PerformanceController, DetailsView, MemoryCallTreeView } = panel.panelWin;
|
||||
|
||||
// Enable memory to test.
|
||||
Services.prefs.setBoolPref(ALLOCATIONS_PREF, true);
|
||||
|
||||
yield startRecording(panel);
|
||||
yield busyWait(100);
|
||||
yield waitUntil(() => PerformanceController.getCurrentRecording().getAllocations().timestamps.length);
|
||||
yield stopRecording(panel);
|
||||
|
||||
let rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
|
||||
@ -22,6 +22,8 @@ function* spawnTest() {
|
||||
|
||||
ok(true, "MemoryCallTreeView rendered after recording is stopped.");
|
||||
|
||||
ok($$("#memory-calltree-view .call-tree-item").length, "there are several allocations rendered.");
|
||||
|
||||
yield startRecording(panel);
|
||||
yield busyWait(100);
|
||||
|
||||
|
@ -9,11 +9,7 @@
|
||||
let test = Task.async(function*() {
|
||||
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
|
||||
let { RecordingsView, PerformanceController, PerformanceView,
|
||||
EVENTS, $, L10N, ViewHelpers } = panel.panelWin;
|
||||
|
||||
// This should be removed with bug 1163763.
|
||||
let DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
|
||||
let DBG_L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
|
||||
EVENTS, $, L10N } = panel.panelWin;
|
||||
|
||||
info("Start to record");
|
||||
yield startRecording(panel);
|
||||
@ -34,7 +30,7 @@ let test = Task.async(function*() {
|
||||
yield willStop;
|
||||
|
||||
is(durationNode.getAttribute("value"),
|
||||
DBG_L10N.getStr("loadingText"),
|
||||
L10N.getStr("recordingsList.loadingLabel"),
|
||||
"The duration node should show the 'loading' message while stopping");
|
||||
|
||||
let stateChanged = once(PerformanceView, EVENTS.UI_STATE_CHANGED);
|
||||
|
25
browser/devtools/performance/test/doc_allocs.html
Normal file
25
browser/devtools/performance/test/doc_allocs.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Performance test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
var allocs = [];
|
||||
function test() {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
allocs.push({});
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent this script from being garbage collected.
|
||||
window.setInterval(test, 1);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -24,6 +24,7 @@ const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-u
|
||||
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/performance/test/";
|
||||
const SIMPLE_URL = EXAMPLE_URL + "doc_simple-test.html";
|
||||
const MARKERS_URL = EXAMPLE_URL + "doc_markers.html";
|
||||
const ALLOCS_URL = EXAMPLE_URL + "doc_allocs.html";
|
||||
|
||||
const MEMORY_SAMPLE_PROB_PREF = "devtools.performance.memory.sample-probability";
|
||||
const MEMORY_MAX_LOG_LEN_PREF = "devtools.performance.memory.max-log-length";
|
||||
|
@ -47,7 +47,7 @@ add_task(function () {
|
||||
|
||||
equal(Utils.getMarkerClassName("Javascript"), "Function Call",
|
||||
"getMarkerClassName() returns correct string when defined via function");
|
||||
equal(Utils.getMarkerClassName("GarbageCollection"), "GC Event",
|
||||
equal(Utils.getMarkerClassName("GarbageCollection"), "Incremental GC",
|
||||
"getMarkerClassName() returns correct string when defined via function");
|
||||
equal(Utils.getMarkerClassName("Reflow"), "Layout",
|
||||
"getMarkerClassName() returns correct string when defined via string");
|
||||
@ -60,7 +60,7 @@ add_task(function () {
|
||||
ok(true, "getMarkerClassName() should throw when no label on blueprint.");
|
||||
}
|
||||
|
||||
TIMELINE_BLUEPRINT["fakemarker"] = { group: 0, label: () => void 0};
|
||||
TIMELINE_BLUEPRINT["fakemarker"] = { group: 0, label: () => void 0 };
|
||||
try {
|
||||
Utils.getMarkerClassName("fakemarker");
|
||||
ok(false, "getMarkerClassName() should throw when label function returnd undefined.");
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
|
||||
const OPTIMIZATION_FAILURE = L10N.getStr("jit.optimizationFailure");
|
||||
const JIT_SAMPLES = L10N.getStr("jit.samples2");
|
||||
const JIT_SAMPLES = L10N.getStr("jit.samples");
|
||||
const JIT_EMPTY_TEXT = L10N.getStr("jit.empty");
|
||||
const PROPNAME_MAX_LENGTH = 4;
|
||||
|
||||
|
@ -3,10 +3,6 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
// This should be removed with bug 1163763.
|
||||
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
|
||||
const DBG_L10N = new ViewHelpers.L10N(DBG_STRINGS_URI);
|
||||
|
||||
/**
|
||||
* Functions handling the recordings UI.
|
||||
*/
|
||||
@ -151,7 +147,7 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
|
||||
|
||||
// Mark the corresponding item as loading.
|
||||
let durationNode = $(".recording-item-duration", recordingItem.target);
|
||||
durationNode.setAttribute("value", DBG_L10N.getStr("loadingText"));
|
||||
durationNode.setAttribute("value", L10N.getStr("recordingsList.loadingLabel"));
|
||||
},
|
||||
|
||||
/**
|
||||
@ -214,8 +210,7 @@ let RecordingsView = Heritage.extend(WidgetMethods, {
|
||||
*/
|
||||
_onSaveButtonClick: function (e) {
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
// TODO localize? in bug 1163763
|
||||
fp.init(window, "Save recording…", Ci.nsIFilePicker.modeSave);
|
||||
fp.init(window, L10N.getStr("recordingsList.saveDialogTitle"), Ci.nsIFilePicker.modeSave);
|
||||
fp.appendFilter(L10N.getStr("recordingsList.saveDialogJSONFilter"), "*.json");
|
||||
fp.appendFilter(L10N.getStr("recordingsList.saveDialogAllFilter"), "*.*");
|
||||
fp.defaultString = "profile.json";
|
||||
|
@ -1025,6 +1025,7 @@ SwatchBasedEditorTooltip.prototype = {
|
||||
* @param {object} callbacks
|
||||
* Callbacks that will be executed when the editor wants to preview a
|
||||
* value change, or revert a change, or commit a change.
|
||||
* - onShow: will be called when one of the swatch tooltip is shown
|
||||
* - onPreview: will be called when one of the sub-classes calls
|
||||
* preview
|
||||
* - onRevert: will be called when the user ESCapes out of the tooltip
|
||||
@ -1032,6 +1033,9 @@ SwatchBasedEditorTooltip.prototype = {
|
||||
* outside the tooltip.
|
||||
*/
|
||||
addSwatch: function(swatchEl, callbacks={}) {
|
||||
if (!callbacks.onShow) {
|
||||
callbacks.onShow = function() {};
|
||||
}
|
||||
if (!callbacks.onPreview) {
|
||||
callbacks.onPreview = function() {};
|
||||
}
|
||||
@ -1069,6 +1073,7 @@ SwatchBasedEditorTooltip.prototype = {
|
||||
if (swatch) {
|
||||
this.activeSwatch = event.target;
|
||||
this.show();
|
||||
swatch.callbacks.onShow();
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
@ -2849,6 +2849,9 @@ function TextPropertyEditor(aRuleEditor, aProperty) {
|
||||
this._onStartEditing = this._onStartEditing.bind(this);
|
||||
this._onNameDone = this._onNameDone.bind(this);
|
||||
this._onValueDone = this._onValueDone.bind(this);
|
||||
this._onSwatchCommit = this._onSwatchCommit.bind(this);
|
||||
this._onSwatchPreview = this._onSwatchPreview.bind(this);
|
||||
this._onSwatchRevert = this._onSwatchRevert.bind(this);
|
||||
this._onValidate = throttle(this._previewValue, 10, this);
|
||||
this.update = this.update.bind(this);
|
||||
|
||||
@ -3075,7 +3078,7 @@ TextPropertyEditor.prototype = {
|
||||
|
||||
this.warning.hidden = this.editing || this.isValid();
|
||||
|
||||
if ((this.prop.overridden || !this.prop.enabled) && !this.editing) {
|
||||
if (this.prop.overridden || !this.prop.enabled) {
|
||||
this.element.classList.add("ruleview-overridden");
|
||||
} else {
|
||||
this.element.classList.remove("ruleview-overridden");
|
||||
@ -3130,9 +3133,10 @@ TextPropertyEditor.prototype = {
|
||||
// Adding this swatch to the list of swatches our colorpicker
|
||||
// knows about
|
||||
this.ruleView.tooltips.colorPicker.addSwatch(span, {
|
||||
onPreview: () => this._previewValue(this.valueSpan.textContent),
|
||||
onCommit: () => this._onValueDone(this.valueSpan.textContent, true),
|
||||
onRevert: () => this._onValueDone(undefined, false)
|
||||
onShow: this._onStartEditing,
|
||||
onPreview: this._onSwatchPreview,
|
||||
onCommit: this._onSwatchCommit,
|
||||
onRevert: this._onSwatchRevert
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -3145,9 +3149,10 @@ TextPropertyEditor.prototype = {
|
||||
// Adding this swatch to the list of swatches our colorpicker
|
||||
// knows about
|
||||
this.ruleView.tooltips.cubicBezier.addSwatch(span, {
|
||||
onPreview: () => this._previewValue(this.valueSpan.textContent),
|
||||
onCommit: () => this._onValueDone(this.valueSpan.textContent, true),
|
||||
onRevert: () => this._onValueDone(undefined, false)
|
||||
onShow: this._onStartEditing,
|
||||
onPreview: this._onSwatchPreview,
|
||||
onCommit: this._onSwatchCommit,
|
||||
onRevert: this._onSwatchRevert
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -3159,9 +3164,10 @@ TextPropertyEditor.prototype = {
|
||||
parserOptions.filterSwatch = true;
|
||||
|
||||
this.ruleView.tooltips.filterEditor.addSwatch(span, {
|
||||
onPreview: () => this._previewValue(this.valueSpan.textContent),
|
||||
onCommit: () => this._onValueDone(this.valueSpan.textContent, true),
|
||||
onRevert: () => this._onValueDone(undefined, false)
|
||||
onShow: this._onStartEditing,
|
||||
onPreview: this._onSwatchPreview,
|
||||
onCommit: this._onSwatchCommit,
|
||||
onRevert: this._onSwatchRevert
|
||||
}, outputParser, parserOptions);
|
||||
}
|
||||
}
|
||||
@ -3422,6 +3428,30 @@ TextPropertyEditor.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the swatch editor wants to commit a value change.
|
||||
*/
|
||||
_onSwatchCommit: function() {
|
||||
this._onValueDone(this.valueSpan.textContent, true);
|
||||
this.update();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the swatch editor wants to preview a value change.
|
||||
*/
|
||||
_onSwatchPreview: function() {
|
||||
this._previewValue(this.valueSpan.textContent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the swatch editor closes from an ESC. Revert to the original
|
||||
* value of this property before editing.
|
||||
*/
|
||||
_onSwatchRevert: function() {
|
||||
this.rule.setPropertyEnabled(this.prop, this.prop.enabled);
|
||||
this.update();
|
||||
},
|
||||
|
||||
/**
|
||||
* Parse a value string and break it into pieces, starting with the
|
||||
* first value, and into an array of additional properties (if any).
|
||||
|
@ -6,33 +6,32 @@
|
||||
|
||||
// Test that a color change in the color picker is reverted when ESC is pressed
|
||||
|
||||
const PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' body {',
|
||||
' background-color: #ededed;',
|
||||
' }',
|
||||
'</style>',
|
||||
'Testing the color picker tooltip!'
|
||||
let TEST_URI = [
|
||||
"<style type='text/css'>",
|
||||
" body {",
|
||||
" background-color: #EDEDED;",
|
||||
" }",
|
||||
"</style>",
|
||||
].join("\n");
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8,rule view color picker tooltip test");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
let swatch = getRuleViewProperty(view, "body", "background-color").valueSpan
|
||||
.querySelector(".ruleview-colorswatch");
|
||||
yield testPressingEscapeRevertsChanges(swatch, view);
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {view} = yield openRuleView();
|
||||
yield testPressingEscapeRevertsChanges(view);
|
||||
yield testPressingEscapeRevertsChangesAndDisables(view);
|
||||
});
|
||||
|
||||
function* testPressingEscapeRevertsChanges(swatch, ruleView) {
|
||||
let cPicker = ruleView.tooltips.colorPicker;
|
||||
function* testPressingEscapeRevertsChanges(view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = ruleEditor.rule.textProps[0].editor;
|
||||
let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch");
|
||||
let cPicker = view.tooltips.colorPicker;
|
||||
|
||||
let onShown = cPicker.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShown;
|
||||
|
||||
yield simulateColorPickerChange(ruleView, cPicker, [0, 0, 0, 1], {
|
||||
yield simulateColorPickerChange(view, cPicker, [0, 0, 0, 1], {
|
||||
element: content.document.body,
|
||||
name: "backgroundColor",
|
||||
value: "rgb(0, 0, 0)"
|
||||
@ -40,17 +39,83 @@ function* testPressingEscapeRevertsChanges(swatch, ruleView) {
|
||||
|
||||
is(swatch.style.backgroundColor, "rgb(0, 0, 0)",
|
||||
"The color swatch's background was updated");
|
||||
is(getRuleViewProperty(ruleView, "body", "background-color").valueSpan.textContent,
|
||||
"#000", "The text of the background-color css property was updated");
|
||||
is(propEditor.valueSpan.textContent, "#000",
|
||||
"The text of the background-color css property was updated");
|
||||
|
||||
let spectrum = yield cPicker.spectrum;
|
||||
|
||||
// ESC out of the color picker
|
||||
info("Pressing ESCAPE to close the tooltip");
|
||||
let onHidden = cPicker.tooltip.once("hidden");
|
||||
EventUtils.sendKey("ESCAPE", spectrum.element.ownerDocument.defaultView);
|
||||
yield onHidden;
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
yield waitForSuccess(() => {
|
||||
return content.getComputedStyle(content.document.body).backgroundColor === "rgb(237, 237, 237)";
|
||||
}, "The element's background-color was reverted");
|
||||
yield waitForComputedStyleProperty("body", null, "background-color",
|
||||
"rgb(237, 237, 237)");
|
||||
is(propEditor.valueSpan.textContent, "#EDEDED",
|
||||
"Got expected property value.");
|
||||
}
|
||||
|
||||
function* testPressingEscapeRevertsChangesAndDisables(view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = ruleEditor.rule.textProps[0].editor;
|
||||
let swatch = propEditor.valueSpan.querySelector(".ruleview-colorswatch");
|
||||
let cPicker = view.tooltips.colorPicker;
|
||||
|
||||
info("Disabling background-color property");
|
||||
propEditor.enable.click();
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
ok(propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property is overridden.");
|
||||
is(propEditor.enable.style.visibility, "visible",
|
||||
"property enable checkbox is visible.");
|
||||
ok(!propEditor.enable.getAttribute("checked"),
|
||||
"property enable checkbox is not checked.");
|
||||
ok(!propEditor.prop.enabled,
|
||||
"background-color property is disabled.");
|
||||
let newValue = yield getRulePropertyValue("background-color");
|
||||
is(newValue, "", "background-color should have been unset.");
|
||||
|
||||
let onShown = cPicker.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShown;
|
||||
|
||||
ok(!propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property overridden is not displayed.");
|
||||
is(propEditor.enable.style.visibility, "hidden",
|
||||
"property enable checkbox is hidden.");
|
||||
|
||||
let spectrum = yield cPicker.spectrum;
|
||||
info("Simulating a color picker change in the widget");
|
||||
spectrum.rgb = [0, 0, 0, 1];
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
info("Pressing ESCAPE to close the tooltip");
|
||||
let onHidden = cPicker.tooltip.once("hidden");
|
||||
EventUtils.sendKey("ESCAPE", spectrum.element.ownerDocument.defaultView);
|
||||
yield onHidden;
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
ok(propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property is overridden.");
|
||||
is(propEditor.enable.style.visibility, "visible",
|
||||
"property enable checkbox is visible.");
|
||||
ok(!propEditor.enable.getAttribute("checked"),
|
||||
"property enable checkbox is not checked.");
|
||||
ok(!propEditor.prop.enabled,
|
||||
"background-color property is disabled.");
|
||||
newValue = yield getRulePropertyValue("background-color");
|
||||
is(newValue, "", "background-color should have been unset.");
|
||||
is(propEditor.valueSpan.textContent, "#EDEDED",
|
||||
"Got expected property value.");
|
||||
}
|
||||
|
||||
function* getRulePropertyValue(name) {
|
||||
let propValue = yield executeInContent("Test:GetRulePropertyValue", {
|
||||
styleSheetIndex: 0,
|
||||
ruleIndex: 0,
|
||||
name: name
|
||||
});
|
||||
return propValue;
|
||||
}
|
||||
|
@ -4,30 +4,29 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that changes made to the cubic-bezier timing-function in the cubic-bezier
|
||||
// tooltip are reverted when ESC is pressed
|
||||
// Test that changes made to the cubic-bezier timing-function in the
|
||||
// cubic-bezier tooltip are reverted when ESC is pressed
|
||||
|
||||
const PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' body {',
|
||||
' animation-timing-function: linear;',
|
||||
' }',
|
||||
'</style>',
|
||||
let TEST_URI = [
|
||||
"<style type='text/css'>",
|
||||
" body {",
|
||||
" animation-timing-function: linear;",
|
||||
" }",
|
||||
"</style>",
|
||||
].join("\n");
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8,rule view cubic-bezier tooltip test");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
info("Getting the bezier swatch element");
|
||||
let swatch = getRuleViewProperty(view, "body", "animation-timing-function").valueSpan
|
||||
.querySelector(".ruleview-bezierswatch");
|
||||
yield testPressingEscapeRevertsChanges(swatch, view);
|
||||
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
let {view} = yield openRuleView();
|
||||
yield testPressingEscapeRevertsChanges(view);
|
||||
yield testPressingEscapeRevertsChangesAndDisables(view);
|
||||
});
|
||||
|
||||
function* testPressingEscapeRevertsChanges(swatch, ruleView) {
|
||||
let bezierTooltip = ruleView.tooltips.cubicBezier;
|
||||
function* testPressingEscapeRevertsChanges(view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = ruleEditor.rule.textProps[0].editor;
|
||||
let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch");
|
||||
let bezierTooltip = view.tooltips.cubicBezier;
|
||||
|
||||
let onShown = bezierTooltip.tooltip.once("shown");
|
||||
swatch.click();
|
||||
@ -36,18 +35,85 @@ function* testPressingEscapeRevertsChanges(swatch, ruleView) {
|
||||
let widget = yield bezierTooltip.widget;
|
||||
info("Simulating a change of curve in the widget");
|
||||
widget.coordinates = [0.1, 2, 0.9, -1];
|
||||
let expected = "cubic-bezier(0.1, 2, 0.9, -1)";
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
yield waitForSuccess(() => {
|
||||
return content.getComputedStyle(content.document.body).animationTimingFunction === expected;
|
||||
}, "Waiting for the change to be previewed on the element");
|
||||
yield waitForComputedStyleProperty("body", null, "animation-timing-function",
|
||||
"cubic-bezier(0.1, 2, 0.9, -1)");
|
||||
is(propEditor.valueSpan.textContent, "cubic-bezier(.1,2,.9,-1)",
|
||||
"Got expected property value.");
|
||||
|
||||
info("Pressing ESCAPE to close the tooltip");
|
||||
let onHidden = bezierTooltip.tooltip.once("hidden");
|
||||
EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView);
|
||||
yield onHidden;
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
yield waitForSuccess(() => {
|
||||
return content.getComputedStyle(content.document.body).animationTimingFunction === "cubic-bezier(0, 0, 1, 1)";
|
||||
}, "Waiting for the change to be reverted on the element");
|
||||
yield waitForComputedStyleProperty("body", null, "animation-timing-function",
|
||||
"cubic-bezier(0, 0, 1, 1)");
|
||||
is(propEditor.valueSpan.textContent, "linear",
|
||||
"Got expected property value.");
|
||||
}
|
||||
|
||||
function* testPressingEscapeRevertsChangesAndDisables(view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = ruleEditor.rule.textProps[0].editor;
|
||||
let swatch = propEditor.valueSpan.querySelector(".ruleview-bezierswatch");
|
||||
let bezierTooltip = view.tooltips.cubicBezier;
|
||||
|
||||
info("Disabling animation-timing-function property");
|
||||
propEditor.enable.click();
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
ok(propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property is overridden.");
|
||||
is(propEditor.enable.style.visibility, "visible",
|
||||
"property enable checkbox is visible.");
|
||||
ok(!propEditor.enable.getAttribute("checked"),
|
||||
"property enable checkbox is not checked.");
|
||||
ok(!propEditor.prop.enabled,
|
||||
"animation-timing-function property is disabled.");
|
||||
let newValue = yield getRulePropertyValue("animation-timing-function");
|
||||
is(newValue, "", "animation-timing-function should have been unset.");
|
||||
|
||||
let onShown = bezierTooltip.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShown;
|
||||
|
||||
ok(!propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property overridden is not displayed.");
|
||||
is(propEditor.enable.style.visibility, "hidden",
|
||||
"property enable checkbox is hidden.");
|
||||
|
||||
let widget = yield bezierTooltip.widget;
|
||||
info("Simulating a change of curve in the widget");
|
||||
widget.coordinates = [0.1, 2, 0.9, -1];
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
info("Pressing ESCAPE to close the tooltip");
|
||||
let onHidden = bezierTooltip.tooltip.once("hidden");
|
||||
EventUtils.sendKey("ESCAPE", widget.parent.ownerDocument.defaultView);
|
||||
yield onHidden;
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
ok(propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property is overridden.");
|
||||
is(propEditor.enable.style.visibility, "visible",
|
||||
"property enable checkbox is visible.");
|
||||
ok(!propEditor.enable.getAttribute("checked"),
|
||||
"property enable checkbox is not checked.");
|
||||
ok(!propEditor.prop.enabled,
|
||||
"animation-timing-function property is disabled.");
|
||||
newValue = yield getRulePropertyValue("animation-timing-function");
|
||||
is(newValue, "", "animation-timing-function should have been unset.");
|
||||
is(propEditor.valueSpan.textContent, "linear",
|
||||
"Got expected property value.");
|
||||
}
|
||||
|
||||
function* getRulePropertyValue(name) {
|
||||
let propValue = yield executeInContent("Test:GetRulePropertyValue", {
|
||||
styleSheetIndex: 0,
|
||||
ruleIndex: 0,
|
||||
name: name
|
||||
});
|
||||
return propValue;
|
||||
}
|
||||
|
@ -3,36 +3,102 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests the Filter Editor Tooltip reverting changes on ESC
|
||||
// Tests that changes made to the Filter Editor Tooltip are reverted when
|
||||
// ESC is pressed
|
||||
|
||||
const TEST_URL = TEST_URL_ROOT + "doc_filter.html";
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(TEST_URL);
|
||||
let {view} = yield openRuleView();
|
||||
yield testPressingEscapeRevertsChanges(view);
|
||||
yield testPressingEscapeRevertsChangesAndDisables(view);
|
||||
});
|
||||
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
info("Getting the filter swatch element");
|
||||
let swatch = getRuleViewProperty(view, "body", "filter").valueSpan
|
||||
.querySelector(".ruleview-filterswatch");
|
||||
|
||||
function* testPressingEscapeRevertsChanges(view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = ruleEditor.rule.textProps[0].editor;
|
||||
let swatch = propEditor.valueSpan.querySelector(".ruleview-filterswatch");
|
||||
let filterTooltip = view.tooltips.filterEditor;
|
||||
|
||||
let onShow = filterTooltip.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShow;
|
||||
|
||||
let widget = yield filterTooltip.widget;
|
||||
|
||||
widget.setCssValue("blur(2px)");
|
||||
yield waitForComputedStyleProperty("body", null, "filter", "blur(2px)");
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
ok(true, "Changes previewed on the element");
|
||||
yield waitForComputedStyleProperty("body", null, "filter", "blur(2px)");
|
||||
is(propEditor.valueSpan.textContent, "blur(2px)",
|
||||
"Got expected property value.");
|
||||
|
||||
info("Pressing ESCAPE to close the tooltip");
|
||||
EventUtils.sendKey("ESCAPE", widget.styleWindow);
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
yield waitForSuccess(() => {
|
||||
const computed = content.getComputedStyle(content.document.body);
|
||||
return computed.filter === "blur(2px) contrast(2)";
|
||||
}, "Waiting for the change to be reverted on the element");
|
||||
});
|
||||
yield waitForComputedStyleProperty("body", null, "filter",
|
||||
"blur(2px) contrast(2)");
|
||||
is(propEditor.valueSpan.textContent, "blur(2px) contrast(2)",
|
||||
"Got expected property value.");
|
||||
}
|
||||
|
||||
function* testPressingEscapeRevertsChangesAndDisables(view) {
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = ruleEditor.rule.textProps[0].editor;
|
||||
let swatch = propEditor.valueSpan.querySelector(".ruleview-filterswatch");
|
||||
let filterTooltip = view.tooltips.filterEditor;
|
||||
|
||||
info("Disabling filter property");
|
||||
propEditor.enable.click();
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
ok(propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property is overridden.");
|
||||
is(propEditor.enable.style.visibility, "visible",
|
||||
"property enable checkbox is visible.");
|
||||
ok(!propEditor.enable.getAttribute("checked"),
|
||||
"property enable checkbox is not checked.");
|
||||
ok(!propEditor.prop.enabled,
|
||||
"filter property is disabled.");
|
||||
let newValue = yield getRulePropertyValue("filter");
|
||||
is(newValue, "", "filter should have been unset.");
|
||||
|
||||
let onShow = filterTooltip.tooltip.once("shown");
|
||||
swatch.click();
|
||||
yield onShow;
|
||||
|
||||
ok(!propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property overridden is not displayed.");
|
||||
is(propEditor.enable.style.visibility, "hidden",
|
||||
"property enable checkbox is hidden.");
|
||||
|
||||
let widget = yield filterTooltip.widget;
|
||||
widget.setCssValue("blur(2px)");
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
info("Pressing ESCAPE to close the tooltip");
|
||||
EventUtils.sendKey("ESCAPE", widget.styleWindow);
|
||||
yield ruleEditor.rule._applyingModifications;
|
||||
|
||||
ok(propEditor.element.classList.contains("ruleview-overridden"),
|
||||
"property is overridden.");
|
||||
is(propEditor.enable.style.visibility, "visible",
|
||||
"property enable checkbox is visible.");
|
||||
ok(!propEditor.enable.getAttribute("checked"),
|
||||
"property enable checkbox is not checked.");
|
||||
ok(!propEditor.prop.enabled, "filter property is disabled.");
|
||||
newValue = yield getRulePropertyValue("filter");
|
||||
is(newValue, "", "filter should have been unset.");
|
||||
is(propEditor.valueSpan.textContent, "blur(2px) contrast(2)",
|
||||
"Got expected property value.");
|
||||
}
|
||||
|
||||
function* getRulePropertyValue(name) {
|
||||
let propValue = yield executeInContent("Test:GetRulePropertyValue", {
|
||||
styleSheetIndex: 0,
|
||||
ruleIndex: 0,
|
||||
name: name
|
||||
});
|
||||
return propValue;
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
# 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/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used inside the Performance Tools
|
||||
# which is available from the Web Developer sub-menu -> 'Performance'.
|
||||
# The correct localization of this file might be to keep it in
|
||||
# English, or another language commonly spoken among web developers.
|
||||
# You want to make that choice consistent across the developer tools.
|
||||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web. These strings
|
||||
# are specifically for marker names in the performance tool.
|
||||
|
||||
# LOCALIZATION NOTE (marker.label.*):
|
||||
# These strings are displayed in the Performance Tool waterfall, identifying markers.
|
||||
# We want to use the same wording as Google Chrome when appropriate.
|
||||
marker.label.styles=Recalculate Style
|
||||
marker.label.reflow=Layout
|
||||
marker.label.paint=Paint
|
||||
marker.label.javascript=Function Call
|
||||
marker.label.parseHTML=Parse HTML
|
||||
marker.label.parseXML=Parse XML
|
||||
marker.label.domevent=DOM Event
|
||||
marker.label.consoleTime=Console
|
||||
marker.label.garbageCollection=Incremental GC
|
||||
marker.label.garbageCollection.nonIncremental=Non-incremental GC
|
||||
marker.label.cycleCollection=Cycle Collection
|
||||
marker.label.cycleCollection.forgetSkippable=CC Graph Reduction
|
||||
marker.label.timestamp=Timestamp
|
||||
marker.label.unknown=Unknown
|
||||
|
||||
# LOCALIZATION NOTE (marker.label.javascript.*):
|
||||
# These strings are displayed as JavaScript markers that have special
|
||||
# reasons that can be translated.
|
||||
marker.label.javascript.scriptElement=Script Tag
|
||||
marker.label.javascript.promiseCallback=Promise Callback
|
||||
marker.label.javascript.promiseInit=Promise Init
|
||||
marker.label.javascript.workerRunnable=Worker
|
||||
marker.label.javascript.jsURI=JavaScript URI
|
||||
marker.label.javascript.eventHandler=Event Handler
|
||||
|
||||
# LOCALIZATION NOTE (marker.fieldFormat):
|
||||
# Some timeline markers come with details, like a size, a name, a js function.
|
||||
# %1$S is replaced with one of the above label (marker.label.*) and %2$S
|
||||
# with the details. For examples: Paint (200x100), or console.time (FOO)
|
||||
marker.fieldFormat=%1$S (%2$S)
|
||||
|
||||
# LOCALIZATION NOTE (marker.field.*):
|
||||
# Strings used in the waterfall sidebar as property names.
|
||||
|
||||
# General marker fields
|
||||
marker.field.start=Start:
|
||||
marker.field.end=End:
|
||||
marker.field.duration=Duration:
|
||||
# Field names for stack values
|
||||
marker.field.stack=Stack:
|
||||
marker.field.startStack=Stack at start:
|
||||
marker.field.endStack=Stack at end:
|
||||
# %S is the "Async Cause" of a marker, and this signifies that the cause
|
||||
# was an asynchronous one in a displayed stack.
|
||||
marker.field.asyncStack=(Async: %S)
|
||||
# For console.time markers
|
||||
marker.field.consoleTimerName=Timer Name:
|
||||
# For DOM Event markers
|
||||
marker.field.DOMEventType=Event Type:
|
||||
marker.field.DOMEventPhase=Phase:
|
||||
# Non-incremental cause for a Garbage Collection marker
|
||||
marker.field.nonIncrementalCause=Non-incremental Cause:
|
||||
# For "Recalculate Style" markers
|
||||
marker.field.restyleHint=Restyle Hint:
|
||||
# General "reason" for a marker (JavaScript, Garbage Collection)
|
||||
marker.field.causeName=Cause:
|
||||
# General "type" for a marker (Cycle Collection, Garbage Collection)
|
||||
marker.field.type=Type:
|
||||
|
||||
# Strings used in the waterfall sidebar as values.
|
||||
marker.value.unknownFrame=<unknown location>
|
||||
marker.value.DOMEventTargetPhase=Target
|
||||
marker.value.DOMEventCapturingPhase=Capture
|
||||
marker.value.DOMEventBubblingPhase=Bubbling
|
157
browser/locales/en-US/chrome/browser/devtools/performance.dtd
Normal file
157
browser/locales/en-US/chrome/browser/devtools/performance.dtd
Normal file
@ -0,0 +1,157 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE This file contains the Performance strings -->
|
||||
<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
|
||||
- keep it in English, or another language commonly spoken among web developers.
|
||||
- You want to make that choice consistent across the developer tools.
|
||||
- A good criteria is the language in which you'd find the best
|
||||
- documentation on web development on the web. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.startRecording/performanceUI.stopRecording): These are
|
||||
- the labels shown on the main recording buttons to start/stop recording. -->
|
||||
<!ENTITY performanceUI.startRecording "Start Recording Performance">
|
||||
<!ENTITY performanceUI.stopRecording "Stop Recording Performance">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.bufferStatusTooltip): This string
|
||||
- is displayed as the tooltip for the buffer capacity during a recording. -->
|
||||
<!ENTITY performanceUI.bufferStatusTooltip "The profiler stores samples in a circular buffer, and once the buffer reaches the limit for a recording, newer samples begin to overwrite samples at the beginning of the recording.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.disabledRealTime.nonE10SBuild): This string
|
||||
- is displayed as a message for why the real time overview graph is disabled
|
||||
- when running on a non-multiprocess build. -->
|
||||
<!ENTITY performanceUI.disabledRealTime.nonE10SBuild "Realtime recording data disabled on non-multiprocess Firefox.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.disabledRealTime.disabledE10S): This string
|
||||
- is displayed as a message for why the real time overview graph is disabled
|
||||
- when running on a build that can run multiprocess Firefox, but just is not enabled. -->
|
||||
<!ENTITY performanceUI.disabledRealTime.disabledE10S "Enable multiprocess Firefox in preferences for rendering recording data in realtime.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.bufferStatusFull): This string
|
||||
- is displayed when the profiler's circular buffer has started to overlap. -->
|
||||
<!ENTITY performanceUI.bufferStatusFull "The buffer is full. Older samples are now being overwritten.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.loadingNotice): This is the label shown
|
||||
- in the call list view while loading a profile. -->
|
||||
<!ENTITY performanceUI.loadingNotice "Loading…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.recordButton): This string is displayed
|
||||
- on a button that starts a new profile. -->
|
||||
<!ENTITY performanceUI.recordButton.tooltip "Toggle the recording state of a performance recording.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.importButton): This string is displayed
|
||||
- on a button that opens a dialog to import a saved profile data file. -->
|
||||
<!ENTITY performanceUI.importButton "Import…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.exportButton): This string is displayed
|
||||
- on a button that opens a dialog to export a saved profile data file. -->
|
||||
<!ENTITY performanceUI.exportButton "Save">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.clearButton): This string is displayed
|
||||
- on a button that remvoes all the recordings. -->
|
||||
<!ENTITY performanceUI.clearButton "Clear">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.toolbar.*): These strings are displayed
|
||||
- in the toolbar on buttons that select which view is currently shown. -->
|
||||
<!ENTITY performanceUI.toolbar.waterfall "Waterfall">
|
||||
<!ENTITY performanceUI.toolbar.js-calltree "Call Tree">
|
||||
<!ENTITY performanceUI.toolbar.memory-calltree "Allocations">
|
||||
<!ENTITY performanceUI.toolbar.js-flamegraph "JS Flame Chart">
|
||||
<!ENTITY performanceUI.toolbar.memory-flamegraph "Allocations Flame Chart">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.table.*): These strings are displayed
|
||||
- in the call tree headers for a recording. -->
|
||||
<!ENTITY performanceUI.table.totalDuration "Total Time">
|
||||
<!ENTITY performanceUI.table.totalDuration.tooltip "The amount of time spent in this function and functions it calls.">
|
||||
<!ENTITY performanceUI.table.selfDuration "Self Time">
|
||||
<!ENTITY performanceUI.table.selfDuration.tooltip "The amount of time spent only within this function.">
|
||||
<!ENTITY performanceUI.table.totalPercentage "Total Cost">
|
||||
<!ENTITY performanceUI.table.totalPercentage.tooltip "The percentage of time spent in this function and functions it calls.">
|
||||
<!ENTITY performanceUI.table.selfPercentage "Self Cost">
|
||||
<!ENTITY performanceUI.table.selfPercentage.tooltip "The percentage of time spent only within this function.">
|
||||
<!ENTITY performanceUI.table.samples "Samples">
|
||||
<!ENTITY performanceUI.table.samples.tooltip "The number of times this function was on the stack when the profiler took a sample.">
|
||||
<!ENTITY performanceUI.table.function "Function">
|
||||
<!ENTITY performanceUI.table.function.tooltip "The name and source location of the sampled function.">
|
||||
<!ENTITY performanceUI.table.totalAlloc "Total Sampled Allocations">
|
||||
<!ENTITY performanceUI.table.totalAlloc.tooltip "The total number of Object allocations sampled at this location and in callees.">
|
||||
<!ENTITY performanceUI.table.selfAlloc "Self Sampled Allocations">
|
||||
<!ENTITY performanceUI.table.selfAlloc.tooltip "The number of Object allocations sampled at this location.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.newtab.tooltiptext): The tooltiptext shown
|
||||
- on the "+" (new tab) button for a profile when a selection is available. -->
|
||||
<!ENTITY performanceUI.newtab.tooltiptext "Add new tab from selection">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.toolbar.filter.tooltiptext): This string
|
||||
- is displayed next to the filter button-->
|
||||
<!ENTITY performanceUI.options.filter.tooltiptext "Select what data to display in the timeline">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.options.tooltiptext): This is the tooltip
|
||||
- for the options button. -->
|
||||
<!ENTITY performanceUI.options.gear.tooltiptext "Configure performance preferences.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.invertTree): This is the label shown next to
|
||||
- a checkbox that inverts and un-inverts the profiler's call tree. -->
|
||||
<!ENTITY performanceUI.invertTree "Invert Call Tree">
|
||||
<!ENTITY performanceUI.invertTree.tooltiptext "Inverting the call tree displays the profiled call paths starting from the youngest frames and expanding out to the older frames.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.invertFlameGraph): This is the label shown next to
|
||||
- a checkbox that inverts and un-inverts the profiler's flame graph. -->
|
||||
<!ENTITY performanceUI.invertFlameGraph "Invert Flame Chart">
|
||||
<!ENTITY performanceUI.invertFlameGraph.tooltiptext "Inverting the flame chart displays the profiled call paths starting from the youngest frames and expanding out to the older frames.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.showPlatformData): This is the
|
||||
- label for the checkbox that toggles whether or not Gecko platform data
|
||||
- is displayed in the profiler. -->
|
||||
<!ENTITY performanceUI.showPlatformData "Show Gecko Platform Data">
|
||||
<!ENTITY performanceUI.showPlatformData.tooltiptext "Showing platform data enables the JavaScript Profiler reports to include Gecko platform symbols.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.flattenTreeRecursion): This is the
|
||||
- label for the checkbox that toggles the flattening of tree recursion in inspected
|
||||
- functions in the profiler. -->
|
||||
<!ENTITY performanceUI.flattenTreeRecursion "Flatten Tree Recursion">
|
||||
<!ENTITY performanceUI.flattenTreeRecursion.tooltiptext "Flatten recursion when inspecting functions.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.enableMemory): This string
|
||||
- is displayed next to a checkbox determining whether or not memory
|
||||
- measurements are enabled. -->
|
||||
<!ENTITY performanceUI.enableMemory "Record Memory">
|
||||
<!ENTITY performanceUI.enableMemory.tooltiptext "Record memory consumption while profiling.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.enableAllocations): This string
|
||||
- is displayed next to a checkbox determining whether or not allocation
|
||||
- measurements are enabled. -->
|
||||
<!ENTITY performanceUI.enableAllocations "Record Allocations">
|
||||
<!ENTITY performanceUI.enableAllocations.tooltiptext "Record Object allocations while profiling.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.enableFramerate): This string
|
||||
- is displayed next to a checkbox determining whether or not framerate
|
||||
- is recorded. -->
|
||||
<!ENTITY performanceUI.enableFramerate "Record Framerate">
|
||||
<!ENTITY performanceUI.enableFramerate.tooltiptext "Record framerate while profiling.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.enableJITOptimizations): This string
|
||||
- is displayed next to a checkbox determining whether or not JIT optimization data
|
||||
- should be recorded. -->
|
||||
<!ENTITY performanceUI.enableJITOptimizations "Record JIT Optimizations">
|
||||
<!ENTITY performanceUI.enableJITOptimizations.tooltiptext "Record JIT optimization data sampled in each JavaScript frame.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.JITOptimizationsTitle): This string
|
||||
- is displayed as the title of the JIT Optimizations panel. -->
|
||||
<!ENTITY performanceUI.JITOptimizationsTitle "JIT Optimizations">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.console.recordingNoticeStart/recordingNoticeEnd):
|
||||
- This string is displayed when a recording is selected that started via console.profile.
|
||||
- Wraps the command used to start, like "Currently recording via console.profile("label")" -->
|
||||
<!ENTITY performanceUI.console.recordingNoticeStart "Currently recording via">
|
||||
<!ENTITY performanceUI.console.recordingNoticeEnd "">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.console.stopCommandStart/stopCommandEnd):
|
||||
- This string is displayed when a recording is selected that started via console.profile.
|
||||
- Indicates how to stop the recording, wrapping the command, like
|
||||
- "Stop recording by entering console.profileEnd("label") into the console." -->
|
||||
<!ENTITY performanceUI.console.stopCommandStart "Stop recording by entering">
|
||||
<!ENTITY performanceUI.console.stopCommandEnd "into the console.">
|
@ -2,77 +2,83 @@
|
||||
# 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/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used inside the Profiler
|
||||
# which is available from the Web Developer sub-menu -> 'Profiler'.
|
||||
# LOCALIZATION NOTE These strings are used inside the Performance Tools
|
||||
# which is available from the Web Developer sub-menu -> 'Performance'.
|
||||
# The correct localization of this file might be to keep it in
|
||||
# English, or another language commonly spoken among web developers.
|
||||
# You want to make that choice consistent across the developer tools.
|
||||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web.
|
||||
|
||||
# LOCALIZATION NOTE (profiler.label):
|
||||
# LOCALIZATION NOTE (performance.label):
|
||||
# This string is displayed in the title of the tab when the profiler is
|
||||
# displayed inside the developer tools window and in the Developer Tools Menu.
|
||||
profiler.label2=Performance
|
||||
performance.label=Performance
|
||||
|
||||
# LOCALIZATION NOTE (profiler.panelLabel):
|
||||
# LOCALIZATION NOTE (performance.panelLabel):
|
||||
# This is used as the label for the toolbox panel.
|
||||
profiler.panelLabel2=Performance Panel
|
||||
performance.panelLabel=Performance Panel
|
||||
|
||||
# LOCALIZATION NOTE (profiler2.commandkey, profiler.accesskey)
|
||||
# LOCALIZATION NOTE (performance.commandkey, performance.accesskey)
|
||||
# Used for the menuitem in the tool menu
|
||||
profiler.commandkey2=VK_F5
|
||||
profiler.accesskey=P
|
||||
performance.commandkey=VK_F5
|
||||
performance.accesskey=P
|
||||
|
||||
# LOCALIZATION NOTE (profiler.tooltip3):
|
||||
# LOCALIZATION NOTE (performance.tooltip):
|
||||
# This string is displayed in the tooltip of the tab when the profiler is
|
||||
# displayed inside the developer tools window.
|
||||
# Keyboard shortcut for JS Profiler will be shown inside brackets.
|
||||
profiler.tooltip3=JavaScript Profiler (%S)
|
||||
# Keyboard shortcut for Performance Tools will be shown inside brackets.
|
||||
performance.tooltip=Performance (%S)
|
||||
|
||||
# LOCALIZATION NOTE (noRecordingsText): The text to display in the
|
||||
# recordings menu when there are no recorded profiles yet.
|
||||
noRecordingsText=There are no profiles yet.
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.itemLabel):
|
||||
# This string is displayed in the recordings list of the Profiler,
|
||||
# This string is displayed in the recordings list of the Performance Tools,
|
||||
# identifying a set of function calls.
|
||||
recordingsList.itemLabel=Recording #%S
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.recordingLabel):
|
||||
# This string is displayed in the recordings list of the Profiler,
|
||||
# This string is displayed in the recordings list of the Performance Tools,
|
||||
# for an item that has not finished recording.
|
||||
recordingsList.recordingLabel=In progress…
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.loadingLabel):
|
||||
# This string is displayed in the recordings list of the Performance Tools,
|
||||
# for an item that is finished and is loading.
|
||||
recordingsList.loadingLabel=Loading…
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.durationLabel):
|
||||
# This string is displayed in the recordings list of the Profiler,
|
||||
# This string is displayed in the recordings list of the Performance Tools,
|
||||
# for an item that has finished recording.
|
||||
recordingsList.durationLabel=%S ms
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.saveLabel):
|
||||
# This string is displayed in the recordings list of the Profiler,
|
||||
# This string is displayed in the recordings list of the Performance Tools,
|
||||
# for saving an item to disk.
|
||||
recordingsList.saveLabel=Save
|
||||
|
||||
# LOCALIZATION NOTE (profile.tab):
|
||||
# This string is displayed in the profile view for a tab, after the
|
||||
# recording has finished, as the recording 'start → stop' range in milliseconds.
|
||||
profile.tab=%1$S ms → %2$S ms
|
||||
|
||||
# LOCALIZATION NOTE (graphs.fps):
|
||||
# This string is displayed in the framerate graph of the Profiler,
|
||||
# This string is displayed in the framerate graph of the Performance Tools,
|
||||
# as the unit used to measure frames per second. This label should be kept
|
||||
# AS SHORT AS POSSIBLE so it doesn't obstruct important parts of the graph.
|
||||
graphs.fps=fps
|
||||
|
||||
# LOCALIZATION NOTE (graphs.ms):
|
||||
# This string is displayed in the flamegraph of the Profiler,
|
||||
# This string is displayed in the flamegraph of the Performance Tools,
|
||||
# as the unit used to measure time (in milliseconds). This label should be kept
|
||||
# AS SHORT AS POSSIBLE so it doesn't obstruct important parts of the graph.
|
||||
graphs.ms=ms
|
||||
|
||||
# LOCALIZATION NOTE (graphs.memory):
|
||||
# This string is displayed in the memory graph of the Performance tool,
|
||||
# as the unit used to memory consumption. This label should be kept
|
||||
# AS SHORT AS POSSIBLE so it doesn't obstruct important parts of the graph.
|
||||
graphs.memory=MB
|
||||
|
||||
# LOCALIZATION NOTE (category.*):
|
||||
# These strings are displayed in the categories graph of the Profiler,
|
||||
# These strings are displayed in the categories graph of the Performance Tools,
|
||||
# as the legend for each block in every bar. These labels should be kept
|
||||
# AS SHORT AS POSSIBLE so they don't obstruct important parts of the graph.
|
||||
category.other=Gecko
|
||||
@ -85,11 +91,11 @@ category.storage=Storage
|
||||
category.events=Input & Events
|
||||
category.tools=Tools
|
||||
|
||||
# LOCALIZATION NOTE (graphs.ms):
|
||||
# LOCALIZATION NOTE (table.ms):
|
||||
# This string is displayed in the call tree after units of time in milliseconds.
|
||||
table.ms=ms
|
||||
|
||||
# LOCALIZATION NOTE (graphs.ms):
|
||||
# LOCALIZATION NOTE (table.percentage):
|
||||
# This string is displayed in the call tree after units representing percentages.
|
||||
table.percentage=%
|
||||
|
||||
@ -116,10 +122,13 @@ table.zoom.tooltiptext=Inspect frame in new tab
|
||||
# have optimization data
|
||||
table.view-optimizations.tooltiptext=View optimizations in JIT View
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.importDialogTitle):
|
||||
# This string is displayed as a title for importing a recoring from disk.
|
||||
recordingsList.importDialogTitle=Import recording…
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.saveDialogTitle):
|
||||
# This string is displayed as a title for saving a recording to disk.
|
||||
recordingsList.saveDialogTitle=Save profile…
|
||||
recordingsList.saveDialogTitle=Save recording…
|
||||
|
||||
# LOCALIZATION NOTE (recordingsList.saveDialogJSONFilter):
|
||||
# This string is displayed as a filter for saving a recording to disk.
|
||||
@ -133,25 +142,31 @@ recordingsList.saveDialogAllFilter=All Files
|
||||
# This string is displayed in a tooltip when no JIT optimizations were detected.
|
||||
jit.optimizationFailure=Optimization failed
|
||||
|
||||
# LOCALIZATION NOTE (jit.samples2):
|
||||
# LOCALIZATION NOTE (jit.samples):
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# This string is displayed for the unit representing the number of times a
|
||||
# frame is sampled.
|
||||
# "#1" represents the number of samples
|
||||
# example: 30 samples
|
||||
jit.samples2=#1 sample;#1 samples
|
||||
jit.samples=#1 sample;#1 samples
|
||||
|
||||
# LOCALIZATION NOTE (jit.empty):
|
||||
# This string is displayed when there are no JIT optimizations to display.
|
||||
jit.empty=No JIT optimizations recorded for this frame.
|
||||
|
||||
# LOCALIZATION NOTE (consoleProfile.recordingNotice/stopCommand):
|
||||
# These strings are displayed when a recording is in progress, that was started from the console.
|
||||
# TODO REMOVE
|
||||
consoleProfile.recordingNotice=Currently recording profile "%S".
|
||||
# TODO REMOVE
|
||||
consoleProfile.stopCommand=Stop profiling by typing \"console.profileEnd(\'%S\')\" into the console.
|
||||
# LOCALIZATION NOTE (timeline.tick):
|
||||
# This string is displayed in the timeline overview, for delimiting ticks
|
||||
# by time, in milliseconds.
|
||||
timeline.tick=%S ms
|
||||
|
||||
# LOCALIZATION NOTE (profiler.bufferStatus):
|
||||
# This string is displayed illustrating how full the profiler's circular buffer is.
|
||||
profiler.bufferStatus=Buffer capacity: %S%
|
||||
# LOCALIZATION NOTE (timeline.records):
|
||||
# This string is displayed in the timeline waterfall, as a title for the menu.
|
||||
timeline.records=RECORDS
|
||||
|
||||
# LOCALIZATION NOTE (profiler.bufferFull):
|
||||
# This string is displayed when recording, indicating how much of the
|
||||
# buffer is currently be used.
|
||||
# %S is the percentage of the buffer used -- there are two "%"s after to escape
|
||||
# the % that is actually displayed.
|
||||
# Example: "Buffer 54% full"
|
||||
profiler.bufferFull=Buffer %S%% full
|
@ -1,166 +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/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE This file contains the Profiler strings -->
|
||||
<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
|
||||
- keep it in English, or another language commonly spoken among web developers.
|
||||
- You want to make that choice consistent across the developer tools.
|
||||
- A good criteria is the language in which you'd find the best
|
||||
- documentation on web development on the web. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.emptyNotice1/2): This is the label shown
|
||||
- in the call list view when empty. -->
|
||||
<!-- TODO remove -->
|
||||
<!ENTITY profilerUI.emptyNotice1 "Click on the">
|
||||
<!-- TODO remove -->
|
||||
<!ENTITY profilerUI.emptyNotice2 "button to start recording JavaScript function calls.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.stopNotice1/2): This is the label shown
|
||||
- in the call list view while recording a profile. -->
|
||||
<!-- TODO remove -->
|
||||
<!ENTITY profilerUI.stopNotice1 "Click on the">
|
||||
<!-- TODO remove -->
|
||||
<!ENTITY profilerUI.stopNotice2 "button again to stop profiling.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.startRecording/profilerUI.stopRecording): These are
|
||||
- the labels shown on the main recording buttons to start/stop recording. -->
|
||||
<!ENTITY profilerUI.startRecording "Start Recording Performance">
|
||||
<!ENTITY profilerUI.stopRecording "Stop Recording Performance">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.bufferStatusTooltip): This string
|
||||
- is displayed as the tooltip for the buffer capacity during a recording. -->
|
||||
<!ENTITY profilerUI.bufferStatusTooltip "The profiler stores samples in a circular buffer, and once the buffer reaches the limit for a recording, newer samples begin to overwrite samples at the beginning of the recording.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.bufferStatusFull): This string
|
||||
- is displayed when the profiler's circular buffer has started to overlap. -->
|
||||
<!ENTITY profilerUI.bufferStatusFull "The buffer is full. Older samples are now being overwritten.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.loadingNotice): This is the label shown
|
||||
- in the call list view while loading a profile. -->
|
||||
<!ENTITY profilerUI.loadingNotice "Loading…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.recordButton): This string is displayed
|
||||
- on a button that starts a new profile. -->
|
||||
<!-- TODO remove -->
|
||||
<!ENTITY profilerUI.recordButton.tooltip "Record JavaScript function calls.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.recordButton2): This string is displayed
|
||||
- on a button that starts a new profile. -->
|
||||
<!ENTITY profilerUI.recordButton2.tooltip "Toggle the recording state of a performance recording.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.importButton): This string is displayed
|
||||
- on a button that opens a dialog to import a saved profile data file. -->
|
||||
<!ENTITY profilerUI.importButton "Import…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.exportButton): This string is displayed
|
||||
- on a button that opens a dialog to export a saved profile data file. -->
|
||||
<!ENTITY profilerUI.exportButton "Save">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.clearButton): This string is displayed
|
||||
- on a button that remvoes all the recordings. -->
|
||||
<!ENTITY profilerUI.clearButton "Clear">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.toolbar.*): These strings are displayed
|
||||
- in the toolbar on buttons that select which view is currently shown. -->
|
||||
<!ENTITY profilerUI.toolbar.waterfall "Timeline">
|
||||
<!ENTITY profilerUI.toolbar.js-calltree "JavaScript">
|
||||
<!ENTITY profilerUI.toolbar.memory-calltree1 "Allocations">
|
||||
<!ENTITY profilerUI.toolbar.js-flamegraph "JS Flame Chart">
|
||||
<!ENTITY profilerUI.toolbar.memory-flamegraph1 "Allocations Flame Chart">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.table.*): These strings are displayed
|
||||
- in the call tree headers for a recording. -->
|
||||
<!ENTITY profilerUI.table.totalDuration2 "Total Time">
|
||||
<!ENTITY profilerUI.table.totalDuration.tooltip "The amount of time spent in this function and functions it calls.">
|
||||
<!ENTITY profilerUI.table.selfDuration2 "Self Time">
|
||||
<!ENTITY profilerUI.table.selfDuration.tooltip "The amount of time spent only within this function.">
|
||||
<!ENTITY profilerUI.table.totalPercentage "Total Cost">
|
||||
<!ENTITY profilerUI.table.totalPercentage.tooltip "The percentage of time spent in this function and functions it calls.">
|
||||
<!ENTITY profilerUI.table.selfPercentage "Self Cost">
|
||||
<!ENTITY profilerUI.table.selfPercentage.tooltip "The percentage of time spent only within this function.">
|
||||
<!ENTITY profilerUI.table.samples "Samples">
|
||||
<!ENTITY profilerUI.table.samples.tooltip "The number of times this function was on the stack when the profiler took a sample.">
|
||||
<!ENTITY profilerUI.table.function "Function">
|
||||
<!ENTITY profilerUI.table.function.tooltip "The name and source location of the sampled function.">
|
||||
<!ENTITY profilerUI.table.totalAlloc1 "Total Sampled Allocations">
|
||||
<!ENTITY profilerUI.table.totalAlloc.tooltip "The total number of Object allocations sampled at this location and in callees.">
|
||||
<!ENTITY profilerUI.table.selfAlloc1 "Self Sampled Allocations">
|
||||
<!ENTITY profilerUI.table.selfAlloc.tooltip "The number of Object allocations sampled at this location.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.newtab.tooltiptext): The tooltiptext shown
|
||||
- on the "+" (new tab) button for a profile when a selection is available. -->
|
||||
<!ENTITY profilerUI.newtab.tooltiptext "Add new tab from selection">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.toolbar.filter.tooltiptext): This string
|
||||
- is displayed next to the filter button-->
|
||||
<!ENTITY profilerUI.options.filter.tooltiptext "Select what data to display in the timeline">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.options.tooltiptext): This is the tooltip
|
||||
- for the options button. -->
|
||||
<!ENTITY profilerUI.options.gear.tooltiptext "Configure performance preferences.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.invertTree): This is the label shown next to
|
||||
- a checkbox that inverts and un-inverts the profiler's call tree. -->
|
||||
<!ENTITY profilerUI.invertTree "Invert Call Tree">
|
||||
<!ENTITY profilerUI.invertTree.tooltiptext "Inverting the call tree displays the profiled call paths starting from the youngest frames and expanding out to the older frames.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.invertFlameGraph): This is the label shown next to
|
||||
- a checkbox that inverts and un-inverts the profiler's flame graph. -->
|
||||
<!ENTITY profilerUI.invertFlameGraph "Invert Flame Chart">
|
||||
<!ENTITY profilerUI.invertFlameGraph.tooltiptext "Inverting the flame chart displays the profiled call paths starting from the youngest frames and expanding out to the older frames.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.showPlatformData): This is the
|
||||
- label for the checkbox that toggles whether or not Gecko platform data
|
||||
- is displayed in the profiler. -->
|
||||
<!ENTITY profilerUI.showPlatformData "Show Gecko Platform Data">
|
||||
<!ENTITY profilerUI.showPlatformData.tooltiptext "Showing platform data enables the JavaScript Profiler reports to include Gecko platform symbols.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.flattenTreeRecursion): This is the
|
||||
- label for the checkbox that toggles the flattening of tree recursion in inspected
|
||||
- functions in the profiler. -->
|
||||
<!ENTITY profilerUI.flattenTreeRecursion "Flatten Tree Recursion">
|
||||
<!ENTITY profilerUI.flattenTreeRecursion.tooltiptext "Flatten recursion when inspecting functions.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.enableMemory): This string
|
||||
- is displayed next to a checkbox determining whether or not memory
|
||||
- measurements are enabled. -->
|
||||
<!ENTITY profilerUI.enableMemory "Record Memory">
|
||||
<!ENTITY profilerUI.enableMemory.tooltiptext "Record memory consumption while profiling.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.enableAllocations): This string
|
||||
- is displayed next to a checkbox determining whether or not allocation
|
||||
- measurements are enabled. -->
|
||||
<!ENTITY profilerUI.enableAllocations "Record Allocations">
|
||||
<!ENTITY profilerUI.enableAllocations.tooltiptext "Record Object allocations while profiling.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.enableFramerate): This string
|
||||
- is displayed next to a checkbox determining whether or not framerate
|
||||
- is recorded. -->
|
||||
<!ENTITY profilerUI.enableFramerate "Record Framerate">
|
||||
<!ENTITY profilerUI.enableFramerate.tooltiptext "Record framerate while profiling.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.enableJITOptimizations): This string
|
||||
- is displayed next to a checkbox determining whether or not JIT optimization data
|
||||
- should be recorded. -->
|
||||
<!ENTITY profilerUI.enableJITOptimizations "Record JIT Optimizations">
|
||||
<!ENTITY profilerUI.enableJITOptimizations.tooltiptext "Record JIT optimization data sampled in each JavaScript frame.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.JITOptimizationsTitle): This string
|
||||
- is displayed as the title of the JIT Optimizations panel. -->
|
||||
<!ENTITY profilerUI.JITOptimizationsTitle "JIT Optimizations">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.console.recordingNoticeStart/recordingNoticeEnd):
|
||||
- This string is displayed when a recording is selected that started via console.profile.
|
||||
- Wraps the command used to start, like "Currently recording via console.profile("label")" -->
|
||||
<!ENTITY profilerUI.console.recordingNoticeStart "Currently recording via">
|
||||
<!ENTITY profilerUI.console.recordingNoticeEnd "">
|
||||
|
||||
<!-- LOCALIZATION NOTE (profilerUI.console.stopCommandStart/stopCommandEnd):
|
||||
- This string is displayed when a recording is selected that started via console.profile.
|
||||
- Indicates how to stop the recording, wrapping the command, like
|
||||
- "Stop recording by entering console.profilEnd("label") into the console." -->
|
||||
<!ENTITY profilerUI.console.stopCommandStart "Stop recording by entering">
|
||||
<!ENTITY profilerUI.console.stopCommandEnd "into the console.">
|
@ -1,43 +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/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE This file contains the Timeline strings -->
|
||||
<!-- LOCALIZATION NOTE : FILE Do not translate commandkey -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
|
||||
- keep it in English, or another language commonly spoken among web developers.
|
||||
- You want to make that choice consistent across the developer tools.
|
||||
- A good criteria is the language in which you'd find the best
|
||||
- documentation on web development on the web. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (timelineUI.recordButton): This string is displayed
|
||||
- on a button that starts a new recording. -->
|
||||
<!ENTITY timelineUI.recordButton.tooltip "Record timeline operations">
|
||||
|
||||
<!-- LOCALIZATION NOTE (timelineUI.recordLabel): This string is displayed
|
||||
- as a label to signal that a recording is in progress. -->
|
||||
<!ENTITY timelineUI.recordLabel "Recording…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (timelineUI.memoryCheckbox.label): This string
|
||||
- is displayed next to a checkbox determining whether or not memory
|
||||
- measurements are enabled. -->
|
||||
<!ENTITY timelineUI.memoryCheckbox.label "Memory">
|
||||
|
||||
<!-- LOCALIZATION NOTE (timelineUI.memoryCheckbox.tooltip): This string
|
||||
- is displayed next to the memory checkbox -->
|
||||
<!ENTITY timelineUI.memoryCheckbox.tooltip "Enable memory measurements">
|
||||
|
||||
<!-- LOCALIZATION NOTE (timelineUI.filterButton.tooltip): This string
|
||||
- is displayed next to the filter button-->
|
||||
<!ENTITY timelineUI.filterButton.tooltip "Select what data to display">
|
||||
|
||||
<!-- LOCALIZATION NOTE (timelineUI.emptyNotice1/2): This is the label shown
|
||||
- in the timeline view when empty. -->
|
||||
<!ENTITY timelineUI.emptyNotice1 "Click on the">
|
||||
<!ENTITY timelineUI.emptyNotice2 "button to start recording timeline events.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (timelineUI.stopNotice1/2): This is the label shown
|
||||
- in the timeline view while recording. -->
|
||||
<!ENTITY timelineUI.stopNotice1 "Click on the">
|
||||
<!ENTITY timelineUI.stopNotice2 "button again to stop recording.">
|
@ -1,79 +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/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used inside the Timeline
|
||||
# which is available from the Web Developer sub-menu -> 'Timeline'.
|
||||
# The correct localization of this file might be to keep it in
|
||||
# English, or another language commonly spoken among web developers.
|
||||
# You want to make that choice consistent across the developer tools.
|
||||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web.
|
||||
|
||||
# LOCALIZATION NOTE (timeline.label):
|
||||
# This string is displayed in the title of the tab when the timeline is
|
||||
# displayed inside the developer tools window and in the Developer Tools Menu.
|
||||
timeline.label=Timeline
|
||||
|
||||
# LOCALIZATION NOTE (timeline.panelLabel):
|
||||
# This is used as the label for the toolbox panel.
|
||||
timeline.panelLabel=Timeline Panel
|
||||
|
||||
# LOCALIZATION NOTE (timeline.tooltip):
|
||||
# This string is displayed in the tooltip of the tab when the timeline is
|
||||
# displayed inside the developer tools window.
|
||||
timeline.tooltip=Performance Timeline
|
||||
|
||||
# LOCALIZATION NOTE (timeline.tick):
|
||||
# This string is displayed in the timeline overview, for delimiting ticks
|
||||
# by time, in milliseconds.
|
||||
timeline.tick=%S ms
|
||||
|
||||
# LOCALIZATION NOTE (timeline.records):
|
||||
# This string is displayed in the timeline waterfall, as a title for the menu.
|
||||
timeline.records=RECORDS
|
||||
|
||||
# LOCALIZATION NOTE (timeline.label.*):
|
||||
# These strings are displayed in the timeline waterfall, identifying markers.
|
||||
# We want to use the same wording as Google Chrome
|
||||
timeline.label.styles2=Recalculate Style
|
||||
timeline.label.reflow2=Layout
|
||||
timeline.label.paint=Paint
|
||||
timeline.label.javascript2=Function Call
|
||||
timeline.label.parseHTML=Parse HTML
|
||||
timeline.label.parseXML=Parse XML
|
||||
timeline.label.domevent=DOM Event
|
||||
timeline.label.consoleTime=Console
|
||||
timeline.label.garbageCollection=GC Event
|
||||
timeline.label.timestamp=Timestamp
|
||||
timeline.label.unknown=Unknown
|
||||
|
||||
# LOCALIZATION NOTE (graphs.memory):
|
||||
# This string is displayed in the memory graph of the Performance tool,
|
||||
# as the unit used to memory consumption. This label should be kept
|
||||
# AS SHORT AS POSSIBLE so it doesn't obstruct important parts of the graph.
|
||||
graphs.memory=MB
|
||||
|
||||
# LOCALIZATION NOTE (timeline.markerDetailFormat):
|
||||
# Some timeline markers come with details, like a size, a name, a js function.
|
||||
# %1$S is replaced with one of the above label (timeline.label.*) and %2$S
|
||||
# with the details. For examples: Paint (200x100), or console.time (FOO)
|
||||
timeline.markerDetailFormat=%1$S (%2$S)
|
||||
|
||||
# LOCALIZATION NOTE (time.markerDetail.*):
|
||||
# Strings used in the waterfall sidebar.
|
||||
timeline.markerDetail.start=Start:
|
||||
timeline.markerDetail.end=End:
|
||||
timeline.markerDetail.duration=Duration:
|
||||
timeline.markerDetail.consoleTimerName=Timer Name:
|
||||
timeline.markerDetail.DOMEventType=Event Type:
|
||||
timeline.markerDetail.DOMEventPhase=Phase:
|
||||
timeline.markerDetail.DOMEventTargetPhase=Target
|
||||
timeline.markerDetail.DOMEventCapturingPhase=Capture
|
||||
timeline.markerDetail.DOMEventBubblingPhase=Bubbling
|
||||
timeline.markerDetail.stack=Stack:
|
||||
timeline.markerDetail.startStack=Stack at start:
|
||||
timeline.markerDetail.endStack=Stack at end:
|
||||
timeline.markerDetail.unknownFrame=<unknown location>
|
||||
timeline.markerDetail.asyncStack=(Async: %S)
|
||||
timeline.markerDetail.causeName=Cause:
|
@ -117,6 +117,9 @@ valid_email_text_description=Please enter a valid email address
|
||||
## panel.
|
||||
add_or_import_contact_title=Add or Import Contact
|
||||
import_contacts_button2=Import from Google
|
||||
## LOCALIZATION NOTE (import_contacts_button3): Text for button used to import
|
||||
## contacts into the contact list.
|
||||
import_contacts_button3=Import
|
||||
importing_contacts_progress_button=Importing…
|
||||
import_contacts_failure_message=Some contacts could not be imported. Please try again.
|
||||
## LOCALIZATION NOTE(import_contacts_success_message): Success notification message
|
||||
|
@ -59,17 +59,16 @@
|
||||
locale/browser/devtools/VariablesView.dtd (%chrome/browser/devtools/VariablesView.dtd)
|
||||
locale/browser/devtools/sourceeditor.properties (%chrome/browser/devtools/sourceeditor.properties)
|
||||
locale/browser/devtools/sourceeditor.dtd (%chrome/browser/devtools/sourceeditor.dtd)
|
||||
locale/browser/devtools/profiler.dtd (%chrome/browser/devtools/profiler.dtd)
|
||||
locale/browser/devtools/profiler.properties (%chrome/browser/devtools/profiler.properties)
|
||||
locale/browser/devtools/promisedebugger.dtd (%chrome/browser/devtools/promisedebugger.dtd)
|
||||
locale/browser/devtools/promisedebugger.properties (%chrome/browser/devtools/promisedebugger.properties)
|
||||
locale/browser/devtools/performance.dtd (%chrome/browser/devtools/performance.dtd)
|
||||
locale/browser/devtools/performance.properties (%chrome/browser/devtools/performance.properties)
|
||||
locale/browser/devtools/layoutview.dtd (%chrome/browser/devtools/layoutview.dtd)
|
||||
locale/browser/devtools/responsiveUI.properties (%chrome/browser/devtools/responsiveUI.properties)
|
||||
locale/browser/devtools/toolbox.dtd (%chrome/browser/devtools/toolbox.dtd)
|
||||
locale/browser/devtools/toolbox.properties (%chrome/browser/devtools/toolbox.properties)
|
||||
locale/browser/devtools/inspector.dtd (%chrome/browser/devtools/inspector.dtd)
|
||||
locale/browser/devtools/timeline.dtd (%chrome/browser/devtools/timeline.dtd)
|
||||
locale/browser/devtools/timeline.properties (%chrome/browser/devtools/timeline.properties)
|
||||
locale/browser/devtools/markers.properties (%chrome/browser/devtools/markers.properties)
|
||||
locale/browser/devtools/projecteditor.properties (%chrome/browser/devtools/projecteditor.properties)
|
||||
locale/browser/devtools/eyedropper.properties (%chrome/browser/devtools/eyedropper.properties)
|
||||
locale/browser/devtools/connection-screen.dtd (%chrome/browser/devtools/connection-screen.dtd)
|
||||
|
@ -262,6 +262,7 @@ bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
|
||||
bool nsContentUtils::sEncodeDecodeURLHash = false;
|
||||
bool nsContentUtils::sGettersDecodeURLHash = false;
|
||||
bool nsContentUtils::sPrivacyResistFingerprinting = false;
|
||||
bool nsContentUtils::sSendPerformanceTimingNotifications = false;
|
||||
|
||||
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
|
||||
|
||||
@ -553,6 +554,9 @@ nsContentUtils::Init()
|
||||
"dom.event.handling-user-input-time-limit",
|
||||
1000);
|
||||
|
||||
Preferences::AddBoolVarCache(&sSendPerformanceTimingNotifications,
|
||||
"dom.performance.enable_notify_performance_timing", false);
|
||||
|
||||
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
|
||||
Preferences::AddBoolVarCache(&sDOMWindowDumpEnabled,
|
||||
"browser.dom.window.dump.enabled");
|
||||
|
@ -1948,6 +1948,14 @@ public:
|
||||
return sIsResourceTimingEnabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if notification should be sent for peformance timing events.
|
||||
*/
|
||||
static bool SendPerformanceTimingNotifications()
|
||||
{
|
||||
return sSendPerformanceTimingNotifications;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if URL setters should percent encode the Hash/Ref segment
|
||||
* and getters should return the percent decoded value of the segment
|
||||
@ -2544,6 +2552,7 @@ private:
|
||||
static bool sEncodeDecodeURLHash;
|
||||
static bool sGettersDecodeURLHash;
|
||||
static bool sPrivacyResistFingerprinting;
|
||||
static bool sSendPerformanceTimingNotifications;
|
||||
|
||||
static nsHtml5StringParser* sHTMLFragmentParser;
|
||||
static nsIParser* sXMLFragmentParser;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "PerformanceResourceTiming.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/PerformanceBinding.h"
|
||||
#include "mozilla/dom/PerformanceEntryEvent.h"
|
||||
#include "mozilla/dom/PerformanceTimingBinding.h"
|
||||
#include "mozilla/dom/PerformanceNavigationBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@ -738,14 +739,24 @@ nsPerformance::InsertUserEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled()) {
|
||||
nsAutoCString uri;
|
||||
nsAutoCString uri;
|
||||
uint64_t markCreationEpoch = 0;
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled() ||
|
||||
nsContentUtils::SendPerformanceTimingNotifications()) {
|
||||
nsresult rv = GetOwner()->GetDocumentURI()->GetHost(uri);
|
||||
if(NS_FAILED(rv)) {
|
||||
// If we have no URI, just put in "none".
|
||||
uri.AssignLiteral("none");
|
||||
}
|
||||
PerformanceBase::LogEntry(aEntry, uri);
|
||||
markCreationEpoch = static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC);
|
||||
|
||||
if (nsContentUtils::IsUserTimingLoggingEnabled()) {
|
||||
PerformanceBase::LogEntry(aEntry, uri);
|
||||
}
|
||||
}
|
||||
|
||||
if (nsContentUtils::SendPerformanceTimingNotifications()) {
|
||||
TimingNotification(aEntry, uri, markCreationEpoch);
|
||||
}
|
||||
|
||||
PerformanceBase::InsertUserEntry(aEntry);
|
||||
@ -986,6 +997,29 @@ PerformanceBase::LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) co
|
||||
static_cast<uint64_t>(PR_Now() / PR_USEC_PER_MSEC));
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner, uint64_t aEpoch)
|
||||
{
|
||||
PerformanceEntryEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
init.mName = aEntry->GetName();
|
||||
init.mEntryType = aEntry->GetEntryType();
|
||||
init.mStartTime = aEntry->StartTime();
|
||||
init.mDuration = aEntry->Duration();
|
||||
init.mEpoch = aEpoch;
|
||||
init.mOrigin = NS_ConvertUTF8toUTF16(aOwner.BeginReading());
|
||||
|
||||
nsRefPtr<PerformanceEntryEvent> perfEntryEvent =
|
||||
PerformanceEntryEvent::Constructor(this, NS_LITERAL_STRING("performanceentry"), init);
|
||||
|
||||
nsCOMPtr<EventTarget> et = do_QueryInterface(GetOwner());
|
||||
if (et) {
|
||||
bool dummy = false;
|
||||
et->DispatchEvent(perfEntryEvent, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceBase::InsertUserEntry(PerformanceEntry* aEntry)
|
||||
{
|
||||
|
@ -351,6 +351,7 @@ protected:
|
||||
}
|
||||
|
||||
void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const;
|
||||
void TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner, uint64_t epoch);
|
||||
|
||||
private:
|
||||
nsTArray<nsRefPtr<PerformanceEntry>> mUserEntries;
|
||||
|
@ -10,6 +10,12 @@ function verifyVoiceCellLocationInfo(aLac, aCid) {
|
||||
|
||||
is(cell.gsmLocationAreaCode, aLac, "check voice.cell.gsmLocationAreaCode");
|
||||
is(cell.gsmCellId, aCid, "check voice.cell.gsmCellId");
|
||||
|
||||
// TODO: Since gecko doesn't reset these values below to their invalid values,
|
||||
// the tests below will fail after we once change to CDMA mode. Please refer
|
||||
// to Bug 1190274 for more information.
|
||||
|
||||
/*
|
||||
is(cell.cdmaBaseStationId, -1, "check voice.cell.cdmaBaseStationId");
|
||||
is(cell.cdmaBaseStationLatitude, -2147483648,
|
||||
"check voice.cell.cdmaBaseStationLatitude");
|
||||
@ -17,6 +23,7 @@ function verifyVoiceCellLocationInfo(aLac, aCid) {
|
||||
"check voice.cell.cdmaBaseStationLongitude");
|
||||
is(cell.cdmaSystemId, -1, "check voice.cell.cdmaSystemId");
|
||||
is(cell.cdmaNetworkId, -1, "check voice.cell.cdmaNetworkId");
|
||||
*/
|
||||
}
|
||||
|
||||
/* Test Voice Cell Location Info Change */
|
||||
|
@ -4,25 +4,6 @@
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = "head.js";
|
||||
|
||||
const INITIAL_STATES = {
|
||||
state: "registered",
|
||||
connected: true,
|
||||
emergencyCallsOnly: false,
|
||||
roaming: false,
|
||||
signalStrength: -99,
|
||||
relSignalStrength: 44,
|
||||
|
||||
cell: {
|
||||
gsmLocationAreaCode: 0,
|
||||
gsmCellId: 0,
|
||||
cdmaBaseStationId: -1,
|
||||
cdmaBaseStationLatitude: -2147483648,
|
||||
cdmaBaseStationLongitude: -2147483648,
|
||||
cdmaSystemId: -1,
|
||||
cdmaNetworkId: -1,
|
||||
}
|
||||
};
|
||||
|
||||
const TEST_DATA = [{
|
||||
// Test state becomes to "unregistered"
|
||||
state: "unregistered",
|
||||
@ -126,8 +107,6 @@ function testVoiceStateUpdate(aNewState, aExpected) {
|
||||
startTestCommon(function() {
|
||||
log("Test initial voice connection info");
|
||||
|
||||
verifyVoiceInfo(INITIAL_STATES);
|
||||
|
||||
let promise = Promise.resolve();
|
||||
for (let i = 0; i < TEST_DATA.length; i++) {
|
||||
let entry = TEST_DATA[i];
|
||||
|
@ -276,16 +276,68 @@ let emulator = (function() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param aVoiceType
|
||||
* The voice type of a mobileConnection, which can be obtained from
|
||||
* |<mobileConnection>.voice.type|.
|
||||
* @return A string with format of the emulator voice tech.
|
||||
*/
|
||||
function voiceTypeToTech(aVoiceType) {
|
||||
switch(aVoiceType) {
|
||||
case "gsm":
|
||||
case "gprs":
|
||||
case "edge":
|
||||
return "gsm";
|
||||
|
||||
case "umts":
|
||||
case "hsdpa":
|
||||
case "hsupa":
|
||||
case "hspa":
|
||||
case "hspa+":
|
||||
return "wcdma";
|
||||
|
||||
case "is95a":
|
||||
case "is95b":
|
||||
case "1xrtt":
|
||||
return "cdma";
|
||||
|
||||
case "evdo0":
|
||||
case "evdoa":
|
||||
case "evdob":
|
||||
return "evdo";
|
||||
|
||||
case "ehrpd":
|
||||
case "lte":
|
||||
return "lte";
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Promise
|
||||
*/
|
||||
function changeModemTech(aTech, aPreferredMask) {
|
||||
return Promise.resolve()
|
||||
let mobileConn = navigator.mozMobileConnections[0];
|
||||
|
||||
function isTechMatched() {
|
||||
return aTech === voiceTypeToTech(mobileConn.voice.type);
|
||||
}
|
||||
|
||||
let promise1 = isTechMatched() ? Promise.resolve()
|
||||
: waitForEvent(mobileConn,
|
||||
"voicechange",
|
||||
isTechMatched);
|
||||
|
||||
let promise2 = Promise.resolve()
|
||||
.then(() => emulator.runCmd("modem tech " + aTech + " " + aPreferredMask))
|
||||
.then(() => emulator.runCmd("modem tech"))
|
||||
.then(result => is(result[0],
|
||||
aTech + " " + aPreferredMask,
|
||||
"Check modem 'tech/preferred mask'"));
|
||||
|
||||
return Promise.all([promise1, promise2]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,6 +45,7 @@ qemu = true
|
||||
[test_mmi_unlock_puk.js]
|
||||
[test_mmi_unlock_puk2.js]
|
||||
[test_mmi_ussd.js]
|
||||
[test_modem_switch_tech.js]
|
||||
[test_multiple_hold.js]
|
||||
[test_outgoing_already_held.js]
|
||||
[test_outgoing_answer_hangup_oncallschanged.js]
|
||||
|
27
dom/webidl/PerformanceEntryEvent.webidl
Normal file
27
dom/webidl/PerformanceEntryEvent.webidl
Normal file
@ -0,0 +1,27 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
dictionary PerformanceEntryEventInit : EventInit
|
||||
{
|
||||
DOMString name = "";
|
||||
DOMString entryType = "";
|
||||
DOMHighResTimeStamp startTime = 0;
|
||||
DOMHighResTimeStamp duration = 0;
|
||||
double epoch = 0;
|
||||
DOMString origin = "";
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional PerformanceEntryEventInit eventInitDict),
|
||||
ChromeOnly]
|
||||
interface PerformanceEntryEvent : Event
|
||||
{
|
||||
readonly attribute DOMString name;
|
||||
readonly attribute DOMString entryType;
|
||||
readonly attribute DOMHighResTimeStamp startTime;
|
||||
readonly attribute DOMHighResTimeStamp duration;
|
||||
readonly attribute double epoch;
|
||||
readonly attribute DOMString origin;
|
||||
};
|
@ -779,6 +779,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
||||
'MozStkCommandEvent.webidl',
|
||||
'MozVoicemailEvent.webidl',
|
||||
'PageTransitionEvent.webidl',
|
||||
'PerformanceEntryEvent.webidl',
|
||||
'PluginCrashedEvent.webidl',
|
||||
'PopStateEvent.webidl',
|
||||
'PopupBlockedEvent.webidl',
|
||||
|
@ -789,7 +789,7 @@ public class AndroidFxAccount {
|
||||
updateBundleValues(BUNDLE_KEY_PROFILE_JSON, resultData);
|
||||
Logger.info(LOG_TAG, "Profile JSON fetch succeeeded!");
|
||||
FxAccountUtils.pii(LOG_TAG, "Profile JSON fetch returned: " + resultData);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(makeDeletedAccountIntent());
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(makeProfileJSONUpdatedIntent());
|
||||
break;
|
||||
case Activity.RESULT_CANCELED:
|
||||
Logger.warn(LOG_TAG, "Failed to fetch profile JSON; ignoring.");
|
||||
|
@ -51,7 +51,6 @@ import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewStub;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Animation;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user