Merge mozilla-central to mozilla-inbound. CLOSED TREE

This commit is contained in:
Cosmin Sabou 2019-08-10 01:17:41 +03:00
Родитель 23d4f0c224 7a5022a31f
Коммит c317b7ed38
753 изменённых файлов: 7543 добавлений и 5097 удалений

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

@ -117,8 +117,8 @@ devtools/startup/preferences/devtools-startup.js
# Ignore devtools generated code
devtools/shared/css/generated/properties-db.js
devtools/client/webconsole/test/fixtures/stubs/*.js
!devtools/client/webconsole/test/fixtures/stubs/index.js
devtools/client/webconsole/test/node/fixtures/stubs/*.js
!devtools/client/webconsole/test/node/fixtures/stubs/index.js
# Ignore devtools third-party libs
devtools/shared/jsbeautify/*
@ -146,8 +146,8 @@ devtools/client/debugger/test/mochitest/code_*.js
devtools/client/framework/test/code_*
devtools/client/inspector/markup/test/events_bundle.js
devtools/client/netmonitor/test/xhr_bundle.js
devtools/client/webconsole/test/mochitest/code_bundle_nosource.js
devtools/client/webconsole/test/mochitest/code_bundle_invalidmap.js
devtools/client/webconsole/test/browser/code_bundle_nosource.js
devtools/client/webconsole/test/browser/code_bundle_invalidmap.js
devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
devtools/server/tests/unit/setBreakpoint*
devtools/server/tests/unit/sourcemapped.js
@ -275,7 +275,6 @@ services/fxaccounts/FxAccountsPairingChannel.js
# Uses `#filter substitution`
services/sync/modules/constants.js
services/sync/services-sync.js
# Servo is imported.
servo/**

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

@ -29,8 +29,6 @@ modules/libpref/test/unit/data/testPrefLocked.js
modules/libpref/test/unit/data/testPrefSticky.js
modules/libpref/test/unit/extdata/testExt.js
remote/pref/remote.js
services/common/services-common.js
services/sync/services-sync.js
services/sync/tests/unit/prefs_test_prefs_store.js
testing/marionette/prefs/marionette.js
toolkit/components/telemetry/datareporting-prefs.js

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

@ -40,7 +40,6 @@
# push: {owner, pushlog_id, revision},
# repository: {url, project, level},
# input,
# parameters,
# taskId, // targetted taskId
# taskGroupId, // targetted taskGroupId
# action: {name, title, description, taskGroupId, symbol, repo_scope, cb_name}
@ -208,7 +207,6 @@ tasks:
ACTION_TASK_ID: {$json: {$eval: 'taskId'}} # taskId of the target task (JSON-encoded)
ACTION_INPUT: {$json: {$eval: 'input'}}
ACTION_CALLBACK: '${action.cb_name}'
ACTION_PARAMETERS: {$json: {$eval: 'parameters'}}
cache:
level-${repository.level}-checkouts-sparse-v2: /builds/worker/checkouts
@ -287,7 +285,6 @@ tasks:
taskGroupId: '${action.taskGroupId}'
taskId: {$eval: 'taskId'}
input: {$eval: 'input'}
parameters: {$eval: 'parameters'}
clientId: {$eval: 'clientId'}
- $if: 'tasks_for == "cron"'
then:

6
Cargo.lock сгенерированный
Просмотреть файл

@ -2257,7 +2257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "plane-split"
version = "0.14.0"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3648,7 +3648,7 @@ dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plane-split 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
@ -4092,7 +4092,7 @@ dependencies = [
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
"checksum plane-split 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91821c7436aefc1b912552d494232efcaf9810c0189918749532be1e9dbace59"
"checksum plane-split 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68a117c887fbcd9af8dfc1b8b12ee19ba9dec0b2a91d0a9d2bd9114e459f9c78"
"checksum plist 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "95bef0807b4fe77618f8d24f0c4ec37a4ad1dad9348c3b27d8b624c824d8cf48"
"checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9"
"checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0"

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

@ -1613,6 +1613,15 @@ pref("browser.contentblocking.report.monitor.enabled", true);
pref("browser.contentblocking.report.monitor.url", "https://monitor.firefox.com");
pref("browser.contentblocking.report.lockwise.url", "https://lockwise.firefox.com/");
// Protection Report's SUMO urls
pref("browser.contentblocking.report.monitor.how_it_works.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/monitor-faq");
pref("browser.contentblocking.report.lockwise.how_it_works.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/password-manager-report");
pref("browser.contentblocking.report.social.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/social-media-tracking-report");
pref("browser.contentblocking.report.cookie.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/cross-site-tracking-report");
pref("browser.contentblocking.report.tracker.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/tracking-content-report");
pref("browser.contentblocking.report.fingerprinter.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/fingerprinters-report");
pref("browser.contentblocking.report.cryptominer.url", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/cryptominers-report");
// Enables the new Protections Panel.
#ifdef NIGHTLY_BUILD
pref("browser.protections_panel.enabled", true);

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

@ -1399,7 +1399,10 @@ var gIdentityHandler = {
"identity-popup-permission-icon",
aPermission.id + "-icon"
);
if (aPermission.state == SitePermissions.BLOCK) {
if (
aPermission.state == SitePermissions.BLOCK ||
aPermission.state == SitePermissions.AUTOPLAY_BLOCKED_ALL
) {
img.classList.add("blocked-permission-icon");
}

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

@ -48,6 +48,12 @@ function autoplayBlockedIcon() {
);
}
function permissionListBlockedIcons() {
return document.querySelectorAll(
"image.identity-popup-permission-icon.blocked-permission-icon"
);
}
function sleep(ms) {
/* eslint-disable mozilla/no-arbitrary-setTimeout */
return new Promise(resolve => setTimeout(resolve, ms));
@ -251,6 +257,12 @@ add_task(async function testBlockedAll() {
await openIdentityPopup();
Assert.equal(
permissionListBlockedIcons().length,
1,
"Blocked icon is shown"
);
let menulist = document.getElementById("identity-popup-popup-menulist");
await EventUtils.synthesizeMouseAtCenter(menulist, { type: "mousedown" });
await TestUtils.waitForCondition(() => {

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

@ -2689,7 +2689,7 @@ BrowserGlue.prototype = {
_migrateUI: function BG__migrateUI() {
// Use an increasing number to keep track of the current migration state.
// Completely unrelated to the current Firefox release number.
const UI_VERSION = 85;
const UI_VERSION = 86;
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
let currentUIVersion;
@ -3080,6 +3080,25 @@ BrowserGlue.prototype = {
Services.prefs.setBoolPref(CUSTOM_BLOCKING_PREF, true);
}
}
if (currentUIVersion < 86) {
// If the user has set "media.autoplay.allow-muted" to false
// migrate that to media.autoplay.default=BLOCKED_ALL.
if (
Services.prefs.prefHasUserValue("media.autoplay.allow-muted") &&
!Services.prefs.getBoolPref("media.autoplay.allow-muted") &&
!Services.prefs.prefHasUserValue("media.autoplay.default") &&
Services.prefs.getIntPref("media.autoplay.default") ==
Ci.nsIAutoplay.BLOCKED
) {
Services.prefs.setIntPref(
"media.autoplay.default",
Ci.nsIAutoplay.BLOCKED_ALL
);
}
Services.prefs.clearUserPref("media.autoplay.allow-muted");
}
// Update the migration version.
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
},

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

@ -15,14 +15,17 @@
<panelmultiview id="protections-popup-multiView"
mainViewId="protections-popup-mainView">
<panelview id="protections-popup-mainView"
role="document"
descriptionheightworkaround="true">
<hbox id="protections-popup-mainView-panel-header"
flex="1"
onclick="gProtectionsHandler.onHeaderClicked(event);">
<label id="protections-popup-main-header-label" flex="1">
<label id="protections-popup-main-header-label" flex="1"
role="heading" aria-level="1">
<html:span id="protections-popup-mainView-panel-header-span"/>
</label>
<toolbarbutton id="protections-popup-info-button" class="panel-info-button">
<toolbarbutton id="protections-popup-info-button" class="panel-info-button"
aria-label="&protections.etpMoreInfo.label;">
<image/>
</toolbarbutton>
<description id="protections-popup-toast-panel-tp-on-desc">&protections.etpON.header;</description>
@ -35,8 +38,12 @@
<hbox id="protections-popup-tp-switch-section" class="protections-popup-section">
<vbox class="protections-popup-tp-switch-label-box" flex="1">
<label class="protections-popup-tp-switch-on-header">&protections.etpON.header;</label>
<label class="protections-popup-tp-switch-off-header">&protections.etpOFF.header;</label>
<label class="protections-popup-tp-switch-on-header"
role="heading"
aria-level="2">&protections.etpON.header;</label>
<label class="protections-popup-tp-switch-off-header"
role="heading"
aria-level="2">&protections.etpOFF.header;</label>
<label id="protections-popup-tp-switch-breakage-link"
class="text-link"
onclick="gProtectionsHandler.showSiteNotWorkingView();">&protections.siteNotWorking.label;</label>
@ -56,7 +63,10 @@
<tooltip id="protections-popup-not-blocking-why-etp-off-tooltip">&protections.notBlocking.why.etpOff.tooltip;</tooltip>
<vbox id="protections-popup-content" flex="1">
<vbox id="protections-popup-category-list">
<description id="protections-popup-blocking-section-header" hidden="true">&protections.blocking.label;</description>
<description id="protections-popup-blocking-section-header"
hidden="true"
role="heading"
aria-level="2">&protections.blocking.label;</description>
<hbox id="protections-popup-not-blocking-section-header" hidden="true">
<description id="protections-popup-not-blocking-section-description">&protections.notBlocking.label;</description>
<label id="protections-popup-not-blocking-section-why"
@ -133,13 +143,18 @@
<!-- Site Not Working? SubView -->
<panelview id="protections-popup-siteNotWorkingView"
role="document"
title="&protections.siteNotWorkingView.title;"
descriptionheightworkaround="true"
flex="1">
<hbox id="protections-popup-siteNotWorkingView-header">
<vbox class="protections-popup-tp-switch-label-box" flex="1">
<label class="protections-popup-tp-switch-on-header">&protections.etpON.header;</label>
<label class="protections-popup-tp-switch-off-header">&protections.etpOFF.header;</label>
<label class="protections-popup-tp-switch-on-header"
role="heading"
aria-level="1">&protections.etpON.header;</label>
<label class="protections-popup-tp-switch-off-header"
role="heading"
aria-level="1">&protections.etpOFF.header;</label>
</vbox>
<vbox class="protections-popup-tp-switch-box">
<toolbarbutton id="protections-popup-siteNotWorking-tp-switch"
@ -149,7 +164,7 @@
</vbox>
</hbox>
<vbox id="protections-popup-siteNotWorkingView-body">
<label>&protections.siteNotWorkingView.header;</label>
<label role="heading" aria-level="2">&protections.siteNotWorkingView.header;</label>
<label>
<html:ul id="protections-popup-siteNotWorkingView-body-issue-list">
<html:li>&protections.siteNotWorkingView.issueList.logInFields;</html:li>
@ -261,12 +276,12 @@
</vbox>
<vbox id="protections-popup-sendReportView-body" class="panel-view-body-unscrollable">
<vbox class="protections-popup-sendReportView-collection-section">
<label>&contentBlocking.breakageReportView.collection.url.label;</label>
<html:input readonly="readonly" id="protections-popup-sendReportView-collection-url"/>
<label control="protections-popup-sendReportView-collection-url">&contentBlocking.breakageReportView.collection.url.label;</label>
<html:input readonly="readonly" id="protections-popup-sendReportView-collection-url" aria-label="&contentBlocking.breakageReportView.collection.url.label;"/>
</vbox>
<vbox class="protections-popup-sendReportView-collection-section">
<label>&contentBlocking.breakageReportView2.collection.comments.label;</label>
<html:textarea id="protections-popup-sendReportView-collection-comments"/>
<label control="protections-popup-sendReportView-collection-comments">&contentBlocking.breakageReportView2.collection.comments.label;</label>
<html:textarea id="protections-popup-sendReportView-collection-comments" aria-label="&contentBlocking.breakageReportView2.collection.comments.label;"/>
</vbox>
</vbox>
<vbox id="protections-popup-sendReportView-footer"

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

@ -539,6 +539,10 @@ var PanelMultiView = class extends AssociatedToNode {
try {
canCancel = false;
this._panel.openPopup(anchor, options, ...args);
// Set an attribute on the popup to let consumers style popup elements -
// for example, the anchor arrow is styled to match the color of the header
// in the Protections Panel main view.
this._panel.setAttribute("mainviewshowing", true);
// On Windows, if another popup is hiding while we call openPopup, the
// call won't fail but the popup won't open. In this case, we have to
@ -1019,6 +1023,17 @@ var PanelMultiView = class extends AssociatedToNode {
// Kick off the transition!
details.phase = TRANSITION_PHASES.TRANSITION;
// If we're going to show the main view, we can remove the
// min-height property on the view container. It's also time
// to set the mainviewshowing attribute on the popup.
if (viewNode.getAttribute("mainview")) {
this._viewContainer.style.removeProperty("min-height");
this._panel.setAttribute("mainviewshowing", true);
} else {
this._panel.removeAttribute("mainviewshowing");
}
this._viewStack.style.transform =
"translateX(" + (moveToLeft ? "" : "-") + deltaX + "px)";

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

@ -377,7 +377,7 @@ export class ASRouterUISurface extends React.PureComponent {
sendUserActionTelemetry={this.sendUserActionTelemetry}
executeAction={ASRouterUtils.executeAction}
dispatch={this.props.dispatch}
onBlock={this.onBlockById(this.state.message.id)}
onBlockById={ASRouterUtils.blockById}
onDismiss={this.onDismissById(this.state.message.id)}
fxaEndpoint={this.props.fxaEndpoint}
fetchFlowParams={this.fetchFlowParams}

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

@ -7,6 +7,9 @@ import { Interrupt } from "./Interrupt";
import { Triplets } from "./Triplets";
import { BASE_PARAMS } from "./addUtmParams";
// Note: should match the transition time on .trailheadCards in _Trailhead.scss
const TRANSITION_LENGTH = 500;
export const FLUENT_FILES = [
"branding/brand.ftl",
"browser/branding/brandings.ftl",
@ -140,10 +143,11 @@ export class FirstRun extends React.PureComponent {
closeTriplets() {
this.setState({ isTripletsContainerVisible: false });
// TODO: Needs to block ALL extended triplets as well
if (this.props.message.template === "extended_triplets") {
this.props.onBlock();
}
// Closing triplets should prevent any future extended triplets from showing up
setTimeout(() => {
this.props.onBlockById("EXTENDED_TRIPLETS_1");
}, TRANSITION_LENGTH);
}
render() {
@ -175,6 +179,7 @@ export class FirstRun extends React.PureComponent {
onNextScene={this.closeInterrupt}
UTMTerm={UTMTerm}
sendUserActionTelemetry={sendUserActionTelemetry}
executeAction={executeAction}
dispatch={dispatch}
flowParams={flowParams}
onDismiss={this.closeInterrupt}

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

@ -265,8 +265,13 @@
background: var(--trailhead-cards-background-color);
overflow: hidden;
text-align: center;
// Note: should match TRANSITION_LENGTH in FirstRun.jsx
transition: max-height 0.5s $photon-easing;
// This is needed for the transition to work, but will cut off content at the smallest breakpoint
@media (min-width: $break-point-medium) {
max-height: 1000px;
}
&.collapsed {
max-height: 0;

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

@ -4123,6 +4123,9 @@ a.firstrun-link {
overflow: hidden;
text-align: center;
transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
@media (min-width: 610px) {
.trailheadCards {
max-height: 1000px; } }
.trailheadCards.collapsed {
max-height: 0; }
.trailheadCards h1 {

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

@ -4126,6 +4126,9 @@ a.firstrun-link {
overflow: hidden;
text-align: center;
transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
@media (min-width: 610px) {
.trailheadCards {
max-height: 1000px; } }
.trailheadCards.collapsed {
max-height: 0; }
.trailheadCards h1 {

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

@ -4123,6 +4123,9 @@ a.firstrun-link {
overflow: hidden;
text-align: center;
transition: max-height 0.5s cubic-bezier(0.07, 0.95, 0, 1); }
@media (min-width: 610px) {
.trailheadCards {
max-height: 1000px; } }
.trailheadCards.collapsed {
max-height: 0; }
.trailheadCards h1 {

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

@ -2220,7 +2220,7 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_6___default.a.Pur
sendUserActionTelemetry: this.sendUserActionTelemetry,
executeAction: ASRouterUtils.executeAction,
dispatch: this.props.dispatch,
onBlock: this.onBlockById(this.state.message.id),
onBlockById: ASRouterUtils.blockById,
onDismiss: this.onDismissById(this.state.message.id),
fxaEndpoint: this.props.fxaEndpoint,
fetchFlowParams: this.fetchFlowParams
@ -13264,7 +13264,7 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
});
switch (action.type) {
case Actions["actionTypes"].DISCOVERY_STREAM_CONFIG_CHANGE: // The reason this is a separate action is so it doesn't trigger a listener update on init
case Actions["actionTypes"].DISCOVERY_STREAM_CONFIG_CHANGE: // Fall through to a separate action is so it doesn't trigger a listener update on init
case Actions["actionTypes"].DISCOVERY_STREAM_CONFIG_SETUP:
return { ...prevState,
@ -13545,7 +13545,9 @@ var addUtmParams = __webpack_require__(22);
// Note: should match the transition time on .trailheadCards in _Trailhead.scss
const TRANSITION_LENGTH = 500;
const FLUENT_FILES = ["branding/brand.ftl", "browser/branding/brandings.ftl", "browser/branding/sync-brand.ftl", "browser/newtab/onboarding.ftl"];
const helpers = {
selectInterruptAndTriplets(message = {}) {
@ -13671,11 +13673,11 @@ class FirstRun_FirstRun extends external_React_default.a.PureComponent {
closeTriplets() {
this.setState({
isTripletsContainerVisible: false
}); // TODO: Needs to block ALL extended triplets as well
}); // Closing triplets should prevent any future extended triplets from showing up
if (this.props.message.template === "extended_triplets") {
this.props.onBlock();
}
setTimeout(() => {
this.props.onBlockById("EXTENDED_TRIPLETS_1");
}, TRANSITION_LENGTH);
}
render() {
@ -13704,6 +13706,7 @@ class FirstRun_FirstRun extends external_React_default.a.PureComponent {
onNextScene: this.closeInterrupt,
UTMTerm: UTMTerm,
sendUserActionTelemetry: sendUserActionTelemetry,
executeAction: executeAction,
dispatch: dispatch,
flowParams: flowParams,
onDismiss: this.closeInterrupt,

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

@ -94,6 +94,11 @@ const TRAILHEAD_CONFIG = {
},
LOCALES: ["en-US", "en-GB", "en-CA", "de", "de-DE", "fr", "fr-FR"],
EXPERIMENT_RATIOS: [["", 0], ["interrupts", 1], ["triplets", 3]],
// Per bug 1571817, for those who meet the targeting criteria of extended
// triplets, 99% users (control group) will see the extended triplets, and
// the rest 1% (holdback group) won't.
EXPERIMENT_RATIOS_FOR_EXTENDED_TRIPLETS: [["control", 99], ["holdback", 1]],
EXTENDED_TRIPLETS_EXPERIMENT_PREF: "trailhead.extendedTriplets.experiment",
};
const INCOMING_MESSAGE_NAME = "ASRouter:child-to-parent";
@ -490,6 +495,8 @@ class _ASRouter {
trailheadTriplet: "",
messages: [],
errors: [],
extendedTripletsInitialized: false,
showExtendedTriplets: true,
};
this._triggerHandler = this._triggerHandler.bind(this);
this._localProviders = localProviders;
@ -988,6 +995,40 @@ class _ASRouter {
});
}
async setupExtendedTriplets() {
// Don't re-initialize
if (this.state.extendedTripletsInitialized) {
return;
}
let branch = Services.prefs.getStringPref(
TRAILHEAD_CONFIG.EXTENDED_TRIPLETS_EXPERIMENT_PREF,
""
);
if (!branch) {
const { userId } = ClientEnvironment;
branch = await chooseBranch(
`${userId}-extended-triplets-experiment`,
TRAILHEAD_CONFIG.EXPERIMENT_RATIOS_FOR_EXTENDED_TRIPLETS
);
Services.prefs.setStringPref(
TRAILHEAD_CONFIG.EXTENDED_TRIPLETS_EXPERIMENT_PREF,
branch
);
}
// In order for ping centre to pick this up, it MUST contain a substring activity-stream
const experimentName = `activity-stream-extended-triplets`;
TelemetryEnvironment.setExperimentActive(experimentName, branch);
const state = { extendedTripletsInitialized: true };
// Disable the extended triplets for the "holdback" group.
if (branch === "holdback") {
state.showExtendedTriplets = false;
}
await this.setState(state);
}
async setupTrailhead() {
// Don't initialize
if (
@ -1823,11 +1864,24 @@ class _ASRouter {
}));
} else {
// On new tab, send cards if they match; othwerise send a snippet
message =
(await this.handleMessageRequest({
provider: "onboarding",
template: "extended_triplets",
})) || (await this.handleMessageRequest({ provider: "snippets" }));
message = await this.handleMessageRequest({
provider: "onboarding",
template: "extended_triplets",
});
// Set up the experiment for extended triplets. It's done here because we
// only want to enroll users (for both control and holdback) if they meet
// the targeting criteria.
if (message) {
await this.setupExtendedTriplets();
}
// If no extended triplets message was returned, or the holdback experiment
// is active, show snippets instead
if (!message || !this.state.showExtendedTriplets) {
message = await this.handleMessageRequest({ provider: "snippets" });
}
await this.setState({ lastMessageId: message ? message.id : null });
}

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

@ -68,7 +68,12 @@ class PageAction {
this._showPopupOnClick = this._showPopupOnClick.bind(this);
this.dispatchUserAction = this.dispatchUserAction.bind(this);
this._l10n = new DOMLocalization(["browser/newtab/asrouter.ftl"]);
this._l10n = new DOMLocalization([
"browser/newtab/asrouter.ftl",
"browser/branding/brandings.ftl",
"browser/branding/sync-brand.ftl",
"branding/brand.ftl",
]);
// Saved timeout IDs for scheduled state changes, so they can be cancelled
this.stateTransitionTimeoutIDs = [];

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

@ -101,6 +101,7 @@ const ONBOARDING_MESSAGES = () => [
{
id: "EXTENDED_TRIPLETS_1",
template: "extended_triplets",
campaign: "firstrun_triplets",
targeting:
"trailheadTriplet && ((currentDate|date - profileAgeCreated) / 86400000) < 7",
includeBundle: {

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

@ -2,8 +2,12 @@
# 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/.
## These messages are used as headings in the recommendation doorhanger
cfr-doorhanger-extension-heading = Recommended Extension
cfr-doorhanger-feature-heading = Recommended Feature
cfr-doorhanger-pintab-heading = Try This: Pin Tab
##
cfr-doorhanger-extension-sumo-link =
.tooltiptext = Why am I seeing this
@ -81,3 +85,25 @@ cfr-whatsnew-button =
.tooltiptext = Whats New
cfr-whatsnew-panel-header = Whats New
## Bookmark Sync
cfr-doorhanger-sync-bookmarks-header = Get this bookmark on your phone
cfr-doorhanger-sync-bookmarks-body = Take your bookmarks, passwords, history and more everywhere youre signed into { -brand-product-name }.
cfr-doorhanger-sync-bookmarks-ok-button = Turn on { -sync-brand-short-name }
.accesskey = T
## Send Tab
cfr-doorhanger-send-tab-header = Read this on the go
cfr-doorhanger-send-tab-recipe-header = Take this recipe to the kitchen
cfr-doorhanger-send-tab-body = Send Tab lets you easily share this link to your phone or anywhere youre signed in to { -brand-product-name }.
cfr-doorhanger-send-tab-ok-button = Try Send Tab
.accesskey = T
## Firefox Send
cfr-doorhanger-firefox-send-header = Share this PDF securely
cfr-doorhanger-firefox-send-body = Keep your sensitive documents safe from prying eyes with end-to-end encryption and a link that disappears when youre done.
cfr-doorhanger-firefox-send-ok-button = Try { -send-brand-name }
.accesskey = T

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

@ -23,6 +23,7 @@ cd /mozilla-central && ./mach build \
browser/base/content/test/static/browser_parsable_css.js \
browser/base/content/test/tabs/browser_new_tab_in_privileged_process_pref.js \
browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js \
browser/components/extensions/test/browser/browser_ext_topSites.js \
browser/components/preferences/in-content/tests/browser_hometab_restore_defaults.js \
browser/components/preferences/in-content/tests/browser_newtab_menu.js \
browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_1.js \

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

@ -1222,6 +1222,81 @@ describe("ASRouter", () => {
assert.lengthOf(Router.state.providers.filter(p => p.url === url), 0);
});
it("should handle onboarding message provider", async () => {
const handleMessageRequestStub = sandbox.stub(
Router,
"handleMessageRequest"
);
handleMessageRequestStub
.withArgs({
provider: "onboarding",
template: "extended_triplets",
})
.resolves({ id: "foo" });
const spy = sandbox.spy(Router, "setupExtendedTriplets");
const msg = fakeAsyncMessage({
type: "NEWTAB_MESSAGE_REQUEST",
data: {},
});
await Router.onMessage(msg);
assert.calledOnce(spy);
});
it("should fallback to snippets if one was assigned to the holdback experiment", async () => {
sandbox.stub(global.Sampling, "ratioSample").resolves(1); // 1 = holdback branch
const handleMessageRequestStub = sandbox.stub(
Router,
"handleMessageRequest"
);
handleMessageRequestStub
.withArgs({
provider: "onboarding",
template: "extended_triplets",
})
.resolves({ id: "foo" });
const msg = fakeAsyncMessage({
type: "NEWTAB_MESSAGE_REQUEST",
data: {},
});
await Router.onMessage(msg);
assert.calledTwice(handleMessageRequestStub);
assert.calledWithExactly(handleMessageRequestStub, {
provider: "onboarding",
template: "extended_triplets",
});
assert.calledWithExactly(handleMessageRequestStub, {
provider: "snippets",
});
});
it("should fallback to snippets if onboarding message provider returned none", async () => {
const handleMessageRequestStub = sandbox.stub(
Router,
"handleMessageRequest"
);
handleMessageRequestStub
.withArgs({
provider: "onboarding",
template: "extended_triplets",
})
.resolves(null);
const spy = sandbox.spy(Router, "setupExtendedTriplets");
const msg = fakeAsyncMessage({
type: "NEWTAB_MESSAGE_REQUEST",
data: {},
});
await Router.onMessage(msg);
assert.notCalled(spy);
assert.calledTwice(handleMessageRequestStub);
assert.calledWithExactly(handleMessageRequestStub, {
provider: "onboarding",
template: "extended_triplets",
});
assert.calledWithExactly(handleMessageRequestStub, {
provider: "snippets",
});
});
});
describe("#onMessage: BLOCK_MESSAGE_BY_ID", () => {
@ -2882,6 +2957,75 @@ describe("ASRouter", () => {
});
});
});
describe(".setupExtendedTriplets", () => {
let setStringPrefStub;
let setExperimentActiveStub;
beforeEach(() => {
setStringPrefStub = sandbox.stub(
global.Services.prefs,
"setStringPref"
);
setExperimentActiveStub = sandbox.stub(
global.TelemetryEnvironment,
"setExperimentActive"
);
});
it("should generates a control branch configuration and update Router.state", async () => {
sandbox.stub(global.Sampling, "ratioSample").resolves(0); // 0 = control branch
await Router.setupExtendedTriplets();
assert.propertyVal(Router.state, "extendedTripletsInitialized", true);
assert.propertyVal(Router.state, "showExtendedTriplets", true);
assert.calledWith(
setStringPrefStub,
TRAILHEAD_CONFIG.EXTENDED_TRIPLETS_EXPERIMENT_PREF,
"control"
);
assert.calledWith(
setExperimentActiveStub,
"activity-stream-extended-triplets",
"control"
);
});
it("should generates a test branch configuration and update Router.state", async () => {
sandbox.stub(global.Sampling, "ratioSample").resolves(1); // 1 = holdback branch
await Router.setupExtendedTriplets();
assert.propertyVal(Router.state, "extendedTripletsInitialized", true);
assert.propertyVal(Router.state, "showExtendedTriplets", false);
assert.calledWith(
setStringPrefStub,
TRAILHEAD_CONFIG.EXTENDED_TRIPLETS_EXPERIMENT_PREF,
"holdback"
);
assert.calledWith(
setExperimentActiveStub,
"activity-stream-extended-triplets",
"holdback"
);
});
it("should reuse the existing branch if it's already defined", async () => {
getStringPrefStub.returns("control");
await Router.setupExtendedTriplets();
assert.notCalled(setStringPrefStub);
});
it("should only run once", async () => {
sandbox.spy(Router, "setState");
await Router.setupExtendedTriplets();
await Router.setupExtendedTriplets();
await Router.setupExtendedTriplets();
assert.calledOnce(Router.setState);
});
});
});
describe("chooseBranch", () => {

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

@ -44,9 +44,12 @@ describe("<FirstRun>", () => {
let message;
let fakeDoc;
let sandbox;
let clock;
let onBlockByIdStub;
async function setup() {
sandbox = sinon.createSandbox();
clock = sandbox.useFakeTimers();
message = await getTestMessage("TRAILHEAD_1");
fakeDoc = {
body: document.createElement("body"),
@ -55,6 +58,7 @@ describe("<FirstRun>", () => {
getElementById: () => document.createElement("div"),
activeElement: document.createElement("div"),
};
onBlockByIdStub = sandbox.stub();
sandbox
.stub(global, "fetch")
@ -71,6 +75,7 @@ describe("<FirstRun>", () => {
document={fakeDoc}
dispatch={() => {}}
sendUserActionTelemetry={() => {}}
onBlockById={onBlockByIdStub}
/>
);
}
@ -132,6 +137,16 @@ describe("<FirstRun>", () => {
});
});
it("should pass along executeAction appropriately", () => {
const stub = sandbox.stub();
wrapper = mount(
<FirstRun message={message} document={fakeDoc} executeAction={stub} />
);
assert.propertyVal(wrapper.find(Interrupt).props(), "executeAction", stub);
assert.propertyVal(wrapper.find(Triplets).props(), "onAction", stub);
});
it("should load flow params on mount if fxaEndpoint is defined", () => {
const stub = sandbox.stub();
wrapper = mount(
@ -198,7 +213,7 @@ describe("<FirstRun>", () => {
);
});
it("should hide triplets when closeTriplets is called", () => {
it("should hide triplets when closeTriplets is called and block extended triplets after 500ms", () => {
// Simulate calling next scene
wrapper
.find(Triplets)
@ -212,5 +227,9 @@ describe("<FirstRun>", () => {
.hasClass("show"),
"Show triplet content"
);
assert.notCalled(onBlockByIdStub);
clock.tick(500);
assert.calledWith(onBlockByIdStub, "EXTENDED_TRIPLETS_1");
});
});

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

@ -1,5 +1,6 @@
import { _ToolbarPanelHub } from "lib/ToolbarPanelHub.jsm";
import { GlobalOverrider } from "test/unit/utils";
import { OnboardingMessageProvider } from "lib/OnboardingMessageProvider.jsm";
import { PanelTestProvider } from "lib/PanelTestProvider.jsm";
describe("ToolbarPanelHub", () => {
@ -15,6 +16,7 @@ describe("ToolbarPanelHub", () => {
let addObserverStub;
let removeObserverStub;
let getBoolPrefStub;
let setBoolPrefStub;
let waitForInitializedStub;
let isBrowserPrivateStub;
let fakeDispatch;
@ -31,6 +33,7 @@ describe("ToolbarPanelHub", () => {
appendChild: sandbox.stub(),
addEventListener: sandbox.stub(),
hasAttribute: sandbox.stub(),
toggleAttribute: sandbox.stub(),
};
fakeDocument = {
l10n: {
@ -75,6 +78,7 @@ describe("ToolbarPanelHub", () => {
addObserverStub = sandbox.stub();
removeObserverStub = sandbox.stub();
getBoolPrefStub = sandbox.stub();
setBoolPrefStub = sandbox.stub();
fakeDispatch = sandbox.stub();
isBrowserPrivateStub = sandbox.stub();
globals.set("EveryWindow", everyWindowStub);
@ -84,6 +88,7 @@ describe("ToolbarPanelHub", () => {
addObserver: addObserverStub,
removeObserver: removeObserverStub,
getBoolPref: getBoolPrefStub,
setBoolPref: setBoolPrefStub,
},
});
globals.set("PrivateBrowsingUtils", {
@ -476,4 +481,48 @@ describe("ToolbarPanelHub", () => {
});
});
});
describe("#insertProtectionPanelMessage", () => {
const fakeInsert = () =>
instance.insertProtectionPanelMessage({
target: { ownerGlobal: fakeWindow, ownerDocument: fakeDocument },
});
beforeEach(async () => {
const onboardingMsgs = await OnboardingMessageProvider.getUntranslatedMessages();
await instance.init(waitForInitializedStub, {
dispatch: fakeDispatch,
getMessages: () =>
onboardingMsgs.find(msg => msg.template === "protections_panel"),
});
});
it("should remember it showed", async () => {
await fakeInsert();
assert.calledWithExactly(
setBoolPrefStub,
"browser.protections_panel.infoMessage.seen",
true
);
});
it("should toggle/expand when default collapsed/disabled", async () => {
fakeElementById.hasAttribute.returns(true);
await fakeInsert();
assert.calledTwice(fakeElementById.toggleAttribute);
});
it("should toggle again when popup hides", async () => {
fakeElementById.addEventListener.callsArg(1);
await fakeInsert();
assert.callCount(fakeElementById.toggleAttribute, 4);
});
it("should open link on click", async () => {
await fakeInsert();
eventListeners.click();
assert.calledOnce(fakeWindow.ownerGlobal.openLinkIn);
});
});
});

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

@ -8,6 +8,9 @@ const LOCKWISE_URL = RPMGetStringPref(
"browser.contentblocking.report.lockwise.url",
""
);
const HOW_IT_WORKS_URL_PREF = RPMGetFormatURLPref(
"browser.contentblocking.report.lockwise.how_it_works.url"
);
export default class LockwiseCard {
constructor(document) {
@ -26,18 +29,25 @@ export default class LockwiseCard {
RPMSendAsyncMessage("OpenAboutLogins");
});
const syncLink = this.doc.querySelector(".synced-devices-text a");
const syncLink = this.doc.getElementById("turn-on-sync");
// Register a click handler for the anchor since it's not possible to navigate to about:preferences via href
syncLink.addEventListener("click", () => {
this.doc.sendTelemetryEvent("click", "lw_app_link");
RPMSendAsyncMessage("OpenSyncPreferences");
});
const eventHandler = evt => {
if (evt.keyCode == evt.DOM_VK_RETURN || evt.type == "click") {
this.doc.sendTelemetryEvent("click", "lw_app_link");
RPMSendAsyncMessage("OpenSyncPreferences");
}
};
syncLink.addEventListener("click", eventHandler);
syncLink.addEventListener("keydown", eventHandler);
// Attach link to Firefox Lockwise app page.
const lockwiseAppLink = this.doc.getElementById("lockwise-inline-link");
lockwiseAppLink.href = LOCKWISE_URL;
lockwiseAppLink.addEventListener("click", () => {
this.doc.sendTelemetryEvent("click", "lw_sync_link");
});
// Attack link to Firefox Lockwise "How it works" page.
const lockwiseReportLink = this.doc.getElementById("lockwise-how-it-works");
lockwiseReportLink.addEventListener("click", () => {
this.doc.sendTelemetryEvent("click", "lw_about_link");
@ -115,6 +125,9 @@ export default class LockwiseCard {
"lockwise-passwords-stored"
);
const howItWorksLink = this.doc.getElementById("lockwise-how-it-works");
howItWorksLink.href = HOW_IT_WORKS_URL_PREF;
// Set the text for the number of synced devices.
const syncedDevicesBlock = container.querySelector(
".number-of-synced-devices.block"
@ -134,7 +147,7 @@ export default class LockwiseCard {
}
// Display the link for enabling sync if no synced devices are detected.
if (syncedDevices === 0) {
const syncLink = syncedDevicesText.querySelector("a");
const syncLink = this.doc.getElementById("turn-on-sync");
syncLink.classList.remove("hidden");
}
}

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

@ -8,6 +8,9 @@ const MONITOR_SIGN_IN_URL = RPMGetStringPref(
"browser.contentblocking.report.monitor.url",
""
);
const HOW_IT_WORKS_URL_PREF = RPMGetFormatURLPref(
"browser.contentblocking.report.monitor.how_it_works.url"
);
export default class MonitorClass {
constructor(document) {
@ -15,6 +18,9 @@ export default class MonitorClass {
}
init() {
const monitorLinkTag = this.doc.getElementById("monitor-inline-link");
monitorLinkTag.href = MONITOR_SIGN_IN_URL;
RPMAddMessageListener("SendUserLoginsData", ({ data }) => {
// Wait for monitor data and display the card.
this.getMonitorData(data);
@ -111,6 +117,9 @@ export default class MonitorClass {
);
monitorCardBody.classList.remove("hidden");
const howItWorksLink = this.doc.getElementById("monitor-link");
howItWorksLink.href = HOW_IT_WORKS_URL_PREF;
const storedEmail = this.doc.querySelector(
"span[data-type='stored-emails']"
);

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

@ -526,6 +526,7 @@ label[for="tab-cryptominer"]:hover ~ #highlight-hover {
.monitor-card #monitor-header-content > a {
display: block;
margin-block-start: 5px;
width: max-content;
}
.monitor-card.has-logins #monitor-body-content {

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

@ -41,19 +41,19 @@ etp-card-content = Trackers follow you around online to collect information abou
graph-today = Today
social-tab-title = Social Media Trackers
social-tab-contant = Social media like, post, and comment buttons on other websites can track you — even if you dont use them. Logging in to sites using your Facebook or Twitter account is another way they can track what you do on those sites. We remove these trackers so Facebook and Twitter see less of what you do online.
social-tab-contant = Social media like, post, and comment buttons on other websites can track you — even if you dont use them. Logging in to sites using your Facebook or Twitter account is another way they can track what you do on those sites. We remove these trackers so Facebook and Twitter see less of what you do online. <a data-l10n-name="learn-more-link">Learn more</a>
cookie-tab-title = Cross-Site Tracking Cookies
cookie-tab-content = Cross-site tracking cookies follow you from site to site to collect data about your browsing habits. Advertisers and analytics companies gather this data to create a profile of your interests across many sites. Blocking them reduces the number of personalized ads that follow you around.
cookie-tab-content = Cross-site tracking cookies follow you from site to site to collect data about your browsing habits. Advertisers and analytics companies gather this data to create a profile of your interests across many sites. Blocking them reduces the number of personalized ads that follow you around. <a data-l10n-name="learn-more-link">Learn more</a>
tracker-tab-title = Tracking Content
tracker-tab-content = Websites may load outside ads, videos, and other content that contain hidden trackers. Blocking tracking content can make websites load faster, but some buttons, forms, and login fields might not work.
tracker-tab-content = Websites may load outside ads, videos, and other content that contain hidden trackers. Blocking tracking content can make websites load faster, but some buttons, forms, and login fields might not work. <a data-l10n-name="learn-more-link">Learn more</a>
fingerprinter-tab-title = Fingerprinters
fingerprinter-tab-content = Fingerprinting is a form of online tracking thats different from your real fingerprints. Companies use it to create a unique profile of you using data about your browser, device, and other settings. We block ad trackers from fingerprinting your device.
fingerprinter-tab-content = Fingerprinting is a form of online tracking thats different from your real fingerprints. Companies use it to create a unique profile of you using data about your browser, device, and other settings. We block ad trackers from fingerprinting your device. <a data-l10n-name="learn-more-link">Learn more</a>
cryptominer-tab-title = Cryptominers
cryptominer-tab-content = Some websites host hidden malware that secretly uses your systems computing power to mine cryptocurrency, or digital money. It drains your battery, slows down your computer, and increases your energy bill. We block known cryptominers from using your computing resources to make money.
cryptominer-tab-content = Some websites host hidden malware that secretly uses your systems computing power to mine cryptocurrency, or digital money. It drains your battery, slows down your computer, and increases your energy bill. We block known cryptominers from using your computing resources to make money. <a data-l10n-name="learn-more-link">Learn more</a>
lockwise-title = Never forget a password again
lockwise-title-logged-in = { -lockwise-brand-name }
@ -133,3 +133,14 @@ go-to-privacy-settings = Go to Privacy Settings
# This is the title attribute describing the Lockwise card's link to about:logins
go-to-saved-logins = Go to Saved Logins
bar-tooltip-social =
.title = Social Media Trackers
bar-tooltip-cookie =
.title = Cross-Site Tracking Cookies
bar-tooltip-tracker =
.title = Tracking Content
bar-tooltip-fingerprinter =
.title = Fingerprinters
bar-tooltip-cryptominer =
.title = Cryptominers

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

@ -57,23 +57,33 @@
<div id=highlight-hover></div>
<div id="social" class="tab-content">
<p class="content-title" data-l10n-id="social-tab-title"></p>
<p data-l10n-id="social-tab-contant"></p>
<p data-l10n-id="social-tab-contant">
<a target="_blank" id="social-link" data-l10n-name="learn-more-link"></a>
</p>
</div>
<div id="cookie" class="tab-content">
<p class="content-title" data-l10n-id="cookie-tab-title"></p>
<p data-l10n-id="cookie-tab-content"></p>
<p data-l10n-id="cookie-tab-content">
<a target="_blank" id="cookie-link" data-l10n-name="learn-more-link"></a>
</p>
</div>
<div id="tracker" class="tab-content">
<p class="content-title" data-l10n-id="tracker-tab-title"></p>
<p data-l10n-id="tracker-tab-content"></p>
<p data-l10n-id="tracker-tab-content">
<a target="_blank" id="tracker-link" data-l10n-name="learn-more-link"></a>
</p>
</div>
<div id="fingerprinter" class="tab-content">
<p class="content-title" data-l10n-id="fingerprinter-tab-title"></p>
<p data-l10n-id="fingerprinter-tab-content"></p>
<p data-l10n-id="fingerprinter-tab-content">
<a target="_blank" id="fingerprinter-link" data-l10n-name="learn-more-link"></a>
</p>
</div>
<div id="cryptominer" class="tab-content">
<p class="content-title" data-l10n-id="cryptominer-tab-title"></p>
<p data-l10n-id="cryptominer-tab-content"></p>
<p data-l10n-id="cryptominer-tab-content">
<a target="_blank" id="cryptominer-link" data-l10n-name="learn-more-link"></a>
</p>
</div>
</div>
</div>
@ -91,7 +101,7 @@
<span>
<!-- Insert Monitor header content here. -->
</span>
<a id="monitor-link" href="" data-l10n-id="monitor-link"></a>
<a target="_blank" href="" id="monitor-link" data-l10n-id="monitor-link"></a>
</p>
<span class="inline-text-icon monitor-scanned-text" data-l10n-id="auto-scan"></span>
</div>
@ -130,14 +140,14 @@
<span id="info-exposed-passwords" class="info-text"></span>
</div>
<div id="full-report-link" class="monitor-view-full-report" data-l10n-id="full-report-link">
<a id="monitor-inline-link" data-l10n-name="monitor-inline-link" href=""></a>
<a target="_blank" id="monitor-inline-link" data-l10n-name="monitor-inline-link" href=""></a>
</div>
<div class="monitor-breached-passwords hidden">
<span data-type="breached-lockwise-passwords" class="number-of-breaches block">
<!-- Display number of exposed stored passwords here. -->
</span>
<span id="password-warning">
<a id="lockwise-link" href="" data-l10n-name="lockwise-link"></a>
<a target="_blank" href="about:logins" id="lockwise-link" data-l10n-name="lockwise-link" data-l10n-title="go-to-saved-logins"></a>
</span>
</div>
</div>
@ -163,7 +173,7 @@
<div class="no-logins hidden">
<div class="lockwise-mobile-app-icon"></div>
<span data-l10n-id="lockwise-no-logins-content">
<a id="lockwise-inline-link" data-l10n-name="lockwise-inline-link" href=""></a>
<a target="_blank" id="lockwise-inline-link" data-l10n-name="lockwise-inline-link" href=""></a>
</span>
</div>
<div class="has-logins hidden">
@ -172,7 +182,7 @@
</span>
<span id="lockwise-passwords-stored" class="inline-text-icon passwords-stored-text">
<!-- Display message for stored logins here. -->
<a id="lockwise-how-it-works" data-l10n-name="lockwise-how-it-works" href=""></a>
<a target="_blank" id="lockwise-how-it-works" data-l10n-name="lockwise-how-it-works" href=""></a>
</span>
<span class="number-of-synced-devices block">
<!-- Display number of synced devices here. -->
@ -181,7 +191,7 @@
<span>
<!-- Display message for status of synced devices here. -->
</span>
<a id="turn-on-sync" class="hidden" href="" data-l10n-id="turn-on-sync"></a>
<a id="turn-on-sync" tabindex="0" class="hidden" href="" data-l10n-id="turn-on-sync"></a>
</span>
</div>
</div>

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

@ -124,6 +124,7 @@ document.addEventListener("DOMContentLoaded", e => {
div.className = `${type}-bar inner-bar`;
div.setAttribute("data-type", type);
div.style.height = `${dataHeight}%`;
div.setAttribute("data-l10n-id", `bar-tooltip-${type}`);
weekTypeCounts[type] += content[type];
innerBar.appendChild(div);
}
@ -151,10 +152,15 @@ document.addEventListener("DOMContentLoaded", e => {
graph.append(label);
date.setDate(date.getDate() - 1);
}
// Set the total number of each type of tracker on the tabs
// Set the total number of each type of tracker on the tabs as well as their
// "Learn More" links
for (let type of dataTypes) {
document.querySelector(`label[data-type=${type}]`).textContent =
weekTypeCounts[type];
const learnMoreLink = document.getElementById(`${type}-link`);
learnMoreLink.href = RPMGetFormatURLPref(
`browser.contentblocking.report.${type}.url`
);
}
// Hide the trackers tab if the user is in standard and

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

@ -137,6 +137,7 @@ add_task(async function checkTelemetryClickEvents() {
}
const syncLink = await ContentTaskUtils.waitForCondition(() => {
// Opens an extra tab
return content.document.getElementById("turn-on-sync");
}, "syncLink exists");
@ -154,6 +155,7 @@ add_task(async function checkTelemetryClickEvents() {
await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
const openAboutLogins = await ContentTaskUtils.waitForCondition(() => {
// Opens an extra tab
return content.document.getElementById("open-about-logins-button");
}, "openAboutLogins exists");
@ -208,6 +210,7 @@ add_task(async function checkTelemetryClickEvents() {
await ContentTask.spawn(tab.linkedBrowser, {}, async function() {
let openLockwise = await ContentTaskUtils.waitForCondition(() => {
// Opens an extra tab
return content.document.getElementById("lockwise-link");
}, "openLockwise exists");
@ -279,7 +282,11 @@ add_task(async function checkTelemetryClickEvents() {
is(events.length, 1, `recorded telemetry for mtr_signup_button`);
await BrowserTestUtils.removeTab(tab);
// We open two extra tabs with the click events.
// We open three extra tabs with the click events.
// 1. Monitor's "Viewed Saved Logins" link (goes to about:logins)
// 2. Lockwise's "Turn on sync..." link (goes to about:preferences#sync)
// 3. Lockwise's "Open Nightly" button (goes to about:logins)
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

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

@ -0,0 +1,717 @@
{
"data": [
{
"engineName": "google",
"orderHint": 1000,
"webExtensionId": "google@search.mozilla.org",
"searchUrlGetExtraCodes": "client=firefox-b-d",
"appliesTo": [{
"included": { "everywhere": true },
"default": "yes"
}, {
"included": {
"regions": ["ru", "tr", "by", "kz"],
"locales": {
"matches": ["ru", "tr", "be", "kk"],
"startsWith": ["en"]
}
},
"default": "no"
}, {
"included": {
"regions": ["cn"],
"locales": {
"matches": ["zh-CN"]
}
},
"default": "no"
}, {
"included": { "regions": ["us"] },
"searchUrlGetExtraCodes": "client=firefox-b-1-d"
}],
"aliases": ["@google"]
},
{
"engineName": "bing",
"webExtensionId": "bing@search.mozilla.org",
"appliesTo": [{
"included": {
"locales": {
"matches": [
"ach", "af", "an", "ar", "ast", "az", "ca", "cak", "da", "de",
"dsb", "el", "eo", "es-CL", "es-ES",
"es-MX", "eu", "fa", "ff", "fi", "fr", "fy-NL", "gn",
"gu-IN", "hi-IN", "hr", "hsb", "ia", "is", "it",
"ja-JP-mac", "ja", "ka", "kab", "km", "kn", "lij", "lo",
"lt", "mai", "mk", "ml", "ms", "my", "nb-NO", "ne-NP", "nl",
"nn-NO", "oc", "or", "pa-IN", "pt-BR", "rm", "ro", "son",
"sq", "sr", "sv-SE", "th", "tl", "trs", "uk", "ur", "uz",
"wo", "xh", "zh-CN"
],
"startsWith": ["bn", "en"]
}
}
}],
"aliases": ["@bing"]
},
{
"engineName": "baidu",
"webExtensionId": "baidu@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["zh-CN"] } }
}, {
"included": {
"regions": ["cn"],
"locales": { "matches": ["zh-CN"] }
},
"default": "yes"
}],
"aliases": ["@\u767E\u5EA6", "@baidu"]
},
{
"engineName": "amazon",
"orderHint": 500,
"webExtensionId": "amazondotcom@search.mozilla.org",
"appliesTo": [{
"included": {
"locales": {
"matches": [
"ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
"es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
"lt", "mk", "ms", "my", "ro", "si", "th", "tl",
"trs", "uz"
]
}
}
}, {
"included": {
"regions": ["au"],
"locales": {
"matches": [
"ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
"es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
"lt", "mk", "ms", "my", "ro", "si", "th", "tl",
"trs", "uz"
]
}
},
"webExtensionId": "amazon@search.mozilla.org",
"webExtensionLocale": "au"
}, {
"included": {
"regions": ["ca"],
"locales": {
"matches": [
"ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
"es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
"lt", "mk", "ms", "my", "ro", "si", "th", "tl",
"trs", "uz"
]
}
},
"webExtensionId": "amazon@search.mozilla.org",
"webExtensionLocale": "ca"
}, {
"included": {
"regions": ["fr"],
"locales": {
"matches": [
"ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
"es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
"lt", "mk", "ms", "my", "ro", "si", "th", "tl",
"trs", "uz"
]
}
},
"webExtensionId": "amazon@search.mozilla.org",
"webExtensionLocale": "france"
}, {
"included": {
"regions": ["gb"],
"locales": {
"matches": [
"ach", "af", "ar", "az", "bg", "cak", "en-US", "eo",
"es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km",
"lt", "mk", "ms", "my", "ro", "si", "th", "tl",
"trs", "uz"
]
}
},
"webExtensionId": "amazon@search.mozilla.org",
"webExtensionLocale": "en-GB"
}],
"aliases": ["amazon"]
},
{
"engineName": "amazon",
"orderHint": 500,
"webExtensionId": "amazon@search.mozilla.org",
"appliesTo": [{
"included": {
"locales": { "matches": [
"as", "bn", "bn-IN", "kn", "gu-IN", "mai", "ml", "mr",
"or", "pa-IN", "ta", "te", "ur"
]}
},
"webExtensionLocale": "in"
}, {
"included": {
"locales": { "matches": ["br", "ff", "fr", "son", "wo"] }
},
"webExtensionLocale": "france"
}, {
"included": {
"regions": ["ca"],
"locales": { "matches": ["br", "ff", "fr", "son", "wo"] }
},
"webExtensionLocale": "ca"
}, {
"included": { "locales": { "matches": ["en-CA"] } },
"webExtensionLocale": "ca"
}, {
"included": { "locales": { "matches": ["ja-JP-mac", "ja"] } },
"webExtensionLocale": "jp"
}, {
"included": { "locales": { "matches": ["it", "lij"] } },
"webExtensionLocale": "it"
}, {
"included": { "locales": { "matches": ["de", "dsb", "hsb"] } },
"webExtensionLocale": "de"
}, {
"included": {
"locales": {
"matches": [
"cy", "da", "el", "en-GB", "eu", "ga-IE", "gd", "gl", "hr",
"nb-NO", "nn-NO", "pt-PT", "sq", "sr"
]
}
},
"webExtensionLocale": "en-GB"
}, {
"included": {
"regions": ["au"],
"locales": {
"matches": [
"cy", "da", "el", "en-GB", "eu", "ga-IE", "gd", "gl", "hr",
"nb-NO", "nn-NO", "pt-PT", "sq", "sr"
]
}
},
"webExtensionLocale": "au"
}],
"aliases": ["amazon"]
},
{
"engineName": "amazon",
"orderHint": 500,
"webExtensionId": "amazondotcn@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["zh-CN"] } }
}],
"aliases": ["amazon"]
},
{
"engineName": "ebay",
"orderHint": 500,
"webExtensionId": "ebay@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["en-US"] } },
"excluded": { "regions": ["ru", "tr", "by", "kz"] }
}, {
"included": {
"locales": { "matches": ["en-US"] },
"regions": ["au"]
},
"webExtensionLocale": "au"
}, {
"included": {
"locales": { "matches": ["en-US"] },
"regions": ["ie"]
},
"webExtensionLocale": "ie"
}, {
"included": {
"locales": { "matches": ["en-US"] },
"regions": ["be"]
},
"webExtensionLocale": "be"
}, {
"included": { "locales": {
"matches": ["an", "ast", "ca", "es-ES", "eu", "gl"]
}},
"webExtensionLocale": "es"
}, {
"included": { "locales": { "matches": ["br", "fr", "wo"] }},
"webExtensionLocale": "fr"
}, {
"included": {
"locales": { "matches": ["br", "fr", "wo"] },
"regions": ["be"]
},
"webExtensionLocale": "be"
}, {
"included": {
"locales": { "matches": ["br", "fr", "wo"] },
"regions": ["ca"]
},
"webExtensionLocale": "ca"
}, {
"included": {
"locales": { "matches": ["br", "fr", "wo"] },
"regions": ["ch"]
},
"webExtensionLocale": "ch"
}, {
"included": { "locales": { "matches": ["cy", "en-GB", "gd"] }},
"webExtensionLocale": "uk"
}, {
"included": {
"locales": { "matches": ["cy", "en-GB", "gd"] },
"regions": ["au"]
},
"webExtensionLocale": "au"
}, {
"included": {
"locales": { "matches": ["cy", "en-GB", "gd"] },
"regions": ["ie"]
},
"webExtensionLocale": "ie"
}, {
"included": { "locales": { "matches": ["de", "dsb", "hsb"] }},
"webExtensionLocale": "de"
}, {
"included": {
"locales": { "matches": ["de", "dsb", "hsb"] },
"regions": ["at"]
},
"webExtensionLocale": "at"
}, {
"included": {
"locales": { "matches": ["de", "dsb", "hsb"] },
"regions": ["ch"]
},
"webExtensionLocale": "ch"
}, {
"included": { "locales": { "matches": ["en-CA"] }},
"webExtensionLocale": "ca"
}, {
"included": { "locales": { "matches": ["fy-NL", "nl"] }},
"webExtensionLocale": "nl"
}, {
"included": {
"locales": { "matches": ["fy-NL", "nl"] },
"regions": ["be"]
},
"webExtensionLocale": "be"
}, {
"included": { "locales": { "matches": ["ga-IE"] }},
"webExtensionLocale": "ie"
}, {
"included": { "locales": { "matches": ["it", "lij"] }},
"webExtensionLocale": "it"
}, {
"included": { "locales": { "matches": ["rm"] }},
"webExtensionLocale": "ch"
}],
"aliases": ["@ebay"]
},
{
"engineName": "ddg",
"orderHint": 500,
"appliesTo": [{
"webExtensionId": "ddg@search.mozilla.org",
"included": {
"everywhere": true
}
}],
"aliases": ["@duckduckgo", "@ddg"]
},
{
"engineName": "yandex",
"webExtensionId": "yandex@search.mozilla.org",
"appliesTo": [{
"default": "yes",
"included": {
"regions": ["ru", "tr", "by", "kz"],
"locales": {
"matches": ["ru", "tr", "be", "kk"],
"startsWith": ["en"]
}
},
"webExtensionLocale": "en"
}, {
"included": { "locales": { "matches": ["az"] }},
"webExtensionLocale": "az"
}, {
"included": { "locales": { "matches": ["be"] }},
"webExtensionLocale": "by"
}, {
"included": { "locales": { "matches": ["kk"] }},
"webExtensionLocale": "kk"
}, {
"included": { "locales": { "matches": ["ru"] }},
"webExtensionLocale": "ru"
}, {
"included": { "locales": { "matches": ["tr"] }},
"webExtensionLocale": "tr"
}],
"aliases": ["@\u044F\u043D\u0434\u0435\u043A\u0441", "@yandex"]
},
{
"engineName": "allegro-pl",
"webExtensionId": "allegro-pl@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["pl"]}}}]
},
{
"engineName": "atlas-sk",
"webExtensionId": "atlas-sk@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sk"]}}}]
},
{
"engineName": "azerdict",
"webExtensionId": "azerdict@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["az"]}}}]
},
{
"engineName": "azet-sk",
"webExtensionId": "azet-sk@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sk"]}}}]
},
{
"engineName": "bbc-alba",
"webExtensionId": "bbc-alba@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["gd"]}}}]
},
{
"engineName": "bok-NO",
"webExtensionId": "bok-NO@search.mozilla.org",
"appliesTo": [{ "included": {
"locales": { "matches": ["nb-NO", "nn-NO"]}
}}]
},
{
"engineName": "bolcom",
"webExtensionId": "bolcom@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["fy-NL"]}},
"webExtensionLocale": "fy-NL"
}, {
"included": { "locales": { "matches": ["nl"]}},
"webExtensionLocale": "nl"
}]
},
{
"engineName": "ceneji",
"webExtensionId": "ceneji@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sl"]}}}]
},
{
"engineName": "chambers-en-GB",
"webExtensionId": "chambers-en-GB@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["en-GB"]}}}]
},
{
"engineName": "coccoc",
"webExtensionId": "coccoc@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["vi"]}}}]
},
{
"engineName": "daum-kr",
"webExtensionId": "daum-kr@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ko"]}}}]
},
{
"engineName": "diec2",
"webExtensionId": "diec2@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ca"]}}}]
},
{
"engineName": "drae",
"webExtensionId": "drae@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["es-AR", "es-CL", "es-ES"]}}
}]
},
{
"engineName": "ecosia",
"webExtensionId": "ecosia@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["de"]}}}]
},
{
"engineName": "eki-ee",
"webExtensionId": "eki-ee@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["et"]}}}]
},
{
"engineName": "eudict",
"webExtensionId": "eudict@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["hr"]}}}]
},
{
"engineName": "faclair-beag",
"webExtensionId": "faclair-beag@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["gd"]}}}]
},
{
"engineName": "flip",
"webExtensionId": "flip@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["kk"]}}}]
},
{
"engineName": "freelang",
"webExtensionId": "freelang@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["br"]}}}]
},
{
"engineName": "gulesider-NO",
"webExtensionId": "gulesider-NO@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["nn-NO", "nb-NO"]}}}]
},
{
"engineName": "heureka-cz",
"webExtensionId": "heureka-cz@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["cs"]}}}]
},
{
"engineName": "hotline-ua",
"webExtensionId": "hotline-ua@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["uk"]}}}]
},
{
"engineName": "kannadastore",
"webExtensionId": "kannadastore@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["kn"]}}}]
},
{
"engineName": "leo_ende_de",
"webExtensionId": "leo_ende_de@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["de", "dsb", "hsb" , "rm"]}}}]
},
{
"engineName": "list-am",
"webExtensionId": "list-am@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["hy-AM"]}}}]
},
{
"engineName": "longdo",
"webExtensionId": "longdo@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["th"]}}}]
},
{
"engineName": "mailru",
"webExtensionId": "mailru@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ru"]}}}]
},
{
"engineName": "mapy-cz",
"webExtensionId": "mapy-cz@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["cs"]}}}]
},
{
"engineName": "marktplaats",
"webExtensionId": "marktplaats@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["fy-NL"]}},
"webExtensionLocale": "fy-NL"
}, {
"included": { "locales": { "matches": ["nl"]}},
"webExtensionLocale": "nl"
}]
},
{
"engineName": "mercadolibre",
"webExtensionId": "mercadolibre@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["es-AR"]}},
"webExtensionLocale": "ar"
}, {
"included": { "locales": { "matches": ["es-CL"]}},
"webExtensionLocale": "cl"
}, {
"included": { "locales": { "matches": ["es-MX"]}},
"webExtensionLocale": "mx"
}]
},
{
"engineName": "mercadolivre",
"webExtensionId": "mercadolivre@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["pt-BR"]}}}]
},
{
"engineName": "morfix-dic",
"webExtensionId": "morfix-dic@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["he"]}}}]
},
{
"engineName": "najdi-si",
"webExtensionId": "najdi-si@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sl"]}}}]
},
{
"engineName": "naver-kr",
"webExtensionId": "naver-kr@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ko"]}}}]
},
{
"engineName": "neti-ee",
"webExtensionId": "neti-ee@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["et"]}}}]
},
{
"engineName": "odpiralni",
"webExtensionId": "odpiralni@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sl"]}}}]
},
{
"engineName": "olx",
"webExtensionId": "olx@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["bs"]}}}]
},
{
"engineName": "oshiete-goo",
"webExtensionId": "oshiete-goo@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ja-JP-mac", "jp"]}}}]
},
{
"engineName": "osta-ee",
"webExtensionId": "osta-ee@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["et"]}}}]
},
{
"engineName": "ozonru",
"webExtensionId": "ozonru@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ru"]}}}]
},
{
"engineName": "palasprint",
"webExtensionId": "palasprint@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["cy"]}}}]
},
{
"engineName": "pazaruvaj",
"webExtensionId": "pazaruvaj@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["bg"]}}}]
},
{
"engineName": "pogodak",
"webExtensionId": "pogodak@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sr"]}}}]
},
{
"engineName": "priberam",
"webExtensionId": "priberam@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["pt-PT"]}}}]
},
{
"engineName": "priceru",
"webExtensionId": "priceru@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ru"]}}}]
},
{
"engineName": "prisjakt-sv-SE",
"webExtensionId": "prisjakt-sv-SE@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sv-SE"]}}}]
},
{
"engineName": "pwn-pl",
"webExtensionId": "pwn-pl@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["pl"]}}}]
},
{
"engineName": "qwant",
"webExtensionId": "qwant@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["fr"]}}}]
},
{
"engineName": "qxl-NO",
"webExtensionId": "qxl-NO@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["nb-NO", "nn-NO"]}}}]
},
{
"engineName": "rakuten",
"webExtensionId": "rakuten@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ja-JP-mac", "jp"]}}}]
},
{
"engineName": "readmoo",
"webExtensionId": "readmoo@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["zh-TW"]}}}]
},
{
"engineName": "salidzinilv",
"webExtensionId": "salidzinilv@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ltg", "lv"]}}}]
},
{
"engineName": "seznam-cz",
"webExtensionId": "seznam-cz@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["cs"]}}}]
},
{
"engineName": "sslv",
"webExtensionId": "sslv@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ltg", "lv"]}}}]
},
{
"engineName": "tearma",
"webExtensionId": "tearma@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ga-IE"]}}}]
},
{
"engineName": "twitter",
"webExtensionId": "twitter@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": [
"en-US", "ach", "an", "bs", "ca", "crh", "en-CA", "ga-IE",
"gn", "hr", "ia", "ka", "kk", "km", "lo", "lt", "mai",
"ms", "my", "ne-NP", "oc", "pt-BR", "sl", "tl", "tr",
"ur", "uz", "wo"
]}}
}, {
"included": { "locales": { "matches": ["ja-JP-mac", "ja"]}},
"webExtensionLocale": "ja"
}]
},
{
"engineName": "tyda-sv-SE",
"webExtensionId": "tyda-sv-SE@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sv-SE"]}}}]
},
{
"engineName": "vatera",
"webExtensionId": "vatera@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["hu"]}}}]
},
{
"engineName": "wiktionary",
"webExtensionId": "wiktionary@search.mozilla.org",
"appliesTo": [{
"included": { "locales": { "matches": ["te"]}},
"webExtensionLocale": "te"
}, {
"included": { "locales": { "matches": ["oc"]}},
"webExtensionLocale": "oc"
}]
},
{
"engineName": "wolnelektury-pl",
"webExtensionId": "wolnelektury-pl@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["pl"]}}}]
},
{
"engineName": "yahoo-jp",
"webExtensionId": "yahoo-jp@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ja-JP-mac", "ja"]}}}]
},
{
"engineName": "yahoo-jp-auctions",
"webExtensionId": "yahoo-jp-auctions@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["ja-JP-mac", "ja"]}}}]
},
{
"engineName": "zoznam-sk",
"webExtensionId": "zoznam-sk@search.mozilla.org",
"appliesTo": [{ "included": { "locales": { "matches": ["sk"]}}}]
}
]
}

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

@ -304,9 +304,6 @@
; gre location for now.
@RESPATH@/defaults/pref/channel-prefs.js
; Services (gre) prefs
@RESPATH@/defaults/pref/services-sync.js
; [Layout Engine Resources]
; Style Sheets, Graphics and other Resources used by the layout engine.
@RESPATH@/res/EditorOverride.css

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

@ -2,8 +2,12 @@
# 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/.
## These messages are used as headings in the recommendation doorhanger
cfr-doorhanger-extension-heading = Recommended Extension
cfr-doorhanger-feature-heading = Recommended Feature
cfr-doorhanger-pintab-heading = Try This: Pin Tab
##
cfr-doorhanger-extension-sumo-link =
.tooltiptext = Why am I seeing this
@ -81,3 +85,25 @@ cfr-whatsnew-button =
.tooltiptext = Whats New
cfr-whatsnew-panel-header = Whats New
## Bookmark Sync
cfr-doorhanger-sync-bookmarks-header = Get this bookmark on your phone
cfr-doorhanger-sync-bookmarks-body = Take your bookmarks, passwords, history and more everywhere youre signed into { -brand-product-name }.
cfr-doorhanger-sync-bookmarks-ok-button = Turn on { -sync-brand-short-name }
.accesskey = T
## Send Tab
cfr-doorhanger-send-tab-header = Read this on the go
cfr-doorhanger-send-tab-recipe-header = Take this recipe to the kitchen
cfr-doorhanger-send-tab-body = Send Tab lets you easily share this link to your phone or anywhere youre signed in to { -brand-product-name }.
cfr-doorhanger-send-tab-ok-button = Try Send Tab
.accesskey = T
## Firefox Send
cfr-doorhanger-firefox-send-header = Share this PDF securely
cfr-doorhanger-firefox-send-body = Keep your sensitive documents safe from prying eyes with end-to-end encryption and a link that disappears when youre done.
cfr-doorhanger-firefox-send-ok-button = Try { -send-brand-name }
.accesskey = T

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

@ -741,6 +741,9 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY protections.etpON.header "Enhanced Tracking Protection is ON for this site">
<!ENTITY protections.etpOFF.header "Enhanced Tracking Protection is OFF for this site">
<!-- LOCALIZATION NOTE:
protections.etpMoreInfo.label: The text a screen reader speaks when focused on the info button. -->
<!ENTITY protections.etpMoreInfo.label "More information about Enhanced Tracking Protection">
<!ENTITY protections.settings.label "Protection Settings">
<!ENTITY protections.report.label "Show Full Report">
<!-- LOCALIZATION NOTE:

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

@ -211,10 +211,16 @@
}
#protections-popup > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow {
transition-property: fill;
transition-timing-function: var(--animation-easing-function);
transition-duration: var(--panelui-subview-transition-duration);
}
#protections-popup[mainviewshowing] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow {
fill: #0A51BF;
}
:root[lwt-popup-brighttext] #protections-popup > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow {
:root[lwt-popup-brighttext] #protections-popup[mainviewshowing] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow {
fill: #0CB0F5;
}

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

@ -1,4 +1,4 @@
<!-- 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 width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M.5.5h16v16H.5V.5zm12 8a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" id="a"/><linearGradient x1="0%" y1=".107%" y2="99.893%" id="b"><stop stop-color="#C689FF" offset="0%"/><stop stop-color="#00B3F4" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(-.5 -.5)"><mask id="c" fill="#fff"><use xlink:href="#a"/></mask><path d="M6.14 5.02c.405.908.884 2.668-.016 2.455-.327-.078-.57-.13-.648-.153l-.005-.002a.016.016 0 0 0 .005.002c-1.145-.343-2.852-.487-3.696.088-.843.574-.44 1.091-.337 1.755-.68.748-.506 1.559.036 2.345-.44.896-.085 1.646.57 2.29-.212 1.308.59 1.772 1.904 2.121.16.043.49.055.862.055h.014c.52 0 1.117-.024 1.453-.025 1.43-.005 2.735-.178 4.175-.234 1.44-.055 3.037.243 4.506.256.013-1.989.015-4.004.028-6.003a79.917 79.917 0 0 0-1.385.001c-.534.003-1.068.006-1.608-.003-.226-.088-.74-.547-.826-.66-.085-.111-.1-.231-.1-.231s-.313-.663-.589-.938C9.347 7.003 8.49 5.021 8.023 3.386c-.313-.498.658-1.226-.583-1.379A.969.969 0 0 0 7.32 2C6.17 2 5.75 4.14 6.14 5.02" fill="url(#b)" mask="url(#c)"/></g><path d="M12 6.188c-.364 0-.702-.098-1.005-.256l2.937-2.937c.158.303.255.64.255 1.005 0 1.208-.979 2.188-2.187 2.188m0-4.375c.364 0 .702.097 1.005.255l-2.937 2.937A2.163 2.163 0 0 1 9.813 4c0-1.208.979-2.188 2.187-2.188M12 .5a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7" fill="#ED1C24"/></g></svg>
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M.5.5h16v16H.5V.5zm12 8a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" id="a"/><linearGradient x1="62.533%" y1=".107%" x2="0%" y2="109.9%" id="b"><stop stop-color="#AB71FF" offset="0%"/><stop stop-color="#00B3F4" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(-.5 -.5)"><mask id="c" fill="#fff"><use xlink:href="#a"/></mask><path d="M6.14 5.02c.405.908.884 2.668-.016 2.455-.327-.078-.57-.13-.648-.153l-.005-.002a.016.016 0 0 0 .005.002c-1.145-.343-2.852-.487-3.696.088-.843.574-.44 1.091-.337 1.755-.68.748-.506 1.559.036 2.345-.44.896-.085 1.646.57 2.29-.212 1.308.59 1.772 1.904 2.121.16.043.49.055.862.055h.014c.52 0 1.117-.024 1.453-.025 1.43-.005 2.735-.178 4.175-.234 1.44-.055 3.037.243 4.506.256.013-1.989.015-4.004.028-6.003a79.917 79.917 0 0 0-1.385.001c-.534.003-1.068.006-1.608-.003-.226-.088-.74-.547-.826-.66-.085-.111-.1-.231-.1-.231s-.313-.663-.589-.938C9.347 7.003 8.49 5.021 8.023 3.386c-.313-.498.658-1.226-.583-1.379A.969.969 0 0 0 7.32 2C6.17 2 5.75 4.14 6.14 5.02" fill="url(#b)" fill-rule="nonzero" mask="url(#c)"/></g><path d="M12 6.188c-.364 0-.702-.098-1.005-.256l2.937-2.937c.158.303.255.64.255 1.005 0 1.208-.979 2.188-2.187 2.188m0-4.375c.364 0 .702.097 1.005.255l-2.937 2.937A2.163 2.163 0 0 1 9.813 4c0-1.208.979-2.188 2.187-2.188M12 .5a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7" fill="#ED1C24"/></g></svg>

До

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

После

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

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

@ -1,4 +1,4 @@
<!-- 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 width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M.5.5h16v16H.5V.5zm12 8a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" id="a"/><linearGradient x1="0%" y1=".107%" y2="99.893%" id="b"><stop stop-color="#9059FF" offset="0%"/><stop stop-color="#0250BB" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(-.5 -.5)"><mask id="c" fill="#fff"><use xlink:href="#a"/></mask><path d="M6.14 5.02c.405.908.884 2.668-.016 2.455-.327-.078-.57-.13-.648-.153l-.005-.002a.016.016 0 0 0 .005.002c-1.145-.343-2.852-.487-3.696.088-.843.574-.44 1.091-.337 1.755-.68.748-.506 1.559.036 2.345-.44.896-.085 1.646.57 2.29-.212 1.308.59 1.772 1.904 2.121.16.043.49.055.862.055h.014c.52 0 1.117-.024 1.453-.025 1.43-.005 2.735-.178 4.175-.234 1.44-.055 3.037.243 4.506.256.013-1.989.015-4.004.028-6.003a79.917 79.917 0 0 0-1.385.001c-.534.003-1.068.006-1.608-.003-.226-.088-.74-.547-.826-.66-.085-.111-.1-.231-.1-.231s-.313-.663-.589-.938C9.347 7.003 8.49 5.021 8.023 3.386c-.313-.498.658-1.226-.583-1.379A.969.969 0 0 0 7.32 2C6.17 2 5.75 4.14 6.14 5.02" fill="url(#b)" mask="url(#c)"/></g><path d="M12 6.188c-.364 0-.702-.098-1.005-.256l2.937-2.937c.158.303.255.64.255 1.005 0 1.208-.979 2.188-2.187 2.188m0-4.375c.364 0 .702.097 1.005.255l-2.937 2.937A2.163 2.163 0 0 1 9.813 4c0-1.208.979-2.188 2.187-2.188M12 .5a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7" fill="#ED1C24"/></g></svg>
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path d="M.5.5h16v16H.5V.5zm12 8a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" id="a"/><linearGradient x1="53.384%" y1=".107%" x2="0%" y2="113.918%" id="b"><stop stop-color="#7542E5" offset="0%"/><stop stop-color="#0060DF" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><g transform="translate(-.5 -.5)"><mask id="c" fill="#fff"><use xlink:href="#a"/></mask><path d="M6.14 5.02c.405.908.884 2.668-.016 2.455-.327-.078-.57-.13-.648-.153l-.005-.002a.016.016 0 0 0 .005.002c-1.145-.343-2.852-.487-3.696.088-.843.574-.44 1.091-.337 1.755-.68.748-.506 1.559.036 2.345-.44.896-.085 1.646.57 2.29-.212 1.308.59 1.772 1.904 2.121.16.043.49.055.862.055h.014c.52 0 1.117-.024 1.453-.025 1.43-.005 2.735-.178 4.175-.234 1.44-.055 3.037.243 4.506.256.013-1.989.015-4.004.028-6.003a79.917 79.917 0 0 0-1.385.001c-.534.003-1.068.006-1.608-.003-.226-.088-.74-.547-.826-.66-.085-.111-.1-.231-.1-.231s-.313-.663-.589-.938C9.347 7.003 8.49 5.021 8.023 3.386c-.313-.498.658-1.226-.583-1.379A.969.969 0 0 0 7.32 2C6.17 2 5.75 4.14 6.14 5.02" fill="url(#b)" fill-rule="nonzero" mask="url(#c)"/></g><path d="M12 6.188c-.364 0-.702-.098-1.005-.256l2.937-2.937c.158.303.255.64.255 1.005 0 1.208-.979 2.188-2.187 2.188m0-4.375c.364 0 .702.097 1.005.255l-2.937 2.937A2.163 2.163 0 0 1 9.813 4c0-1.208.979-2.188 2.187-2.188M12 .5a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7" fill="#ED1C24"/></g></svg>

До

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

После

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

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

@ -161,19 +161,14 @@ js_option(env='MOZ_LD64_KNOWN_GOOD',
imply_option('MOZ_LD64_KNOWN_GOOD', depends_if('MOZ_AUTOMATION')(lambda _: True))
@depends('--enable-lto', 'MOZ_PGO', '--enable-profile-generate', c_compiler,
'MOZ_LD64_KNOWN_GOOD', target)
@depends('--enable-lto', c_compiler, 'MOZ_LD64_KNOWN_GOOD', target)
@imports('multiprocessing')
def lto(value, pgo, profile_generate, c_compiler, ld64_known_good, target):
def lto(value, c_compiler, ld64_known_good, target):
cflags = []
ldflags = []
enabled = None
rust_lto = False
# MSVC's implementation of PGO implies LTO. Make clang-cl match this.
if c_compiler.type == 'clang-cl' and pgo and not profile_generate and value.origin == 'default':
value = ['cross']
if value:
enabled = True
# `cross` implies `thin`, but with Rust code participating in LTO

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

@ -7,6 +7,7 @@ export MAKECAB=$TOOLTOOL_DIR/makecab.exe
if [ -z "$USE_ARTIFACT" ]; then
if [ -n "$MOZ_PGO_PROFILE_USE" ]; then
export MOZ_LTO=cross
ac_add_options --enable-profile-use
ac_add_options --with-pgo-jarlog="${WORKSPACE}/fetches/en-US.log"
ac_add_options --with-pgo-profile-path="${WORKSPACE}/fetches"

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

@ -14,7 +14,6 @@ const {
} = require("devtools/client/shared/vendor/react");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const { combineReducers } = require("devtools/client/shared/vendor/redux");
// Accessibility Panel
const MainFrame = createFactory(require("./components/MainFrame"));
@ -23,11 +22,11 @@ const OldVersionDescription = createFactory(
);
// Store
const createStore = require("devtools/client/shared/redux/create-store")();
const createStore = require("devtools/client/shared/redux/create-store");
// Reducers
const { reducers } = require("./reducers/index");
const store = createStore(combineReducers(reducers));
const store = createStore(reducers);
// Actions
const { reset } = require("./actions/ui");

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

@ -28,7 +28,7 @@ window.onload = async function() {
const { createFactory, createElement } =
browserRequire("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const createStore = require("devtools/client/shared/redux/create-store")();
const createStore = require("devtools/client/shared/redux/create-store");
const { Simulate } =
browserRequire("devtools/client/shared/vendor/react-dom-test-utils");
const Accessible = createFactory(
@ -59,7 +59,13 @@ window.onload = async function() {
let URL = "http://example.com";
const mockStore = createStore((state, action) =>
action ? { ...state, ...action } : state,
{ details: { DOMNode: {}, accessible: { value: URL } }, ui: { supports: {} } });
{
initialState: {
details: { DOMNode: {}, accessible: { value: URL } },
ui: { supports: {} }
},
}
);
const provider = createElement(Provider, { store: mockStore }, a);
const accessible = ReactDOM.render(provider, window.document.body);
ok(accessible, "Should be able to mount Accessible instances");

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

@ -26,7 +26,7 @@ window.onload = async function() {
const { createFactory, createElement } =
browserRequire("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const createStore = require("devtools/client/shared/redux/create-store")();
const createStore = require("devtools/client/shared/redux/create-store");
const { Simulate } =
browserRequire("devtools/client/shared/vendor/react-dom-test-utils");
const Accessible = createFactory(
@ -49,7 +49,7 @@ window.onload = async function() {
};
const mockStore = createStore((state, action) =>
action ? { ...state, ...action } : state, mockState);
action ? { ...state, ...action } : state, { initialState: mockState });
const provider = createElement(Provider, { store: mockStore }, a);
const accessible = ReactDOM.render(provider, window.document.body);
ok(accessible, "Should be able to mount Accessible instances");

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

@ -28,7 +28,7 @@ window.onload = async function() {
const { createFactory, createElement } =
browserRequire("devtools/client/shared/vendor/react");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const createStore = require("devtools/client/shared/redux/create-store")();
const createStore = require("devtools/client/shared/redux/create-store");
const { Simulate } =
browserRequire("devtools/client/shared/vendor/react-dom-test-utils");
const AccessibilityRow = createFactory(
@ -54,7 +54,7 @@ window.onload = async function() {
const accRow = AccessibilityRow(newProps);
const mockStore = createStore((state, action) =>
action ? { ...state, ...action } : state, newState);
action ? { ...state, ...action } : state, { initialState: newState });
const provider = createElement(Provider, { store: mockStore }, accRow);
container = document.createElement("div");

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

@ -46,7 +46,7 @@ const SUITES = {
type: TEST_TYPES.JEST,
},
webconsole: {
path: "../webconsole/test",
path: "../webconsole/test/node",
type: TEST_TYPES.MOCHA,
},
};

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

@ -18,3 +18,4 @@
[options]
suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe

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

@ -0,0 +1,9 @@
/* 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/>. */
// @flow
declare module "devtools/client/framework/store-provider" {
declare module.exports: any;
}

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

@ -71,6 +71,10 @@ DebuggerPanel.prototype = {
return this._store.getState();
},
getToolboxStore: function() {
return this.toolbox.store;
},
openLink: function(url) {
openContentLink(url);
},

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

@ -382,4 +382,5 @@ export type Panel = {|
openConsoleAndEvaluate: (input: string) => void,
highlightDomElement: (grip: Object) => void,
unHighlightDomElement: (grip: Object) => void,
getToolboxStore: () => any,
|};

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

@ -101,7 +101,7 @@ export async function onConnect(
client: client.clientCommands,
});
bootstrapApp(store);
bootstrapApp(store, panel);
await connected;
return { store, actions, selectors, client: commands };
}

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

@ -30,5 +30,8 @@ bootstrap(React, ReactDOM).then(connection => {
console.log("highlighting dom element"),
unHighlightDomElement: (grip: Object) =>
console.log("unhighlighting dom element"),
getToolboxStore: () => {
throw new Error("Cannot connect to Toolbox store when running Launchpad");
},
});
});

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

@ -9,6 +9,7 @@ import { bindActionCreators, combineReducers } from "redux";
import ReactDOM from "react-dom";
const { Provider } = require("react-redux");
import ToolboxProvider from "devtools/client/framework/store-provider";
import { isFirefoxPanel, isDevelopment, isTesting } from "devtools-environment";
import SourceMaps, {
startSourceMapWorker,
@ -28,7 +29,7 @@ import type { Panel } from "../client/firefox/types";
let parser;
function renderPanel(component, store) {
function renderPanel(component, store, panel: Panel) {
const root = document.createElement("div");
root.className = "launchpad-root theme-body";
root.style.setProperty("flex", "1");
@ -39,7 +40,15 @@ function renderPanel(component, store) {
mount.appendChild(root);
ReactDOM.render(
React.createElement(Provider, { store }, React.createElement(component)),
React.createElement(
Provider,
{ store },
React.createElement(
ToolboxProvider,
{ store: panel.getToolboxStore() },
React.createElement(component)
)
),
root
);
}
@ -106,9 +115,9 @@ export function teardownWorkers() {
search.stop();
}
export function bootstrapApp(store: any) {
export function bootstrapApp(store: any, panel: Panel) {
if (isFirefoxPanel()) {
renderPanel(App, store);
renderPanel(App, store, panel);
} else {
const { renderRoot } = require("devtools-launchpad");
renderRoot(React, ReactDOM, App, store);

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

@ -8,10 +8,15 @@ import * as React from "react";
export function connect<Config, RSP: {}, MDP: {}>(
mapStateToProps: (state: any, props: any) => RSP,
mapDispatchToProps?: (Function => MDP) | MDP
mapDispatchToProps?: (Function => MDP) | MDP,
mergeProps?: void,
opts?: ?{|
storeKey?: string,
|}
): (
Component: React.AbstractComponent<Config>
) => React.AbstractComponent<$Diff<Config, RSP & MDP>> {
// TODO: Bug 1572214 - We should use the standard type definitions directly.
// $FlowFixMe
return reduxConnect(mapStateToProps, mapDispatchToProps);
return reduxConnect(mapStateToProps, mapDispatchToProps, null, opts);
}

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

@ -9,18 +9,15 @@
const React = require("devtools/client/shared/vendor/react");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const { combineReducers } = require("devtools/client/shared/vendor/redux");
// DOM Panel
const MainFrame = React.createFactory(require("./components/MainFrame"));
// Store
const createStore = require("devtools/client/shared/redux/create-store")({
log: false,
});
const createStore = require("devtools/client/shared/redux/create-store");
const { reducers } = require("./reducers/index");
const store = createStore(combineReducers(reducers));
const store = createStore(reducers);
/**
* This object represents view of the DOM panel and is responsible

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

@ -0,0 +1,144 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
"use strict";
const { assert } = require("devtools/shared/DevToolsUtils");
const {
getDOMMutationBreakpoint,
getDOMMutationBreakpoints,
} = require("devtools/client/framework/reducers/dom-mutation-breakpoints");
exports.registerWalkerListeners = registerWalkerListeners;
function registerWalkerListeners(toolbox) {
const { walker } = toolbox;
walker.on("mutations", mutations =>
handleWalkerMutations(mutations, toolbox)
);
}
function handleWalkerMutations(mutations, toolbox) {
// If we got BP updates for detach/unload, we want to drop those nodes from
// the list of active DOM mutation breakpoints. We explicitly check these
// cases because BP updates could also happen due to explicitly API
// operations to add/remove bps.
const mutationItems = mutations.filter(
mutation => mutation.type === "mutationBreakpoint"
);
if (mutationItems.length > 0) {
toolbox.store.dispatch(updateBreakpointsForMutations(mutationItems));
}
}
exports.createDOMMutationBreakpoint = createDOMMutationBreakpoint;
function createDOMMutationBreakpoint(nodeFront, mutationType) {
assert(typeof nodeFront === "object" && nodeFront);
assert(typeof mutationType === "string");
return async function(dispatch) {
const walker = nodeFront.parent();
dispatch({
type: "ADD_DOM_MUTATION_BREAKPOINT",
nodeFront,
mutationType,
});
await walker.setMutationBreakpoints(nodeFront, {
[mutationType]: true,
});
};
}
exports.deleteDOMMutationBreakpoint = deleteDOMMutationBreakpoint;
function deleteDOMMutationBreakpoint(nodeFront, mutationType) {
assert(typeof nodeFront === "object" && nodeFront);
assert(typeof mutationType === "string");
return async function(dispatch) {
dispatch({
type: "REMOVE_DOM_MUTATION_BREAKPOINT",
nodeFront,
mutationType,
});
const walker = nodeFront.parent();
await walker.setMutationBreakpoints(nodeFront, {
[mutationType]: false,
});
};
}
function updateBreakpointsForMutations(mutationItems) {
return async function(dispatch, getState) {
const removedNodeFronts = [];
const changedNodeFronts = new Set();
for (const { target: nodeFront, mutationReason } of mutationItems) {
switch (mutationReason) {
case "api":
changedNodeFronts.add(nodeFront);
break;
default:
console.error(
"Unexpected mutation reason",
mutationReason,
", removing"
);
// Fall Through
case "detach":
case "unload":
removedNodeFronts.push(nodeFront);
break;
}
}
if (removedNodeFronts.length > 0) {
dispatch({
type: "REMOVE_DOM_MUTATION_BREAKPOINTS_FOR_FRONTS",
nodeFronts: removedNodeFronts,
});
}
if (changedNodeFronts.length > 0) {
const enabledStates = [];
for (const {
id,
nodeFront,
mutationType,
enabled,
} of getDOMMutationBreakpoints(getState())) {
if (changedNodeFronts.has(nodeFront)) {
const bpEnabledOnFront = nodeFront.mutationBreakpoints[mutationType];
if (bpEnabledOnFront !== enabled) {
// Sync the bp state from the front into the store.
enabledStates.push([id, bpEnabledOnFront]);
}
}
}
dispatch({
type: "SET_DOM_MUTATION_BREAKPOINTS_ENABLED_STATE",
enabledStates,
});
}
};
}
exports.toggleDOMMutationBreakpointState = toggleDOMMutationBreakpointState;
function toggleDOMMutationBreakpointState(id, enabled) {
assert(typeof id === "string");
assert(typeof enabled === "boolean");
return async function(dispatch, getState) {
const bp = getDOMMutationBreakpoint(getState(), id);
if (!bp) {
throw new Error(`No DOM mutation BP with ID ${id}`);
}
const walker = bp.nodeFront.parent();
await walker.setMutationBreakpoints(bp.nodeFront, {
[bp.mutationType]: enabled,
});
};
}

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

@ -0,0 +1,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/. */
"use strict";
module.exports = {
...require("./dom-mutation-breakpoints"),
};

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

@ -0,0 +1,11 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'dom-mutation-breakpoints.js',
'index.js',
)
with Files('**'):
BUG_COMPONENT = ('DevTools', 'Framework')

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

@ -17,6 +17,8 @@ XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
DIRS += [
'components',
'actions',
'reducers',
]
DevToolsModules(
@ -28,6 +30,8 @@ DevToolsModules(
'selection.js',
'sidebar.js',
'source-map-url-service.js',
'store-provider.js',
'store.js',
'target-from-url.js',
'target.js',
'toolbox-context-menu.js',

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

@ -0,0 +1,115 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
"use strict";
const initialReducerState = {
counter: 1,
breakpoints: [],
};
exports.reducer = domMutationBreakpointReducer;
function domMutationBreakpointReducer(state = initialReducerState, action) {
switch (action.type) {
case "ADD_DOM_MUTATION_BREAKPOINT":
const hasExistingBp = state.breakpoints.some(
bp =>
bp.nodeFront === action.nodeFront &&
bp.mutationType === action.mutationType
);
if (hasExistingBp) {
break;
}
state = {
...state,
counter: state.counter + 1,
breakpoints: [
...state.breakpoints,
{
id: `${state.counter}`,
nodeFront: action.nodeFront,
mutationType: action.mutationType,
enabled: true,
},
],
};
break;
case "REMOVE_DOM_MUTATION_BREAKPOINT":
for (const [index, bp] of state.breakpoints.entries()) {
if (
bp.nodeFront === action.nodeFront &&
bp.mutationType === action.mutationType
) {
state = {
...state,
breakpoints: [
...state.breakpoints.slice(0, index),
...state.breakpoints.slice(index + 1),
],
};
break;
}
}
break;
case "REMOVE_DOM_MUTATION_BREAKPOINTS_FOR_FRONTS": {
const { nodeFronts } = action;
const nodeFrontSet = new Set(nodeFronts);
const breakpoints = state.breakpoints.filter(
bp => !nodeFrontSet.has(bp.nodeFront)
);
// Since we might not have made any actual changes, we verify first
// to avoid unnecessary changes in the state.
if (state.breakpoints.length !== breakpoints.length) {
state = {
...state,
breakpoints,
};
}
break;
}
case "SET_DOM_MUTATION_BREAKPOINTS_ENABLED_STATE": {
const { enabledStates } = action;
const toUpdateById = new Map(enabledStates);
const breakpoints = state.breakpoints.map(bp => {
const newBpState = toUpdateById.get(bp.id);
if (typeof newBpState === "boolean" && newBpState !== bp.enabled) {
bp = {
...bp,
enabled: newBpState,
};
}
return bp;
});
// Since we might not have made any actual changes, we verify first
// to avoid unnecessary changes in the state.
if (state.breakpoints.some((bp, i) => breakpoints[i] !== bp)) {
state = {
...state,
breakpoints,
};
}
break;
}
}
return state;
}
exports.getDOMMutationBreakpoints = getDOMMutationBreakpoints;
function getDOMMutationBreakpoints(state) {
return state.domMutationBreakpoints.breakpoints;
}
exports.getDOMMutationBreakpoint = getDOMMutationBreakpoint;
function getDOMMutationBreakpoint(state, id) {
return (
state.domMutationBreakpoints.breakpoints.find(v => v.id === id) || null
);
}

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

@ -0,0 +1,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/. */
"use strict";
module.exports = {
domMutationBreakpoints: require("./dom-mutation-breakpoints").reducer,
};

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

@ -0,0 +1,11 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'dom-mutation-breakpoints.js',
'index.js',
)
with Files('**'):
BUG_COMPONENT = ('DevTools', 'Framework')

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

@ -0,0 +1,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/. */
"use strict";
const { createProvider } = require("devtools/client/shared/vendor/react-redux");
module.exports = createProvider("toolbox-store");

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

@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const createStore = require("devtools/client/shared/redux/create-store");
const reducers = require("./reducers/index");
exports.createToolboxStore = () =>
createStore(reducers, {
// Uncomment this for logging in tests.
// shouldLog: true,
});

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

@ -25,6 +25,20 @@ var ChromeUtils = require("ChromeUtils");
var { gDevTools } = require("devtools/client/framework/devtools");
var EventEmitter = require("devtools/shared/event-emitter");
var Telemetry = require("devtools/client/shared/telemetry");
loader.lazyRequireGetter(
this,
"createToolboxStore",
"devtools/client/framework/store",
true
);
loader.lazyRequireGetter(
this,
"registerWalkerListeners",
"devtools/client/framework/actions/index",
true
);
const { getUnicodeUrl } = require("devtools/client/shared/unicode-url");
var {
DOMHelpers,
@ -328,6 +342,13 @@ Toolbox.prototype = {
SIDE_ENABLED: "devtools.toolbox.sideEnabled",
},
get store() {
if (!this._store) {
this._store = createToolboxStore();
}
return this._store;
},
get currentToolId() {
return this._currentToolId;
},
@ -3321,6 +3342,7 @@ Toolbox.prototype = {
this.walker.on("highlighter-ready", this._highlighterReady);
this.walker.on("highlighter-hide", this._highlighterHidden);
this._selection.on("new-node-front", this._onNewSelectedNodeFront);
registerWalkerListeners(this);
}.bind(this)();
}
return this._initInspector;

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

@ -21,6 +21,18 @@ const MarkupReadOnlyContainer = require("devtools/client/inspector/markup/views/
const MarkupTextContainer = require("devtools/client/inspector/markup/views/text-container");
const RootContainer = require("devtools/client/inspector/markup/views/root-container");
loader.lazyRequireGetter(
this,
"createDOMMutationBreakpoint",
"devtools/client/framework/actions/index",
true
);
loader.lazyRequireGetter(
this,
"deleteDOMMutationBreakpoint",
"devtools/client/framework/actions/index",
true
);
loader.lazyRequireGetter(
this,
"MarkupContextMenu",
@ -1270,11 +1282,14 @@ MarkupView.prototype = {
return;
}
const toolboxStore = this.inspector.toolbox.store;
const nodeFront = this.inspector.selection.nodeFront;
const mutationBreakpoints = nodeFront.mutationBreakpoints;
await this.walker.setMutationBreakpoints(nodeFront, {
[name]: !mutationBreakpoints[name],
});
if (nodeFront.mutationBreakpoints[name]) {
toolboxStore.dispatch(deleteDOMMutationBreakpoint(nodeFront, name));
} else {
toolboxStore.dispatch(createDOMMutationBreakpoint(nodeFront, name));
}
},
/**

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

@ -4,30 +4,11 @@
"use strict";
const { combineReducers } = require("devtools/client/shared/vendor/redux");
const createStore = require("devtools/client/shared/redux/create-store");
const reducers = require("devtools/client/inspector/reducers");
const flags = require("devtools/shared/flags");
module.exports = function() {
let shouldLog = false;
let history;
// If testing, store the action history in an array
// we'll later attach to the store
if (flags.testing) {
history = [];
shouldLog = true;
}
const store = createStore({
log: shouldLog,
history,
})(combineReducers(reducers), {});
if (history) {
store.history = history;
}
return store;
};
module.exports = () =>
createStore(reducers, {
// Uncomment this for logging in tests.
shouldLog: true,
});

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

@ -240,6 +240,7 @@ devtools.jar:
content/netmonitor/index.html (netmonitor/index.html)
content/netmonitor/src/assets/styles/StatusCode.css (netmonitor/src/assets/styles/StatusCode.css)
content/netmonitor/src/assets/styles/websockets.css (netmonitor/src/assets/styles/websockets.css)
content/netmonitor/src/assets/styles/search.css (netmonitor/src/assets/styles/search.css)
# Application panel
content/application/index.html (application/index.html)

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

@ -739,6 +739,26 @@ netmonitor.ws.time.format=%1$S.%2$S
# in the messages panel identifying the raw data.
netmonitor.ws.rawData.header=Raw Data (%S)
# LOCALIZATION NOTE (netmonitor.search.toolbar.inputPlaceholder): This is the label
# displayed in the search toolbar for the search input as the placeholder.
netmonitor.search.toolbar.inputPlaceholder=Find in resources…
# LOCALIZATION NOTE (netmonitor.search.toolbar.close): This is the label
# displayed in the search toolbar to close the search panel.
netmonitor.search.toolbar.close=Close Search Panel
# LOCALIZATION NOTE (netmonitor.search.toolbar.clear): This is the label
# displayed in the search toolbar to clear the search panel.
netmonitor.search.toolbar.clear=Clear Search Results
# LOCALIZATION NOTE (netmonitor.search.labels.responseHeaders): This is the label
# displayed in the search results as the label for the response headers
netmonitor.search.labels.responseHeaders=Response Header
# LOCALIZATION NOTE (netmonitor.search.labels.requestHeaders): This is the label
# displayed in the search results as the label for the request headers
netmonitor.search.labels.requestHeaders=Request Header
# LOCALIZATION NOTE (netmonitor.tab.headers): This is the label displayed
# in the network details pane identifying the headers tab.
netmonitor.tab.headers=Headers

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

@ -4,31 +4,11 @@
"use strict";
const { combineReducers } = require("../shared/vendor/redux");
const createStore = require("../shared/redux/create-store");
const reducers = require("./reducers");
const flags = require("devtools/shared/flags");
module.exports = function() {
const shouldLog = false;
let history;
// If testing, store the action history in an array
// we'll later attach to the store
if (flags.testing) {
history = [];
// Uncomment this for TONS of logging in tests.
// shouldLog = true;
}
const store = createStore({
log: shouldLog,
history,
})(combineReducers(reducers), {});
if (history) {
store.history = history;
}
return store;
};
module.exports = () =>
createStore(reducers, {
// Uncomment this for logging in tests.
// shouldLog: true,
});

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

@ -23,6 +23,7 @@
@import "chrome://devtools/content/netmonitor/src/assets/styles/CustomRequestPanel.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/StatusCode.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/websockets.css";
@import "chrome://devtools/content/netmonitor/src/assets/styles/search.css";
/* General */

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

@ -0,0 +1,68 @@
/* 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/. */
.network-monitor .monitor-panel .request-list-container .requests-list-scroll {
width: 100% !important;
}
.search-panel {
display: flex;
flex-direction: column;
overflow: hidden;
}
.search-panel-content {
width: 100%;
overflow: auto;
}
/* Custom tree styles for the Search results panel*/
.search-panel .treeTable .treeLabelCell::after {
content: "";
}
/* Color for resource label */
.search-panel .resourceCell {
color: var(--theme-text-color-inactive);
}
/* Color for search result label */
.search-panel .resultCell {
color: var(--table-text-color);
text-overflow: ellipsis;
}
/* Color for search result label */
.search-panel .treeLabel.resultLabel {
color: var(--theme-text-color-inactive);
}
/* Break the column layout and make the search result output more compact */
.search-panel .treeTable tr {
display: block;
}
.search-panel .treeTable {
width: 100%;
}
#devtools-network-search-close::before {
background-image: url("chrome://devtools/skin/images/close.svg");
}
#devtools-network-search-close > button {
margin: 0 !important;
border-radius: 0 !important;
position: relative;
min-width: 26px;
}
/* Color for query matches */
.search-panel .resultCell .query-match {
background-color: var(--theme-selection-background);
color: white;
padding: 1px 4px;
margin: 0 2px 0 2px;
border-radius: 2px;
}

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

@ -34,6 +34,10 @@ loader.lazyGetter(this, "NetworkDetailsPanel", function() {
return createFactory(require("./NetworkDetailsPanel"));
});
loader.lazyGetter(this, "SearchPanel", function() {
return createFactory(require("./search/SearchPanel"));
});
// MediaQueryList object responsible for switching sidebar splitter
// between landscape and portrait mode (depending on browser window size).
const MediaQueryVert = window.matchMedia("(min-width: 700px)");
@ -62,6 +66,7 @@ class MonitorPanel extends Component {
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
updateRequest: PropTypes.func.isRequired,
panelOpen: PropTypes.bool.isRequired,
};
}
@ -80,6 +85,8 @@ class MonitorPanel extends Component {
componentDidMount() {
MediaQuerySingleRow.addListener(this.onLayoutChange);
MediaQueryVert.addListener(this.onLayoutChange);
this.persistDetailsPanelSize();
this.persistSearchPanelSize();
}
componentWillReceiveProps(nextProps) {
@ -96,7 +103,11 @@ class MonitorPanel extends Component {
componentWillUnmount() {
MediaQuerySingleRow.removeListener(this.onLayoutChange);
MediaQueryVert.removeListener(this.onLayoutChange);
this.persistDetailsPanelSize();
this.persistSearchPanelSize();
}
persistDetailsPanelSize() {
const { clientWidth, clientHeight } = findDOMNode(this.refs.endPanel) || {};
if (this.state.isVerticalSpliter && clientWidth) {
@ -113,6 +124,23 @@ class MonitorPanel extends Component {
}
}
persistSearchPanelSize() {
const { clientWidth, clientHeight } =
findDOMNode(this.refs.searchPanel) || {};
if (clientWidth) {
Services.prefs.setIntPref(
"devtools.netmonitor.panes-search-width",
clientWidth
);
}
if (clientHeight) {
Services.prefs.setIntPref(
"devtools.netmonitor.panes-search-height",
clientHeight
);
}
}
onLayoutChange() {
this.setState({
isSingleRow: MediaQuerySingleRow.matches,
@ -130,6 +158,32 @@ class MonitorPanel extends Component {
);
}
renderSearchPanel(connector) {
const { isEmpty } = this.props;
const initialWidth = Services.prefs.getIntPref(
"devtools.netmonitor.panes-search-width"
);
const initialHeight = Services.prefs.getIntPref(
"devtools.netmonitor.panes-search-height"
);
return SplitBox({
className: "devtools-responsive-container",
initialWidth,
initialHeight,
minSize: "50px",
maxSize: "80%",
splitterSize: 1,
startPanel: SearchPanel({
ref: "searchPanel",
connector,
}),
endPanel: RequestList({ isEmpty, connector }),
endPanelControl: false,
vert: true,
onControlledPanelResized: () => {},
});
}
render() {
const {
actions,
@ -139,15 +193,21 @@ class MonitorPanel extends Component {
openLink,
openSplitConsole,
sourceMapService,
panelOpen,
} = this.props;
const initialWidth = Services.prefs.getIntPref(
"devtools.netmonitor.panes-network-details-width"
);
const initialHeight = Services.prefs.getIntPref(
"devtools.netmonitor.panes-network-details-height"
);
const startPanel = panelOpen
? this.renderSearchPanel(connector)
: RequestList({ isEmpty, connector });
return div(
{ className: "monitor-panel" },
Toolbar({
@ -163,7 +223,7 @@ class MonitorPanel extends Component {
minSize: "50px",
maxSize: "80%",
splitterSize: networkDetailsOpen ? 1 : 0,
startPanel: RequestList({ isEmpty, connector }),
startPanel,
endPanel:
networkDetailsOpen &&
NetworkDetailsPanel({
@ -185,6 +245,7 @@ module.exports = connect(
state => ({
isEmpty: state.requests.requests.size == 0,
networkDetailsOpen: state.ui.networkDetailsOpen,
panelOpen: state.search.panelOpen,
request: getSelectedRequest(state),
selectedRequestVisible: isSelectedRequestVisible(state),
}),

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

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'search',
'websockets',
]

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

@ -0,0 +1,136 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
Component,
createRef,
createFactory,
} = require("devtools/client/shared/vendor/react");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { div, span } = dom;
const Actions = require("devtools/client/netmonitor/src/actions/index");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {
connect,
} = require("devtools/client/shared/redux/visibility-handler-connect");
const TreeViewClass = require("devtools/client/shared/components/tree/TreeView");
const TreeView = createFactory(TreeViewClass);
const { SearchProvider } = require("./search-provider");
const Toolbar = createFactory(require("./Toolbar"));
/**
* This component is responsible for rendering all search results
* coming from the current search.
*/
class SearchPanel extends Component {
static get propTypes() {
return {
clearSearchResults: PropTypes.func.isRequired,
openSearch: PropTypes.func.isRequired,
closeSearch: PropTypes.func.isRequired,
search: PropTypes.func.isRequired,
connector: PropTypes.object.isRequired,
addSearchQuery: PropTypes.func.isRequired,
query: PropTypes.string.isRequired,
results: PropTypes.array,
};
}
constructor(props) {
super(props);
this.searchboxRef = createRef();
this.renderValue = this.renderValue.bind(this);
}
renderTree() {
const { results } = this.props;
return TreeView({
object: results,
provider: SearchProvider,
expandableStrings: false,
renderValue: this.renderValue,
columns: [
{
id: "value",
width: "100%",
},
],
});
}
/**
* Custom tree value rendering. This method is responsible for
* rendering highlighted query string within the search result.
*/
renderValue(props) {
const member = props.member;
/**
* Handle only second level (zero based) that displays
* the search result. Find the query string inside the
* search result value (`props.object`) and render it
* within a span element with proper class name.
*
* level 0 = resource name
*/
if (member.level === 1) {
const { query } = this.props;
const indexStart = props.object.indexOf(query);
const indexEnd = indexStart + query.length;
return span(
{},
span({}, props.object.substring(0, indexStart)),
span({ className: "query-match" }, query),
span({}, props.object.substring(indexEnd, props.object.length))
);
}
return props.object;
}
render() {
const {
openSearch,
closeSearch,
clearSearchResults,
connector,
addSearchQuery,
search,
} = this.props;
return div(
{ className: "search-panel", style: { width: "100%" } },
Toolbar({
searchboxRef: this.searchboxRef,
openSearch,
closeSearch,
clearSearchResults,
addSearchQuery,
search,
connector,
}),
div(
{ className: "search-panel-content", style: { width: "100%" } },
this.renderTree()
)
);
}
}
module.exports = connect(
state => ({
query: state.search.query,
results: state.search.results,
ongoingSearch: state.search.ongoingSearch,
status: state.search.status,
}),
dispatch => ({
closeSearch: () => dispatch(Actions.closeSearch()),
openSearch: () => dispatch(Actions.openSearch()),
search: () => dispatch(Actions.search()),
clearSearchResults: () => dispatch(Actions.clearSearchResults()),
addSearchQuery: query => dispatch(Actions.addSearchQuery(query)),
})
)(SearchPanel);

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

@ -0,0 +1,132 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
Component,
createFactory,
} = require("devtools/client/shared/vendor/react");
const {
connect,
} = require("devtools/client/shared/redux/visibility-handler-connect");
const { FILTER_SEARCH_DELAY } = require("../../constants");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const Actions = require("devtools/client/netmonitor/src/actions/index");
const dom = require("devtools/client/shared/vendor/react-dom-factories");
const { L10N } = require("devtools/client/netmonitor/src/utils/l10n.js");
const { button, span, div } = dom;
// Components
const SearchBox = createFactory(
require("devtools/client/shared/components/SearchBox")
);
/**
* Network Search toolbar component.
*
* Provides tools for greater control over search.
*/
class Toolbar extends Component {
static get propTypes() {
return {
searchboxRef: PropTypes.object.isRequired,
clearSearchResults: PropTypes.func.isRequired,
search: PropTypes.func.isRequired,
closeSearch: PropTypes.func.isRequired,
addSearchQuery: PropTypes.func.isRequired,
connector: PropTypes.object.isRequired,
};
}
/**
* Render a separator.
*/
renderSeparator() {
return span({ className: "devtools-separator" });
}
/**
* Handles what we do when key is pressed in search input.
* @param event
* @param conn
*/
onKeyDown(event, connector) {
switch (event.key) {
case "Escape":
event.preventDefault();
this.props.closeSearch();
break;
case "Enter":
event.preventDefault();
this.props.addSearchQuery(event.target.value);
this.props.search(connector, event.target.value);
break;
}
}
renderCloseButton() {
const { closeSearch } = this.props;
return button({
id: "devtools-network-search-close",
className: "devtools-button",
title: L10N.getStr("netmonitor.search.toolbar.close"),
onClick: () => closeSearch(),
});
}
/**
* Render a clear button to clear search results.
*/
renderClearButton() {
return button({
className:
"devtools-button devtools-clear-icon ws-frames-list-clear-button",
title: L10N.getStr("netmonitor.search.toolbar.clear"),
onClick: () => {
this.props.clearSearchResults();
},
});
}
/**
* Render filter Search box.
*/
renderFilterBox() {
const { addSearchQuery, connector } = this.props;
return SearchBox({
keyShortcut: "CmdOrCtrl+Shift+F",
placeholder: L10N.getStr("netmonitor.search.toolbar.inputPlaceholder"),
type: "search",
delay: FILTER_SEARCH_DELAY,
ref: this.props.searchboxRef,
onChange: query => addSearchQuery(query),
onKeyDown: event => this.onKeyDown(event, connector),
});
}
render() {
return div(
{
id: "netmonitor-toolbar-container",
className: "devtools-toolbar devtools-input-toolbar",
},
this.renderClearButton(),
this.renderSeparator(),
this.renderFilterBox(),
this.renderCloseButton()
);
}
}
module.exports = connect(
state => ({}),
dispatch => ({
closeSearch: () => dispatch(Actions.closeSearch()),
openSearch: () => dispatch(Actions.openSearch()),
clearSearchResults: () => dispatch(Actions.clearSearchResults()),
search: (connector, query) => dispatch(Actions.search(connector, query)),
addSearchQuery: query => dispatch(Actions.addSearchQuery(query)),
})
)(Toolbar);

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

@ -0,0 +1,9 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'search-provider.js',
'SearchPanel.js',
'Toolbar.js',
)

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

@ -0,0 +1,123 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
const {
ObjectProvider,
} = require("devtools/client/shared/components/tree/ObjectProvider");
const {
getFileName,
} = require("devtools/client/netmonitor/src/utils/request-utils");
/**
* This provider is responsible for providing data from the
* search reducer to the SearchPanel.
*/
const SearchProvider = {
...ObjectProvider,
getChildren(object) {
if (Array.isArray(object)) {
return object;
} else if (object.resource) {
return object.results;
} else if (object.type) {
return [];
}
return ObjectProvider.getLabel(object);
},
hasChildren(object) {
return this.getChildren(object).length > 0;
},
getLabel(object) {
if (object.resource) {
return this.getResourceLabel(object);
} else if (object.type) {
switch (object.type) {
case "url":
return this.getUrlLabel(object);
case "responseContent":
return this.getResponseContent(object);
case "requestCookies":
return this.getRequestCookies();
case "responseCookies":
return this.getResponseCookies();
case "requestHeaders":
return this.getRequestHeaders();
case "responseHeaders":
return this.getResponseHeaders();
}
}
return ObjectProvider.getLabel(object);
},
getValue(object) {
if (object.resource) {
return object.resource.url;
} else if (object.type) {
return object.value;
}
return ObjectProvider.getValue(object);
},
getKey(object) {
if (object.resource) {
return object.resource.id;
} else if (object.type) {
return object.key;
}
return ObjectProvider.getKey(object);
},
getType(object) {
if (object.resource) {
return "resource";
} else if (object.type) {
return "result";
}
return ObjectProvider.getType(object);
},
getResourceLabel(object) {
const resourceLabel =
getFileName(object.resource.urlDetails.baseNameWithQuery) ||
object.resource.urlDetails.host;
if (resourceLabel.length > 30) {
return resourceLabel.substring(0, 30) + "…";
}
return resourceLabel;
},
getUrlLabel(object) {
return object.label.substring(0, 100);
},
getResponseContent(object) {
return object.line + "";
},
getRequestCookies() {
return "Set-Cookie";
},
getResponseCookies() {
return "Cookie";
},
getRequestHeaders() {
return L10N.getStr("netmonitor.search.labels.requestHeaders");
},
getResponseHeaders() {
return L10N.getStr("netmonitor.search.labels.responseHeaders");
},
};
module.exports = {
SearchProvider,
};

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

@ -15,7 +15,7 @@ const { require } = BrowserLoader({
const Perf = require("devtools/client/performance-new/components/Perf");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const React = require("devtools/client/shared/vendor/react");
const createStore = require("devtools/client/shared/redux/create-store")();
const createStore = require("devtools/client/shared/redux/create-store");
const selectors = require("devtools/client/performance-new/store/selectors");
const reducers = require("devtools/client/performance-new/store/reducers");
const actions = require("devtools/client/performance-new/store/actions");

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

@ -183,7 +183,7 @@ function createPerfComponent() {
const React = require("devtools/client/shared/vendor/react");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const ReactRedux = require("devtools/client/shared/vendor/react-redux");
const createStore = require("devtools/client/shared/redux/create-store")();
const createStore = require("devtools/client/shared/redux/create-store");
const reducers = require("devtools/client/performance-new/store/reducers");
const actions = require("devtools/client/performance-new/store/actions");
const selectors = require("devtools/client/performance-new/store/selectors");

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

@ -400,3 +400,8 @@ pref("devtools.aboutdebugging.collapsibilities.temporaryExtension", false);
// Map top-level await expressions in the console
pref("devtools.debugger.features.map-await-expression", true);
// Disable autohide for DevTools popups and tooltips.
// This is currently not exposed by any UI to avoid making
// about:devtools-toolbox tabs unusable by mistake.
pref("devtools.popup.disable_autohide", false);

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

@ -4,30 +4,11 @@
"use strict";
const { combineReducers } = require("devtools/client/shared/vendor/redux");
const createStore = require("devtools/client/shared/redux/create-store");
const reducers = require("./reducers");
const flags = require("devtools/shared/flags");
module.exports = function() {
let shouldLog = false;
let history;
// If testing, store the action history in an array
// we'll later attach to the store
if (flags.testing) {
history = [];
shouldLog = true;
}
const store = createStore({
log: shouldLog,
history,
})(combineReducers(reducers), {});
if (history) {
store.history = history;
}
return store;
};
module.exports = () =>
createStore(reducers, {
// Uncomment this for logging in tests.
shouldLog: true,
});

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

@ -47,8 +47,8 @@ define(function(require, exports, module) {
static get propTypes() {
return {
member: PropTypes.shape({
object: PropTypes.obSject,
name: PropTypes.sring,
object: PropTypes.object,
name: PropTypes.string,
type: PropTypes.string.isRequired,
rowClass: PropTypes.string.isRequired,
level: PropTypes.number.isRequired,

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

@ -4,6 +4,7 @@
"use strict";
const {
combineReducers,
createStore,
applyMiddleware,
} = require("devtools/client/shared/vendor/redux");
@ -11,6 +12,7 @@ const { thunk } = require("./middleware/thunk");
const { waitUntilService } = require("./middleware/wait-service");
const { task } = require("./middleware/task");
const { promise } = require("./middleware/promise");
const flags = require("devtools/shared/flags");
loader.lazyRequireGetter(
this,
@ -36,7 +38,7 @@ loader.lazyRequireGetter(
* used in tests.
* - middleware: array of middleware to be included in the redux store
*/
module.exports = (opts = {}) => {
const createStoreWithMiddleware = (opts = {}) => {
const middleware = [
task,
thunk,
@ -63,3 +65,30 @@ module.exports = (opts = {}) => {
return applyMiddleware(...middleware)(createStore);
};
module.exports = (
reducers,
{ shouldLog = false, initialState = undefined } = {}
) => {
const reducer =
typeof reducers === "function" ? reducers : combineReducers(reducers);
let historyEntries;
// If testing, store the action history in an array
// we'll later attach to the store
if (flags.testing) {
historyEntries = [];
}
const store = createStoreWithMiddleware({
log: flags.testing && shouldLog,
history: historyEntries,
})(reducer, initialState);
if (history) {
store.history = historyEntries;
}
return store;
};

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

@ -754,7 +754,7 @@ HTMLTooltip.prototype = {
*/
async hide({ fromMouseup = false } = {}) {
// Exit if the disable autohide setting is in effect.
if (Services.prefs.getBoolPref("ui.popup.disable_autohide", false)) {
if (Services.prefs.getBoolPref("devtools.popup.disable_autohide", false)) {
return;
}

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

@ -1,29 +1,30 @@
# Console Tests
The console panel uses currently two different frameworks for tests:
* Mochitest - [Mochitest](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Mochitest) is an automated testing framework built on top of the MochiKit JavaScript libraries. It's just one of the automated regression testing frameworks used by Mozilla.
- Mochitest - [Mochitest](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Mochitest) is an automated testing framework built on top of the MochiKit JavaScript libraries. It's just one of the automated regression testing frameworks used by Mozilla.
Mochitests are located in `devtools/client/webconsole/test/mochitest/` and can be run with the following command:
Mochitests are located in `devtools/client/webconsole/test/browser/` and can be run with the following command:
```sh
./mach test devtools/client/webconsole/test/mochitest/
./mach test devtools/client/webconsole/test/browser/
```
These tests can be run on CI when pushing to TRY. Not all tests are enabled at the moment since they were copied over from the old frontend (See Bug 1400847).
* Mocha + Enzyme - [mocha](https://mochajs.org/) Mocha is JavaScript test framework running on Node.js
[Enzyme](http://airbnb.io/enzyme/) is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components' output.
- Mocha + Enzyme - [mocha](https://mochajs.org/) Mocha is JavaScript test framework running on Node.js
[Enzyme](http://airbnb.io/enzyme/) is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components' output.
These tests are located in `test/components/` and `test/store/`, and can be run with the following command:
These tests are located in `tests/node/`, and can be run with the following command:
```sh
cd devtools/client/webconsole/test/ && npm install && npm test
cd devtools/client/webconsole/test/node && npm install && npm test
```
or using yarn with
```sh
cd devtools/client/webconsole/test/ && yarn && yarn test
cd devtools/client/webconsole/test/node && yarn && yarn test
```
---
@ -32,51 +33,29 @@ The team is leaning towards Enzyme since it's well known and suitable for React.
It's also easier to contribute to tests written on top of Enzyme.
# Stubs
Many tests depends on fix data structures (aka stubs) that mimic
<abbr title="Remote Debugging Protocol">RDP<abbr> packets that represents Console logs.
Stubs are stored in `test/fixtures` directory and you might automatically generate them.
## Append new Console API stubs
See how to generate stubs for Console API calls.
## Append new stubs
* Append new entry into `consoleApiCommands` array. The array is defined in this module:
`\test\fixtures\stub-generators\stub-snippets.js`
* Generate stubs with existing mochitest:
`\test\fixtures\stub-generators\browser_webconsole_check_stubs_console_api.js`
- Append new entry into the `getCommands` function return value in on of the `\tests\browser\browser_webconsole_stubs_*.js`
and run the generator using `mach` command, with the `WEBCONSOLE_STUBS_UPDATE=true` environment variable.
Run the generator using `mach` command.
`./mach test devtools/client/webconsole/test/fixtures/stub-generators/browser_webconsole_check_stubs_console_api.js --headless`
For console API stubs, you can do:
This will override `test/fixtures/stubs/consoleApi.js`.
`./mach test devtools/client/webconsole/test/browser/browser_webconsole_stubs_console_api.js --headless --setenv WEBCONSOLE_STUBS_UPDATE=true`
## Append new CSS Messages stubs
See how to generate stubs for CSS messages.
This will override `tests/node/fixtures/stubs/consoleApi.js`.
* Append new entry into `cssMessage` map into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_check_stubs_css_message.js`
The same can be done in:
This will override `test/fixtures/stubs/cssMessage.js`.
- `browser_webconsole_stubs_css_message.js` (writes to `tests/node/fixtures/stubs/cssMessage.js`)
- `browser_webconsole_stubs_evaluation_result.js` (writes to `tests/node/fixtures/stubs/evaluationResult.js`)
- `browser_webconsole_stubs_network_event.js` (writes to `tests/node/fixtures/stubs/networkEvent.js`)
- `browser_webconsole_stubs_page_error.js` (writes to `tests/node/fixtures/stubs/pageError.js`)
## Append new Evaluation Result stubs
See how to generate stubs for evaluation results.
If you made some changes that impact all stubs, you can update all at once using:
* Append new entry into `evaluationResultCommands` map into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_check_stubs_evaluation_result.js`
This will override `test/fixtures/stubs/evaluationResult.js`.
## Append new Network Events stubs
See how to generate stubs for network events
* Append new entry into `networkEvent` map into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_update_stubs_network_event.js`
This will override `test/fixtures/stubs/networkEvent.js`.
## Append new Page Error stubs
See how to generate stubs for page errors.
* Append new entry into `pageError` array into `stub-snippets.js`
* Generate stubs with: `browser_webconsole_update_stubs_page_error.js`
This will override `test/fixtures/stubs/pageError.js`.
`./mach test devtools/client/webconsole/test/browser/browser_webconsole_stubs --headless --setenv WEBCONSOLE_STUBS_UPDATE=true`

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

@ -155,7 +155,7 @@ support-files =
skip-if = !e10s # This test is only valid in e10s
[browser_console_clear_cache.js]
[browser_console_clear_method.js]
skip-if = true # Bug 1437843
skip-if = true # Bug XXX # Bug 1437843
[browser_console_consolejsm_output.js]
[browser_console_context_menu_entries.js]
skip-if = os == "linux" # Bug 1440059, disabled for all build types
@ -285,7 +285,7 @@ skip-if = fission
[browser_webconsole_close_unfocused_window.js]
[browser_webconsole_closing_after_completion.js]
[browser_webconsole_close_sidebar.js]
skip-if = true # Bug 1405250
skip-if = true # Bug XXX # Bug 1405250
[browser_webconsole_console_api_iframe.js]
[browser_webconsole_console_dir.js]
[browser_webconsole_console_dir_uninspectable.js]
@ -334,7 +334,7 @@ skip-if = fission
[browser_webconsole_execution_scope.js]
[browser_webconsole_external_script_errors.js]
[browser_webconsole_file_uri.js]
skip-if = true # Bug 1404382
skip-if = true # Bug XXX # Bug 1404382
[browser_webconsole_filter_buttons_overflow.js]
[browser_webconsole_filter_by_input.js]
[browser_webconsole_filter_by_regex_input.js]
@ -377,7 +377,7 @@ skip-if = fission
[browser_webconsole_network_message_close_on_escape.js]
[browser_webconsole_network_message_ctrl_click.js]
[browser_webconsole_network_messages_expand.js]
skip-if = true # Bug 1438979
skip-if = true # Bug XXX # Bug 1438979
[browser_webconsole_network_messages_openinnet.js]
fail-if = fission
[browser_webconsole_network_messages_resend_request.js]
@ -451,6 +451,16 @@ skip-if = verify
[browser_webconsole_stacktrace_location_scratchpad_link.js]
[browser_webconsole_strict_mode_errors.js]
[browser_webconsole_string.js]
[browser_webconsole_stubs_console_api.js]
skip-if = true # Bug 1572667
[browser_webconsole_stubs_css_message.js]
skip-if = true # Bug 1572667
[browser_webconsole_stubs_evaluation_result.js]
skip-if = true # Bug 1572667
[browser_webconsole_stubs_network_event.js]
skip-if = true # Bug 1572667
[browser_webconsole_stubs_page_error.js]
skip-if = true # Bug 1572667
[browser_webconsole_telemetry_js_errors.js]
[browser_webconsole_telemetry_filters_changed.js]
[browser_webconsole_telemetry_persist_toggle_changed.js]

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

@ -9,11 +9,11 @@
const TEST_URI =
"http://example.com/browser/devtools/client/webconsole/" +
"test/mochitest/test-console.html?" +
"test/browser/test-console.html?" +
Date.now();
const TEST_FILE =
"chrome://mochitests/content/browser/devtools/client/" +
"webconsole/test/mochitest/" +
"webconsole/test/browser/" +
"test-cu-reporterror.js";
const TEST_XHR_ERROR_URI = `http://example.com/404.html?${Date.now()}`;

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

@ -7,7 +7,7 @@
const TEST_URI =
"http://example.com/browser/devtools/client/webconsole/" +
"test/mochitest/test-console.html";
"test/browser/test-console.html";
add_task(async function() {
await pushPref("devtools.browserconsole.contentMessages", true);

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