зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1576284 - Add Firefox wordmark, protection template and bug fixes to New Tab Page r=pdahiya
Differential Revision: https://phabricator.services.mozilla.com/D43310 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
294674d0c5
Коммит
3cf7e1697b
|
@ -62,6 +62,7 @@ const INITIAL_STATE = {
|
|||
},
|
||||
spocs: {
|
||||
spocs_endpoint: "",
|
||||
spocs_per_domain: 1,
|
||||
lastUpdated: null,
|
||||
data: {}, // {spocs: []}
|
||||
loaded: false,
|
||||
|
@ -597,7 +598,11 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
|
|||
spocs: {
|
||||
...INITIAL_STATE.DiscoveryStream.spocs,
|
||||
spocs_endpoint:
|
||||
action.data || INITIAL_STATE.DiscoveryStream.spocs.spocs_endpoint,
|
||||
action.data.url ||
|
||||
INITIAL_STATE.DiscoveryStream.spocs.spocs_endpoint,
|
||||
spocs_per_domain:
|
||||
action.data.spocs_per_domain ||
|
||||
INITIAL_STATE.DiscoveryStream.spocs.spocs_per_domain,
|
||||
},
|
||||
};
|
||||
case at.DISCOVERY_STREAM_SPOCS_UPDATE:
|
||||
|
|
|
@ -38,6 +38,7 @@ Please note that some targeting attributes require stricter controls on the tele
|
|||
* [isWhatsNewPanelEnabled](#iswhatsnewpanelenabled)
|
||||
* [earliestFirefoxVersion](#earliestfirefoxversion)
|
||||
* [isFxABadgeEnabled](#isfxabadgeenabled)
|
||||
* [totalBlockedCount](#totalblockedcount)
|
||||
|
||||
## Detailed usage
|
||||
|
||||
|
@ -518,3 +519,13 @@ Boolean pref that controls if the FxA toolbar button is badged by Messaging Syst
|
|||
```ts
|
||||
declare const isFxABadgeEnabled: boolean;
|
||||
```
|
||||
|
||||
### `totalBlockedCount`
|
||||
|
||||
Total number of events from the content blocking database
|
||||
|
||||
#### Definition
|
||||
|
||||
```ts
|
||||
declare const totalBlockedCount: number;
|
||||
```
|
||||
|
|
|
@ -31,6 +31,7 @@ export class Interrupt extends React.PureComponent {
|
|||
>
|
||||
<ReturnToAMO
|
||||
{...message}
|
||||
document={this.props.document}
|
||||
UISurface="NEWTAB_OVERLAY"
|
||||
onBlock={onDismiss}
|
||||
onAction={executeAction}
|
||||
|
@ -41,6 +42,7 @@ export class Interrupt extends React.PureComponent {
|
|||
case "fxa_overlay":
|
||||
return (
|
||||
<StartupOverlay
|
||||
document={this.props.document}
|
||||
onBlock={onDismiss}
|
||||
dispatch={dispatch}
|
||||
fxa_endpoint={fxaEndpoint}
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
}
|
||||
},
|
||||
"properties": {
|
||||
"layout": {
|
||||
"description": "Different message layouts",
|
||||
"enum": ["tracking-protections"]
|
||||
},
|
||||
"published_date": {
|
||||
"type": "integer",
|
||||
"description": "The date/time (number of milliseconds elapsed since January 1, 1970 00:00:00 UTC) the message was published."
|
||||
|
@ -34,6 +38,12 @@
|
|||
{"description": "Id of localized string or message override of What's New message title"}
|
||||
]
|
||||
},
|
||||
"subtitle": {
|
||||
"allOf": [
|
||||
{"$ref": "#/definitions/localizableText"},
|
||||
{"description": "Id of localized string or message override of What's New message subtitle"}
|
||||
]
|
||||
},
|
||||
"body": {
|
||||
"allOf": [
|
||||
{"$ref": "#/definitions/localizableText"},
|
||||
|
@ -51,6 +61,10 @@
|
|||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"cta_type": {
|
||||
"description": "Type of url open action",
|
||||
"enum": ["OPEN_URL", "OPEN_ABOUT_PAGE"]
|
||||
},
|
||||
"icon_url": {
|
||||
"description": "(optional) URL for the What's New message icon.",
|
||||
"type": "string",
|
||||
|
|
|
@ -24,6 +24,10 @@ export class ReturnToAMO extends React.PureComponent {
|
|||
event: "IMPRESSION",
|
||||
id: this.props.UISurface,
|
||||
});
|
||||
// Hide the page content from screen readers while the modal is open
|
||||
this.props.document
|
||||
.getElementById("root")
|
||||
.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
|
||||
onClickAddExtension() {
|
||||
|
@ -41,6 +45,10 @@ export class ReturnToAMO extends React.PureComponent {
|
|||
event: "BLOCK",
|
||||
id: this.props.UISurface,
|
||||
});
|
||||
// Re-enable the document for screen readers
|
||||
this.props.document
|
||||
.getElementById("root")
|
||||
.setAttribute("aria-hidden", "false");
|
||||
}
|
||||
|
||||
renderText() {
|
||||
|
|
|
@ -91,7 +91,12 @@
|
|||
}
|
||||
|
||||
@media (max-width: 865px) {
|
||||
margin: 0 60px 0 0;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
// There is an off-by-one gap between breakpoints; this is to prevent weirdness at exactly 610px.
|
||||
@media (max-width: $break-point-medium - 1px) {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
// Disable breakpoints for now if discovery stream is enabled.
|
||||
|
@ -142,6 +147,10 @@
|
|||
@include full-width-styles;
|
||||
}
|
||||
|
||||
@media (max-width: $break-point-medium) {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
// Disable breakpoints for now if discovery stream is enabled.
|
||||
.ds-outer-wrapper-breakpoint-override & {
|
||||
@include full-width-styles;
|
||||
|
@ -170,10 +179,6 @@
|
|||
inset-inline-end: 2%;
|
||||
}
|
||||
|
||||
@media (max-width: 865px) {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.ds-outer-wrapper-breakpoint-override & {
|
||||
inset-inline-end: -10%;
|
||||
margin: auto;
|
||||
|
@ -190,11 +195,25 @@
|
|||
flex-shrink: 0;
|
||||
margin: auto 0;
|
||||
margin-inline-end: 10px;
|
||||
|
||||
@media (max-width: $break-point-medium) {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
margin: auto;
|
||||
margin-inline-end: 0;
|
||||
|
||||
@media (max-width: $break-point-medium) {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
@media (max-width: $break-point-medium) {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,20 @@ export class StartupOverlay extends React.PureComponent {
|
|||
setTimeout(() => {
|
||||
this.setState({ show: true });
|
||||
}, 10);
|
||||
// Hide the page content from screen readers while the modal is open
|
||||
this.props.document
|
||||
.getElementById("root")
|
||||
.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
|
||||
removeOverlay() {
|
||||
window.removeEventListener("visibilitychange", this.removeOverlay);
|
||||
document.body.classList.remove("hide-main", "fxa");
|
||||
this.setState({ show: false });
|
||||
// Re-enable the document for screen readers
|
||||
this.props.document
|
||||
.getElementById("root")
|
||||
.setAttribute("aria-hidden", "false");
|
||||
|
||||
setTimeout(() => {
|
||||
// Allow scrolling and fully remove overlay after animation finishes.
|
||||
|
|
|
@ -7,6 +7,7 @@ import { CardGrid } from "content-src/components/DiscoveryStreamComponents/CardG
|
|||
import { CollapsibleSection } from "content-src/components/CollapsibleSection/CollapsibleSection";
|
||||
import { connect } from "react-redux";
|
||||
import { DSMessage } from "content-src/components/DiscoveryStreamComponents/DSMessage/DSMessage";
|
||||
import { DSTextPromo } from "content-src/components/DiscoveryStreamComponents/DSTextPromo/DSTextPromo";
|
||||
import { Hero } from "content-src/components/DiscoveryStreamComponents/Hero/Hero";
|
||||
import { Highlights } from "content-src/components/DiscoveryStreamComponents/Highlights/Highlights";
|
||||
import { HorizontalRule } from "content-src/components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule";
|
||||
|
@ -114,6 +115,17 @@ export class _DiscoveryStreamBase extends React.PureComponent {
|
|||
return <Highlights />;
|
||||
case "TopSites":
|
||||
return <TopSites header={component.header} />;
|
||||
case "TextPromo":
|
||||
return (
|
||||
<DSTextPromo
|
||||
image={component.properties.image_src}
|
||||
alt_text={component.properties.alt_text}
|
||||
header={component.properties.excerpt}
|
||||
cta_text={component.properties.cta_text}
|
||||
cta_url={component.properties.cta_url}
|
||||
subtitle={component.properties.context}
|
||||
/>
|
||||
);
|
||||
case "Message":
|
||||
return (
|
||||
<DSMessage
|
||||
|
|
|
@ -10,6 +10,7 @@ import React from "react";
|
|||
import { SafeAnchor } from "../SafeAnchor/SafeAnchor";
|
||||
import { DSContextFooter } from "../DSContextFooter/DSContextFooter.jsx";
|
||||
|
||||
// Default Meta that displays CTA as link if cta_variant in layout is set as "link"
|
||||
export const DefaultMeta = ({
|
||||
source,
|
||||
title,
|
||||
|
@ -18,13 +19,14 @@ export const DefaultMeta = ({
|
|||
context_type,
|
||||
cta,
|
||||
engagement,
|
||||
cta_variant,
|
||||
}) => (
|
||||
<div className="meta">
|
||||
<div className="info-wrap">
|
||||
<p className="source clamp">{source}</p>
|
||||
<header className="title clamp">{title}</header>
|
||||
{excerpt && <p className="excerpt clamp">{excerpt}</p>}
|
||||
{cta && (
|
||||
{cta_variant === "link" && cta && (
|
||||
<div role="link" className="cta-link icon icon-arrow" tabIndex="0">
|
||||
{cta}
|
||||
</div>
|
||||
|
@ -38,7 +40,7 @@ export const DefaultMeta = ({
|
|||
</div>
|
||||
);
|
||||
|
||||
export const VariantMeta = ({
|
||||
export const CTAButtonMeta = ({
|
||||
source,
|
||||
title,
|
||||
excerpt,
|
||||
|
@ -147,6 +149,8 @@ export class DSCard extends React.PureComponent {
|
|||
<div className="ds-card placeholder" ref={this.setPlaceholderRef} />
|
||||
);
|
||||
}
|
||||
const isButtonCTA = this.props.cta_variant === "button";
|
||||
|
||||
return (
|
||||
<div className="ds-card">
|
||||
<SafeAnchor
|
||||
|
@ -162,8 +166,8 @@ export class DSCard extends React.PureComponent {
|
|||
rawSource={this.props.raw_image_src}
|
||||
/>
|
||||
</div>
|
||||
{this.props.cta_variant && (
|
||||
<VariantMeta
|
||||
{isButtonCTA ? (
|
||||
<CTAButtonMeta
|
||||
source={this.props.source}
|
||||
title={this.props.title}
|
||||
excerpt={this.props.excerpt}
|
||||
|
@ -173,8 +177,7 @@ export class DSCard extends React.PureComponent {
|
|||
cta={this.props.cta}
|
||||
sponsor={this.props.sponsor}
|
||||
/>
|
||||
)}
|
||||
{!this.props.cta_variant && (
|
||||
) : (
|
||||
<DefaultMeta
|
||||
source={this.props.source}
|
||||
title={this.props.title}
|
||||
|
@ -183,6 +186,7 @@ export class DSCard extends React.PureComponent {
|
|||
engagement={this.props.engagement}
|
||||
context_type={this.props.context_type}
|
||||
cta={this.props.cta}
|
||||
cta_variant={this.props.cta_variant}
|
||||
/>
|
||||
)}
|
||||
<ImpressionStats
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/* 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/. */
|
||||
|
||||
import React from "react";
|
||||
import { SafeAnchor } from "../SafeAnchor/SafeAnchor";
|
||||
|
||||
export class DSTextPromo extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className="ds-text-promo">
|
||||
<img src={this.props.image} alt={this.props.alt_text} />
|
||||
<div className="text">
|
||||
<h3>
|
||||
{`${this.props.header}\u2003`}
|
||||
<SafeAnchor className="ds-chevron-link" url={this.props.cta_url}>
|
||||
{this.props.cta_text}
|
||||
</SafeAnchor>
|
||||
</h3>
|
||||
<p className="subtitle">{this.props.subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
.ds-text-promo {
|
||||
display: flex;
|
||||
max-width: 744px;
|
||||
margin: 16px auto;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 12px 0 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.text {
|
||||
line-height: 24px;
|
||||
margin: -4.5px 0 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@include dark-theme-only {
|
||||
color: $grey-10;
|
||||
}
|
||||
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
@include dark-theme-only {
|
||||
color: $grey-40;
|
||||
}
|
||||
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
color: $grey-50;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-chevron-link {
|
||||
color: $blue-60;
|
||||
display: inline-block;
|
||||
outline: 0;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@include dark-theme-only {
|
||||
color: $blue-50;
|
||||
}
|
||||
|
||||
color: $blue-70;
|
||||
|
||||
&::after {
|
||||
@include dark-theme-only {
|
||||
background-color: $blue-50;
|
||||
}
|
||||
|
||||
background-color: $blue-70;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
@include dark-theme-only {
|
||||
box-shadow: 0 0 0 2px $grey-80, 0 0 0 5px $blue-50-50;
|
||||
}
|
||||
|
||||
box-shadow: 0 0 0 2px $white, 0 0 0 5px $blue-50-50;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
@include dark-theme-only {
|
||||
background-color: $blue-40;
|
||||
}
|
||||
|
||||
content: ' ';
|
||||
mask: url('#{$image-path}glyph-caret-right.svg') 0 -8px no-repeat;
|
||||
background-color: $blue-60;
|
||||
margin: 0 0 0 4px;
|
||||
width: 5px;
|
||||
height: 8px;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@ $glyph-forward: url('chrome://browser/skin/forward.svg');
|
|||
}
|
||||
|
||||
.logo-and-wordmark {
|
||||
$logo-size: 97px;
|
||||
$wordmark-size: 142px;
|
||||
$logo-size: 96px;
|
||||
$wordmark-size: 172px;
|
||||
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
|
|
@ -162,6 +162,7 @@ input {
|
|||
@import '../components/DiscoveryStreamComponents/DSMessage/DSMessage';
|
||||
@import '../components/DiscoveryStreamImpressionStats/ImpressionStats';
|
||||
@import '../components/DiscoveryStreamComponents/DSEmptyState/DSEmptyState';
|
||||
@import '../components/DiscoveryStreamComponents/DSTextPromo/DSTextPromo';
|
||||
|
||||
// AS Router
|
||||
@import '../asrouter/components/Button/Button';
|
||||
|
|
|
@ -53,6 +53,7 @@ $grey-90-90: rgba($grey-90, 0.9);
|
|||
$blue-40-40: rgba($blue-40, 0.4);
|
||||
$blue-50-50: rgba($blue-50, 0.5);
|
||||
$blue-50-30: rgba($blue-50, 0.3);
|
||||
$blue-50-50: rgba($blue-50, 0.5);
|
||||
|
||||
$black: #000;
|
||||
$black-5: rgba($black, 0.05);
|
||||
|
|
|
@ -1020,19 +1020,19 @@ main {
|
|||
margin-bottom: 49px; }
|
||||
.search-wrapper .logo-and-wordmark .logo {
|
||||
background: url("chrome://branding/content/icon128.png") no-repeat center center;
|
||||
background-size: 97px;
|
||||
background-size: 96px;
|
||||
display: inline-block;
|
||||
height: 97px;
|
||||
width: 97px; }
|
||||
height: 96px;
|
||||
width: 96px; }
|
||||
.search-wrapper .logo-and-wordmark .wordmark {
|
||||
background: url("../data/content/assets/firefox-wordmark.svg") no-repeat center center;
|
||||
background-size: 142px;
|
||||
background-size: 172px;
|
||||
-moz-context-properties: fill;
|
||||
display: inline-block;
|
||||
fill: var(--newtab-search-wordmark-color);
|
||||
height: 97px;
|
||||
height: 96px;
|
||||
margin-inline-start: 15px;
|
||||
width: 142px; }
|
||||
width: 172px; }
|
||||
@media (max-width: 609px) {
|
||||
.search-wrapper .logo-and-wordmark .logo {
|
||||
background-size: 64px;
|
||||
|
@ -2976,6 +2976,62 @@ main {
|
|||
to {
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.ds-text-promo {
|
||||
display: flex;
|
||||
max-width: 744px;
|
||||
margin: 16px auto; }
|
||||
.ds-text-promo img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 12px 0 0;
|
||||
border-radius: 4px; }
|
||||
.ds-text-promo .text {
|
||||
line-height: 24px;
|
||||
margin: -4.5px 0 0; }
|
||||
.ds-text-promo h3 {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
font-size: 15px; }
|
||||
[lwt-newtab-brighttext] .ds-text-promo h3 {
|
||||
color: #F9F9FA; }
|
||||
.ds-text-promo .subtitle {
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
color: #737373; }
|
||||
[lwt-newtab-brighttext] .ds-text-promo .subtitle {
|
||||
color: #B1B1B3; }
|
||||
|
||||
.ds-chevron-link {
|
||||
color: #0060DF;
|
||||
display: inline-block;
|
||||
outline: 0; }
|
||||
.ds-chevron-link:hover {
|
||||
text-decoration: underline; }
|
||||
.ds-chevron-link:active {
|
||||
color: #003EAA; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:active {
|
||||
color: #0A84FF; }
|
||||
.ds-chevron-link:active::after {
|
||||
background-color: #003EAA; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:active::after {
|
||||
background-color: #0A84FF; }
|
||||
.ds-chevron-link:focus {
|
||||
box-shadow: 0 0 0 2px #FFF, 0 0 0 5px rgba(10, 132, 255, 0.5);
|
||||
border-radius: 2px; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:focus {
|
||||
box-shadow: 0 0 0 2px #2A2A2E, 0 0 0 5px rgba(10, 132, 255, 0.5); }
|
||||
.ds-chevron-link::after {
|
||||
content: ' ';
|
||||
mask: url("../data/content/assets/glyph-caret-right.svg") 0 -8px no-repeat;
|
||||
background-color: #0060DF;
|
||||
margin: 0 0 0 4px;
|
||||
width: 5px;
|
||||
height: 8px;
|
||||
text-decoration: none;
|
||||
display: inline-block; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link::after {
|
||||
background-color: #45A1FF; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
@ -3359,7 +3415,10 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
margin: 0 60px; } }
|
||||
@media (max-width: 865px) {
|
||||
.SimpleBelowSearchSnippet .innerWrapper {
|
||||
margin: 0 60px 0 0; } }
|
||||
margin-inline-start: 0; } }
|
||||
@media (max-width: 609px) {
|
||||
.SimpleBelowSearchSnippet .innerWrapper {
|
||||
margin: auto; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet .innerWrapper {
|
||||
align-items: flex-start;
|
||||
background-color: transparent;
|
||||
|
@ -3394,6 +3453,9 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
.SimpleBelowSearchSnippet .icon {
|
||||
height: 24px;
|
||||
width: 24px; } }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet .icon {
|
||||
margin: auto; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet .icon {
|
||||
height: 24px;
|
||||
width: 24px; }
|
||||
|
@ -3414,9 +3476,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
@media (max-width: 1120px) {
|
||||
.SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
inset-inline-end: 2%; } }
|
||||
@media (max-width: 865px) {
|
||||
.SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
margin-top: 10px; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
inset-inline-end: -10%;
|
||||
margin: auto; }
|
||||
|
@ -3429,9 +3488,18 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
flex-shrink: 0;
|
||||
margin: auto 0;
|
||||
margin-inline-end: 10px; }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet.withButton .icon {
|
||||
margin: auto; } }
|
||||
.SimpleBelowSearchSnippet.withButton .buttonContainer {
|
||||
margin: auto;
|
||||
margin-inline-end: 0; }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet.withButton .buttonContainer {
|
||||
margin: auto; } }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet button {
|
||||
margin: auto; } }
|
||||
.SimpleBelowSearchSnippet .body {
|
||||
display: inline;
|
||||
position: sticky;
|
||||
|
|
|
@ -1023,19 +1023,19 @@ main {
|
|||
margin-bottom: 49px; }
|
||||
.search-wrapper .logo-and-wordmark .logo {
|
||||
background: url("chrome://branding/content/icon128.png") no-repeat center center;
|
||||
background-size: 97px;
|
||||
background-size: 96px;
|
||||
display: inline-block;
|
||||
height: 97px;
|
||||
width: 97px; }
|
||||
height: 96px;
|
||||
width: 96px; }
|
||||
.search-wrapper .logo-and-wordmark .wordmark {
|
||||
background: url("../data/content/assets/firefox-wordmark.svg") no-repeat center center;
|
||||
background-size: 142px;
|
||||
background-size: 172px;
|
||||
-moz-context-properties: fill;
|
||||
display: inline-block;
|
||||
fill: var(--newtab-search-wordmark-color);
|
||||
height: 97px;
|
||||
height: 96px;
|
||||
margin-inline-start: 15px;
|
||||
width: 142px; }
|
||||
width: 172px; }
|
||||
@media (max-width: 609px) {
|
||||
.search-wrapper .logo-and-wordmark .logo {
|
||||
background-size: 64px;
|
||||
|
@ -2979,6 +2979,62 @@ main {
|
|||
to {
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.ds-text-promo {
|
||||
display: flex;
|
||||
max-width: 744px;
|
||||
margin: 16px auto; }
|
||||
.ds-text-promo img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 12px 0 0;
|
||||
border-radius: 4px; }
|
||||
.ds-text-promo .text {
|
||||
line-height: 24px;
|
||||
margin: -4.5px 0 0; }
|
||||
.ds-text-promo h3 {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
font-size: 15px; }
|
||||
[lwt-newtab-brighttext] .ds-text-promo h3 {
|
||||
color: #F9F9FA; }
|
||||
.ds-text-promo .subtitle {
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
color: #737373; }
|
||||
[lwt-newtab-brighttext] .ds-text-promo .subtitle {
|
||||
color: #B1B1B3; }
|
||||
|
||||
.ds-chevron-link {
|
||||
color: #0060DF;
|
||||
display: inline-block;
|
||||
outline: 0; }
|
||||
.ds-chevron-link:hover {
|
||||
text-decoration: underline; }
|
||||
.ds-chevron-link:active {
|
||||
color: #003EAA; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:active {
|
||||
color: #0A84FF; }
|
||||
.ds-chevron-link:active::after {
|
||||
background-color: #003EAA; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:active::after {
|
||||
background-color: #0A84FF; }
|
||||
.ds-chevron-link:focus {
|
||||
box-shadow: 0 0 0 2px #FFF, 0 0 0 5px rgba(10, 132, 255, 0.5);
|
||||
border-radius: 2px; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:focus {
|
||||
box-shadow: 0 0 0 2px #2A2A2E, 0 0 0 5px rgba(10, 132, 255, 0.5); }
|
||||
.ds-chevron-link::after {
|
||||
content: ' ';
|
||||
mask: url("../data/content/assets/glyph-caret-right.svg") 0 -8px no-repeat;
|
||||
background-color: #0060DF;
|
||||
margin: 0 0 0 4px;
|
||||
width: 5px;
|
||||
height: 8px;
|
||||
text-decoration: none;
|
||||
display: inline-block; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link::after {
|
||||
background-color: #45A1FF; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
@ -3362,7 +3418,10 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
margin: 0 60px; } }
|
||||
@media (max-width: 865px) {
|
||||
.SimpleBelowSearchSnippet .innerWrapper {
|
||||
margin: 0 60px 0 0; } }
|
||||
margin-inline-start: 0; } }
|
||||
@media (max-width: 609px) {
|
||||
.SimpleBelowSearchSnippet .innerWrapper {
|
||||
margin: auto; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet .innerWrapper {
|
||||
align-items: flex-start;
|
||||
background-color: transparent;
|
||||
|
@ -3397,6 +3456,9 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
.SimpleBelowSearchSnippet .icon {
|
||||
height: 24px;
|
||||
width: 24px; } }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet .icon {
|
||||
margin: auto; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet .icon {
|
||||
height: 24px;
|
||||
width: 24px; }
|
||||
|
@ -3417,9 +3479,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
@media (max-width: 1120px) {
|
||||
.SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
inset-inline-end: 2%; } }
|
||||
@media (max-width: 865px) {
|
||||
.SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
margin-top: 10px; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
inset-inline-end: -10%;
|
||||
margin: auto; }
|
||||
|
@ -3432,9 +3491,18 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
flex-shrink: 0;
|
||||
margin: auto 0;
|
||||
margin-inline-end: 10px; }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet.withButton .icon {
|
||||
margin: auto; } }
|
||||
.SimpleBelowSearchSnippet.withButton .buttonContainer {
|
||||
margin: auto;
|
||||
margin-inline-end: 0; }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet.withButton .buttonContainer {
|
||||
margin: auto; } }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet button {
|
||||
margin: auto; } }
|
||||
.SimpleBelowSearchSnippet .body {
|
||||
display: inline;
|
||||
position: sticky;
|
||||
|
|
|
@ -1020,19 +1020,19 @@ main {
|
|||
margin-bottom: 49px; }
|
||||
.search-wrapper .logo-and-wordmark .logo {
|
||||
background: url("chrome://branding/content/icon128.png") no-repeat center center;
|
||||
background-size: 97px;
|
||||
background-size: 96px;
|
||||
display: inline-block;
|
||||
height: 97px;
|
||||
width: 97px; }
|
||||
height: 96px;
|
||||
width: 96px; }
|
||||
.search-wrapper .logo-and-wordmark .wordmark {
|
||||
background: url("../data/content/assets/firefox-wordmark.svg") no-repeat center center;
|
||||
background-size: 142px;
|
||||
background-size: 172px;
|
||||
-moz-context-properties: fill;
|
||||
display: inline-block;
|
||||
fill: var(--newtab-search-wordmark-color);
|
||||
height: 97px;
|
||||
height: 96px;
|
||||
margin-inline-start: 15px;
|
||||
width: 142px; }
|
||||
width: 172px; }
|
||||
@media (max-width: 609px) {
|
||||
.search-wrapper .logo-and-wordmark .logo {
|
||||
background-size: 64px;
|
||||
|
@ -2976,6 +2976,62 @@ main {
|
|||
to {
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.ds-text-promo {
|
||||
display: flex;
|
||||
max-width: 744px;
|
||||
margin: 16px auto; }
|
||||
.ds-text-promo img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 0 12px 0 0;
|
||||
border-radius: 4px; }
|
||||
.ds-text-promo .text {
|
||||
line-height: 24px;
|
||||
margin: -4.5px 0 0; }
|
||||
.ds-text-promo h3 {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
font-size: 15px; }
|
||||
[lwt-newtab-brighttext] .ds-text-promo h3 {
|
||||
color: #F9F9FA; }
|
||||
.ds-text-promo .subtitle {
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
color: #737373; }
|
||||
[lwt-newtab-brighttext] .ds-text-promo .subtitle {
|
||||
color: #B1B1B3; }
|
||||
|
||||
.ds-chevron-link {
|
||||
color: #0060DF;
|
||||
display: inline-block;
|
||||
outline: 0; }
|
||||
.ds-chevron-link:hover {
|
||||
text-decoration: underline; }
|
||||
.ds-chevron-link:active {
|
||||
color: #003EAA; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:active {
|
||||
color: #0A84FF; }
|
||||
.ds-chevron-link:active::after {
|
||||
background-color: #003EAA; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:active::after {
|
||||
background-color: #0A84FF; }
|
||||
.ds-chevron-link:focus {
|
||||
box-shadow: 0 0 0 2px #FFF, 0 0 0 5px rgba(10, 132, 255, 0.5);
|
||||
border-radius: 2px; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link:focus {
|
||||
box-shadow: 0 0 0 2px #2A2A2E, 0 0 0 5px rgba(10, 132, 255, 0.5); }
|
||||
.ds-chevron-link::after {
|
||||
content: ' ';
|
||||
mask: url("../data/content/assets/glyph-caret-right.svg") 0 -8px no-repeat;
|
||||
background-color: #0060DF;
|
||||
margin: 0 0 0 4px;
|
||||
width: 5px;
|
||||
height: 8px;
|
||||
text-decoration: none;
|
||||
display: inline-block; }
|
||||
[lwt-newtab-brighttext] .ds-chevron-link::after {
|
||||
background-color: #45A1FF; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
@ -3359,7 +3415,10 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
margin: 0 60px; } }
|
||||
@media (max-width: 865px) {
|
||||
.SimpleBelowSearchSnippet .innerWrapper {
|
||||
margin: 0 60px 0 0; } }
|
||||
margin-inline-start: 0; } }
|
||||
@media (max-width: 609px) {
|
||||
.SimpleBelowSearchSnippet .innerWrapper {
|
||||
margin: auto; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet .innerWrapper {
|
||||
align-items: flex-start;
|
||||
background-color: transparent;
|
||||
|
@ -3394,6 +3453,9 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
.SimpleBelowSearchSnippet .icon {
|
||||
height: 24px;
|
||||
width: 24px; } }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet .icon {
|
||||
margin: auto; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet .icon {
|
||||
height: 24px;
|
||||
width: 24px; }
|
||||
|
@ -3414,9 +3476,6 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
@media (max-width: 1120px) {
|
||||
.SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
inset-inline-end: 2%; } }
|
||||
@media (max-width: 865px) {
|
||||
.SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
margin-top: 10px; } }
|
||||
.ds-outer-wrapper-breakpoint-override .SimpleBelowSearchSnippet.withButton .blockButton {
|
||||
inset-inline-end: -10%;
|
||||
margin: auto; }
|
||||
|
@ -3429,9 +3488,18 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
|
|||
flex-shrink: 0;
|
||||
margin: auto 0;
|
||||
margin-inline-end: 10px; }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet.withButton .icon {
|
||||
margin: auto; } }
|
||||
.SimpleBelowSearchSnippet.withButton .buttonContainer {
|
||||
margin: auto;
|
||||
margin-inline-end: 0; }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet.withButton .buttonContainer {
|
||||
margin: auto; } }
|
||||
@media (max-width: 610px) {
|
||||
.SimpleBelowSearchSnippet button {
|
||||
margin: auto; } }
|
||||
.SimpleBelowSearchSnippet .body {
|
||||
display: inline;
|
||||
position: sticky;
|
||||
|
|
|
@ -3142,7 +3142,9 @@ class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCompo
|
|||
this.props.sendUserActionTelemetry({
|
||||
event: "IMPRESSION",
|
||||
id: this.props.UISurface
|
||||
});
|
||||
}); // Hide the page content from screen readers while the modal is open
|
||||
|
||||
this.props.document.getElementById("root").setAttribute("aria-hidden", "true");
|
||||
}
|
||||
|
||||
onClickAddExtension() {
|
||||
|
@ -3159,7 +3161,9 @@ class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCompo
|
|||
this.props.sendUserActionTelemetry({
|
||||
event: "BLOCK",
|
||||
id: this.props.UISurface
|
||||
});
|
||||
}); // Re-enable the document for screen readers
|
||||
|
||||
this.props.document.getElementById("root").setAttribute("aria-hidden", "false");
|
||||
}
|
||||
|
||||
renderText() {
|
||||
|
@ -3247,7 +3251,9 @@ class StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCo
|
|||
this.setState({
|
||||
show: true
|
||||
});
|
||||
}, 10);
|
||||
}, 10); // Hide the page content from screen readers while the modal is open
|
||||
|
||||
this.props.document.getElementById("root").setAttribute("aria-hidden", "true");
|
||||
}
|
||||
|
||||
removeOverlay() {
|
||||
|
@ -3255,7 +3261,9 @@ class StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCo
|
|||
document.body.classList.remove("hide-main", "fxa");
|
||||
this.setState({
|
||||
show: false
|
||||
});
|
||||
}); // Re-enable the document for screen readers
|
||||
|
||||
this.props.document.getElementById("root").setAttribute("aria-hidden", "false");
|
||||
setTimeout(() => {
|
||||
// Allow scrolling and fully remove overlay after animation finishes.
|
||||
this.props.onBlock();
|
||||
|
@ -7931,6 +7939,7 @@ class DSContextFooter_DSContextFooter extends external_React_default.a.PureCompo
|
|||
|
||||
|
||||
|
||||
// Default Meta that displays CTA as link if cta_variant in layout is set as "link"
|
||||
|
||||
const DefaultMeta = ({
|
||||
source,
|
||||
|
@ -7939,7 +7948,8 @@ const DefaultMeta = ({
|
|||
context,
|
||||
context_type,
|
||||
cta,
|
||||
engagement
|
||||
engagement,
|
||||
cta_variant
|
||||
}) => external_React_default.a.createElement("div", {
|
||||
className: "meta"
|
||||
}, external_React_default.a.createElement("div", {
|
||||
|
@ -7950,7 +7960,7 @@ const DefaultMeta = ({
|
|||
className: "title clamp"
|
||||
}, title), excerpt && external_React_default.a.createElement("p", {
|
||||
className: "excerpt clamp"
|
||||
}, excerpt), cta && external_React_default.a.createElement("div", {
|
||||
}, excerpt), cta_variant === "link" && cta && external_React_default.a.createElement("div", {
|
||||
role: "link",
|
||||
className: "cta-link icon icon-arrow",
|
||||
tabIndex: "0"
|
||||
|
@ -7959,7 +7969,7 @@ const DefaultMeta = ({
|
|||
context: context,
|
||||
engagement: engagement
|
||||
}));
|
||||
const VariantMeta = ({
|
||||
const CTAButtonMeta = ({
|
||||
source,
|
||||
title,
|
||||
excerpt,
|
||||
|
@ -8059,6 +8069,7 @@ class DSCard_DSCard extends external_React_default.a.PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
const isButtonCTA = this.props.cta_variant === "button";
|
||||
return external_React_default.a.createElement("div", {
|
||||
className: "ds-card"
|
||||
}, external_React_default.a.createElement(SafeAnchor_SafeAnchor, {
|
||||
|
@ -8072,7 +8083,7 @@ class DSCard_DSCard extends external_React_default.a.PureComponent {
|
|||
extraClassNames: "img",
|
||||
source: this.props.image_src,
|
||||
rawSource: this.props.raw_image_src
|
||||
})), this.props.cta_variant && external_React_default.a.createElement(VariantMeta, {
|
||||
})), isButtonCTA ? external_React_default.a.createElement(CTAButtonMeta, {
|
||||
source: this.props.source,
|
||||
title: this.props.title,
|
||||
excerpt: this.props.excerpt,
|
||||
|
@ -8081,14 +8092,15 @@ class DSCard_DSCard extends external_React_default.a.PureComponent {
|
|||
engagement: this.props.engagement,
|
||||
cta: this.props.cta,
|
||||
sponsor: this.props.sponsor
|
||||
}), !this.props.cta_variant && external_React_default.a.createElement(DefaultMeta, {
|
||||
}) : external_React_default.a.createElement(DefaultMeta, {
|
||||
source: this.props.source,
|
||||
title: this.props.title,
|
||||
excerpt: this.props.excerpt,
|
||||
context: this.props.context,
|
||||
engagement: this.props.engagement,
|
||||
context_type: this.props.context_type,
|
||||
cta: this.props.cta
|
||||
cta: this.props.cta,
|
||||
cta_variant: this.props.cta_variant
|
||||
}), external_React_default.a.createElement(ImpressionStats["ImpressionStats"], {
|
||||
campaignId: this.props.campaignId,
|
||||
rows: [{
|
||||
|
@ -8325,6 +8337,30 @@ class DSMessage_DSMessage extends external_React_default.a.PureComponent {
|
|||
}, this.props.link_text)));
|
||||
}
|
||||
|
||||
}
|
||||
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSTextPromo/DSTextPromo.jsx
|
||||
/* 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/. */
|
||||
|
||||
|
||||
class DSTextPromo_DSTextPromo extends external_React_default.a.PureComponent {
|
||||
render() {
|
||||
return external_React_default.a.createElement("div", {
|
||||
className: "ds-text-promo"
|
||||
}, external_React_default.a.createElement("img", {
|
||||
src: this.props.image,
|
||||
alt: this.props.alt_text
|
||||
}), external_React_default.a.createElement("div", {
|
||||
className: "text"
|
||||
}, external_React_default.a.createElement("h3", null, `${this.props.header}\u2003`, external_React_default.a.createElement(SafeAnchor_SafeAnchor, {
|
||||
className: "ds-chevron-link",
|
||||
url: this.props.cta_url
|
||||
}, this.props.cta_text)), external_React_default.a.createElement("p", {
|
||||
className: "subtitle"
|
||||
}, this.props.subtitle)));
|
||||
}
|
||||
|
||||
}
|
||||
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/List/List.jsx
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
|
@ -9036,6 +9072,7 @@ const TopSites_TopSites_TopSites = Object(external_ReactRedux_["connect"])(state
|
|||
|
||||
|
||||
|
||||
|
||||
const ALLOWED_CSS_URL_PREFIXES = ["chrome://", "resource://", "https://img-getpocket.cdn.mozilla.net/"];
|
||||
const DUMMY_CSS_SELECTOR = "DUMMY#CSS.SELECTOR";
|
||||
let rickRollCache = []; // Cache of random probability values for a spoc position
|
||||
|
@ -9120,6 +9157,16 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
|
|||
header: component.header
|
||||
});
|
||||
|
||||
case "TextPromo":
|
||||
return external_React_default.a.createElement(DSTextPromo_DSTextPromo, {
|
||||
image: component.properties.image_src,
|
||||
alt_text: component.properties.alt_text,
|
||||
header: component.properties.excerpt,
|
||||
cta_text: component.properties.cta_text,
|
||||
cta_url: component.properties.cta_url,
|
||||
subtitle: component.properties.context
|
||||
});
|
||||
|
||||
case "Message":
|
||||
return external_React_default.a.createElement(DSMessage_DSMessage, {
|
||||
title: component.header && component.header.title,
|
||||
|
@ -12823,6 +12870,7 @@ const INITIAL_STATE = {
|
|||
},
|
||||
spocs: {
|
||||
spocs_endpoint: "",
|
||||
spocs_per_domain: 1,
|
||||
lastUpdated: null,
|
||||
data: {},
|
||||
// {spocs: []}
|
||||
|
@ -13439,7 +13487,8 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
|
|||
case Actions["actionTypes"].DISCOVERY_STREAM_SPOCS_ENDPOINT:
|
||||
return { ...prevState,
|
||||
spocs: { ...INITIAL_STATE.DiscoveryStream.spocs,
|
||||
spocs_endpoint: action.data || INITIAL_STATE.DiscoveryStream.spocs.spocs_endpoint
|
||||
spocs_endpoint: action.data.url || INITIAL_STATE.DiscoveryStream.spocs.spocs_endpoint,
|
||||
spocs_per_domain: action.data.spocs_per_domain || INITIAL_STATE.DiscoveryStream.spocs.spocs_per_domain
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13626,6 +13675,7 @@ class Interrupt_Interrupt extends external_React_default.a.PureComponent {
|
|||
amo_html: message.content.text
|
||||
})
|
||||
}, external_React_default.a.createElement(ReturnToAMO["ReturnToAMO"], _extends({}, message, {
|
||||
document: this.props.document,
|
||||
UISurface: "NEWTAB_OVERLAY",
|
||||
onBlock: onDismiss,
|
||||
onAction: executeAction,
|
||||
|
@ -13634,6 +13684,7 @@ class Interrupt_Interrupt extends external_React_default.a.PureComponent {
|
|||
|
||||
case "fxa_overlay":
|
||||
return external_React_default.a.createElement(StartupOverlay["StartupOverlay"], {
|
||||
document: this.props.document,
|
||||
onBlock: onDismiss,
|
||||
dispatch: dispatch,
|
||||
fxa_endpoint: fxaEndpoint
|
||||
|
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="138" height="38"><path fill="context-fill" d="M136.837 10.212H131.5l-5.7 9.9-5.644-9.9h-5.542l8.364 12.778-9.438 14.265h5.337l6.723-11.443 6.62 11.443h5.7l-9.391-14.471zM22.844 37.255h4.721V10.212h-4.721zm15.42-21.339l-.462-5.7h-4.054v27.039h4.721V23.306c0-4.205 3.079-8.878 6.466-8.878a8.5 8.5 0 0 1 2.361.308l.872-4.618A11.516 11.516 0 0 0 45.5 9.81c-3.284 0-5.8 2.053-7.236 6.106zM0 37.255h4.875V21.707h11.546v-3.849H4.875V5.8h13.342l.565-3.9H0zM25.153.163A3.139 3.139 0 0 0 21.869 3.4a3.129 3.129 0 0 0 3.284 3.182A3.143 3.143 0 0 0 28.489 3.4 3.153 3.153 0 0 0 25.153.163zm76.491 9.647c-7.7 0-12.11 5.585-12.11 13.949 0 8.57 4.362 14.112 12.059 14.112 7.646 0 12.059-5.8 12.059-14.163 0-8.57-4.31-13.898-12.008-13.898zm-.051 24.264c-4.516 0-6.979-3.284-6.979-10.315 0-7.081 2.515-10.152 7.03-10.152 4.465 0 6.928 3.071 6.928 10.1 0 7.083-2.463 10.367-6.979 10.367zM82.47 8.339c0-2.617 1.027-4.542 4-4.542a11.567 11.567 0 0 1 4.721 1.027l1.488-3.438A14.907 14.907 0 0 0 86.216 0c-5.49 0-8.467 3.447-8.467 7.963v2.249h-4.824v3.643h4.824v23.4h4.721v-23.4h6.056l.513-3.643H82.47zM59.952 9.81c-6.979 0-11.238 5.79-11.238 14.206 0 8.57 4.413 13.855 11.957 13.855a14.741 14.741 0 0 0 9.442-3.387l-2.053-2.822a11.384 11.384 0 0 1-7.03 2.361c-3.9 0-6.825-2.412-7.287-8.673h17.242c.052-.616.1-1.488.1-2.412.003-8.262-3.846-13.128-11.133-13.128zm6.466 12.051H53.743c.359-6 2.72-8.305 6.312-8.305 4.259 0 6.363 2.711 6.363 8z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="172" height="42"><path fill="context-fill #20123a" d="M.19 2.82h25.72v7H7.57v9.43h18.34v6.9H7.57v15.14H.19zM34.65.13a4.14 4.14 0 0 1 4.27 4.33 4.12 4.12 0 0 1-4.32 4.32 4.09 4.09 0 0 1-4.27-4.22A4.27 4.27 0 0 1 34.65.13zM31 12.83h7.27v28.46H31zm28.35 7.91a5.89 5.89 0 0 0-3.53-1.27c-3 0-4.64 1.9-4.64 6.06v15.76H44V12.83h6.9v4.11a6.79 6.79 0 0 1 6.8-4.37A8.69 8.69 0 0 1 62.53 14zm3 6.48c0-8.17 6.06-15 14.65-15s14.59 6.06 14.59 14.49v3H69.48c.79 3.58 3.58 6 7.85 6a7.62 7.62 0 0 0 7.06-4.21l6.06 3.63c-3 4.43-7.27 6.75-13.33 6.75-9.22-.01-14.75-6.18-14.75-14.66zM69.59 24h15c-.79-3.63-3.74-5.63-7.59-5.63A7.31 7.31 0 0 0 69.59 24zM93.4 12.83h5.11v-1.42c0-7.75 3.27-11 10.44-11h2.53v6.31h-2.06c-3.37 0-4.11 1.16-4.11 4.69v1.42h6.17v6.54h-6v21.92h-7V19.37H93.4zm19.45 14.23a14.56 14.56 0 0 1 14.85-14.81 14.81 14.81 0 1 1 0 29.62c-8.85 0-14.85-6.49-14.85-14.81zm22.65 0a7.8 7.8 0 1 0-15.59 0 7.8 7.8 0 1 0 15.59 0zm16.86-.32l-10.27-13.91h8.53l6.06 8.75 6.22-8.75h8.38l-10.43 13.86 11 14.6h-8.49L156.53 32l-6.59 9.28h-8.48z"/></svg>
|
До Ширина: | Высота: | Размер: 1.4 KiB После Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg width="5" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M.248 8.204a.77.77 0 0 1 1.088.044L4.8 12l-3.464 3.752a.77.77 0 1 1-1.132-1.045L2.704 12l-2.5-2.707a.77.77 0 0 1 .044-1.089z" fill="#0C0C0D"/></svg>
|
После Ширина: | Высота: | Размер: 272 B |
Двоичные данные
browser/components/newtab/data/content/assets/protection-report-icon.png
Normal file
Двоичные данные
browser/components/newtab/data/content/assets/protection-report-icon.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 4.2 KiB |
|
@ -36,7 +36,7 @@ if you run into any problems.
|
|||
|
||||
You will also need to install:
|
||||
|
||||
- Node.js 7+ (On Mac, the best way to install Node.js is to use the [install link on the Node.js homepage](https://nodejs.org/en/))
|
||||
- Node.js version 8 (To install this legacy version of Node, [use this URL](https://nodejs.org/en/download/releases/))
|
||||
- npm (packaged with Node.js)
|
||||
|
||||
### Activity Stream Github repository
|
||||
|
|
|
@ -742,6 +742,7 @@ class _ASRouter {
|
|||
ToolbarPanelHub.init(this.waitForInitialized, {
|
||||
getMessages: this.handleMessageRequest,
|
||||
dispatch: this.dispatch,
|
||||
handleUserAction: this.handleUserAction,
|
||||
});
|
||||
|
||||
this._loadLocalProviders();
|
||||
|
@ -1531,6 +1532,7 @@ class _ASRouter {
|
|||
handleMessageRequest({
|
||||
triggerId,
|
||||
triggerParam,
|
||||
triggerContext,
|
||||
template,
|
||||
provider,
|
||||
returnAll = false,
|
||||
|
@ -1552,13 +1554,21 @@ class _ASRouter {
|
|||
if (returnAll) {
|
||||
return this._findAllMessages(
|
||||
msgs,
|
||||
triggerId && { id: triggerId, param: triggerParam }
|
||||
triggerId && {
|
||||
id: triggerId,
|
||||
param: triggerParam,
|
||||
context: triggerContext,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return this._findMessage(
|
||||
msgs,
|
||||
triggerId && { id: triggerId, param: triggerParam }
|
||||
triggerId && {
|
||||
id: triggerId,
|
||||
param: triggerParam,
|
||||
context: triggerContext,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1903,6 +1913,7 @@ class _ASRouter {
|
|||
const message = await this.handleMessageRequest({
|
||||
triggerId: trigger.id,
|
||||
triggerParam: trigger.param,
|
||||
triggerContext: trigger.context,
|
||||
});
|
||||
|
||||
await this.setState({ lastMessageId: message ? message.id : null });
|
||||
|
|
|
@ -56,6 +56,12 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
"@mozilla.org/updates/update-manager;1",
|
||||
"nsIUpdateManager"
|
||||
);
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"TrackingDBService",
|
||||
"@mozilla.org/tracking-db-service;1",
|
||||
"nsITrackingDBService"
|
||||
);
|
||||
|
||||
const FXA_USERNAME_PREF = "services.sync.username";
|
||||
const FXA_ENABLED_PREF = "identity.fxaccounts.enabled";
|
||||
|
@ -422,6 +428,9 @@ const TargetingGetters = {
|
|||
false
|
||||
);
|
||||
},
|
||||
get totalBlockedCount() {
|
||||
return TrackingDBService.sumAllEvents();
|
||||
},
|
||||
};
|
||||
|
||||
this.ASRouterTargeting = {
|
||||
|
|
|
@ -370,7 +370,7 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
) {
|
||||
sendUpdate({
|
||||
type: at.DISCOVERY_STREAM_SPOCS_ENDPOINT,
|
||||
data: layout.spocs.url,
|
||||
data: layout.spocs,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1341,7 +1341,6 @@ defaultLayoutResp = {
|
|||
components: [
|
||||
{
|
||||
type: "CardGrid",
|
||||
cta_variant: false,
|
||||
properties: {
|
||||
items: 21,
|
||||
},
|
||||
|
|
|
@ -45,7 +45,7 @@ this.DownloadsManager = class DownloadsManager {
|
|||
DownloadsViewUI.getSizeWithUnits(download) ||
|
||||
DownloadsCommon.strings.sizeUnknown,
|
||||
referrer: download.source.referrerInfo
|
||||
? download.source.referrerInfo.originalReferrer
|
||||
? download.source.referrerInfo.originalReferrer.spec
|
||||
: null,
|
||||
date_added: download.endTime,
|
||||
};
|
||||
|
|
|
@ -405,6 +405,7 @@ const ONBOARDING_MESSAGES = () => [
|
|||
cta_url: `${Services.urlFormatter.formatURLPref(
|
||||
"app.support.baseURL"
|
||||
)}etp-promotions?as=u&utm_source=inproduct`,
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
trigger: { id: "protectionsPanelOpen" },
|
||||
},
|
||||
|
|
|
@ -92,6 +92,7 @@ const MESSAGES = () => [
|
|||
{
|
||||
id: "WHATS_NEW_70_1",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 3,
|
||||
content: {
|
||||
published_date: 1560969794394,
|
||||
title: "Protection Is Our Focus",
|
||||
|
@ -101,6 +102,7 @@ const MESSAGES = () => [
|
|||
body:
|
||||
"The New Enhanced Tracking Protection, gives you the best level of protection and performance. Discover how this version is the safest version of firefox ever made.",
|
||||
cta_url: "https://blog.mozilla.org/",
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
targeting: `firefoxVersion > 69`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
|
@ -108,6 +110,7 @@ const MESSAGES = () => [
|
|||
{
|
||||
id: "WHATS_NEW_70_2",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 1,
|
||||
content: {
|
||||
published_date: 1560969794394,
|
||||
title: "Another thing new in Firefox 70",
|
||||
|
@ -115,6 +118,7 @@ const MESSAGES = () => [
|
|||
"The New Enhanced Tracking Protection, gives you the best level of protection and performance. Discover how this version is the safest version of firefox ever made.",
|
||||
link_text: "Learn more on our blog",
|
||||
cta_url: "https://blog.mozilla.org/",
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
targeting: `firefoxVersion > 69`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
|
@ -122,6 +126,7 @@ const MESSAGES = () => [
|
|||
{
|
||||
id: "WHATS_NEW_69_1",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 1,
|
||||
content: {
|
||||
published_date: 1557346235089,
|
||||
title: "Something new in Firefox 69",
|
||||
|
@ -129,10 +134,31 @@ const MESSAGES = () => [
|
|||
"The New Enhanced Tracking Protection, gives you the best level of protection and performance. Discover how this version is the safest version of firefox ever made.",
|
||||
link_text: "Learn more on our blog",
|
||||
cta_url: "https://blog.mozilla.org/",
|
||||
cta_type: "OPEN_URL",
|
||||
},
|
||||
targeting: `firefoxVersion > 68`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
},
|
||||
{
|
||||
id: "WHATS_NEW_70_3",
|
||||
template: "whatsnew_panel_message",
|
||||
order: 2,
|
||||
content: {
|
||||
published_date: 1560969794394,
|
||||
layout: "tracking-protections",
|
||||
title: { string_id: "cfr-whatsnew-tracking-blocked-title" },
|
||||
subtitle: { string_id: "cfr-whatsnew-tracking-blocked-subtitle" },
|
||||
icon_url:
|
||||
"resource://activity-stream/data/content/assets/protection-report-icon.png",
|
||||
icon_alt: "Protection Report icon",
|
||||
body: { string_id: "cfr-whatsnew-tracking-protect-body" },
|
||||
link_text: { string_id: "cfr-whatsnew-tracking-blocked-link-text" },
|
||||
cta_url: "protections",
|
||||
cta_type: "OPEN_ABOUT_PAGE",
|
||||
},
|
||||
targeting: `firefoxVersion > 69 && totalBlockedCount > 0`,
|
||||
trigger: { id: "whatsNewPanelOpened" },
|
||||
},
|
||||
];
|
||||
|
||||
const PanelTestProvider = {
|
||||
|
|
|
@ -3,20 +3,19 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Services",
|
||||
"resource://gre/modules/Services.jsm"
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
EveryWindow: "resource:///modules/EveryWindow.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
});
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"EveryWindow",
|
||||
"resource:///modules/EveryWindow.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
||||
"TrackingDBService",
|
||||
"@mozilla.org/tracking-db-service;1",
|
||||
"nsITrackingDBService"
|
||||
);
|
||||
|
||||
const WHATSNEW_ENABLED_PREF = "browser.messaging-system.whatsNewPanel.enabled";
|
||||
|
@ -43,9 +42,10 @@ class _ToolbarPanelHub {
|
|||
this.state = null;
|
||||
}
|
||||
|
||||
async init(waitForInitialized, { getMessages, dispatch }) {
|
||||
async init(waitForInitialized, { getMessages, dispatch, handleUserAction }) {
|
||||
this._getMessages = getMessages;
|
||||
this._dispatch = dispatch;
|
||||
this._handleUserAction = handleUserAction;
|
||||
// Wait for ASRouter messages to become available in order to know
|
||||
// if we can show the What's New panel
|
||||
await waitForInitialized;
|
||||
|
@ -137,23 +137,45 @@ class _ToolbarPanelHub {
|
|||
});
|
||||
}
|
||||
|
||||
// Newer messages first and use `order` field to decide between messages
|
||||
// with the same timestamp
|
||||
_sortWhatsNewMessages(m1, m2) {
|
||||
// Sort by published_date in descending order.
|
||||
if (m1.content.published_date === m2.content.published_date) {
|
||||
// Ascending order
|
||||
return m1.order - m2.order;
|
||||
}
|
||||
if (m1.content.published_date > m2.content.published_date) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Render what's new messages into the panel.
|
||||
async renderMessages(win, doc, containerId) {
|
||||
const messages = (await this.messages).sort((m1, m2) => {
|
||||
// Sort by published_date in descending order.
|
||||
if (m1.content.published_date === m2.content.published_date) {
|
||||
return 0;
|
||||
}
|
||||
if (m1.content.published_date > m2.content.published_date) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
const messages = (await this.messages).sort(this._sortWhatsNewMessages);
|
||||
const container = doc.getElementById(containerId);
|
||||
|
||||
if (messages && !container.querySelector(".whatsNew-message")) {
|
||||
let previousDate = 0;
|
||||
// Get and store any variable part of the message content
|
||||
this.state.contentArguments = await this._contentArguments();
|
||||
for (let message of messages) {
|
||||
// Only render date if it is different from the one rendered before.
|
||||
if (message.content.published_date !== previousDate) {
|
||||
container.appendChild(
|
||||
this._createElement(doc, "p", {
|
||||
classList: "whatsNew-message-date",
|
||||
content: new Date(
|
||||
message.content.published_date
|
||||
).toLocaleDateString("default", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
}),
|
||||
})
|
||||
);
|
||||
}
|
||||
container.appendChild(
|
||||
this._createMessageElements(win, doc, message, previousDate)
|
||||
);
|
||||
|
@ -181,33 +203,36 @@ class _ToolbarPanelHub {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach click event listener defined in message payload
|
||||
*/
|
||||
_attachClickListener(win, element, message) {
|
||||
element.addEventListener("click", () => {
|
||||
this._handleUserAction({
|
||||
target: win,
|
||||
data: {
|
||||
type: message.content.cta_type,
|
||||
data: {
|
||||
args: message.content.cta_url,
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.sendUserEventTelemetry(win, "CLICK", message);
|
||||
});
|
||||
}
|
||||
|
||||
_createMessageElements(win, doc, message, previousDate) {
|
||||
const { content } = message;
|
||||
const messageEl = this._createElement(doc, "div");
|
||||
messageEl.classList.add("whatsNew-message");
|
||||
|
||||
// Only render date if it is different from the one rendered before.
|
||||
if (content.published_date !== previousDate) {
|
||||
messageEl.appendChild(
|
||||
this._createDateElement(doc, content.published_date)
|
||||
);
|
||||
}
|
||||
|
||||
const wrapperEl = this._createElement(doc, "button");
|
||||
// istanbul ignore next
|
||||
wrapperEl.doCommand = () => {};
|
||||
wrapperEl.classList.add("whatsNew-message-body");
|
||||
messageEl.appendChild(wrapperEl);
|
||||
wrapperEl.addEventListener("click", () => {
|
||||
win.ownerGlobal.openLinkIn(content.cta_url, "tabshifted", {
|
||||
private: false,
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
|
||||
{}
|
||||
),
|
||||
csp: null,
|
||||
});
|
||||
|
||||
this.sendUserEventTelemetry(win, "CLICK", message);
|
||||
});
|
||||
|
||||
if (content.icon_url) {
|
||||
wrapperEl.classList.add("has-icon");
|
||||
|
@ -218,81 +243,141 @@ class _ToolbarPanelHub {
|
|||
wrapperEl.appendChild(iconEl);
|
||||
}
|
||||
|
||||
const titleEl = this._createElement(doc, "h2");
|
||||
titleEl.classList.add("whatsNew-message-title");
|
||||
this._setString(doc, titleEl, content.title);
|
||||
wrapperEl.appendChild(titleEl);
|
||||
|
||||
const bodyEl = this._createElement(doc, "p");
|
||||
this._setString(doc, bodyEl, content.body);
|
||||
wrapperEl.appendChild(bodyEl);
|
||||
wrapperEl.appendChild(this._createMessageContent(win, doc, content));
|
||||
|
||||
if (content.link_text) {
|
||||
const linkEl = this._createElement(doc, "a");
|
||||
linkEl.classList.add("text-link");
|
||||
this._setString(doc, linkEl, content.link_text);
|
||||
wrapperEl.appendChild(linkEl);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "a", {
|
||||
classList: "text-link",
|
||||
content: content.link_text,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Attach event listener on entire message container
|
||||
this._attachClickListener(win, wrapperEl, message);
|
||||
|
||||
return messageEl;
|
||||
}
|
||||
|
||||
_createHeroElement(win, doc, content) {
|
||||
/**
|
||||
* Return message title (optional subtitle) and body
|
||||
*/
|
||||
_createMessageContent(win, doc, content) {
|
||||
const wrapperEl = new win.DocumentFragment();
|
||||
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title",
|
||||
content: content.title,
|
||||
})
|
||||
);
|
||||
|
||||
switch (content.layout) {
|
||||
case "tracking-protections":
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h4", {
|
||||
classList: "whatsNew-message-subtitle",
|
||||
content: content.subtitle,
|
||||
})
|
||||
);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title-large",
|
||||
content: this.state.contentArguments.blockedCount,
|
||||
})
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "p", { content: content.body })
|
||||
);
|
||||
|
||||
return wrapperEl;
|
||||
}
|
||||
|
||||
_createHeroElement(win, doc, message) {
|
||||
const messageEl = this._createElement(doc, "div");
|
||||
messageEl.setAttribute("id", "protections-popup-message");
|
||||
messageEl.classList.add("whatsNew-hero-message");
|
||||
const wrapperEl = this._createElement(doc, "div");
|
||||
wrapperEl.classList.add("whatsNew-message-body");
|
||||
messageEl.appendChild(wrapperEl);
|
||||
wrapperEl.addEventListener("click", () => {
|
||||
win.ownerGlobal.openLinkIn(content.cta_url, "tabshifted", {
|
||||
private: false,
|
||||
relatedToCurrent: true,
|
||||
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
|
||||
{}
|
||||
),
|
||||
csp: null,
|
||||
});
|
||||
});
|
||||
const titleEl = this._createElement(doc, "h2");
|
||||
titleEl.classList.add("whatsNew-message-title");
|
||||
this._setString(doc, titleEl, content.title);
|
||||
wrapperEl.appendChild(titleEl);
|
||||
|
||||
const bodyEl = this._createElement(doc, "p");
|
||||
this._setString(doc, bodyEl, content.body);
|
||||
wrapperEl.appendChild(bodyEl);
|
||||
this._attachClickListener(win, wrapperEl, message);
|
||||
|
||||
if (content.link_text) {
|
||||
const linkEl = this._createElement(doc, "a");
|
||||
linkEl.classList.add("text-link");
|
||||
this._setString(doc, linkEl, content.link_text);
|
||||
wrapperEl.appendChild(linkEl);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title",
|
||||
content: message.content.title,
|
||||
})
|
||||
);
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "p", { content: message.content.body })
|
||||
);
|
||||
|
||||
if (message.content.link_text) {
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "a", {
|
||||
classList: "text-link",
|
||||
content: message.content.link_text,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return messageEl;
|
||||
}
|
||||
|
||||
_createElement(doc, elem) {
|
||||
return doc.createElementNS("http://www.w3.org/1999/xhtml", elem);
|
||||
_createElement(doc, elem, options = {}) {
|
||||
const node = doc.createElementNS("http://www.w3.org/1999/xhtml", elem);
|
||||
if (options.classList) {
|
||||
node.classList.add(options.classList);
|
||||
}
|
||||
if (options.content) {
|
||||
this._setString(doc, node, options.content);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
_createDateElement(doc, date) {
|
||||
const dateEl = this._createElement(doc, "p");
|
||||
dateEl.classList.add("whatsNew-message-date");
|
||||
dateEl.textContent = new Date(date).toLocaleDateString("default", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
return dateEl;
|
||||
async _contentArguments() {
|
||||
// Between now and 6 weeks ago
|
||||
const dateTo = new Date();
|
||||
const dateFrom = new Date(dateTo.getTime() - 42 * 24 * 60 * 60 * 1000);
|
||||
const eventsByDate = await TrackingDBService.getEventsByDateRange(
|
||||
dateFrom,
|
||||
dateTo
|
||||
);
|
||||
// Count all events in the past 6 weeks
|
||||
const totalEvents = eventsByDate.reduce(
|
||||
(acc, day) => acc + day.getResultByName("count"),
|
||||
0
|
||||
);
|
||||
return {
|
||||
// Keys need to match variable names used in asrouter.ftl
|
||||
// `earliestDate` will be either 6 weeks ago or when tracking recording
|
||||
// started. Whichever is more recent.
|
||||
earliestDate: new Date(
|
||||
Math.max(
|
||||
new Date(await TrackingDBService.getEarliestRecordedDate()),
|
||||
dateFrom
|
||||
)
|
||||
).getTime(),
|
||||
blockedCount: totalEvents.toLocaleString(),
|
||||
};
|
||||
}
|
||||
|
||||
// If `string_id` is present it means we are relying on fluent for translations.
|
||||
// Otherwise, we have a vanilla string.
|
||||
_setString(doc, el, stringObj) {
|
||||
if (stringObj.string_id) {
|
||||
doc.l10n.setAttributes(el, stringObj.string_id);
|
||||
doc.l10n.setAttributes(
|
||||
el,
|
||||
stringObj.string_id,
|
||||
// Pass all available arguments to Fluent
|
||||
this.state.contentArguments
|
||||
);
|
||||
} else {
|
||||
el.textContent = stringObj;
|
||||
}
|
||||
|
@ -395,7 +480,7 @@ class _ToolbarPanelHub {
|
|||
triggerId: "protectionsPanelOpen",
|
||||
});
|
||||
if (message) {
|
||||
const messageEl = this._createHeroElement(win, doc, message.content);
|
||||
const messageEl = this._createHeroElement(win, doc, message);
|
||||
container.appendChild(messageEl);
|
||||
infoButton.addEventListener("click", toggleMessage);
|
||||
this.sendUserEventTelemetry(win, "IMPRESSION", message.id);
|
||||
|
|
|
@ -13,7 +13,7 @@ cd /mozilla-central && hg pull && hg update -C
|
|||
cd /activity-stream && npm install . && npm run buildmc
|
||||
|
||||
# Build latest m-c with Activity Stream changes
|
||||
cd /mozilla-central && ./mach build \
|
||||
cd /mozilla-central && rm -rf ./objdir-frontend && ./mach build \
|
||||
&& ./mach lint browser/components/newtab \
|
||||
&& ./mach lint -l codespell browser/locales/en-US/browser/newtab \
|
||||
&& ./mach test browser/components/newtab/test/browser --headless \
|
||||
|
|
|
@ -214,6 +214,7 @@ describe("ASRouter", () => {
|
|||
{
|
||||
getMessages: Router.handleMessageRequest,
|
||||
dispatch: Router.dispatch,
|
||||
handleUserAction: Router.handleUserAction,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -930,7 +931,11 @@ describe("ASRouter", () => {
|
|||
assert.deepEqual(result, [message2, message1]);
|
||||
});
|
||||
it("should forward trigger param info", async () => {
|
||||
const trigger = { triggerId: "foo", triggerParam: "bar" };
|
||||
const trigger = {
|
||||
triggerId: "foo",
|
||||
triggerParam: "bar",
|
||||
triggerContext: "context",
|
||||
};
|
||||
const message1 = {
|
||||
id: "1",
|
||||
campaign: "foocampaign",
|
||||
|
@ -951,6 +956,7 @@ describe("ASRouter", () => {
|
|||
assert.calledWithExactly(stub, sinon.match.array, {
|
||||
id: trigger.triggerId,
|
||||
param: trigger.triggerParam,
|
||||
context: trigger.triggerContext,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1624,6 +1630,7 @@ describe("ASRouter", () => {
|
|||
assert.deepEqual(Router._findMessage.firstCall.args[1], {
|
||||
id: "firstRun",
|
||||
param: undefined,
|
||||
context: undefined,
|
||||
});
|
||||
});
|
||||
it("consider the trigger when picking a message", async () => {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { PanelTestProvider } from "lib/PanelTestProvider.jsm";
|
||||
import schema from "content-src/asrouter/schemas/panel/cfr-fxa-bookmark.schema.json";
|
||||
import update_schema from "content-src/asrouter/templates/OnboardingMessage/UpdateAction.schema.json";
|
||||
import whats_new_schema from "content-src/asrouter/templates/OnboardingMessage/WhatsNewMessage.schema.json";
|
||||
const messages = PanelTestProvider.getMessages();
|
||||
|
||||
describe("PanelTestProvider", () => {
|
||||
it("should have a message", () => {
|
||||
// Careful: when changing this number make sure that new messages also go
|
||||
// through schema verifications.
|
||||
assert.lengthOf(messages, 7);
|
||||
assert.lengthOf(messages, 8);
|
||||
});
|
||||
it("should be a valid message", () => {
|
||||
const fxaMessages = messages.filter(
|
||||
|
@ -25,4 +26,14 @@ describe("PanelTestProvider", () => {
|
|||
assert.jsonSchema(message.content, update_schema);
|
||||
}
|
||||
});
|
||||
it("should be a valid message", () => {
|
||||
const whatsNewMessages = messages.filter(
|
||||
({ template }) => template === "whatsnew_panel_message"
|
||||
);
|
||||
for (let message of whatsNewMessages) {
|
||||
assert.jsonSchema(message.content, whats_new_schema);
|
||||
// Not part of `message.content` so it can't be enforced through schema
|
||||
assert.property(message, "order");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -948,12 +948,13 @@ describe("Reducers", () => {
|
|||
});
|
||||
assert.isTrue(state.feeds.loaded);
|
||||
});
|
||||
it("should set spoc_endpoint with DISCOVERY_STREAM_SPOCS_ENDPOINT", () => {
|
||||
it("should set spoc_endpoint and spocs_per_domain with DISCOVERY_STREAM_SPOCS_ENDPOINT", () => {
|
||||
const state = DiscoveryStream(undefined, {
|
||||
type: at.DISCOVERY_STREAM_SPOCS_ENDPOINT,
|
||||
data: "foo.com",
|
||||
data: { url: "foo.com", spocs_per_domain: 2 },
|
||||
});
|
||||
assert.equal(state.spocs.spocs_endpoint, "foo.com");
|
||||
assert.equal(state.spocs.spocs_per_domain, 2);
|
||||
});
|
||||
it("should set spocs with DISCOVERY_STREAM_SPOCS_UPDATE", () => {
|
||||
const data = {
|
||||
|
@ -966,6 +967,7 @@ describe("Reducers", () => {
|
|||
});
|
||||
assert.deepEqual(state.spocs, {
|
||||
spocs_endpoint: "",
|
||||
spocs_per_domain: 1,
|
||||
data: [1, 2, 3],
|
||||
lastUpdated: 123,
|
||||
loaded: true,
|
||||
|
|
|
@ -2,7 +2,7 @@ import {
|
|||
DSCard,
|
||||
DefaultMeta,
|
||||
PlaceholderDSCard,
|
||||
VariantMeta,
|
||||
CTAButtonMeta,
|
||||
} from "content-src/components/DiscoveryStreamComponents/DSCard/DSCard";
|
||||
import {
|
||||
DSContextFooter,
|
||||
|
@ -177,48 +177,54 @@ describe("<DSCard>", () => {
|
|||
assert.notOk(meta.find(".cta-link").exists());
|
||||
});
|
||||
|
||||
it("should render cta-link by default when item has cta", () => {
|
||||
it("should not render cta-link by default when item has cta and cta_variant not link", () => {
|
||||
wrapper.setProps({ cta: "test" });
|
||||
const meta = wrapper.find(DefaultMeta);
|
||||
assert.notOk(meta.find(".cta-link").exists());
|
||||
});
|
||||
|
||||
it("should render cta-link by default when item has cta and cta_variant as link", () => {
|
||||
wrapper.setProps({ cta: "test", cta_variant: "link" });
|
||||
const meta = wrapper.find(DefaultMeta);
|
||||
assert.equal(meta.find(".cta-link").text(), "test");
|
||||
});
|
||||
|
||||
it("should not render cta-button for non spoc content", () => {
|
||||
wrapper.setProps({ cta: "test", cta_variant: true });
|
||||
const meta = wrapper.find(VariantMeta);
|
||||
wrapper.setProps({ cta: "test", cta_variant: "button" });
|
||||
const meta = wrapper.find(CTAButtonMeta);
|
||||
assert.lengthOf(meta.find(".cta-button"), 0);
|
||||
});
|
||||
|
||||
it("should render cta-button when item has cta and cta button variant is true and is spoc", () => {
|
||||
it("should render cta-button when item has cta and cta_variant is button and is spoc", () => {
|
||||
wrapper.setProps({
|
||||
cta: "test",
|
||||
cta_variant: true,
|
||||
cta_variant: "button",
|
||||
context: "Sponsored by Foo",
|
||||
});
|
||||
const meta = wrapper.find(VariantMeta);
|
||||
const meta = wrapper.find(CTAButtonMeta);
|
||||
assert.equal(meta.find(".cta-button").text(), "test");
|
||||
});
|
||||
|
||||
it("should not render Sponsored by label in footer for spoc item with cta button variant", () => {
|
||||
it("should not render Sponsored by label in footer for spoc item with cta_variant button", () => {
|
||||
wrapper.setProps({
|
||||
cta: "test",
|
||||
context: "Sponsored by test",
|
||||
cta_variant: true,
|
||||
cta_variant: "button",
|
||||
});
|
||||
|
||||
assert.ok(wrapper.find(VariantMeta).exists());
|
||||
assert.ok(wrapper.find(CTAButtonMeta).exists());
|
||||
assert.notOk(wrapper.find(DSContextFooter).exists());
|
||||
});
|
||||
|
||||
it("should render sponsor text on top for spoc item and cta_variant true", () => {
|
||||
it("should render sponsor text on top for spoc item and cta button variant", () => {
|
||||
wrapper.setProps({
|
||||
sponsor: "Test",
|
||||
context: "Sponsored by test",
|
||||
cta_variant: true,
|
||||
cta_variant: "button",
|
||||
});
|
||||
|
||||
assert.ok(wrapper.find(VariantMeta).exists());
|
||||
const meta = wrapper.find(VariantMeta);
|
||||
assert.ok(wrapper.find(CTAButtonMeta).exists());
|
||||
const meta = wrapper.find(CTAButtonMeta);
|
||||
assert.equal(meta.find(".source").text(), "Test · Sponsored");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import { DSTextPromo } from "content-src/components/DiscoveryStreamComponents/DSTextPromo/DSTextPromo";
|
||||
import React from "react";
|
||||
import { shallow } from "enzyme";
|
||||
|
||||
describe("<DSTextPromo>", () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(<DSTextPromo />);
|
||||
});
|
||||
|
||||
it("should render", () => {
|
||||
assert.ok(wrapper.exists());
|
||||
assert.ok(wrapper.find(".ds-text-promo").exists());
|
||||
});
|
||||
|
||||
it("should render a header", () => {
|
||||
wrapper.setProps({ header: "foo" });
|
||||
assert.ok(wrapper.find(".text").exists());
|
||||
});
|
||||
|
||||
it("should render a subtitle", () => {
|
||||
wrapper.setProps({ subtitle: "foo" });
|
||||
assert.ok(wrapper.find(".subtitle").exists());
|
||||
});
|
||||
});
|
|
@ -7,6 +7,8 @@ describe("<ReturnToAMO>", () => {
|
|||
let onReady;
|
||||
let sandbox;
|
||||
let wrapper;
|
||||
let dummyNode;
|
||||
let fakeDocument;
|
||||
let sendUserActionTelemetryStub;
|
||||
let content;
|
||||
beforeEach(() => {
|
||||
|
@ -18,6 +20,19 @@ describe("<ReturnToAMO>", () => {
|
|||
primary_button: {},
|
||||
secondary_button: {},
|
||||
};
|
||||
dummyNode = document.createElement("body");
|
||||
sandbox.stub(dummyNode, "querySelector").returns(dummyNode);
|
||||
fakeDocument = {
|
||||
get activeElement() {
|
||||
return dummyNode;
|
||||
},
|
||||
get body() {
|
||||
return dummyNode;
|
||||
},
|
||||
getElementById() {
|
||||
return dummyNode;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -30,6 +45,7 @@ describe("<ReturnToAMO>", () => {
|
|||
|
||||
wrapper = mount(
|
||||
<ReturnToAMO
|
||||
document={fakeDocument}
|
||||
onReady={onReady}
|
||||
dispatch={dispatch}
|
||||
content={content}
|
||||
|
@ -52,6 +68,7 @@ describe("<ReturnToAMO>", () => {
|
|||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<ReturnToAMO
|
||||
document={fakeDocument}
|
||||
onReady={onReady}
|
||||
dispatch={dispatch}
|
||||
content={content}
|
||||
|
|
|
@ -5,6 +5,8 @@ import { StartupOverlay } from "content-src/asrouter/templates/StartupOverlay/St
|
|||
|
||||
describe("<StartupOverlay>", () => {
|
||||
let wrapper;
|
||||
let fakeDocument;
|
||||
let dummyNode;
|
||||
let dispatch;
|
||||
let onBlock;
|
||||
let sandbox;
|
||||
|
@ -13,7 +15,27 @@ describe("<StartupOverlay>", () => {
|
|||
dispatch = sandbox.stub();
|
||||
onBlock = sandbox.stub();
|
||||
|
||||
wrapper = mount(<StartupOverlay onBlock={onBlock} dispatch={dispatch} />);
|
||||
dummyNode = document.createElement("body");
|
||||
sandbox.stub(dummyNode, "querySelector").returns(dummyNode);
|
||||
fakeDocument = {
|
||||
get activeElement() {
|
||||
return dummyNode;
|
||||
},
|
||||
get body() {
|
||||
return dummyNode;
|
||||
},
|
||||
getElementById() {
|
||||
return dummyNode;
|
||||
},
|
||||
};
|
||||
|
||||
wrapper = mount(
|
||||
<StartupOverlay
|
||||
onBlock={onBlock}
|
||||
dispatch={dispatch}
|
||||
document={fakeDocument}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -22,7 +44,14 @@ describe("<StartupOverlay>", () => {
|
|||
|
||||
it("should add show class after mount and timeout", async () => {
|
||||
const clock = sandbox.useFakeTimers();
|
||||
wrapper = mount(<StartupOverlay onBlock={onBlock} dispatch={dispatch} />);
|
||||
// We need to mount here to trigger ComponentDidMount after the FakeTimers are added.
|
||||
wrapper = mount(
|
||||
<StartupOverlay
|
||||
onBlock={onBlock}
|
||||
dispatch={dispatch}
|
||||
document={fakeDocument}
|
||||
/>
|
||||
);
|
||||
assert.isFalse(
|
||||
wrapper.find(".overlay-wrapper").hasClass("show"),
|
||||
".overlay-wrapper does not have .show class"
|
||||
|
|
|
@ -20,6 +20,9 @@ describe("ToolbarPanelHub", () => {
|
|||
let waitForInitializedStub;
|
||||
let isBrowserPrivateStub;
|
||||
let fakeDispatch;
|
||||
let getEarliestRecordedDateStub;
|
||||
let getEventsByDateRangeStub;
|
||||
let handleUserActionStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.createSandbox();
|
||||
|
@ -58,6 +61,10 @@ describe("ToolbarPanelHub", () => {
|
|||
},
|
||||
};
|
||||
fakeWindow = {
|
||||
// eslint-disable-next-line object-shorthand
|
||||
DocumentFragment: function() {
|
||||
return fakeElementById;
|
||||
},
|
||||
document: fakeDocument,
|
||||
browser: {
|
||||
ownerDocument: fakeDocument,
|
||||
|
@ -94,6 +101,16 @@ describe("ToolbarPanelHub", () => {
|
|||
globals.set("PrivateBrowsingUtils", {
|
||||
isBrowserPrivate: isBrowserPrivateStub,
|
||||
});
|
||||
getEarliestRecordedDateStub = sandbox.stub();
|
||||
getEventsByDateRangeStub = sandbox.stub();
|
||||
globals.set("TrackingDBService", {
|
||||
getEarliestRecordedDate: getEarliestRecordedDateStub.returns(
|
||||
// A random date that's not the current timestamp
|
||||
new Date() - 500
|
||||
),
|
||||
getEventsByDateRange: getEventsByDateRangeStub.returns([]),
|
||||
});
|
||||
handleUserActionStub = sandbox.stub();
|
||||
});
|
||||
afterEach(() => {
|
||||
instance.uninit();
|
||||
|
@ -242,6 +259,7 @@ describe("ToolbarPanelHub", () => {
|
|||
instance.init(waitForInitializedStub, {
|
||||
getMessages: getMessagesStub,
|
||||
dispatch: fakeDispatch,
|
||||
handleUserAction: handleUserActionStub,
|
||||
});
|
||||
});
|
||||
it("should render messages to the panel on renderMessages()", async () => {
|
||||
|
@ -250,32 +268,50 @@ describe("ToolbarPanelHub", () => {
|
|||
);
|
||||
messages[0].content.link_text = { string_id: "link_text_id" };
|
||||
|
||||
getMessagesStub.returns([messages[0], messages[2], messages[1]]);
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
for (let message of messages) {
|
||||
assert.ok(
|
||||
createdElements.find(
|
||||
el =>
|
||||
el.tagName === "h2" && el.textContent === message.content.title
|
||||
)
|
||||
);
|
||||
assert.ok(
|
||||
createdElements.find(
|
||||
el => el.tagName === "p" && el.textContent === message.content.body
|
||||
)
|
||||
);
|
||||
assert.ok(createdElements.find(el => el.tagName === "h2"));
|
||||
if (message.content.layout === "tracking-protections") {
|
||||
assert.ok(createdElements.find(el => el.tagName === "h4"));
|
||||
}
|
||||
assert.ok(createdElements.find(el => el.tagName === "p"));
|
||||
}
|
||||
// Call the click handler to make coverage happy.
|
||||
eventListeners.click();
|
||||
assert.calledOnce(fakeWindow.ownerGlobal.openLinkIn);
|
||||
assert.calledOnce(handleUserActionStub);
|
||||
});
|
||||
it("should sort based on order field value", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m =>
|
||||
m.template === "whatsnew_panel_message" &&
|
||||
m.content.published_date === 1560969794394
|
||||
);
|
||||
|
||||
messages.forEach(m => (m.content.title = m.order));
|
||||
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
// Select the title elements that are supposed to be set to the same
|
||||
// value as the `order` field of the message
|
||||
const titleEls = createdElements
|
||||
.filter(
|
||||
el =>
|
||||
el.classList.add.firstCall &&
|
||||
el.classList.add.firstCall.args[0] === "whatsNew-message-title"
|
||||
)
|
||||
.map(el => el.textContent);
|
||||
assert.deepEqual(titleEls, [1, 2, 3]);
|
||||
});
|
||||
it("should accept string for image attributes", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
m => m.id === "WHATS_NEW_70_1"
|
||||
);
|
||||
getMessagesStub.returns([messages[0], messages[2], messages[1]]);
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
|
@ -289,19 +325,55 @@ describe("ToolbarPanelHub", () => {
|
|||
});
|
||||
it("should accept fluent ids for image attributes", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
m => m.id === "WHATS_NEW_70_1"
|
||||
);
|
||||
messages[0].content.icon_alt = { string_id: "foo" };
|
||||
getMessagesStub.returns([messages[0], messages[2], messages[1]]);
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
const imageEl = createdElements.find(el => el.tagName === "img");
|
||||
assert.calledOnce(fakeDocument.l10n.setAttributes);
|
||||
assert.calledWithExactly(fakeDocument.l10n.setAttributes, imageEl, "foo");
|
||||
});
|
||||
it("should accept fluent ids for elements attributes", async () => {
|
||||
const [message] = (await PanelTestProvider.getMessages()).filter(
|
||||
m =>
|
||||
m.template === "whatsnew_panel_message" &&
|
||||
m.content.layout === "tracking-protections"
|
||||
);
|
||||
getMessagesStub.returns([message]);
|
||||
instance.state.contentArguments = { foo: "foo", bar: "bar" };
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
const subtitle = createdElements.find(el => el.tagName === "h4");
|
||||
assert.calledWithExactly(
|
||||
fakeDocument.l10n.setAttributes,
|
||||
subtitle,
|
||||
message.content.subtitle.string_id,
|
||||
instance.state.contentArguments
|
||||
);
|
||||
});
|
||||
it("should correctly compute blocker trackers and date", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
getMessagesStub.returns(messages);
|
||||
getEventsByDateRangeStub.returns([
|
||||
{ getResultByName: sandbox.stub().returns(2) },
|
||||
{ getResultByName: sandbox.stub().returns(3) },
|
||||
]);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledWithExactly(
|
||||
fakeDocument.l10n.setAttributes,
|
||||
sinon.match.object,
|
||||
sinon.match.string,
|
||||
{ blockedCount: "5", earliestDate: getEarliestRecordedDateStub() }
|
||||
);
|
||||
});
|
||||
it("should only render unique dates (no duplicates)", async () => {
|
||||
instance._createDateElement = sandbox.stub();
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
|
@ -312,7 +384,13 @@ describe("ToolbarPanelHub", () => {
|
|||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.callCount(instance._createDateElement, uniqueDates.length);
|
||||
const dateElements = createdElements.filter(
|
||||
el =>
|
||||
el.tagName === "p" &&
|
||||
el.classList.add.firstCall &&
|
||||
el.classList.add.firstCall.args[0] === "whatsNew-message-date"
|
||||
);
|
||||
assert.lengthOf(dateElements, uniqueDates.length);
|
||||
});
|
||||
it("should listen for panelhidden and remove the toolbar button", async () => {
|
||||
getMessagesStub.returns([]);
|
||||
|
@ -492,6 +570,7 @@ describe("ToolbarPanelHub", () => {
|
|||
dispatch: fakeDispatch,
|
||||
getMessages: () =>
|
||||
onboardingMsgs.find(msg => msg.template === "protections_panel"),
|
||||
handleUserAction: handleUserActionStub,
|
||||
});
|
||||
});
|
||||
it("should remember it showed", async () => {
|
||||
|
@ -522,7 +601,17 @@ describe("ToolbarPanelHub", () => {
|
|||
|
||||
eventListeners.click();
|
||||
|
||||
assert.calledOnce(fakeWindow.ownerGlobal.openLinkIn);
|
||||
assert.calledOnce(handleUserActionStub);
|
||||
assert.calledWithExactly(handleUserActionStub, {
|
||||
target: fakeWindow,
|
||||
data: {
|
||||
type: "OPEN_URL",
|
||||
data: {
|
||||
args: sinon.match.string,
|
||||
where: "tabshifted",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче