Bug 1567271 - Newtab Pocket collections r=gvn

Differential Revision: https://phabricator.services.mozilla.com/D61741

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Scott 2020-02-12 21:14:01 +00:00
Родитель c151c6bcac
Коммит 5aef391647
19 изменённых файлов: 960 добавлений и 360 удалений

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

@ -66,7 +66,10 @@ const INITIAL_STATE = {
spocs_endpoint: "",
spocs_per_domain: 1,
lastUpdated: null,
data: {}, // {spocs: []}
data: {
// "spocs": {title: "", context: "", items: []},
// "placement1": {title: "", context: "", items: []},
},
loaded: false,
frequency_caps: [],
blocked: [],
@ -566,11 +569,18 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
const forPlacement = placement => {
const placementSpocs = data[placement.name];
if (!placementSpocs || !placementSpocs.length) {
if (
!placementSpocs ||
!placementSpocs.items ||
!placementSpocs.items.length
) {
return;
}
result[placement.name] = handleSites(placementSpocs);
result[placement.name] = {
...placementSpocs,
items: handleSites(placementSpocs.items),
};
};
if (!placements || !placements.length) {

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

@ -4,6 +4,7 @@
import { actionCreators as ac } from "common/Actions.jsm";
import { CardGrid } from "content-src/components/DiscoveryStreamComponents/CardGrid/CardGrid";
import { CollectionCardGrid } from "content-src/components/DiscoveryStreamComponents/CollectionCardGrid/CollectionCardGrid";
import { CollapsibleSection } from "content-src/components/CollapsibleSection/CollapsibleSection";
import { connect } from "react-redux";
import { DSDismiss } from "content-src/components/DiscoveryStreamComponents/DSDismiss/DSDismiss";
@ -207,6 +208,35 @@ export class _DiscoveryStreamBase extends React.PureComponent {
header={component.header}
/>
);
case "CollectionCardGrid":
if (
!component.data ||
!component.data.spocs ||
!component.data.spocs[0] ||
// We only display complete collections.
component.data.spocs.length < 3
) {
return null;
}
return (
<DSDismiss
dispatch={this.props.dispatch}
shouldSendImpressionStats={true}
extraClasses={`ds-dismiss-ds-collection`}
>
<CollectionCardGrid
placement={component.placement}
data={component.data}
feed={component.feed}
border={component.properties.border}
type={component.type}
dispatch={this.props.dispatch}
items={component.properties.items}
cta_variant={component.cta_variant}
display_engagement_labels={ENGAGEMENT_LABEL_ENABLED}
/>
</DSDismiss>
);
case "CardGrid":
return (
<CardGrid

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

@ -21,11 +21,21 @@ $ds-width: 936px;
.ds-column-grid {
display: grid;
grid-row-gap: var(--gridRowGap);
// We want to completely hide components with no content,
// otherwise, it creates grid-row-gap gaps around nothing.
> div:empty {
display: none;
}
}
}
.ds-header {
margin: 8px 0;
.ds-context {
font-weight: 400;
}
}
.ds-header,

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

@ -78,7 +78,12 @@ export class CardGrid extends React.PureComponent {
return (
<div>
{this.props.title && (
<div className="ds-header">{this.props.title}</div>
<div className="ds-header">
<div>{this.props.title}</div>
{this.props.context && (
<div className="ds-context">{this.props.context}</div>
)}
</div>
)}
{isEmpty ? (
<div className="ds-card-grid empty">

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

@ -0,0 +1,50 @@
/* 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 { CardGrid } from "content-src/components/DiscoveryStreamComponents/CardGrid/CardGrid";
import React from "react";
import { connect } from "react-redux";
export class _CollectionCardGrid extends React.PureComponent {
render() {
const { placement, DiscoveryStream, data, feed } = this.props;
// Handle a render before feed has been fetched by displaying nothing
if (!data) {
return null;
}
const { title, context } = DiscoveryStream.spocs.data[placement.name] || {};
// Generally a card grid displays recs with spocs already injected.
// Normally it doesn't care which rec is a spoc and which isn't,
// it just displays content in a grid.
// For collections, we're only displaying a list of spocs.
// We don't need to tell the card grid that our list of cards are spocs,
// it shouldn't need to care. So we just pass our spocs along as recs.
// Think of it as injecting all rec positions with spocs.
// Consider maybe making recommendations in CardGrid use a more generic name.
const recsData = {
recommendations: data.spocs,
};
return (
<div className="ds-collection-card-grid">
<CardGrid
title={title}
context={context}
data={recsData}
feed={feed}
border={this.props.border}
type={this.props.type}
dispatch={this.props.dispatch}
items={this.props.items}
/>
</div>
);
}
}
export const CollectionCardGrid = connect(state => ({
DiscoveryStream: state.DiscoveryStream,
}))(_CollectionCardGrid);

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

@ -0,0 +1,11 @@
.ds-dismiss-ds-collection {
.ds-dismiss-button {
margin: 0;
}
}
.ds-collection-card-grid {
.story-footer {
display: none;
}
}

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

@ -1,19 +1,10 @@
.ds-dismiss {
position: relative;
overflow: hidden;
border-radius: 8px;
transition-delay: 100ms;
transition-duration: 200ms;
transition-property: background;
&.hovering {
@include dark-theme-only {
background: $grey-90-30;
}
background: $grey-90-10;
}
&:hover {
.ds-dismiss-button {
opacity: 1;
@ -34,10 +25,9 @@
align-items: center;
justify-content: center;
position: absolute;
right: 0;
inset-inline-end: 0;
top: 0;
border-radius: 50%;
margin: 18px 18px 0 0;
background: $grey-90-10;
&:hover {

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

@ -1,6 +1,20 @@
.ds-dismiss-ds-text-promo {
max-width: 744px;
margin: auto;
overflow: hidden;
&.hovering {
@include dark-theme-only {
background: $grey-90-30;
}
background: $grey-90-10;
}
.ds-dismiss-button {
margin-inline: 0 18px;
margin-block: 18px 0;
}
}
.ds-text-promo {

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

@ -82,7 +82,9 @@ export const selectLayoutRender = ({
return {
...component,
data: {
spocs: [],
spocs: {
items: [],
},
},
};
}
@ -114,11 +116,16 @@ export const selectLayoutRender = ({
const placementName = placement.name || "spocs";
const spocsData = spocs.data[placementName];
// We expect a spoc, spocs are loaded, and the server returned spocs.
if (spocs.loaded && spocsData && spocsData.length) {
if (
spocs.loaded &&
spocsData &&
spocsData.items &&
spocsData.items.length
) {
result = rollForSpocs(
result,
component.spocs,
spocsData,
spocsData.items,
placementName
);
}
@ -232,7 +239,12 @@ export const selectLayoutRender = ({
// all other SPOCS that never went through the probabilistic selection, its reason will
// be "out_of_position".
let spocsFill = [];
if (spocs.loaded && feeds.loaded && spocs.data.spocs) {
if (
spocs.loaded &&
feeds.loaded &&
spocs.data.spocs &&
spocs.data.spocs.items
) {
const chosenSpocsFill = [...chosenSpocs].map(spoc => ({
id: spoc.id,
reason: "n/a",
@ -247,7 +259,7 @@ export const selectLayoutRender = ({
displayed: 0,
full_recalc: 0,
}));
const outOfPositionSpocsFill = spocs.data.spocs
const outOfPositionSpocsFill = spocs.data.spocs.items
.slice(spocIndexMap.spocs)
.filter(spoc => !unchosenSpocs.has(spoc))
.map(spoc => ({

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

@ -148,6 +148,7 @@ input {
// Discovery Stream Components
@import '../components/DiscoveryStreamComponents/CardGrid/CardGrid';
@import '../components/DiscoveryStreamComponents/CollectionCardGrid/CollectionCardGrid';
@import '../components/DiscoveryStreamComponents/Hero/Hero';
@import '../components/DiscoveryStreamComponents/Highlights/Highlights';
@import '../components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule';

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

@ -1885,9 +1885,13 @@ main {
.discovery-stream.ds-layout .ds-column-grid {
display: grid;
grid-row-gap: var(--gridRowGap); }
.discovery-stream.ds-layout .ds-column-grid > div:empty {
display: none; }
.ds-header {
margin: 8px 0; }
.ds-header .ds-context {
font-weight: 400; }
.ds-header,
.ds-layout .section-title span {
@ -1984,6 +1988,12 @@ main {
.ds-card-grid.empty {
grid-template-columns: auto; }
.ds-dismiss-ds-collection .ds-dismiss-button {
margin: 0; }
.ds-collection-card-grid .story-footer {
display: none; }
.ds-hero {
position: relative; }
.ds-hero header {
@ -2915,15 +2925,10 @@ main {
.ds-dismiss {
position: relative;
overflow: hidden;
border-radius: 8px;
transition-delay: 100ms;
transition-duration: 200ms;
transition-property: background; }
.ds-dismiss.hovering {
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss.hovering {
background: rgba(12, 12, 13, 0.3); }
.ds-dismiss:hover .ds-dismiss-button {
opacity: 1; }
.ds-dismiss .ds-dismiss-button {
@ -2936,10 +2941,9 @@ main {
align-items: center;
justify-content: center;
position: absolute;
right: 0;
inset-inline-end: 0;
top: 0;
border-radius: 50%;
margin: 18px 18px 0 0;
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss .ds-dismiss-button {
background: rgba(12, 12, 13, 0.3); }
@ -3070,7 +3074,15 @@ main {
.ds-dismiss-ds-text-promo {
max-width: 744px;
margin: auto; }
margin: auto;
overflow: hidden; }
.ds-dismiss-ds-text-promo.hovering {
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss-ds-text-promo.hovering {
background: rgba(12, 12, 13, 0.3); }
.ds-dismiss-ds-text-promo .ds-dismiss-button {
margin-inline: 0 18px;
margin-block: 18px 0; }
.ds-text-promo {
max-width: 640px;

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

@ -1888,9 +1888,13 @@ main {
.discovery-stream.ds-layout .ds-column-grid {
display: grid;
grid-row-gap: var(--gridRowGap); }
.discovery-stream.ds-layout .ds-column-grid > div:empty {
display: none; }
.ds-header {
margin: 8px 0; }
.ds-header .ds-context {
font-weight: 400; }
.ds-header,
.ds-layout .section-title span {
@ -1987,6 +1991,12 @@ main {
.ds-card-grid.empty {
grid-template-columns: auto; }
.ds-dismiss-ds-collection .ds-dismiss-button {
margin: 0; }
.ds-collection-card-grid .story-footer {
display: none; }
.ds-hero {
position: relative; }
.ds-hero header {
@ -2918,15 +2928,10 @@ main {
.ds-dismiss {
position: relative;
overflow: hidden;
border-radius: 8px;
transition-delay: 100ms;
transition-duration: 200ms;
transition-property: background; }
.ds-dismiss.hovering {
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss.hovering {
background: rgba(12, 12, 13, 0.3); }
.ds-dismiss:hover .ds-dismiss-button {
opacity: 1; }
.ds-dismiss .ds-dismiss-button {
@ -2939,10 +2944,9 @@ main {
align-items: center;
justify-content: center;
position: absolute;
right: 0;
inset-inline-end: 0;
top: 0;
border-radius: 50%;
margin: 18px 18px 0 0;
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss .ds-dismiss-button {
background: rgba(12, 12, 13, 0.3); }
@ -3073,7 +3077,15 @@ main {
.ds-dismiss-ds-text-promo {
max-width: 744px;
margin: auto; }
margin: auto;
overflow: hidden; }
.ds-dismiss-ds-text-promo.hovering {
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss-ds-text-promo.hovering {
background: rgba(12, 12, 13, 0.3); }
.ds-dismiss-ds-text-promo .ds-dismiss-button {
margin-inline: 0 18px;
margin-block: 18px 0; }
.ds-text-promo {
max-width: 640px;

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

@ -1885,9 +1885,13 @@ main {
.discovery-stream.ds-layout .ds-column-grid {
display: grid;
grid-row-gap: var(--gridRowGap); }
.discovery-stream.ds-layout .ds-column-grid > div:empty {
display: none; }
.ds-header {
margin: 8px 0; }
.ds-header .ds-context {
font-weight: 400; }
.ds-header,
.ds-layout .section-title span {
@ -1984,6 +1988,12 @@ main {
.ds-card-grid.empty {
grid-template-columns: auto; }
.ds-dismiss-ds-collection .ds-dismiss-button {
margin: 0; }
.ds-collection-card-grid .story-footer {
display: none; }
.ds-hero {
position: relative; }
.ds-hero header {
@ -2915,15 +2925,10 @@ main {
.ds-dismiss {
position: relative;
overflow: hidden;
border-radius: 8px;
transition-delay: 100ms;
transition-duration: 200ms;
transition-property: background; }
.ds-dismiss.hovering {
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss.hovering {
background: rgba(12, 12, 13, 0.3); }
.ds-dismiss:hover .ds-dismiss-button {
opacity: 1; }
.ds-dismiss .ds-dismiss-button {
@ -2936,10 +2941,9 @@ main {
align-items: center;
justify-content: center;
position: absolute;
right: 0;
inset-inline-end: 0;
top: 0;
border-radius: 50%;
margin: 18px 18px 0 0;
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss .ds-dismiss-button {
background: rgba(12, 12, 13, 0.3); }
@ -3070,7 +3074,15 @@ main {
.ds-dismiss-ds-text-promo {
max-width: 744px;
margin: auto; }
margin: auto;
overflow: hidden; }
.ds-dismiss-ds-text-promo.hovering {
background: rgba(12, 12, 13, 0.1); }
[lwt-newtab-brighttext] .ds-dismiss-ds-text-promo.hovering {
background: rgba(12, 12, 13, 0.3); }
.ds-dismiss-ds-text-promo .ds-dismiss-button {
margin-inline: 0 18px;
margin-block: 18px 0; }
.ds-text-promo {
max-width: 640px;

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

@ -93,7 +93,7 @@
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
/* harmony import */ var content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(77);
/* harmony import */ var content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(78);
/* harmony import */ var content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
@ -101,7 +101,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(12);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(81);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(82);
/* 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/. */
@ -566,11 +566,11 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(31);
/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(48);
/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(49);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(76);
/* harmony import */ var content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(59);
/* harmony import */ var content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(77);
/* harmony import */ var content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(60);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -1999,16 +1999,16 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ASRouterUISurface", function() { return ASRouterUISurface; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(80);
/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(81);
/* harmony import */ var _components_ImpressionsWrapper_ImpressionsWrapper__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(78);
/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(79);
/* harmony import */ var content_src_lib_constants__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(11);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(12);
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var _templates_template_manifest__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(79);
/* harmony import */ var _templates_FirstRun_FirstRun__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(82);
/* harmony import */ var _templates_template_manifest__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(80);
/* harmony import */ var _templates_FirstRun_FirstRun__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(83);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -2844,10 +2844,10 @@ module.exports = {"title":"EOYSnippet","description":"Fundraising Snippet","vers
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "convertLinks", function() { return convertLinks; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RichText", function() { return RichText; });
/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(78);
/* harmony import */ var fluent_react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(79);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(80);
/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(81);
/* harmony import */ var _template_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(15);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@ -4091,23 +4091,24 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DiscoveryStreamBase", function() { return DiscoveryStreamBase; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_CardGrid_CardGrid__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(32);
/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(47);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSDismiss_DSDismiss__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(52);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSMessage_DSMessage__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(53);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSPrivacyModal_DSPrivacyModal__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(54);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSTextPromo_DSTextPromo__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(55);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_Hero_Hero__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(56);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_Highlights_Highlights__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(58);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_HorizontalRule_HorizontalRule__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(71);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_List_List__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(57);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_Navigation_Navigation__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(72);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_13__);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_SectionTitle_SectionTitle__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(73);
/* harmony import */ var content_src_lib_selectLayoutRender__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(74);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(75);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_CollectionCardGrid_CollectionCardGrid__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(47);
/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(48);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSDismiss_DSDismiss__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(53);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSMessage_DSMessage__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(54);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSPrivacyModal_DSPrivacyModal__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(55);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_DSTextPromo_DSTextPromo__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(56);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_Hero_Hero__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(57);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_Highlights_Highlights__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(59);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_HorizontalRule_HorizontalRule__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(72);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_List_List__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(58);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_Navigation_Navigation__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(73);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_14___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_14__);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_SectionTitle_SectionTitle__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(74);
/* harmony import */ var content_src_lib_selectLayoutRender__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(75);
/* harmony import */ var content_src_components_DiscoveryStreamComponents_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(76);
/* 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/. */
@ -4128,6 +4129,7 @@ __webpack_require__.r(__webpack_exports__);
const ALLOWED_CSS_URL_PREFIXES = ["chrome://", "resource://", "https://img-getpocket.cdn.mozilla.net/"];
const DUMMY_CSS_SELECTOR = "DUMMY#CSS.SELECTOR";
let rollCache = []; // Cache of random probability values for a spoc position
@ -4148,7 +4150,7 @@ function isAllowedCSS(property, value) {
const urls = value.match(/url\("[^"]+"\)/g);
return !urls || urls.every(url => ALLOWED_CSS_URL_PREFIXES.some(prefix => url.slice(5).startsWith(prefix)));
}
class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a.PureComponent {
class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_14___default.a.PureComponent {
constructor(props) {
super(props);
this.onStyleMount = this.onStyleMount.bind(this);
@ -4207,7 +4209,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
switch (component.type) {
case "Highlights":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_Highlights_Highlights__WEBPACK_IMPORTED_MODULE_9__["Highlights"], null);
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_Highlights_Highlights__WEBPACK_IMPORTED_MODULE_10__["Highlights"], null);
case "TopSites":
let promoAlignment;
@ -4216,7 +4218,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
promoAlignment = component.spocs.positions[0].index === 0 ? "left" : "right";
}
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_16__["TopSites"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_17__["TopSites"], {
header: component.header,
data: component.data,
promoAlignment: promoAlignment
@ -4241,7 +4243,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
id,
shim
} = spoc;
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSDismiss_DSDismiss__WEBPACK_IMPORTED_MODULE_4__["DSDismiss"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSDismiss_DSDismiss__WEBPACK_IMPORTED_MODULE_5__["DSDismiss"], {
data: {
url: spoc.url,
guid: spoc.id,
@ -4250,7 +4252,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
dispatch: this.props.dispatch,
shouldSendImpressionStats: true,
extraClasses: `ds-dismiss-ds-text-promo`
}, react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSTextPromo_DSTextPromo__WEBPACK_IMPORTED_MODULE_7__["DSTextPromo"], {
}, react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSTextPromo_DSTextPromo__WEBPACK_IMPORTED_MODULE_8__["DSTextPromo"], {
dispatch: this.props.dispatch,
image: image_src,
raw_image_src: raw_image_src,
@ -4267,7 +4269,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
}));
case "Message":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSMessage_DSMessage__WEBPACK_IMPORTED_MODULE_5__["DSMessage"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSMessage_DSMessage__WEBPACK_IMPORTED_MODULE_6__["DSMessage"], {
title: component.header && component.header.title,
subtitle: component.header && component.header.subtitle,
link_text: component.header && component.header.link_text,
@ -4276,19 +4278,41 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
});
case "SectionTitle":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_SectionTitle_SectionTitle__WEBPACK_IMPORTED_MODULE_14__["SectionTitle"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_SectionTitle_SectionTitle__WEBPACK_IMPORTED_MODULE_15__["SectionTitle"], {
header: component.header
});
case "Navigation":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_Navigation_Navigation__WEBPACK_IMPORTED_MODULE_12__["Navigation"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_Navigation_Navigation__WEBPACK_IMPORTED_MODULE_13__["Navigation"], {
links: component.properties.links,
alignment: component.properties.alignment,
header: component.header
});
case "CollectionCardGrid":
if (!component.data || !component.data.spocs || !component.data.spocs[0] || // We only display complete collections.
component.data.spocs.length < 3) {
return null;
}
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSDismiss_DSDismiss__WEBPACK_IMPORTED_MODULE_5__["DSDismiss"], {
dispatch: this.props.dispatch,
shouldSendImpressionStats: true,
extraClasses: `ds-dismiss-ds-collection`
}, react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_CollectionCardGrid_CollectionCardGrid__WEBPACK_IMPORTED_MODULE_2__["CollectionCardGrid"], {
placement: component.placement,
data: component.data,
feed: component.feed,
border: component.properties.border,
type: component.type,
dispatch: this.props.dispatch,
items: component.properties.items,
cta_variant: component.cta_variant,
display_engagement_labels: ENGAGEMENT_LABEL_ENABLED
}));
case "CardGrid":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_CardGrid_CardGrid__WEBPACK_IMPORTED_MODULE_1__["CardGrid"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_CardGrid_CardGrid__WEBPACK_IMPORTED_MODULE_1__["CardGrid"], {
title: component.header && component.header.title,
data: component.data,
feed: component.feed,
@ -4301,7 +4325,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
});
case "Hero":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_Hero_Hero__WEBPACK_IMPORTED_MODULE_8__["Hero"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_Hero_Hero__WEBPACK_IMPORTED_MODULE_9__["Hero"], {
subComponentType: embedWidth >= 9 ? `cards` : `list`,
feed: component.feed,
title: component.header && component.header.title,
@ -4313,10 +4337,10 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
});
case "HorizontalRule":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_HorizontalRule_HorizontalRule__WEBPACK_IMPORTED_MODULE_10__["HorizontalRule"], null);
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_HorizontalRule_HorizontalRule__WEBPACK_IMPORTED_MODULE_11__["HorizontalRule"], null);
case "List":
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_List_List__WEBPACK_IMPORTED_MODULE_11__["List"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_List_List__WEBPACK_IMPORTED_MODULE_12__["List"], {
data: component.data,
feed: component.feed,
fullWidth: component.properties.full_width,
@ -4329,7 +4353,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
});
default:
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement("div", null, component.type);
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement("div", null, component.type);
}
}
@ -4337,7 +4361,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
// Use json string as both the key and styles to render so React knows when
// to unmount and mount a new instance for new styles.
const json = JSON.stringify(styles);
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement("style", {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement("style", {
key: json,
"data-styles": json,
ref: this.onStyleMount
@ -4355,7 +4379,7 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
const {
layoutRender,
spocsFill
} = Object(content_src_lib_selectLayoutRender__WEBPACK_IMPORTED_MODULE_15__["selectLayoutRender"])({
} = Object(content_src_lib_selectLayoutRender__WEBPACK_IMPORTED_MODULE_16__["selectLayoutRender"])({
state: this.props.DiscoveryStream,
prefs: this.props.Prefs.values,
rollCache,
@ -4417,12 +4441,12 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
}
}; // Render a DS-style TopSites then the rest if any in a collapsible section
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_13___default.a.Fragment, null, this.props.DiscoveryStream.isPrivacyInfoModalVisible && react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSPrivacyModal_DSPrivacyModal__WEBPACK_IMPORTED_MODULE_6__["DSPrivacyModal"], {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_14___default.a.Fragment, null, this.props.DiscoveryStream.isPrivacyInfoModalVisible && react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_DiscoveryStreamComponents_DSPrivacyModal_DSPrivacyModal__WEBPACK_IMPORTED_MODULE_7__["DSPrivacyModal"], {
dispatch: this.props.dispatch
}), topSites && this.renderLayout([{
width: 12,
components: [topSites]
}]), !!layoutRender.length && react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement(content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__["CollapsibleSection"], {
}]), !!layoutRender.length && react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement(content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_3__["CollapsibleSection"], {
className: "ds-layout",
collapsed: topStories.pref.collapsed,
dispatch: this.props.dispatch,
@ -4448,12 +4472,12 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
renderLayout(layoutRender) {
const styles = [];
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement("div", {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement("div", {
className: "discovery-stream ds-layout"
}, layoutRender.map((row, rowIndex) => react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement("div", {
}, layoutRender.map((row, rowIndex) => react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement("div", {
key: `row-${rowIndex}`,
className: `ds-column ds-column-${row.width}`
}, react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement("div", {
}, react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement("div", {
className: "ds-column-grid"
}, row.components.map((component, componentIndex) => {
if (!component) {
@ -4461,14 +4485,14 @@ class _DiscoveryStreamBase extends react__WEBPACK_IMPORTED_MODULE_13___default.a
}
styles[rowIndex] = [...(styles[rowIndex] || []), component.styles];
return react__WEBPACK_IMPORTED_MODULE_13___default.a.createElement("div", {
return react__WEBPACK_IMPORTED_MODULE_14___default.a.createElement("div", {
key: `component-${componentIndex}`
}, this.renderComponent(component, row.width));
})))), this.renderStyles(styles));
}
}
const DiscoveryStreamBase = Object(react_redux__WEBPACK_IMPORTED_MODULE_3__["connect"])(state => ({
const DiscoveryStreamBase = Object(react_redux__WEBPACK_IMPORTED_MODULE_4__["connect"])(state => ({
DiscoveryStream: state.DiscoveryStream,
Prefs: state.Prefs,
Sections: state.Sections,
@ -4554,7 +4578,9 @@ class CardGrid extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComponen
const isEmpty = data.recommendations.length === 0;
return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", null, this.props.title && react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
className: "ds-header"
}, this.props.title), isEmpty ? react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
}, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", null, this.props.title), this.props.context && react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
className: "ds-context"
}, this.props.context)), isEmpty ? react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
className: "ds-card-grid empty"
}, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(_DSEmptyState_DSEmptyState_jsx__WEBPACK_IMPORTED_MODULE_1__["DSEmptyState"], {
status: data.status,
@ -6325,16 +6351,82 @@ class DSEmptyState extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComp
/* 47 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_CollectionCardGrid", function() { return _CollectionCardGrid; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CollectionCardGrid", function() { return CollectionCardGrid; });
/* harmony import */ var content_src_components_DiscoveryStreamComponents_CardGrid_CardGrid__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(32);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_2__);
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
class _CollectionCardGrid extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
render() {
const {
placement,
DiscoveryStream,
data,
feed
} = this.props; // Handle a render before feed has been fetched by displaying nothing
if (!data) {
return null;
}
const {
title,
context
} = DiscoveryStream.spocs.data[placement.name] || {}; // Generally a card grid displays recs with spocs already injected.
// Normally it doesn't care which rec is a spoc and which isn't,
// it just displays content in a grid.
// For collections, we're only displaying a list of spocs.
// We don't need to tell the card grid that our list of cards are spocs,
// it shouldn't need to care. So we just pass our spocs along as recs.
// Think of it as injecting all rec positions with spocs.
// Consider maybe making recommendations in CardGrid use a more generic name.
const recsData = {
recommendations: data.spocs
};
return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
className: "ds-collection-card-grid"
}, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(content_src_components_DiscoveryStreamComponents_CardGrid_CardGrid__WEBPACK_IMPORTED_MODULE_0__["CardGrid"], {
title: title,
context: context,
data: recsData,
feed: feed,
border: this.props.border,
type: this.props.type,
dispatch: this.props.dispatch,
items: this.props.items
}));
}
}
const CollectionCardGrid = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(state => ({
DiscoveryStream: state.DiscoveryStream
}))(_CollectionCardGrid);
/***/ }),
/* 48 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CollapsibleSection", function() { return CollapsibleSection; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(48);
/* harmony import */ var content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(49);
/* harmony import */ var content_src_components_FluentOrText_FluentOrText__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(45);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var content_src_components_SectionMenu_SectionMenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(50);
/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(51);
/* harmony import */ var content_src_components_SectionMenu_SectionMenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(51);
/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(52);
/* harmony import */ var content_src_components_ContextMenu_ContextMenuButton__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(39);
/* 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,
@ -6611,14 +6703,14 @@ CollapsibleSection.defaultProps = {
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
/* 48 */
/* 49 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ErrorBoundaryFallback", function() { return ErrorBoundaryFallback; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ErrorBoundary", function() { return ErrorBoundary; });
/* harmony import */ var content_src_components_A11yLinkButton_A11yLinkButton__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(49);
/* harmony import */ var content_src_components_A11yLinkButton_A11yLinkButton__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(50);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -6698,7 +6790,7 @@ ErrorBoundary.defaultProps = {
};
/***/ }),
/* 49 */
/* 50 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -6728,7 +6820,7 @@ function A11yLinkButton(props) {
}
/***/ }),
/* 50 */
/* 51 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -6739,7 +6831,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var content_src_components_ContextMenu_ContextMenu__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(37);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(51);
/* harmony import */ var content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(52);
/* 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/. */
@ -6834,7 +6926,7 @@ class _SectionMenu extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComp
const SectionMenu = _SectionMenu;
/***/ }),
/* 51 */
/* 52 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -6964,7 +7056,7 @@ const SectionMenuOptions = {
};
/***/ }),
/* 52 */
/* 53 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7046,7 +7138,7 @@ class DSDismiss extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCompone
}
/***/ }),
/* 53 */
/* 54 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7088,7 +7180,7 @@ class DSMessage extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCompone
}
/***/ }),
/* 54 */
/* 55 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7163,7 +7255,7 @@ class DSPrivacyModal extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCo
}
/***/ }),
/* 55 */
/* 56 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7241,7 +7333,7 @@ class DSTextPromo extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureCompo
}
/***/ }),
/* 56 */
/* 57 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7253,7 +7345,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _DSImage_DSImage_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(34);
/* harmony import */ var _DSLinkMenu_DSLinkMenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(35);
/* harmony import */ var _DiscoveryStreamImpressionStats_ImpressionStats__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(40);
/* harmony import */ var _List_List_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(57);
/* harmony import */ var _List_List_jsx__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(58);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_7__);
/* harmony import */ var _SafeAnchor_SafeAnchor__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(41);
@ -7434,7 +7526,7 @@ Hero.defaultProps = {
};
/***/ }),
/* 57 */
/* 58 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7638,7 +7730,7 @@ const List = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])(state =
}))(_List);
/***/ }),
/* 58 */
/* 59 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7649,7 +7741,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(59);
/* harmony import */ var content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(60);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -7679,7 +7771,7 @@ const Highlights = Object(react_redux__WEBPACK_IMPORTED_MODULE_0__["connect"])(s
}))(_Highlights);
/***/ }),
/* 59 */
/* 60 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -7689,18 +7781,18 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Sections", function() { return _Sections; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sections", function() { return Sections; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(60);
/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(47);
/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(62);
/* harmony import */ var content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(61);
/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(48);
/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(63);
/* harmony import */ var content_src_components_FluentOrText_FluentOrText__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(45);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var content_src_components_MoreRecommendations_MoreRecommendations__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(64);
/* harmony import */ var content_src_components_PocketLoggedInCta_PocketLoggedInCta__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(65);
/* harmony import */ var content_src_components_MoreRecommendations_MoreRecommendations__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(65);
/* harmony import */ var content_src_components_PocketLoggedInCta_PocketLoggedInCta__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(66);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_8__);
/* harmony import */ var content_src_components_Topics_Topics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(66);
/* harmony import */ var content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(67);
/* harmony import */ var content_src_components_Topics_Topics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(67);
/* harmony import */ var content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(68);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -8050,7 +8142,7 @@ const Sections = Object(react_redux__WEBPACK_IMPORTED_MODULE_5__["connect"])(sta
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
/* 60 */
/* 61 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -8066,7 +8158,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var content_src_components_LinkMenu_LinkMenu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(36);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(61);
/* harmony import */ var content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(62);
/* 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/. */
@ -8395,7 +8487,7 @@ const PlaceholderCard = props => react__WEBPACK_IMPORTED_MODULE_5___default.a.cr
});
/***/ }),
/* 61 */
/* 62 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -8464,14 +8556,14 @@ const ScreenshotUtils = {
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
/* 62 */
/* 63 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ComponentPerfTimer", function() { return ComponentPerfTimer; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(63);
/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(64);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__);
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -8644,7 +8736,7 @@ class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Co
}
/***/ }),
/* 63 */
/* 64 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -8776,7 +8868,7 @@ _PerfService.prototype = {
var perfService = new _PerfService();
/***/ }),
/* 64 */
/* 65 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -8808,7 +8900,7 @@ class MoreRecommendations extends react__WEBPACK_IMPORTED_MODULE_0___default.a.P
}
/***/ }),
/* 65 */
/* 66 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -8851,7 +8943,7 @@ const PocketLoggedInCta = Object(react_redux__WEBPACK_IMPORTED_MODULE_0__["conne
}))(_PocketLoggedInCta);
/***/ }),
/* 66 */
/* 67 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -8896,7 +8988,7 @@ class Topics extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent
}
/***/ }),
/* 67 */
/* 68 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -8904,18 +8996,18 @@ __webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_TopSites", function() { return _TopSites; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSites", function() { return TopSites; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(68);
/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(47);
/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(62);
/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69);
/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(48);
/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(63);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _asrouter_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(21);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _SearchShortcutsForm__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(69);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(81);
/* harmony import */ var _TopSiteForm__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(83);
/* harmony import */ var _TopSite__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(70);
/* harmony import */ var _SearchShortcutsForm__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(70);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(82);
/* harmony import */ var _TopSiteForm__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(84);
/* harmony import */ var _TopSite__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(71);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -9123,7 +9215,7 @@ const TopSites = Object(react_redux__WEBPACK_IMPORTED_MODULE_4__["connect"])((st
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
/* 68 */
/* 69 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -9148,7 +9240,7 @@ const MIN_RICH_FAVICON_SIZE = 96; // minimum size necessary to show any icon in
const MIN_CORNER_FAVICON_SIZE = 16;
/***/ }),
/* 69 */
/* 70 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -9158,7 +9250,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(68);
/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69);
/* 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/. */
@ -9339,7 +9431,7 @@ class SearchShortcutsForm extends react__WEBPACK_IMPORTED_MODULE_1___default.a.P
}
/***/ }),
/* 70 */
/* 71 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -9349,13 +9441,13 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSitePlaceholder", function() { return TopSitePlaceholder; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSiteList", function() { return TopSiteList; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(68);
/* harmony import */ var _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69);
/* harmony import */ var content_src_components_LinkMenu_LinkMenu__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(36);
/* harmony import */ var _DiscoveryStreamImpressionStats_ImpressionStats__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(40);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(61);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(81);
/* harmony import */ var content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(62);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(82);
/* harmony import */ var content_src_components_ContextMenu_ContextMenuButton__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(39);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@ -10016,7 +10108,7 @@ class TopSiteList extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
}
/***/ }),
/* 71 */
/* 72 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -10038,7 +10130,7 @@ class HorizontalRule extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCo
}
/***/ }),
/* 72 */
/* 73 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -10093,7 +10185,7 @@ class Navigation extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCompon
}
/***/ }),
/* 73 */
/* 74 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -10125,7 +10217,7 @@ class SectionTitle extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
}
/***/ }),
/* 74 */
/* 75 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -10212,7 +10304,9 @@ const selectLayoutRender = ({
// TODO we now need a placeholder for topsites and textPromo.
return { ...component,
data: {
spocs: []
spocs: {
items: []
}
}
};
}
@ -10246,8 +10340,8 @@ const selectLayoutRender = ({
const placementName = placement.name || "spocs";
const spocsData = spocs.data[placementName]; // We expect a spoc, spocs are loaded, and the server returned spocs.
if (spocs.loaded && spocsData && spocsData.length) {
result = rollForSpocs(result, component.spocs, spocsData, placementName);
if (spocs.loaded && spocsData && spocsData.items && spocsData.items.length) {
result = rollForSpocs(result, component.spocs, spocsData.items, placementName);
}
}
@ -10349,7 +10443,7 @@ const selectLayoutRender = ({
let spocsFill = [];
if (spocs.loaded && feeds.loaded && spocs.data.spocs) {
if (spocs.loaded && feeds.loaded && spocs.data.spocs && spocs.data.spocs.items) {
const chosenSpocsFill = [...chosenSpocs].map(spoc => ({
id: spoc.id,
reason: "n/a",
@ -10362,7 +10456,7 @@ const selectLayoutRender = ({
displayed: 0,
full_recalc: 0
}));
const outOfPositionSpocsFill = spocs.data.spocs.slice(spocIndexMap.spocs).filter(spoc => !unchosenSpocs.has(spoc)).map(spoc => ({
const outOfPositionSpocsFill = spocs.data.spocs.items.slice(spocIndexMap.spocs).filter(spoc => !unchosenSpocs.has(spoc)).map(spoc => ({
id: spoc.id,
reason: "out_of_position",
displayed: 0,
@ -10378,7 +10472,7 @@ const selectLayoutRender = ({
};
/***/ }),
/* 75 */
/* 76 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -10387,8 +10481,8 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSites", function() { return TopSites; });
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(28);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(67);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(81);
/* harmony import */ var content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(68);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(82);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -10529,7 +10623,7 @@ const TopSites = Object(react_redux__WEBPACK_IMPORTED_MODULE_0__["connect"])(sta
}))(_TopSites);
/***/ }),
/* 76 */
/* 77 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -10721,14 +10815,14 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent
const Search = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])()(_Search);
/***/ }),
/* 77 */
/* 78 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DetectUserSessionStart", function() { return DetectUserSessionStart; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(63);
/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(64);
/* 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/. */
@ -10803,7 +10897,7 @@ class DetectUserSessionStart {
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
/* 78 */
/* 79 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -11600,7 +11694,7 @@ localized_Localized.propTypes = {
/***/ }),
/* 79 */
/* 80 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -12768,7 +12862,7 @@ const SnippetsTemplates = {
};
/***/ }),
/* 80 */
/* 81 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -14188,7 +14282,7 @@ function generateBundles(content) {
}
/***/ }),
/* 81 */
/* 82 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -14313,8 +14407,8 @@ const INITIAL_STATE = {
spocs_endpoint: "",
spocs_per_domain: 1,
lastUpdated: null,
data: {},
// {spocs: []}
data: {// {spocs: {items: []}}
},
loaded: false,
frequency_caps: [],
blocked: [],
@ -14910,11 +15004,13 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
const forPlacement = placement => {
const placementSpocs = data[placement.name];
if (!placementSpocs || !placementSpocs.length) {
if (!placementSpocs || !placementSpocs.items || !placementSpocs.items.length) {
return;
}
result[placement.name] = handleSites(placementSpocs);
result[placement.name] = { ...placementSpocs,
items: handleSites(placementSpocs.items)
};
};
if (!placements || !placements.length) {
@ -15139,7 +15235,7 @@ var reducers = {
};
/***/ }),
/* 82 */
/* 83 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -15159,10 +15255,10 @@ var ReturnToAMO = __webpack_require__(24);
var FullPageInterrupt = __webpack_require__(25);
// EXTERNAL MODULE: ./node_modules/fluent-react/src/index.js + 14 modules
var src = __webpack_require__(78);
var src = __webpack_require__(79);
// EXTERNAL MODULE: ./content-src/asrouter/rich-text-strings.js + 8 modules
var rich_text_strings = __webpack_require__(80);
var rich_text_strings = __webpack_require__(81);
// CONCATENATED MODULE: ./content-src/asrouter/templates/FirstRun/Interrupt.jsx
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@ -15420,7 +15516,7 @@ class FirstRun_FirstRun extends external_React_default.a.PureComponent {
}
/***/ }),
/* 83 */
/* 84 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
@ -15430,14 +15526,14 @@ __webpack_require__.r(__webpack_exports__);
var Actions = __webpack_require__(2);
// EXTERNAL MODULE: ./content-src/components/A11yLinkButton/A11yLinkButton.jsx
var A11yLinkButton = __webpack_require__(49);
var A11yLinkButton = __webpack_require__(50);
// EXTERNAL MODULE: external "React"
var external_React_ = __webpack_require__(9);
var external_React_default = /*#__PURE__*/__webpack_require__.n(external_React_);
// EXTERNAL MODULE: ./content-src/components/TopSites/TopSitesConstants.js
var TopSitesConstants = __webpack_require__(68);
var TopSitesConstants = __webpack_require__(69);
// CONCATENATED MODULE: ./content-src/components/TopSites/TopSiteFormInput.jsx
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -15552,7 +15648,7 @@ TopSiteFormInput_TopSiteFormInput.defaultProps = {
validationError: false
};
// EXTERNAL MODULE: ./content-src/components/TopSites/TopSite.jsx
var TopSite = __webpack_require__(70);
var TopSite = __webpack_require__(71);
// CONCATENATED MODULE: ./content-src/components/TopSites/TopSiteForm.jsx
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TopSiteForm", function() { return TopSiteForm_TopSiteForm; });

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

@ -572,6 +572,19 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
}
}
// Bug 1567271 introduced meta data on a list of spocs.
// This involved moving the spocs array into an items prop.
// However, old data could still be returned, and cached data might also be old.
// For ths reason, we want to ensure if we don't find an items array,
// we use the previous array placement, and then stub out title and context to empty strings.
// We need to do this *after* both fresh fetches and cached data to reduce repetition.
normalizeSpocsItems(spocs) {
const items = spocs.items || spocs;
const title = spocs.title || "";
const context = spocs.context || "";
return { items, title, context };
}
async loadSpocs(sendUpdate, isStartup) {
const cachedData = (await this.cache.get()) || {};
let spocsState;
@ -638,12 +651,39 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
this.placementsForEach(placement => {
const freshSpocs = spocsState.spocs[placement.name];
if (!freshSpocs || !freshSpocs.length) {
if (!freshSpocs) {
return;
}
// spocs can be returns as an array, or an object with an items array.
// We want to normalize this so all our spocs have an items array.
// There can also be some meta data for title and context.
// This is mostly because of backwards compat.
const {
items: normalizedSpocsItems,
title,
context,
} = this.normalizeSpocsItems(freshSpocs);
if (!normalizedSpocsItems || !normalizedSpocsItems.length) {
// In the case of old data, we still want to ensure we normalize the data structure,
// even if it's empty. We expect the empty data to be an object with items array,
// and not just an empty array.
spocsState.spocs = {
...spocsState.spocs,
[placement.name]: {
title,
context,
items: [],
},
};
return;
}
// Migrate flight_id
const { data: migratedSpocs } = this.migrateFlightId(freshSpocs);
const { data: migratedSpocs } = this.migrateFlightId(
normalizedSpocsItems
);
const { data: capResult, filtered: caps } = this.frequencyCapSpocs(
migratedSpocs
@ -667,7 +707,11 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
spocsState.spocs = {
...spocsState.spocs,
[placement.name]: transformResult,
[placement.name]: {
title,
context,
items: transformResult,
},
};
});
@ -1144,7 +1188,8 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
async scoreSpocs(spocsState) {
let belowMinScore = [];
this.placementsForEach(placement => {
const items = spocsState.data[placement.name];
const nextSpocs = spocsState.data[placement.name] || {};
const { items } = nextSpocs;
if (!items || !items.length) {
return;
@ -1158,7 +1203,10 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
spocsState.data = {
...spocsState.data,
[placement.name]: scoreResult,
[placement.name]: {
...nextSpocs,
items: scoreResult,
},
};
});
@ -1436,7 +1484,17 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
if (!newSpocs) {
return;
}
flightIds = [...flightIds, ...newSpocs.map(s => `${s.flight_id}`)];
// We need to do a small items migration here.
// In bug 1567271 we moved spoc data array into items,
// but we also need backwards comp here, because
// this is the only place where we use spocs before the migration.
// We however don't need to do a total migration, we *just* need the items.
// A total migration would involve setting the data with new values,
// and also ensuring metadata like context and title are there or empty strings.
// see #normalizeSpocsItems function.
const items = newSpocs.items || newSpocs;
flightIds = [...flightIds, ...items.map(s => `${s.flight_id}`)];
});
if (flightIds && flightIds.length) {
this.cleanUpImpressionPref(
@ -1599,18 +1657,21 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
let frequencyCapped = [];
this.placementsForEach(placement => {
const freshSpocs = spocsState.data[placement.name];
if (!freshSpocs) {
if (!freshSpocs || !freshSpocs.items) {
return;
}
const { data: newSpocs, filtered } = this.frequencyCapSpocs(
freshSpocs
freshSpocs.items
);
frequencyCapped = [...frequencyCapped, ...filtered];
spocsState.data = {
...spocsState.data,
[placement.name]: newSpocs,
[placement.name]: {
...freshSpocs,
items: newSpocs,
},
};
});
if (frequencyCapped.length) {
@ -1636,8 +1697,8 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
let spocsList = [];
this.placementsForEach(placement => {
const spocs = spocsState.data[placement.name];
if (spocs && spocs.length) {
spocsList = [...spocsList, ...spocs];
if (spocs && spocs.items && spocs.items.length) {
spocsList = [...spocsList, ...spocs.items];
}
});
const filtered = spocsList.filter(s => s.url === action.data.url);

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

@ -1055,7 +1055,13 @@ describe("Reducers", () => {
const oldState = {
spocs: {
data: {
spocs: [{ url: "test-spoc.com" }],
spocs: {
items: [
{
url: "test-spoc.com",
},
],
},
},
loaded: true,
},
@ -1067,7 +1073,7 @@ describe("Reducers", () => {
const newState = DiscoveryStream(oldState, deleteAction);
assert.equal(newState.spocs.data.spocs.length, 1);
assert.equal(newState.spocs.data.spocs.items.length, 1);
});
it("should handle no data from DISCOVERY_STREAM_SPOCS_UPDATE", () => {
const data = null;
@ -1133,7 +1139,9 @@ describe("Reducers", () => {
const oldState = {
spocs: {
data: {
spocs: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
spocs: {
items: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
},
},
loaded: true,
placements: [{ name: "spocs" }],
@ -1144,7 +1152,9 @@ describe("Reducers", () => {
},
};
const newState = DiscoveryStream(oldState, deleteAction);
assert.deepEqual(newState.spocs.data.spocs, [{ url: "test-spoc.com" }]);
assert.deepEqual(newState.spocs.data.spocs.items, [
{ url: "test-spoc.com" },
]);
});
it("should remove the site on DISCOVERY_STREAM_LINK_BLOCKED from feeds if spocs data is empty", () => {
const deleteAction = {
@ -1194,7 +1204,9 @@ describe("Reducers", () => {
},
spocs: {
data: {
spocs: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
spocs: {
items: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
},
},
loaded: true,
placements: [{ name: "spocs" }],
@ -1205,7 +1217,9 @@ describe("Reducers", () => {
data: { url: "https://foo.com" },
};
const newState = DiscoveryStream(oldState, deleteAction);
assert.deepEqual(newState.spocs.data.spocs, [{ url: "test-spoc.com" }]);
assert.deepEqual(newState.spocs.data.spocs.items, [
{ url: "test-spoc.com" },
]);
assert.deepEqual(
newState.feeds.data["https://foo.com/feed1"].data.recommendations,
[{ url: "test.com" }]
@ -1234,7 +1248,9 @@ describe("Reducers", () => {
},
spocs: {
data: {
spocs: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
spocs: {
items: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
},
},
placements: [{ name: "spocs" }],
loaded: true,
@ -1251,13 +1267,16 @@ describe("Reducers", () => {
const newState = DiscoveryStream(oldState, action);
assert.lengthOf(newState.spocs.data.spocs, 2);
assert.lengthOf(newState.spocs.data.spocs.items, 2);
assert.equal(
newState.spocs.data.spocs[0].pocket_id,
newState.spocs.data.spocs.items[0].pocket_id,
action.data.pocket_id
);
assert.equal(newState.spocs.data.spocs[0].open_url, action.data.open_url);
assert.isUndefined(newState.spocs.data.spocs[1].pocket_id);
assert.equal(
newState.spocs.data.spocs.items[0].open_url,
action.data.open_url
);
assert.isUndefined(newState.spocs.data.spocs.items[1].pocket_id);
assert.lengthOf(
newState.feeds.data["https://foo.com/feed1"].data.recommendations,
@ -1301,10 +1320,12 @@ describe("Reducers", () => {
},
spocs: {
data: {
spocs: [
{ url: "https://foo.com", pocket_id: 1234 },
{ url: "test-spoc.com" },
],
spocs: {
items: [
{ url: "https://foo.com", pocket_id: 1234 },
{ url: "test-spoc.com" },
],
},
},
loaded: true,
placements: [{ name: "spocs" }],
@ -1318,7 +1339,9 @@ describe("Reducers", () => {
};
const newState = DiscoveryStream(oldState, deleteAction);
assert.deepEqual(newState.spocs.data.spocs, [{ url: "test-spoc.com" }]);
assert.deepEqual(newState.spocs.data.spocs.items, [
{ url: "test-spoc.com" },
]);
assert.deepEqual(
newState.feeds.data["https://foo.com/feed1"].data.recommendations,
[{ url: "test.com" }]
@ -1341,10 +1364,12 @@ describe("Reducers", () => {
},
spocs: {
data: {
spocs: [
{ url: "https://foo.com", pocket_id: 1234 },
{ url: "test-spoc.com" },
],
spocs: {
items: [
{ url: "https://foo.com", pocket_id: 1234 },
{ url: "test-spoc.com" },
],
},
},
loaded: true,
placements: [{ name: "spocs" }],
@ -1358,7 +1383,9 @@ describe("Reducers", () => {
};
const newState = DiscoveryStream(oldState, deleteAction);
assert.deepEqual(newState.spocs.data.spocs, [{ url: "test-spoc.com" }]);
assert.deepEqual(newState.spocs.data.spocs.items, [
{ url: "test-spoc.com" },
]);
assert.deepEqual(
newState.feeds.data["https://foo.com/feed1"].data.recommendations,
[{ url: "test.com" }]
@ -1381,7 +1408,9 @@ describe("Reducers", () => {
},
spocs: {
data: {
spocs: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
spocs: {
items: [{ url: "https://foo.com" }, { url: "test-spoc.com" }],
},
},
loaded: true,
placements: [{ name: "spocs" }],
@ -1399,16 +1428,16 @@ describe("Reducers", () => {
const newState = DiscoveryStream(oldState, bookmarkAction);
assert.lengthOf(newState.spocs.data.spocs, 2);
assert.lengthOf(newState.spocs.data.spocs.items, 2);
assert.equal(
newState.spocs.data.spocs[0].bookmarkGuid,
newState.spocs.data.spocs.items[0].bookmarkGuid,
bookmarkAction.data.bookmarkGuid
);
assert.equal(
newState.spocs.data.spocs[0].bookmarkTitle,
newState.spocs.data.spocs.items[0].bookmarkTitle,
bookmarkAction.data.bookmarkTitle
);
assert.isUndefined(newState.spocs.data.spocs[1].bookmarkGuid);
assert.isUndefined(newState.spocs.data.spocs.items[1].bookmarkGuid);
assert.lengthOf(
newState.feeds.data["https://foo.com/feed1"].data.recommendations,
@ -1451,14 +1480,16 @@ describe("Reducers", () => {
},
spocs: {
data: {
spocs: [
{
url: "https://foo.com",
bookmarkGuid: "bookmark123",
bookmarkTitle: "Title for bar.com",
},
{ url: "test-spoc.com" },
],
spocs: {
items: [
{
url: "https://foo.com",
bookmarkGuid: "bookmark123",
bookmarkTitle: "Title for bar.com",
},
{ url: "test-spoc.com" },
],
},
},
loaded: true,
placements: [{ name: "spocs" }],
@ -1473,9 +1504,9 @@ describe("Reducers", () => {
const newState = DiscoveryStream(oldState, action);
assert.lengthOf(newState.spocs.data.spocs, 2);
assert.isUndefined(newState.spocs.data.spocs[0].bookmarkGuid);
assert.isUndefined(newState.spocs.data.spocs[0].bookmarkTitle);
assert.lengthOf(newState.spocs.data.spocs.items, 2);
assert.isUndefined(newState.spocs.data.spocs.items[0].bookmarkGuid);
assert.isUndefined(newState.spocs.data.spocs.items[0].bookmarkTitle);
assert.lengthOf(
newState.feeds.data["https://foo.com/feed1"].data.recommendations,

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

@ -0,0 +1,103 @@
import { CollectionCardGrid } from "content-src/components/DiscoveryStreamComponents/CollectionCardGrid/CollectionCardGrid";
import { CardGrid } from "content-src/components/DiscoveryStreamComponents/CardGrid/CardGrid";
import { combineReducers, createStore } from "redux";
import { INITIAL_STATE, reducers } from "common/Reducers.jsm";
import { Provider } from "react-redux";
import React from "react";
import { mount } from "enzyme";
function mountCollectionWithProps(props, spocsState) {
const state = {
...INITIAL_STATE,
DiscoveryStream: {
...INITIAL_STATE.DiscoveryStream,
spocs: {
...INITIAL_STATE.DiscoveryStream.spocs,
...spocsState,
},
},
};
const store = createStore(combineReducers(reducers), state);
return mount(
<Provider store={store}>
<CollectionCardGrid {...props} />
</Provider>
);
}
describe("<CollectionCardGrid>", () => {
let wrapper;
beforeEach(() => {
const initialSpocs = [{ id: 123 }, { id: 456 }, { id: 789 }];
wrapper = mountCollectionWithProps(
{
placement: {
name: "spocs",
},
data: {
spocs: initialSpocs,
},
},
{
data: {
spocs: {
title: "title",
context: "context",
items: initialSpocs,
},
},
}
);
});
it("should render an empty div", () => {
wrapper = mountCollectionWithProps({}, {});
assert.ok(wrapper.exists());
assert.ok(!wrapper.exists(".ds-collection-card-grid"));
});
it("should render a CardGrid", () => {
assert.lengthOf(wrapper.find(".ds-collection-card-grid").children(), 1);
assert.equal(
wrapper
.find(".ds-collection-card-grid")
.children()
.at(0)
.type(),
CardGrid
);
});
it("should inject spocs in every CardGrid rec position", () => {
assert.lengthOf(
wrapper
.find(".ds-collection-card-grid")
.children()
.at(0)
.props().data.recommendations,
3
);
});
it("should pass along title and context to CardGrid", () => {
assert.equal(
wrapper
.find(".ds-collection-card-grid")
.children()
.at(0)
.props().title,
"title"
);
assert.equal(
wrapper
.find(".ds-collection-card-grid")
.children()
.at(0)
.props().context,
"context"
);
});
});

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

@ -107,7 +107,7 @@ describe("selectLayoutRender", () => {
assert.lengthOf(layoutRender, 1);
assert.propertyVal(layoutRender[0], "width", 3);
assert.deepEqual(layoutRender[0].components[0].data.spocs, []);
assert.deepEqual(layoutRender[0].components[0].data.spocs.items, []);
});
it("should return layout with spocs data if feed isn't defined but spocs is", () => {
@ -126,7 +126,7 @@ describe("selectLayoutRender", () => {
store.dispatch({ type: at.DISCOVERY_STREAM_FEEDS_UPDATE });
store.dispatch({
type: at.DISCOVERY_STREAM_SPOCS_UPDATE,
data: { lastUpdated: 0, spocs: { spocs: [1, 2, 3] } },
data: { lastUpdated: 0, spocs: { spocs: { items: [1, 2, 3] } } },
});
const { layoutRender } = selectLayoutRender({
@ -181,7 +181,7 @@ describe("selectLayoutRender", () => {
];
const fakeSpocsData = {
lastUpdated: 0,
spocs: { spocs: ["fooSpoc", "barSpoc"] },
spocs: { spocs: { items: ["fooSpoc", "barSpoc"] } },
};
store.dispatch({
@ -241,7 +241,7 @@ describe("selectLayoutRender", () => {
];
const fakeSpocsData = {
lastUpdated: 0,
spocs: { spocs: ["fooSpoc", "barSpoc"] },
spocs: { spocs: { items: ["fooSpoc", "barSpoc"] } },
};
store.dispatch({
@ -301,7 +301,7 @@ describe("selectLayoutRender", () => {
];
const fakeSpocsData = {
lastUpdated: 0,
spocs: { spocs: ["fooSpoc", "barSpoc", "lastSpoc"] },
spocs: { spocs: { items: ["fooSpoc", "barSpoc", "lastSpoc"] } },
};
store.dispatch({
@ -369,7 +369,7 @@ describe("selectLayoutRender", () => {
];
const fakeSpocsData = {
lastUpdated: 0,
spocs: { spocs: ["fooSpoc", "barSpoc"] },
spocs: { spocs: { items: ["fooSpoc", "barSpoc"] } },
};
store.dispatch({
@ -431,7 +431,7 @@ describe("selectLayoutRender", () => {
];
const fakeSpocsData = {
lastUpdated: 0,
spocs: { spocs: ["fooSpoc", "barSpoc"] },
spocs: { spocs: { items: ["fooSpoc", "barSpoc"] } },
};
store.dispatch({
@ -492,7 +492,7 @@ describe("selectLayoutRender", () => {
];
const fakeSpocsData = {
lastUpdated: 0,
spocs: { spocs: ["fooSpoc", "barSpoc"] },
spocs: { spocs: { items: ["fooSpoc", "barSpoc"] } },
};
store.dispatch({
@ -555,7 +555,7 @@ describe("selectLayoutRender", () => {
];
const fakeSpocsData = {
lastUpdated: 0,
spocs: { spocs: ["fooSpoc", "barSpoc"] },
spocs: { spocs: { items: ["fooSpoc", "barSpoc"] } },
};
store.dispatch({
@ -905,7 +905,7 @@ describe("selectLayoutRender", () => {
const fakeSpocsData = {
lastUpdated: 0,
spocs: {
spocs: [{ name: "spoc", url: "https://foo.com" }],
spocs: { items: [{ name: "spoc", url: "https://foo.com" }] },
},
};
store.dispatch({

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

@ -833,21 +833,129 @@ describe("DiscoveryStreamFeed", () => {
sandbox.stub(feed.cache, "get").returns(Promise.resolve());
sandbox
.stub(feed, "fetchFromEndpoint")
.resolves({ spocs: [{ id: "data" }] });
.resolves({ spocs: { items: [{ id: "data" }] } });
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
await feed.loadSpocs(feed.store.dispatch);
assert.calledWith(feed.cache.set, "spocs", {
spocs: { spocs: [{ id: "data", min_score: 0, score: 1 }] },
spocs: {
spocs: {
context: "",
title: "",
items: [{ id: "data", min_score: 0, score: 1 }],
},
},
lastUpdated: 0,
});
assert.deepEqual(
feed.store.getState().DiscoveryStream.spocs.data.spocs[0],
feed.store.getState().DiscoveryStream.spocs.data.spocs.items[0],
{ id: "data", min_score: 0, score: 1 }
);
});
it("should normalizeSpocsItems for older spoc data", async () => {
sandbox.stub(feed.cache, "get").returns(Promise.resolve());
sandbox
.stub(feed, "fetchFromEndpoint")
.resolves({ spocs: [{ id: "data" }] });
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
await feed.loadSpocs(feed.store.dispatch);
assert.deepEqual(
feed.store.getState().DiscoveryStream.spocs.data.spocs.items[0],
{ id: "data", min_score: 0, score: 1 }
);
});
it("should return expected data if normalizeSpocsItems returns no spoc data", async () => {
sandbox.stub(feed.cache, "get").returns(Promise.resolve());
sandbox
.stub(feed, "fetchFromEndpoint")
.resolves({ placement1: [{ id: "data" }], placement2: [] });
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
const fakeComponents = {
components: [
{ placement: { name: "placement1" } },
{ placement: { name: "placement2" } },
],
};
feed.updatePlacements(feed.store.dispatch, [fakeComponents]);
await feed.loadSpocs(feed.store.dispatch);
assert.deepEqual(feed.store.getState().DiscoveryStream.spocs.data, {
placement1: {
title: "",
context: "",
items: [{ id: "data", score: 1, min_score: 0 }],
},
placement2: {
title: "",
context: "",
items: [],
},
});
});
it("should use title and context on spoc data", async () => {
sandbox.stub(feed.cache, "get").returns(Promise.resolve());
sandbox.stub(feed, "fetchFromEndpoint").resolves({
placement1: {
title: "title",
context: "context",
items: [{ id: "data" }],
},
});
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
const fakeComponents = {
components: [{ placement: { name: "placement1" } }],
};
feed.updatePlacements(feed.store.dispatch, [fakeComponents]);
await feed.loadSpocs(feed.store.dispatch);
assert.deepEqual(feed.store.getState().DiscoveryStream.spocs.data, {
placement1: {
title: "title",
context: "context",
items: [{ id: "data", score: 1, min_score: 0 }],
},
});
});
});
describe("#normalizeSpocsItems", () => {
it("should return correct data if new data passed in", async () => {
const spocs = {
title: "title",
context: "context",
items: [{ id: "id" }],
};
const result = feed.normalizeSpocsItems(spocs);
assert.deepEqual(result, spocs);
});
it("should return normalized data if new data passed in without title or context", async () => {
const spocs = {
items: [{ id: "id" }],
};
const result = feed.normalizeSpocsItems(spocs);
assert.deepEqual(result, {
title: "",
context: "",
items: [{ id: "id" }],
});
});
it("should return normalized data if old data passed in", async () => {
const spocs = [{ id: "id" }];
const result = feed.normalizeSpocsItems(spocs);
assert.deepEqual(result, {
title: "",
context: "",
items: [{ id: "id" }],
});
});
});
describe("#showSpocs", () => {
@ -1377,28 +1485,30 @@ describe("DiscoveryStreamFeed", () => {
describe("#cleanUpFlightImpressionPref", () => {
it("should remove flight-3 because it is no longer being used", async () => {
const fakeSpocs = {
spocs: [
{
flight_id: "flight-1",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
spocs: {
items: [
{
flight_id: "flight-1",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
},
},
},
},
{
flight_id: "flight-2",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
{
flight_id: "flight-2",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
},
},
},
},
],
],
},
};
const fakeImpressions = {
"flight-2": [Date.now() - 1],
@ -1413,6 +1523,20 @@ describe("DiscoveryStreamFeed", () => {
"flight-2": [-1],
});
});
it("should use old spocs data strucutre", async () => {
const fakeSpocs = {
spocs: [
{
flight_id: "flight-2",
},
],
};
sandbox.stub(feed, "cleanUpImpressionPref").returns();
feed.cleanUpFlightImpressionPref(fakeSpocs);
assert.calledOnce(feed.cleanUpImpressionPref);
});
});
describe("#recordTopRecImpressions", () => {
@ -1530,30 +1654,32 @@ describe("DiscoveryStreamFeed", () => {
describe("#onAction: DISCOVERY_STREAM_SPOC_IMPRESSION", () => {
beforeEach(() => {
const data = {
spocs: [
{
id: 1,
flight_id: "seen",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
spocs: {
items: [
{
id: 1,
flight_id: "seen",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
},
},
},
},
{
id: 2,
flight_id: "not-seen",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
{
id: 2,
flight_id: "not-seen",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
},
},
},
},
],
],
},
};
sandbox.stub(feed.store, "getState").returns({
DiscoveryStream: {
@ -1571,19 +1697,21 @@ describe("DiscoveryStreamFeed", () => {
seen: [Date.now() - 1],
};
const result = {
spocs: [
{
id: 2,
flight_id: "not-seen",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
spocs: {
items: [
{
id: 2,
flight_id: "not-seen",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
},
},
},
},
],
],
},
};
const spocFillResult = [
{
@ -1600,7 +1728,7 @@ describe("DiscoveryStreamFeed", () => {
await feed.onAction({
type: at.DISCOVERY_STREAM_SPOC_IMPRESSION,
data: { flight_id: "seen" },
data: { flightId: "seen" },
});
assert.deepEqual(
@ -1636,19 +1764,21 @@ describe("DiscoveryStreamFeed", () => {
sandbox.spy(feed, "frequencyCapSpocs");
const data = {
spocs: [
{
id: 2,
flight_id: "seen-2",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
spocs: {
items: [
{
id: 2,
flight_id: "seen-2",
caps: {
lifetime: 3,
flight: {
count: 1,
period: 1,
},
},
},
},
],
],
},
};
sandbox.stub(feed.store, "getState").returns({
DiscoveryStream: {
@ -1666,25 +1796,27 @@ describe("DiscoveryStreamFeed", () => {
});
assert.calledOnce(feed.frequencyCapSpocs);
assert.calledWith(feed.frequencyCapSpocs, data.spocs);
assert.calledWith(feed.frequencyCapSpocs, data.spocs.items);
});
});
describe("#onAction: PLACES_LINK_BLOCKED", () => {
beforeEach(() => {
const data = {
spocs: [
{
id: 1,
flight_id: "foo",
url: "foo.com",
},
{
id: 2,
flight_id: "bar",
url: "bar.com",
},
],
spocs: {
items: [
{
id: 1,
flight_id: "foo",
url: "foo.com",
},
{
id: 2,
flight_id: "bar",
url: "bar.com",
},
],
},
};
sandbox.stub(feed.store, "getState").returns({
DiscoveryStream: {
@ -2512,31 +2644,35 @@ describe("DiscoveryStreamFeed", () => {
const fakeSpocs = {
lastUpdated: 1234,
data: {
placement1: [
{
min_score: 0.5,
item_score: 0.6,
},
{
min_score: 0.5,
item_score: 0.4,
},
{
min_score: 0.5,
item_score: 0.8,
},
],
placement2: [
{
min_score: 0.5,
item_score: 0.6,
},
{
min_score: 0.5,
item_score: 0.8,
},
],
placement3: [],
placement1: {
items: [
{
min_score: 0.5,
item_score: 0.6,
},
{
min_score: 0.5,
item_score: 0.4,
},
{
min_score: 0.5,
item_score: 0.8,
},
],
},
placement2: {
items: [
{
min_score: 0.5,
item_score: 0.6,
},
{
min_score: 0.5,
item_score: 0.8,
},
],
},
placement3: { items: [] },
},
};
@ -2545,31 +2681,35 @@ describe("DiscoveryStreamFeed", () => {
const spocsTestResult = {
lastUpdated: 1234,
spocs: {
placement1: [
{
min_score: 0.5,
score: 0.8,
item_score: 0.8,
},
{
min_score: 0.5,
score: 0.6,
item_score: 0.6,
},
],
placement2: [
{
min_score: 0.5,
score: 0.8,
item_score: 0.8,
},
{
min_score: 0.5,
score: 0.6,
item_score: 0.6,
},
],
placement3: [],
placement1: {
items: [
{
min_score: 0.5,
score: 0.8,
item_score: 0.8,
},
{
min_score: 0.5,
score: 0.6,
item_score: 0.6,
},
],
},
placement2: {
items: [
{
min_score: 0.5,
score: 0.8,
item_score: 0.8,
},
{
min_score: 0.5,
score: 0.6,
item_score: 0.6,
},
],
},
placement3: { items: [] },
},
};
assert.calledWith(feed.cache.set, "spocs", spocsTestResult);