зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1519303 - Add hand-off triggers, add-on icons and bug fixes to Activity Stream r=k88hudson
Differential Revision: https://phabricator.services.mozilla.com/D16394 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
eb75a7a831
Коммит
da497294eb
|
@ -42,6 +42,7 @@ for (const type of [
|
|||
"DISCOVERY_STREAM_CONFIG_CHANGE",
|
||||
"DISCOVERY_STREAM_CONFIG_SETUP",
|
||||
"DISCOVERY_STREAM_CONFIG_SET_VALUE",
|
||||
"DISCOVERY_STREAM_FEEDS_UPDATE",
|
||||
"DISCOVERY_STREAM_LAYOUT_RESET",
|
||||
"DISCOVERY_STREAM_LAYOUT_UPDATE",
|
||||
"DOWNLOAD_CHANGED",
|
||||
|
|
|
@ -455,6 +455,8 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
|
|||
return {...prevState, lastUpdated: action.data.lastUpdated || null, layout: action.data.layout || []};
|
||||
case at.DISCOVERY_STREAM_LAYOUT_RESET:
|
||||
return {...prevState, lastUpdated: INITIAL_STATE.DiscoveryStream.lastUpdated, layout: INITIAL_STATE.DiscoveryStream.layout};
|
||||
case at.DISCOVERY_STREAM_FEEDS_UPDATE:
|
||||
return {...prevState, feeds: action.data || prevState.feeds};
|
||||
default:
|
||||
return prevState;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,8 @@ export class SubmitFormSnippet extends React.PureComponent {
|
|||
}
|
||||
|
||||
expandSnippet() {
|
||||
this.props.sendUserActionTelemetry({event: "CLICK_BUTTON", value: "scene1-button-learn-more", id: this.props.UISurface});
|
||||
|
||||
this.setState({
|
||||
expanded: true,
|
||||
signupSuccess: false,
|
||||
|
|
|
@ -39,8 +39,43 @@ class DiscoveryStreamAdmin extends React.PureComponent {
|
|||
this.setConfigValue("enabled", event.target.checked);
|
||||
}
|
||||
|
||||
renderComponent(width, component) {
|
||||
return (
|
||||
<table><tbody>
|
||||
<Row>
|
||||
<td className="min">Type</td>
|
||||
<td>{component.type}</td>
|
||||
</Row>
|
||||
<Row>
|
||||
<td className="min">Width</td>
|
||||
<td>{width}</td>
|
||||
</Row>
|
||||
{component.feed && this.renderFeed(component.feed)}
|
||||
</tbody></table>
|
||||
);
|
||||
}
|
||||
|
||||
renderFeed(feed) {
|
||||
const {feeds} = this.props.state;
|
||||
if (!feed.url) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Row>
|
||||
<td className="min">Feed url</td>
|
||||
<td>{feed.url}</td>
|
||||
</Row>
|
||||
<Row>
|
||||
<td className="min">Data last fetched</td>
|
||||
<td>{relativeTime(feeds[feed.url].lastUpdated) || "(no data)"}</td>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {config, lastUpdated} = this.props.state;
|
||||
const {config, lastUpdated, layout} = this.props.state;
|
||||
return (<div>
|
||||
<div className="dsEnabled"><input type="checkbox" checked={config.enabled} onChange={this.onEnableToggle} /> enabled</div>
|
||||
|
||||
|
@ -48,6 +83,18 @@ class DiscoveryStreamAdmin extends React.PureComponent {
|
|||
<Row><td className="min">Data last fetched</td><td>{relativeTime(lastUpdated) || "(no data)"}</td></Row>
|
||||
<Row><td className="min">Endpoint</td><td>{config.layout_endpoint || "(empty)"}</td></Row>
|
||||
</tbody></table>
|
||||
|
||||
<h3>Layout</h3>
|
||||
|
||||
{layout.map((row, rowIndex) => (
|
||||
<div key={`row-${rowIndex}`}>
|
||||
{row.components.map((component, componentIndex) => (
|
||||
<div key={`component-${componentIndex}`} className="ds-component">
|
||||
{this.renderComponent(row.width, component)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
@ -496,7 +543,7 @@ export class ASRouterAdminInner extends React.PureComponent {
|
|||
return (<React.Fragment>
|
||||
<h2>Discovery Stream</h2>
|
||||
<DiscoveryStreamAdmin state={this.props.DiscoveryStream} dispatch={this.props.dispatch} />
|
||||
</React.Fragment>);
|
||||
</React.Fragment>);
|
||||
default:
|
||||
return (<React.Fragment>
|
||||
<h2>Message Providers <button title="Restore all provider settings that ship with Firefox" className="button" onClick={this.resetPref}>Restore default prefs</button></h2>
|
||||
|
|
|
@ -146,5 +146,9 @@
|
|||
margin-bottom: 20px;
|
||||
border: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.ds-component {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,13 +15,16 @@ export class _DiscoveryStreamBase extends React.PureComponent {
|
|||
case "SectionTitle":
|
||||
return (<SectionTitle />);
|
||||
case "CardGrid":
|
||||
return (<CardGrid />);
|
||||
return (<CardGrid feed={component.feed} />);
|
||||
case "Hero":
|
||||
return (<Hero />);
|
||||
return (<Hero
|
||||
feed={component.feed}
|
||||
style={component.properties.style}
|
||||
items={component.properties.items} />);
|
||||
case "HorizontalRule":
|
||||
return (<HorizontalRule />);
|
||||
case "List":
|
||||
return (<List />);
|
||||
return (<List feed={component.feed} />);
|
||||
default:
|
||||
return (<div>{component.type}</div>);
|
||||
}
|
||||
|
@ -30,9 +33,9 @@ export class _DiscoveryStreamBase extends React.PureComponent {
|
|||
render() {
|
||||
const {layout} = this.props.DiscoveryStream;
|
||||
return (
|
||||
<div className="discovery-stream layout">
|
||||
<div className="discovery-stream ds-layout">
|
||||
{layout.map((row, rowIndex) => (
|
||||
<div key={`row-${rowIndex}`} className={`column column-${row.width}`}>
|
||||
<div key={`row-${rowIndex}`} className={`ds-column ds-column-${row.width}`}>
|
||||
{row.components.map((component, componentIndex) => (
|
||||
<div key={`component-${componentIndex}`}>
|
||||
{this.renderComponent(component)}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
.discovery-stream.layout {
|
||||
.discovery-stream.ds-layout {
|
||||
$columns: 12;
|
||||
display: grid;
|
||||
grid-template-columns: repeat($columns, 1fr);
|
||||
grid-column-gap: 10px;
|
||||
grid-column-gap: 48px;
|
||||
grid-row-gap: 10px;
|
||||
|
||||
@while $columns > 0 {
|
||||
.column-#{$columns} {
|
||||
.ds-column-#{$columns} {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span $columns;
|
||||
}
|
||||
|
||||
$columns: $columns - 1;
|
||||
}
|
||||
|
||||
.ds-column {
|
||||
display: grid;
|
||||
grid-row-gap: 10px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
|
||||
export class CardGrid extends React.PureComponent {
|
||||
export class _CardGrid extends React.PureComponent {
|
||||
render() {
|
||||
// const feed = this.props.DiscoveryStream.feeds[this.props.feed.url];
|
||||
return (
|
||||
<div>
|
||||
Card Grid
|
||||
|
@ -9,3 +11,5 @@ export class CardGrid extends React.PureComponent {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const CardGrid = connect(state => ({DiscoveryStream: state.DiscoveryStream}))(_CardGrid);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import React from "react";
|
||||
|
||||
export class DSCard extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className="ds-card">
|
||||
<img src={this.props.image_src} />
|
||||
<div className="meta">
|
||||
<header>{this.props.title}</header>
|
||||
<p>{this.props.excerpt}</p>
|
||||
<p>{this.props.source}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
.ds-card {
|
||||
img {
|
||||
width: 100%;
|
||||
border: 0.5px solid $black-10;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.meta {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
header {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: $grey-90;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: $grey-50;
|
||||
}
|
||||
}
|
|
@ -1,11 +1,51 @@
|
|||
import {connect} from "react-redux";
|
||||
import {DSCard} from "../DSCard/DSCard.jsx";
|
||||
import React from "react";
|
||||
|
||||
export class Hero extends React.PureComponent {
|
||||
export class _Hero extends React.PureComponent {
|
||||
render() {
|
||||
const feed = this.props.DiscoveryStream.feeds[this.props.feed.url];
|
||||
|
||||
// Handle a render before feed has been fetched by displaying nothing
|
||||
if (!feed) {
|
||||
return (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
let [heroRec, ...otherRecs] = feed.data.recommendations;
|
||||
|
||||
// TODO: Let this count be determined by the endpoint
|
||||
let cards = otherRecs.slice(1, 5).map((rec, index) => (
|
||||
<DSCard
|
||||
key={`dscard-${index}`}
|
||||
image_src={rec.image_src}
|
||||
title={rec.title}
|
||||
excerpt={rec.excerpt}
|
||||
source="TODO: SOURCE" />
|
||||
));
|
||||
|
||||
return (
|
||||
<div>
|
||||
Hero
|
||||
<div className={`ds-hero ds-hero-${this.props.style}`}>
|
||||
<div className="wrapper">
|
||||
<img src={heroRec.image_src} />
|
||||
<div className="meta">
|
||||
<header>{heroRec.title}</header>
|
||||
<p>{heroRec.excerpt}</p>
|
||||
<p>TODO: SOURCE</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="cards">
|
||||
{ cards }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_Hero.defaultProps = {
|
||||
style: `border`,
|
||||
items: 1, // Number of stories to display
|
||||
};
|
||||
|
||||
export const Hero = connect(state => ({DiscoveryStream: state.DiscoveryStream}))(_Hero);
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
.ds-hero {
|
||||
// "1/3 width layout" (aka "Mobile First")
|
||||
.wrapper {
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.meta {
|
||||
header {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "2/3 width layout"
|
||||
.column-5 &,
|
||||
.column-6 &,
|
||||
.column-7 &,
|
||||
.column-8 & {
|
||||
.wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
img {
|
||||
width: 50%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.meta {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.ds-card {
|
||||
width: 50%;
|
||||
padding: 12px;
|
||||
|
||||
&:nth-child(odd) {
|
||||
padding: 12px 12px 12px 0;
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
padding: 12px 0 12px 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "Full width layout"
|
||||
.column-9 &,
|
||||
.column-10 &,
|
||||
.column-11 &,
|
||||
.column-12 & {
|
||||
.wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
img {
|
||||
width: 67%;
|
||||
}
|
||||
|
||||
.meta {
|
||||
width: 33%;
|
||||
padding: 24px;
|
||||
|
||||
header {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cards {
|
||||
display: flex;
|
||||
|
||||
.ds-card {
|
||||
width: 25%;
|
||||
padding: 12px;
|
||||
|
||||
.meta {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
padding: 12px 12px 12px 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding: 12px 0 12px 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
|
||||
export class List extends React.PureComponent {
|
||||
export class _List extends React.PureComponent {
|
||||
render() {
|
||||
// const feed = this.props.DiscoveryStream.feeds[this.props.feed.url];
|
||||
return (
|
||||
<div>
|
||||
<div className="ds-list">
|
||||
List
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const List = connect(state => ({DiscoveryStream: state.DiscoveryStream}))(_List);
|
||||
|
|
|
@ -11,7 +11,7 @@ export class SectionTitle extends React.PureComponent {
|
|||
render() {
|
||||
const {topics} = this.props;
|
||||
return (
|
||||
<span className="section-title">
|
||||
<span className="ds-section-title">
|
||||
<ul>
|
||||
{topics && topics.map(t => <Topic key={t.name} url={t.url} name={t.name} />)}
|
||||
<li><a className="ds-more-recommendations">More Recommendations</a></li>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.section-title {
|
||||
.ds-section-title {
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import {connect} from "react-redux";
|
||||
import {TopSites as OldTopSites} from "content-src/components/TopSites/TopSites";
|
||||
import React from "react";
|
||||
|
||||
export class _TopSites extends React.PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<div className="ds-topsites">
|
||||
Top Sites
|
||||
<div className="ds-top-sites">
|
||||
<OldTopSites />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// ds topsites wraps the original topsites, with a few css changes.
|
||||
.ds-top-sites {
|
||||
|
||||
// This is the override layer.
|
||||
.top-sites {
|
||||
// Slightly different alignment with the other DS components than AS has.
|
||||
padding: 0;
|
||||
|
||||
// We hide this and don't support it in ds.
|
||||
.section-top-bar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,10 @@ export class _Search extends React.PureComponent {
|
|||
super(props);
|
||||
this.onSearchClick = this.onSearchClick.bind(this);
|
||||
this.onSearchHandoffClick = this.onSearchHandoffClick.bind(this);
|
||||
this.onSearchHandoffKeyDown = this.onSearchHandoffKeyDown.bind(this);
|
||||
this.onSearchHandoffPaste = this.onSearchHandoffPaste.bind(this);
|
||||
this.onInputMount = this.onInputMount.bind(this);
|
||||
this.onSearchHandoffButtonMount = this.onSearchHandoffButtonMount.bind(this);
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
|
@ -42,7 +45,43 @@ export class _Search extends React.PureComponent {
|
|||
// TODO: Send a telemetry ping. BUG 1514732
|
||||
}
|
||||
|
||||
onSearchHandoffKeyDown(event) {
|
||||
if (event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey) {
|
||||
// We only care about key strokes that will produce a character.
|
||||
const text = event.key;
|
||||
this.props.dispatch(ac.OnlyToMain({type: at.HANDOFF_SEARCH_TO_AWESOMEBAR, data: {text}}));
|
||||
|
||||
// TODO: Send a telemetry ping. BUG 1514732
|
||||
}
|
||||
}
|
||||
|
||||
onSearchHandoffPaste(event) {
|
||||
if (!this._searchHandoffButton ||
|
||||
!this._searchHandoffButton.contains(global.document.activeElement)) {
|
||||
// Don't handle every paste on the document. Filter out those that are
|
||||
// not on the Search Hand-off button.
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
const text = event.clipboardData.getData("Text");
|
||||
this.props.dispatch(ac.OnlyToMain({type: at.HANDOFF_SEARCH_TO_AWESOMEBAR, data: {text}}));
|
||||
|
||||
// TODO: Send a telemetry ping. BUG 1514732
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
if (global.document) {
|
||||
// We need to listen to paste events that bubble up from the Search Hand-off
|
||||
// button. Adding the paste listener to the button itself or it's parent
|
||||
// doesn't work consistently until the page is clicked on.
|
||||
global.document.addEventListener("paste", this.onSearchHandoffPaste);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (global.document) {
|
||||
global.document.removeEventListener("paste", this.onDocumentPaste);
|
||||
}
|
||||
delete window.gContentSearchController;
|
||||
}
|
||||
|
||||
|
@ -74,6 +113,11 @@ export class _Search extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
onSearchHandoffButtonMount(button) {
|
||||
// Keep a reference to the button for use during "paste" event handling.
|
||||
this._searchHandoffButton = button;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not change the ID on the input field, as legacy newtab code
|
||||
* specifically looks for the id 'newtab-search-text' on input fields
|
||||
|
@ -118,9 +162,12 @@ export class _Search extends React.PureComponent {
|
|||
<div className="search-inner-wrapper">
|
||||
<button
|
||||
className="search-handoff-button"
|
||||
ref={this.onSearchHandoffButtonMount}
|
||||
onClick={this.onSearchHandoffClick}
|
||||
onKeyDown={this.onSearchHandoffKeyDown}
|
||||
title={this.props.intl.formatMessage({id: "search_web_placeholder"})}>
|
||||
<div className="fake-textbox">{this.props.intl.formatMessage({id: "search_web_placeholder"})}</div>
|
||||
<div className="fake-editable" tabIndex="-1" aria-hidden="true" contentEditable="" />
|
||||
<div className="fake-caret" />
|
||||
</button>
|
||||
{/*
|
||||
|
|
|
@ -164,6 +164,10 @@ $glyph-forward: url('chrome://browser/skin/forward.svg');
|
|||
.search-active & {
|
||||
border: $input-border-active;
|
||||
box-shadow: var(--newtab-textbox-focus-boxshadow);
|
||||
|
||||
.fake-caret {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.search-hidden & {
|
||||
|
@ -171,6 +175,20 @@ $glyph-forward: url('chrome://browser/skin/forward.svg');
|
|||
visibility: hidden;
|
||||
}
|
||||
|
||||
.fake-editable:focus {
|
||||
outline: none;
|
||||
caret-color: transparent;
|
||||
}
|
||||
|
||||
.fake-editable {
|
||||
color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.fake-textbox {
|
||||
opacity: 0.54;
|
||||
text-align: start;
|
||||
|
@ -191,10 +209,6 @@ $glyph-forward: url('chrome://browser/skin/forward.svg');
|
|||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.search-active & {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,7 @@ input {
|
|||
@import '../components/DiscoveryStreamComponents/List/List';
|
||||
@import '../components/DiscoveryStreamComponents/SectionTitle/SectionTitle';
|
||||
@import '../components/DiscoveryStreamComponents/TopSites/TopSites';
|
||||
@import '../components/DiscoveryStreamComponents/DSCard/DSCard';
|
||||
|
||||
// AS Router
|
||||
@import '../asrouter/components/Button/Button';
|
||||
|
|
|
@ -1070,9 +1070,22 @@ main {
|
|||
.search-active .search-handoff-button {
|
||||
border: 1px solid var(--newtab-textbox-focus-color);
|
||||
box-shadow: var(--newtab-textbox-focus-boxshadow); }
|
||||
.search-handoff-button:focus .fake-caret,
|
||||
.search-active .search-handoff-button .fake-caret {
|
||||
display: block; }
|
||||
.search-hidden .search-handoff-button {
|
||||
opacity: 0;
|
||||
visibility: hidden; }
|
||||
.search-handoff-button .fake-editable:focus {
|
||||
outline: none;
|
||||
caret-color: transparent; }
|
||||
.search-handoff-button .fake-editable {
|
||||
color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0; }
|
||||
.search-handoff-button .fake-textbox {
|
||||
opacity: 0.54;
|
||||
text-align: start; }
|
||||
|
@ -1089,8 +1102,6 @@ main {
|
|||
@keyframes caret-animation {
|
||||
to {
|
||||
visibility: hidden; } }
|
||||
.search-active .search-handoff-button .fake-caret {
|
||||
display: block; }
|
||||
|
||||
@media (min-height: 701px) {
|
||||
.fixed-search main {
|
||||
|
@ -1701,6 +1712,8 @@ main {
|
|||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid var(--newtab-border-secondary-color); }
|
||||
.asrouter-admin .ds-component {
|
||||
margin-bottom: 20px; }
|
||||
|
||||
.pocket-logged-in-cta {
|
||||
font-size: 13px;
|
||||
|
@ -1749,61 +1762,170 @@ main {
|
|||
.more-recommendations:dir(rtl)::after {
|
||||
transform: scaleX(-1); }
|
||||
|
||||
.discovery-stream.layout {
|
||||
.discovery-stream.ds-layout {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
grid-column-gap: 10px;
|
||||
grid-column-gap: 48px;
|
||||
grid-row-gap: 10px; }
|
||||
.discovery-stream.layout .column-12 {
|
||||
.discovery-stream.ds-layout .ds-column-12 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 12; }
|
||||
.discovery-stream.layout .column-11 {
|
||||
.discovery-stream.ds-layout .ds-column-11 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 11; }
|
||||
.discovery-stream.layout .column-10 {
|
||||
.discovery-stream.ds-layout .ds-column-10 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 10; }
|
||||
.discovery-stream.layout .column-9 {
|
||||
.discovery-stream.ds-layout .ds-column-9 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 9; }
|
||||
.discovery-stream.layout .column-8 {
|
||||
.discovery-stream.ds-layout .ds-column-8 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 8; }
|
||||
.discovery-stream.layout .column-7 {
|
||||
.discovery-stream.ds-layout .ds-column-7 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 7; }
|
||||
.discovery-stream.layout .column-6 {
|
||||
.discovery-stream.ds-layout .ds-column-6 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 6; }
|
||||
.discovery-stream.layout .column-5 {
|
||||
.discovery-stream.ds-layout .ds-column-5 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 5; }
|
||||
.discovery-stream.layout .column-4 {
|
||||
.discovery-stream.ds-layout .ds-column-4 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 4; }
|
||||
.discovery-stream.layout .column-3 {
|
||||
.discovery-stream.ds-layout .ds-column-3 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 3; }
|
||||
.discovery-stream.layout .column-2 {
|
||||
.discovery-stream.ds-layout .ds-column-2 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 2; }
|
||||
.discovery-stream.layout .column-1 {
|
||||
.discovery-stream.ds-layout .ds-column-1 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 1; }
|
||||
.discovery-stream.ds-layout .ds-column {
|
||||
display: grid;
|
||||
grid-row-gap: 10px; }
|
||||
|
||||
.section-title ul {
|
||||
.ds-hero .wrapper img {
|
||||
width: 100%;
|
||||
height: auto; }
|
||||
|
||||
.ds-hero .wrapper .meta header {
|
||||
font-size: 22px; }
|
||||
|
||||
.ds-hero .wrapper .meta p {
|
||||
font-size: 13px; }
|
||||
|
||||
.column-5 .ds-hero .wrapper,
|
||||
.column-6 .ds-hero .wrapper,
|
||||
.column-7 .ds-hero .wrapper,
|
||||
.column-8 .ds-hero .wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start; }
|
||||
.column-5 .ds-hero .wrapper img,
|
||||
.column-6 .ds-hero .wrapper img,
|
||||
.column-7 .ds-hero .wrapper img,
|
||||
.column-8 .ds-hero .wrapper img {
|
||||
width: 50%;
|
||||
height: auto; }
|
||||
.column-5 .ds-hero .wrapper .meta,
|
||||
.column-6 .ds-hero .wrapper .meta,
|
||||
.column-7 .ds-hero .wrapper .meta,
|
||||
.column-8 .ds-hero .wrapper .meta {
|
||||
width: 50%; }
|
||||
|
||||
.column-5 .ds-hero .cards,
|
||||
.column-6 .ds-hero .cards,
|
||||
.column-7 .ds-hero .cards,
|
||||
.column-8 .ds-hero .cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap; }
|
||||
.column-5 .ds-hero .cards .ds-card,
|
||||
.column-6 .ds-hero .cards .ds-card,
|
||||
.column-7 .ds-hero .cards .ds-card,
|
||||
.column-8 .ds-hero .cards .ds-card {
|
||||
width: 50%;
|
||||
padding: 12px; }
|
||||
.column-5 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-6 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-7 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-8 .ds-hero .cards .ds-card:nth-child(odd) {
|
||||
padding: 12px 12px 12px 0; }
|
||||
.column-5 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-6 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-7 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-8 .ds-hero .cards .ds-card:nth-child(even) {
|
||||
padding: 12px 0 12px 12px; }
|
||||
|
||||
.column-9 .ds-hero .wrapper,
|
||||
.column-10 .ds-hero .wrapper,
|
||||
.column-11 .ds-hero .wrapper,
|
||||
.column-12 .ds-hero .wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start; }
|
||||
.column-9 .ds-hero .wrapper img,
|
||||
.column-10 .ds-hero .wrapper img,
|
||||
.column-11 .ds-hero .wrapper img,
|
||||
.column-12 .ds-hero .wrapper img {
|
||||
width: 67%; }
|
||||
.column-9 .ds-hero .wrapper .meta,
|
||||
.column-10 .ds-hero .wrapper .meta,
|
||||
.column-11 .ds-hero .wrapper .meta,
|
||||
.column-12 .ds-hero .wrapper .meta {
|
||||
width: 33%;
|
||||
padding: 24px; }
|
||||
.column-9 .ds-hero .wrapper .meta header,
|
||||
.column-10 .ds-hero .wrapper .meta header,
|
||||
.column-11 .ds-hero .wrapper .meta header,
|
||||
.column-12 .ds-hero .wrapper .meta header {
|
||||
font-size: 22px; }
|
||||
.column-9 .ds-hero .wrapper .meta p,
|
||||
.column-10 .ds-hero .wrapper .meta p,
|
||||
.column-11 .ds-hero .wrapper .meta p,
|
||||
.column-12 .ds-hero .wrapper .meta p {
|
||||
font-size: 15px; }
|
||||
|
||||
.column-9 .ds-hero .cards,
|
||||
.column-10 .ds-hero .cards,
|
||||
.column-11 .ds-hero .cards,
|
||||
.column-12 .ds-hero .cards {
|
||||
display: flex; }
|
||||
.column-9 .ds-hero .cards .ds-card,
|
||||
.column-10 .ds-hero .cards .ds-card,
|
||||
.column-11 .ds-hero .cards .ds-card,
|
||||
.column-12 .ds-hero .cards .ds-card {
|
||||
width: 25%;
|
||||
padding: 12px; }
|
||||
.column-9 .ds-hero .cards .ds-card .meta,
|
||||
.column-10 .ds-hero .cards .ds-card .meta,
|
||||
.column-11 .ds-hero .cards .ds-card .meta,
|
||||
.column-12 .ds-hero .cards .ds-card .meta {
|
||||
padding: 0; }
|
||||
.column-9 .ds-hero .cards .ds-card:first-child,
|
||||
.column-10 .ds-hero .cards .ds-card:first-child,
|
||||
.column-11 .ds-hero .cards .ds-card:first-child,
|
||||
.column-12 .ds-hero .cards .ds-card:first-child {
|
||||
padding: 12px 12px 12px 0; }
|
||||
.column-9 .ds-hero .cards .ds-card:last-child,
|
||||
.column-10 .ds-hero .cards .ds-card:last-child,
|
||||
.column-11 .ds-hero .cards .ds-card:last-child,
|
||||
.column-12 .ds-hero .cards .ds-card:last-child {
|
||||
padding: 12px 0 12px 12px; }
|
||||
|
||||
.ds-section-title ul {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.section-title ul li {
|
||||
.ds-section-title ul li {
|
||||
display: inline-block; }
|
||||
.section-title ul li::after {
|
||||
.ds-section-title ul li::after {
|
||||
content: '•';
|
||||
padding: 8px; }
|
||||
.section-title ul li:last-child::after {
|
||||
.ds-section-title ul li:last-child::after {
|
||||
content: none; }
|
||||
|
||||
.section-title .ds-more-recommendations::after {
|
||||
.ds-section-title .ds-more-recommendations::after {
|
||||
background: url("../data/content/assets/topic-show-more-12.svg") no-repeat center center;
|
||||
content: '';
|
||||
-moz-context-properties: fill;
|
||||
|
@ -1813,6 +1935,30 @@ main {
|
|||
vertical-align: top;
|
||||
width: 12px; }
|
||||
|
||||
.ds-top-sites .top-sites {
|
||||
padding: 0; }
|
||||
.ds-top-sites .top-sites .section-top-bar {
|
||||
display: none; }
|
||||
|
||||
.ds-card img {
|
||||
width: 100%;
|
||||
border: 0.5px solid rgba(0, 0, 0, 0.1);
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px; }
|
||||
|
||||
.ds-card .meta {
|
||||
padding: 16px; }
|
||||
|
||||
.ds-card header {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: #0C0C0D; }
|
||||
|
||||
.ds-card p {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #737373; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1073,9 +1073,22 @@ main {
|
|||
.search-active .search-handoff-button {
|
||||
border: 1px solid var(--newtab-textbox-focus-color);
|
||||
box-shadow: var(--newtab-textbox-focus-boxshadow); }
|
||||
.search-handoff-button:focus .fake-caret,
|
||||
.search-active .search-handoff-button .fake-caret {
|
||||
display: block; }
|
||||
.search-hidden .search-handoff-button {
|
||||
opacity: 0;
|
||||
visibility: hidden; }
|
||||
.search-handoff-button .fake-editable:focus {
|
||||
outline: none;
|
||||
caret-color: transparent; }
|
||||
.search-handoff-button .fake-editable {
|
||||
color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0; }
|
||||
.search-handoff-button .fake-textbox {
|
||||
opacity: 0.54;
|
||||
text-align: start; }
|
||||
|
@ -1092,8 +1105,6 @@ main {
|
|||
@keyframes caret-animation {
|
||||
to {
|
||||
visibility: hidden; } }
|
||||
.search-active .search-handoff-button .fake-caret {
|
||||
display: block; }
|
||||
|
||||
@media (min-height: 701px) {
|
||||
.fixed-search main {
|
||||
|
@ -1704,6 +1715,8 @@ main {
|
|||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid var(--newtab-border-secondary-color); }
|
||||
.asrouter-admin .ds-component {
|
||||
margin-bottom: 20px; }
|
||||
|
||||
.pocket-logged-in-cta {
|
||||
font-size: 13px;
|
||||
|
@ -1752,61 +1765,170 @@ main {
|
|||
.more-recommendations:dir(rtl)::after {
|
||||
transform: scaleX(-1); }
|
||||
|
||||
.discovery-stream.layout {
|
||||
.discovery-stream.ds-layout {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
grid-column-gap: 10px;
|
||||
grid-column-gap: 48px;
|
||||
grid-row-gap: 10px; }
|
||||
.discovery-stream.layout .column-12 {
|
||||
.discovery-stream.ds-layout .ds-column-12 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 12; }
|
||||
.discovery-stream.layout .column-11 {
|
||||
.discovery-stream.ds-layout .ds-column-11 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 11; }
|
||||
.discovery-stream.layout .column-10 {
|
||||
.discovery-stream.ds-layout .ds-column-10 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 10; }
|
||||
.discovery-stream.layout .column-9 {
|
||||
.discovery-stream.ds-layout .ds-column-9 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 9; }
|
||||
.discovery-stream.layout .column-8 {
|
||||
.discovery-stream.ds-layout .ds-column-8 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 8; }
|
||||
.discovery-stream.layout .column-7 {
|
||||
.discovery-stream.ds-layout .ds-column-7 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 7; }
|
||||
.discovery-stream.layout .column-6 {
|
||||
.discovery-stream.ds-layout .ds-column-6 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 6; }
|
||||
.discovery-stream.layout .column-5 {
|
||||
.discovery-stream.ds-layout .ds-column-5 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 5; }
|
||||
.discovery-stream.layout .column-4 {
|
||||
.discovery-stream.ds-layout .ds-column-4 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 4; }
|
||||
.discovery-stream.layout .column-3 {
|
||||
.discovery-stream.ds-layout .ds-column-3 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 3; }
|
||||
.discovery-stream.layout .column-2 {
|
||||
.discovery-stream.ds-layout .ds-column-2 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 2; }
|
||||
.discovery-stream.layout .column-1 {
|
||||
.discovery-stream.ds-layout .ds-column-1 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 1; }
|
||||
.discovery-stream.ds-layout .ds-column {
|
||||
display: grid;
|
||||
grid-row-gap: 10px; }
|
||||
|
||||
.section-title ul {
|
||||
.ds-hero .wrapper img {
|
||||
width: 100%;
|
||||
height: auto; }
|
||||
|
||||
.ds-hero .wrapper .meta header {
|
||||
font-size: 22px; }
|
||||
|
||||
.ds-hero .wrapper .meta p {
|
||||
font-size: 13px; }
|
||||
|
||||
.column-5 .ds-hero .wrapper,
|
||||
.column-6 .ds-hero .wrapper,
|
||||
.column-7 .ds-hero .wrapper,
|
||||
.column-8 .ds-hero .wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start; }
|
||||
.column-5 .ds-hero .wrapper img,
|
||||
.column-6 .ds-hero .wrapper img,
|
||||
.column-7 .ds-hero .wrapper img,
|
||||
.column-8 .ds-hero .wrapper img {
|
||||
width: 50%;
|
||||
height: auto; }
|
||||
.column-5 .ds-hero .wrapper .meta,
|
||||
.column-6 .ds-hero .wrapper .meta,
|
||||
.column-7 .ds-hero .wrapper .meta,
|
||||
.column-8 .ds-hero .wrapper .meta {
|
||||
width: 50%; }
|
||||
|
||||
.column-5 .ds-hero .cards,
|
||||
.column-6 .ds-hero .cards,
|
||||
.column-7 .ds-hero .cards,
|
||||
.column-8 .ds-hero .cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap; }
|
||||
.column-5 .ds-hero .cards .ds-card,
|
||||
.column-6 .ds-hero .cards .ds-card,
|
||||
.column-7 .ds-hero .cards .ds-card,
|
||||
.column-8 .ds-hero .cards .ds-card {
|
||||
width: 50%;
|
||||
padding: 12px; }
|
||||
.column-5 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-6 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-7 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-8 .ds-hero .cards .ds-card:nth-child(odd) {
|
||||
padding: 12px 12px 12px 0; }
|
||||
.column-5 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-6 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-7 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-8 .ds-hero .cards .ds-card:nth-child(even) {
|
||||
padding: 12px 0 12px 12px; }
|
||||
|
||||
.column-9 .ds-hero .wrapper,
|
||||
.column-10 .ds-hero .wrapper,
|
||||
.column-11 .ds-hero .wrapper,
|
||||
.column-12 .ds-hero .wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start; }
|
||||
.column-9 .ds-hero .wrapper img,
|
||||
.column-10 .ds-hero .wrapper img,
|
||||
.column-11 .ds-hero .wrapper img,
|
||||
.column-12 .ds-hero .wrapper img {
|
||||
width: 67%; }
|
||||
.column-9 .ds-hero .wrapper .meta,
|
||||
.column-10 .ds-hero .wrapper .meta,
|
||||
.column-11 .ds-hero .wrapper .meta,
|
||||
.column-12 .ds-hero .wrapper .meta {
|
||||
width: 33%;
|
||||
padding: 24px; }
|
||||
.column-9 .ds-hero .wrapper .meta header,
|
||||
.column-10 .ds-hero .wrapper .meta header,
|
||||
.column-11 .ds-hero .wrapper .meta header,
|
||||
.column-12 .ds-hero .wrapper .meta header {
|
||||
font-size: 22px; }
|
||||
.column-9 .ds-hero .wrapper .meta p,
|
||||
.column-10 .ds-hero .wrapper .meta p,
|
||||
.column-11 .ds-hero .wrapper .meta p,
|
||||
.column-12 .ds-hero .wrapper .meta p {
|
||||
font-size: 15px; }
|
||||
|
||||
.column-9 .ds-hero .cards,
|
||||
.column-10 .ds-hero .cards,
|
||||
.column-11 .ds-hero .cards,
|
||||
.column-12 .ds-hero .cards {
|
||||
display: flex; }
|
||||
.column-9 .ds-hero .cards .ds-card,
|
||||
.column-10 .ds-hero .cards .ds-card,
|
||||
.column-11 .ds-hero .cards .ds-card,
|
||||
.column-12 .ds-hero .cards .ds-card {
|
||||
width: 25%;
|
||||
padding: 12px; }
|
||||
.column-9 .ds-hero .cards .ds-card .meta,
|
||||
.column-10 .ds-hero .cards .ds-card .meta,
|
||||
.column-11 .ds-hero .cards .ds-card .meta,
|
||||
.column-12 .ds-hero .cards .ds-card .meta {
|
||||
padding: 0; }
|
||||
.column-9 .ds-hero .cards .ds-card:first-child,
|
||||
.column-10 .ds-hero .cards .ds-card:first-child,
|
||||
.column-11 .ds-hero .cards .ds-card:first-child,
|
||||
.column-12 .ds-hero .cards .ds-card:first-child {
|
||||
padding: 12px 12px 12px 0; }
|
||||
.column-9 .ds-hero .cards .ds-card:last-child,
|
||||
.column-10 .ds-hero .cards .ds-card:last-child,
|
||||
.column-11 .ds-hero .cards .ds-card:last-child,
|
||||
.column-12 .ds-hero .cards .ds-card:last-child {
|
||||
padding: 12px 0 12px 12px; }
|
||||
|
||||
.ds-section-title ul {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.section-title ul li {
|
||||
.ds-section-title ul li {
|
||||
display: inline-block; }
|
||||
.section-title ul li::after {
|
||||
.ds-section-title ul li::after {
|
||||
content: '•';
|
||||
padding: 8px; }
|
||||
.section-title ul li:last-child::after {
|
||||
.ds-section-title ul li:last-child::after {
|
||||
content: none; }
|
||||
|
||||
.section-title .ds-more-recommendations::after {
|
||||
.ds-section-title .ds-more-recommendations::after {
|
||||
background: url("../data/content/assets/topic-show-more-12.svg") no-repeat center center;
|
||||
content: '';
|
||||
-moz-context-properties: fill;
|
||||
|
@ -1816,6 +1938,30 @@ main {
|
|||
vertical-align: top;
|
||||
width: 12px; }
|
||||
|
||||
.ds-top-sites .top-sites {
|
||||
padding: 0; }
|
||||
.ds-top-sites .top-sites .section-top-bar {
|
||||
display: none; }
|
||||
|
||||
.ds-card img {
|
||||
width: 100%;
|
||||
border: 0.5px solid rgba(0, 0, 0, 0.1);
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px; }
|
||||
|
||||
.ds-card .meta {
|
||||
padding: 16px; }
|
||||
|
||||
.ds-card header {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: #0C0C0D; }
|
||||
|
||||
.ds-card p {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #737373; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1070,9 +1070,22 @@ main {
|
|||
.search-active .search-handoff-button {
|
||||
border: 1px solid var(--newtab-textbox-focus-color);
|
||||
box-shadow: var(--newtab-textbox-focus-boxshadow); }
|
||||
.search-handoff-button:focus .fake-caret,
|
||||
.search-active .search-handoff-button .fake-caret {
|
||||
display: block; }
|
||||
.search-hidden .search-handoff-button {
|
||||
opacity: 0;
|
||||
visibility: hidden; }
|
||||
.search-handoff-button .fake-editable:focus {
|
||||
outline: none;
|
||||
caret-color: transparent; }
|
||||
.search-handoff-button .fake-editable {
|
||||
color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0; }
|
||||
.search-handoff-button .fake-textbox {
|
||||
opacity: 0.54;
|
||||
text-align: start; }
|
||||
|
@ -1089,8 +1102,6 @@ main {
|
|||
@keyframes caret-animation {
|
||||
to {
|
||||
visibility: hidden; } }
|
||||
.search-active .search-handoff-button .fake-caret {
|
||||
display: block; }
|
||||
|
||||
@media (min-height: 701px) {
|
||||
.fixed-search main {
|
||||
|
@ -1701,6 +1712,8 @@ main {
|
|||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid var(--newtab-border-secondary-color); }
|
||||
.asrouter-admin .ds-component {
|
||||
margin-bottom: 20px; }
|
||||
|
||||
.pocket-logged-in-cta {
|
||||
font-size: 13px;
|
||||
|
@ -1749,61 +1762,170 @@ main {
|
|||
.more-recommendations:dir(rtl)::after {
|
||||
transform: scaleX(-1); }
|
||||
|
||||
.discovery-stream.layout {
|
||||
.discovery-stream.ds-layout {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
grid-column-gap: 10px;
|
||||
grid-column-gap: 48px;
|
||||
grid-row-gap: 10px; }
|
||||
.discovery-stream.layout .column-12 {
|
||||
.discovery-stream.ds-layout .ds-column-12 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 12; }
|
||||
.discovery-stream.layout .column-11 {
|
||||
.discovery-stream.ds-layout .ds-column-11 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 11; }
|
||||
.discovery-stream.layout .column-10 {
|
||||
.discovery-stream.ds-layout .ds-column-10 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 10; }
|
||||
.discovery-stream.layout .column-9 {
|
||||
.discovery-stream.ds-layout .ds-column-9 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 9; }
|
||||
.discovery-stream.layout .column-8 {
|
||||
.discovery-stream.ds-layout .ds-column-8 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 8; }
|
||||
.discovery-stream.layout .column-7 {
|
||||
.discovery-stream.ds-layout .ds-column-7 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 7; }
|
||||
.discovery-stream.layout .column-6 {
|
||||
.discovery-stream.ds-layout .ds-column-6 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 6; }
|
||||
.discovery-stream.layout .column-5 {
|
||||
.discovery-stream.ds-layout .ds-column-5 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 5; }
|
||||
.discovery-stream.layout .column-4 {
|
||||
.discovery-stream.ds-layout .ds-column-4 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 4; }
|
||||
.discovery-stream.layout .column-3 {
|
||||
.discovery-stream.ds-layout .ds-column-3 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 3; }
|
||||
.discovery-stream.layout .column-2 {
|
||||
.discovery-stream.ds-layout .ds-column-2 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 2; }
|
||||
.discovery-stream.layout .column-1 {
|
||||
.discovery-stream.ds-layout .ds-column-1 {
|
||||
grid-column-start: auto;
|
||||
grid-column-end: span 1; }
|
||||
.discovery-stream.ds-layout .ds-column {
|
||||
display: grid;
|
||||
grid-row-gap: 10px; }
|
||||
|
||||
.section-title ul {
|
||||
.ds-hero .wrapper img {
|
||||
width: 100%;
|
||||
height: auto; }
|
||||
|
||||
.ds-hero .wrapper .meta header {
|
||||
font-size: 22px; }
|
||||
|
||||
.ds-hero .wrapper .meta p {
|
||||
font-size: 13px; }
|
||||
|
||||
.column-5 .ds-hero .wrapper,
|
||||
.column-6 .ds-hero .wrapper,
|
||||
.column-7 .ds-hero .wrapper,
|
||||
.column-8 .ds-hero .wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start; }
|
||||
.column-5 .ds-hero .wrapper img,
|
||||
.column-6 .ds-hero .wrapper img,
|
||||
.column-7 .ds-hero .wrapper img,
|
||||
.column-8 .ds-hero .wrapper img {
|
||||
width: 50%;
|
||||
height: auto; }
|
||||
.column-5 .ds-hero .wrapper .meta,
|
||||
.column-6 .ds-hero .wrapper .meta,
|
||||
.column-7 .ds-hero .wrapper .meta,
|
||||
.column-8 .ds-hero .wrapper .meta {
|
||||
width: 50%; }
|
||||
|
||||
.column-5 .ds-hero .cards,
|
||||
.column-6 .ds-hero .cards,
|
||||
.column-7 .ds-hero .cards,
|
||||
.column-8 .ds-hero .cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap; }
|
||||
.column-5 .ds-hero .cards .ds-card,
|
||||
.column-6 .ds-hero .cards .ds-card,
|
||||
.column-7 .ds-hero .cards .ds-card,
|
||||
.column-8 .ds-hero .cards .ds-card {
|
||||
width: 50%;
|
||||
padding: 12px; }
|
||||
.column-5 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-6 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-7 .ds-hero .cards .ds-card:nth-child(odd),
|
||||
.column-8 .ds-hero .cards .ds-card:nth-child(odd) {
|
||||
padding: 12px 12px 12px 0; }
|
||||
.column-5 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-6 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-7 .ds-hero .cards .ds-card:nth-child(even),
|
||||
.column-8 .ds-hero .cards .ds-card:nth-child(even) {
|
||||
padding: 12px 0 12px 12px; }
|
||||
|
||||
.column-9 .ds-hero .wrapper,
|
||||
.column-10 .ds-hero .wrapper,
|
||||
.column-11 .ds-hero .wrapper,
|
||||
.column-12 .ds-hero .wrapper {
|
||||
display: flex;
|
||||
align-items: flex-start; }
|
||||
.column-9 .ds-hero .wrapper img,
|
||||
.column-10 .ds-hero .wrapper img,
|
||||
.column-11 .ds-hero .wrapper img,
|
||||
.column-12 .ds-hero .wrapper img {
|
||||
width: 67%; }
|
||||
.column-9 .ds-hero .wrapper .meta,
|
||||
.column-10 .ds-hero .wrapper .meta,
|
||||
.column-11 .ds-hero .wrapper .meta,
|
||||
.column-12 .ds-hero .wrapper .meta {
|
||||
width: 33%;
|
||||
padding: 24px; }
|
||||
.column-9 .ds-hero .wrapper .meta header,
|
||||
.column-10 .ds-hero .wrapper .meta header,
|
||||
.column-11 .ds-hero .wrapper .meta header,
|
||||
.column-12 .ds-hero .wrapper .meta header {
|
||||
font-size: 22px; }
|
||||
.column-9 .ds-hero .wrapper .meta p,
|
||||
.column-10 .ds-hero .wrapper .meta p,
|
||||
.column-11 .ds-hero .wrapper .meta p,
|
||||
.column-12 .ds-hero .wrapper .meta p {
|
||||
font-size: 15px; }
|
||||
|
||||
.column-9 .ds-hero .cards,
|
||||
.column-10 .ds-hero .cards,
|
||||
.column-11 .ds-hero .cards,
|
||||
.column-12 .ds-hero .cards {
|
||||
display: flex; }
|
||||
.column-9 .ds-hero .cards .ds-card,
|
||||
.column-10 .ds-hero .cards .ds-card,
|
||||
.column-11 .ds-hero .cards .ds-card,
|
||||
.column-12 .ds-hero .cards .ds-card {
|
||||
width: 25%;
|
||||
padding: 12px; }
|
||||
.column-9 .ds-hero .cards .ds-card .meta,
|
||||
.column-10 .ds-hero .cards .ds-card .meta,
|
||||
.column-11 .ds-hero .cards .ds-card .meta,
|
||||
.column-12 .ds-hero .cards .ds-card .meta {
|
||||
padding: 0; }
|
||||
.column-9 .ds-hero .cards .ds-card:first-child,
|
||||
.column-10 .ds-hero .cards .ds-card:first-child,
|
||||
.column-11 .ds-hero .cards .ds-card:first-child,
|
||||
.column-12 .ds-hero .cards .ds-card:first-child {
|
||||
padding: 12px 12px 12px 0; }
|
||||
.column-9 .ds-hero .cards .ds-card:last-child,
|
||||
.column-10 .ds-hero .cards .ds-card:last-child,
|
||||
.column-11 .ds-hero .cards .ds-card:last-child,
|
||||
.column-12 .ds-hero .cards .ds-card:last-child {
|
||||
padding: 12px 0 12px 12px; }
|
||||
|
||||
.ds-section-title ul {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.section-title ul li {
|
||||
.ds-section-title ul li {
|
||||
display: inline-block; }
|
||||
.section-title ul li::after {
|
||||
.ds-section-title ul li::after {
|
||||
content: '•';
|
||||
padding: 8px; }
|
||||
.section-title ul li:last-child::after {
|
||||
.ds-section-title ul li:last-child::after {
|
||||
content: none; }
|
||||
|
||||
.section-title .ds-more-recommendations::after {
|
||||
.ds-section-title .ds-more-recommendations::after {
|
||||
background: url("../data/content/assets/topic-show-more-12.svg") no-repeat center center;
|
||||
content: '';
|
||||
-moz-context-properties: fill;
|
||||
|
@ -1813,6 +1935,30 @@ main {
|
|||
vertical-align: top;
|
||||
width: 12px; }
|
||||
|
||||
.ds-top-sites .top-sites {
|
||||
padding: 0; }
|
||||
.ds-top-sites .top-sites .section-top-bar {
|
||||
display: none; }
|
||||
|
||||
.ds-card img {
|
||||
width: 100%;
|
||||
border: 0.5px solid rgba(0, 0, 0, 0.1);
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px; }
|
||||
|
||||
.ds-card .meta {
|
||||
padding: 16px; }
|
||||
|
||||
.ds-card header {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: #0C0C0D; }
|
||||
|
||||
.ds-card p {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
color: #737373; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -205,6 +205,10 @@ const MessageLoaderUtils = {
|
|||
messages = [];
|
||||
Cu.reportError(new Error(`Tried to load messages for ${provider.id} but the result was not an Array.`));
|
||||
}
|
||||
// Filter out messages we temporarily want to exclude
|
||||
if (provider.exclude && provider.exclude.length) {
|
||||
messages = messages.filter(message => !provider.exclude.includes(message.id));
|
||||
}
|
||||
const lastUpdated = Date.now();
|
||||
return {
|
||||
messages: messages.map(msg => ({weight: 100, ...msg, provider: provider.id}))
|
||||
|
@ -213,8 +217,30 @@ const MessageLoaderUtils = {
|
|||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* _loadAddonIconInURLBar - load addons-notification icon by displaying
|
||||
* box containing addons icon in urlbar. See Bug 1513882
|
||||
*
|
||||
* @param {XULElement} Target browser element for showing addons icon
|
||||
*/
|
||||
_loadAddonIconInURLBar(browser) {
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
const chromeDoc = browser.ownerDocument;
|
||||
let notificationPopupBox = chromeDoc.getElementById("notification-popup-box");
|
||||
if (!notificationPopupBox) {
|
||||
return;
|
||||
}
|
||||
if (notificationPopupBox.style.display === "none" ||
|
||||
notificationPopupBox.style.display === "") {
|
||||
notificationPopupBox.style.display = "block";
|
||||
}
|
||||
},
|
||||
|
||||
async installAddonFromURL(browser, url) {
|
||||
try {
|
||||
MessageLoaderUtils._loadAddonIconInURLBar(browser);
|
||||
const aUri = Services.io.newURI(url);
|
||||
const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
|
||||
|
@ -340,15 +366,10 @@ class _ASRouter {
|
|||
}
|
||||
}
|
||||
|
||||
// Group existing blocked messages with messages blocked through preferences
|
||||
const excludeList = ASRouterPreferences.providers.filter(p => p.exclude)
|
||||
.reduce((blocked, p) => blocked.concat(p.exclude), this.state.messageBlockList);
|
||||
|
||||
this.setState(prevState => ({
|
||||
providers,
|
||||
// Clear any messages from removed providers
|
||||
messages: [...prevState.messages.filter(message => providerIDs.includes(message.provider))],
|
||||
messageBlockList: excludeList,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ const {PersistentCache} = ChromeUtils.import("resource://activity-stream/lib/Per
|
|||
|
||||
const CACHE_KEY = "discovery_stream";
|
||||
const LAYOUT_UPDATE_TIME = 30 * 60 * 1000; // 30 minutes
|
||||
const COMPONENT_FEEDS_UPDATE_TIME = 30 * 60 * 1000; // 30 minutes
|
||||
const CONFIG_PREF_NAME = "browser.newtabpage.activity-stream.discoverystream.config";
|
||||
|
||||
this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
||||
|
@ -69,7 +70,7 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
const response = await fetch(endpoint, {credentials: "omit"});
|
||||
if (!response.ok) {
|
||||
// istanbul ignore next
|
||||
throw new Error(`Stories endpoint returned unexpected status: ${response.status}`);
|
||||
throw new Error(`Layout endpoint returned unexpected status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
} catch (error) {
|
||||
|
@ -80,7 +81,7 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
return null;
|
||||
}
|
||||
|
||||
async loadCachedData() {
|
||||
async loadLayout() {
|
||||
const cachedData = await this.cache.get() || {};
|
||||
let {layout: layoutResponse} = cachedData;
|
||||
if (!layoutResponse || !(Date.now() - layoutResponse._timestamp < LAYOUT_UPDATE_TIME)) {
|
||||
|
@ -104,8 +105,65 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
}
|
||||
}
|
||||
|
||||
async loadComponentFeeds() {
|
||||
const {DiscoveryStream} = this.store.getState();
|
||||
const newFeeds = {};
|
||||
if (DiscoveryStream && DiscoveryStream.layout) {
|
||||
for (let row of DiscoveryStream.layout) {
|
||||
if (!row || !row.components) {
|
||||
continue;
|
||||
}
|
||||
for (let component of row.components) {
|
||||
if (component && component.feed) {
|
||||
const {url} = component.feed;
|
||||
newFeeds[url] = await this.getComponentFeed(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.cache.set("feeds", newFeeds);
|
||||
this.store.dispatch(ac.BroadcastToContent({type: at.DISCOVERY_STREAM_FEEDS_UPDATE, data: newFeeds}));
|
||||
}
|
||||
}
|
||||
|
||||
async getComponentFeed(feedUrl) {
|
||||
const cachedData = await this.cache.get() || {};
|
||||
const {feeds} = cachedData;
|
||||
let feed = feeds && feeds[feedUrl];
|
||||
if (!feed || !(Date.now() - feed.lastUpdated < COMPONENT_FEEDS_UPDATE_TIME)) {
|
||||
const feedResponse = await this.fetchComponentFeed(feedUrl);
|
||||
if (feedResponse) {
|
||||
feed = {
|
||||
lastUpdated: Date.now(),
|
||||
data: feedResponse,
|
||||
};
|
||||
} else {
|
||||
Cu.reportError("No response for feed");
|
||||
}
|
||||
}
|
||||
|
||||
return feed;
|
||||
}
|
||||
|
||||
async fetchComponentFeed(feedUrl) {
|
||||
try {
|
||||
const response = await fetch(feedUrl, {credentials: "omit"});
|
||||
if (!response.ok) {
|
||||
// istanbul ignore next
|
||||
throw new Error(`Component feed endpoint returned unexpected status: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
} catch (error) {
|
||||
// istanbul ignore next
|
||||
Cu.reportError(`Failed to fetch Component feed: ${error.message}`);
|
||||
}
|
||||
// istanbul ignore next
|
||||
return null;
|
||||
}
|
||||
|
||||
async enable() {
|
||||
await this.loadCachedData();
|
||||
await this.loadLayout();
|
||||
await this.loadComponentFeeds();
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
|
@ -118,6 +176,7 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
|
||||
async clearCache() {
|
||||
await this.cache.set("layout", {});
|
||||
await this.cache.set("feeds", {});
|
||||
}
|
||||
|
||||
async onPrefChange() {
|
||||
|
|
|
@ -286,21 +286,32 @@ class PlacesFeed {
|
|||
handoffSearchToAwesomebar({_target, data, meta}) {
|
||||
const urlBar = _target.browser.ownerGlobal.gURLBar;
|
||||
|
||||
if (!data.hiddenFocus) {
|
||||
if (!data.hiddenFocus && !data.text) {
|
||||
// Do a normal focus of awesomebar and reset the in content search (remove fake focus styles).
|
||||
urlBar.focus();
|
||||
this.store.dispatch(ac.OnlyToOneContent({type: at.SHOW_SEARCH}, meta.fromTarget));
|
||||
// We are done here. return early.
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus the awesomebar without the style changes.
|
||||
urlBar.hiddenFocus();
|
||||
const onKeydown = () => {
|
||||
// Once the user starts typing, we want to hide the in content search box
|
||||
// and show the focus styles on the awesomebar.
|
||||
if (data.text) {
|
||||
// Pass the provided text to the awesomebar.
|
||||
urlBar.search(data.text);
|
||||
this.store.dispatch(ac.OnlyToOneContent({type: at.HIDE_SEARCH}, meta.fromTarget));
|
||||
urlBar.removeHiddenFocus();
|
||||
urlBar.removeEventListener("keydown", onKeydown);
|
||||
} else {
|
||||
// Focus the awesomebar without the style changes.
|
||||
urlBar.hiddenFocus();
|
||||
}
|
||||
|
||||
const onKeydown = event => {
|
||||
// We only care about key strokes that will produce a character.
|
||||
if (event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey) {
|
||||
// Once the user starts typing, we want to hide the in content search box
|
||||
// and show the focus styles on the awesomebar.
|
||||
this.store.dispatch(ac.OnlyToOneContent({type: at.HIDE_SEARCH}, meta.fromTarget));
|
||||
urlBar.removeHiddenFocus();
|
||||
urlBar.removeEventListener("keydown", onKeydown);
|
||||
}
|
||||
};
|
||||
const onDone = () => {
|
||||
// When done, let's cleanup everything.
|
||||
|
|
|
@ -40,7 +40,7 @@ confirm_history_delete_p1=Imoko ni imito kwanyo nyig jami weng me potbuk man ki
|
|||
# the same dialog as confirm_history_delete_p1. "This action" refers to deleting a
|
||||
# page from history.
|
||||
confirm_history_delete_notice_p2=Pe ki twero gonyo tic man.
|
||||
menu_action_save_to_pocket=Gwoki i jaba
|
||||
menu_action_save_to_pocket=Gwok i Pocket
|
||||
menu_action_delete_pocket=Kwany ki ii Pocket
|
||||
menu_action_archive_pocket=Kan i Pocket
|
||||
|
||||
|
@ -141,7 +141,6 @@ pocket_read_more=Lok macuk gi lamal:
|
|||
# LOCALIZATION NOTE (pocket_read_even_more): This is shown as a link at the
|
||||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Nen Lok mapol
|
||||
pocket_learn_more=Nong ngec mapol
|
||||
pocket_how_it_works=Kit ma tiyo kwede
|
||||
pocket_cta_button=Nong Pocket
|
||||
pocket_cta_text=Gwok lok ma imaro ii Pocket, ka i pik wii ki jami me akwana ma mako wii.
|
||||
|
|
|
@ -144,9 +144,9 @@ pocket_read_more=জনপ্রিয় বিষয়:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=আরও গল্প দেখুন
|
||||
pocket_more_reccommendations=আরও সুপারিশ
|
||||
pocket_learn_more=আরও জানুন
|
||||
pocket_how_it_works=কিভাবে এটা কাজ করে
|
||||
pocket_cta_button=Pocket ব্যবহার করুন
|
||||
pocket_cta_text=Pocket এ আপনার পছন্দের গল্পগুলো সংরক্ষণ করুন, এবং চমৎকার সব লেখা পড়ে আপনার মনের ইন্ধন যোগান।
|
||||
|
||||
highlights_empty_state=ব্রাউজি করা শুরু করুন, এবং কিছু গুরুত্বপূর্ণ নিবন্ধ, ভিডিও, এবং আপনি সম্প্রতি পরিদর্শন বা বুকমার্ক করেছেন এমন কিছু পৃষ্ঠা আমরা এখানে প্রদর্শন করব।
|
||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||
|
|
|
@ -144,10 +144,7 @@ pocket_read_more=موضوعهای محبوب:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=مشاهده داستانهای بیشتر
|
||||
pocket_more_reccommendations=توصیههای بیشتر
|
||||
pocket_learn_more=بیشتر بدانید
|
||||
pocket_how_it_works=این چجوری کار میکنه
|
||||
pocket_cta_button=دریافت پاکت
|
||||
pocket_cta_text=داستانهایی را که دوست دارید در پاکت خود ذخیره کنید و ذهن خود را با خواندنیهای جذاب پرورش دهید.
|
||||
|
||||
highlights_empty_state=مرور کردن را شروع کنید و شاهد تعداد زیادی مقاله، فیلم و صفحات خوبی باشید که اخیر مشاهده کرده اید یا نشانگ گذاری کرده اید.
|
||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||
|
|
|
@ -38,7 +38,6 @@ confirm_history_delete_p1=Վստահ եք, որ ցանկանում եք ջնջե
|
|||
# the same dialog as confirm_history_delete_p1. "This action" refers to deleting a
|
||||
# page from history.
|
||||
confirm_history_delete_notice_p2=Այս գործողությունը չի կարող վերացվել.
|
||||
menu_action_save_to_pocket=Պահպանեք գրպանում
|
||||
|
||||
# LOCALIZATION NOTE (menu_action_show_file_*): These are platform specific strings
|
||||
# found in the context menu of an item that has been downloaded. The intention behind
|
||||
|
|
|
@ -144,7 +144,6 @@ pocket_read_more=人気のトピック:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=他の記事を見る
|
||||
pocket_more_reccommendations=他のおすすめ
|
||||
pocket_learn_more=詳細
|
||||
pocket_how_it_works=使い方
|
||||
pocket_cta_button=Pocket を入手
|
||||
pocket_cta_text=お気に入りに記事を Pocket に保存して、魅力的な読み物を思う存分楽しみましょう。
|
||||
|
|
|
@ -144,7 +144,6 @@ pocket_read_more=人気のトピック:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=他の記事を見る
|
||||
pocket_more_reccommendations=他のおすすめ
|
||||
pocket_learn_more=詳細
|
||||
pocket_how_it_works=使い方
|
||||
pocket_cta_button=Pocket を入手
|
||||
pocket_cta_text=お気に入りに記事を Pocket に保存して、魅力的な読み物を思う存分楽しみましょう。
|
||||
|
|
|
@ -21,7 +21,7 @@ window.gActivityStreamStrings = {
|
|||
"menu_action_unpin": "War",
|
||||
"confirm_history_delete_p1": "Imoko ni imito kwanyo nyig jami weng me potbuk man ki i gin mukato mamegi?",
|
||||
"confirm_history_delete_notice_p2": "Pe ki twero gonyo tic man.",
|
||||
"menu_action_save_to_pocket": "Gwoki i jaba",
|
||||
"menu_action_save_to_pocket": "Gwok i Pocket",
|
||||
"menu_action_delete_pocket": "Kwany ki ii Pocket",
|
||||
"menu_action_archive_pocket": "Kan i Pocket",
|
||||
"menu_action_show_file_mac_os": "Nyut i Gin nongo",
|
||||
|
@ -107,6 +107,5 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_privacy_notice": "Ngec me mung",
|
||||
"firstrun_continue_to_login": "Mede",
|
||||
"firstrun_skip_login": "Kal citep man",
|
||||
"context_menu_title": "Yab jami ayera",
|
||||
"pocket_learn_more": "Nong ngec mapol"
|
||||
"context_menu_title": "Yab jami ayera"
|
||||
};
|
||||
|
|
|
@ -77,7 +77,7 @@ window.gActivityStreamStrings = {
|
|||
"pocket_more_reccommendations": "আরও সুপারিশ",
|
||||
"pocket_how_it_works": "কিভাবে এটা কাজ করে",
|
||||
"pocket_cta_button": "Pocket ব্যবহার করুন",
|
||||
"pocket_cta_text": "আপনার পছন্দের গল্পগুলো Pocket এ সংরক্ষণ করুন, এবং আকর্ষণীয় মনে পড়ুন।",
|
||||
"pocket_cta_text": "Pocket এ আপনার পছন্দের গল্পগুলো সংরক্ষণ করুন, এবং চমৎকার সব লেখা পড়ে আপনার মনের ইন্ধন যোগান।",
|
||||
"highlights_empty_state": "ব্রাউজি করা শুরু করুন, এবং কিছু গুরুত্বপূর্ণ নিবন্ধ, ভিডিও, এবং আপনি সম্প্রতি পরিদর্শন বা বুকমার্ক করেছেন এমন কিছু পৃষ্ঠা আমরা এখানে প্রদর্শন করব।",
|
||||
"topstories_empty_state": "কিছু একটা ঠিক নেই। {provider} এর শীর্ষ গল্পগুলো পেতে কিছুক্ষণ পর আবার দেখুন। অপেক্ষা করতে চান না? বিশ্বের সেরা গল্পগুলো পেতে কোন জনপ্রিয় বিষয় নির্বাচন করুন।",
|
||||
"manual_migration_explanation2": "অন্য ব্রাউজার থেকে আনা বুকমার্ক, ইতিহাস এবং পাসওয়ার্ডগুলির সাথে ফায়ারফক্স ব্যবহার করে দেখুন।",
|
||||
|
@ -108,5 +108,5 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_continue_to_login": "চালিয়ে যান",
|
||||
"firstrun_skip_login": "এই ধাপটি বাদ দিন",
|
||||
"context_menu_title": "মেনু খুলুন",
|
||||
"pocket_learn_more": "আরও জানুন"
|
||||
"pocket_learn_more": "আরো জানুন"
|
||||
};
|
||||
|
|
|
@ -76,8 +76,8 @@ window.gActivityStreamStrings = {
|
|||
"pocket_read_even_more": "مشاهده داستانهای بیشتر",
|
||||
"pocket_more_reccommendations": "توصیههای بیشتر",
|
||||
"pocket_how_it_works": "این چجوری کار میکنه",
|
||||
"pocket_cta_button": "دریافت پاکت",
|
||||
"pocket_cta_text": "داستانهایی را که دوست دارید در پاکت خود ذخیره کنید و ذهن خود را با خواندنیهای جذاب پرورش دهید.",
|
||||
"pocket_cta_button": "Get Pocket",
|
||||
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
||||
"highlights_empty_state": "مرور کردن را شروع کنید و شاهد تعداد زیادی مقاله، فیلم و صفحات خوبی باشید که اخیر مشاهده کرده اید یا نشانگ گذاری کرده اید.",
|
||||
"topstories_empty_state": "فعلا تموم شد. بعدا دوباره سر بزن تا مطالب جدید از {provider} ببینی. نمیتونی صبر کنی؟ یک موضوع محبوب رو انتخاب کن تا مطالب جالب مرتبط از سراسر دنیا رو پیدا کنی.",
|
||||
"manual_migration_explanation2": "فایرفاکس را با نشانکها، تاریخچهها و کلمات عبور از سایر مرورگر ها تجربه کنید.",
|
||||
|
@ -107,6 +107,5 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_privacy_notice": "نکات حریمخصوصی",
|
||||
"firstrun_continue_to_login": "ادامه",
|
||||
"firstrun_skip_login": "پرش از این مرحله",
|
||||
"context_menu_title": "باز کردن منو",
|
||||
"pocket_learn_more": "بیشتر بدانید"
|
||||
"context_menu_title": "باز کردن منو"
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ window.gActivityStreamStrings = {
|
|||
"menu_action_unpin": "Ապամրացնել",
|
||||
"confirm_history_delete_p1": "Վստահ եք, որ ցանկանում եք ջնջել այս էջի ամեն մի օրինակ ձեր պատմությունից?",
|
||||
"confirm_history_delete_notice_p2": "Այս գործողությունը չի կարող վերացվել.",
|
||||
"menu_action_save_to_pocket": "Պահպանեք գրպանում",
|
||||
"menu_action_save_to_pocket": "Save to Pocket",
|
||||
"menu_action_delete_pocket": "Delete from Pocket",
|
||||
"menu_action_archive_pocket": "Archive in Pocket",
|
||||
"menu_action_show_file_mac_os": "Show in Finder",
|
||||
|
|
|
@ -107,6 +107,5 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_privacy_notice": "プライバシーに関する通知",
|
||||
"firstrun_continue_to_login": "続ける",
|
||||
"firstrun_skip_login": "この手順をスキップ",
|
||||
"context_menu_title": "メニューを開きます",
|
||||
"pocket_learn_more": "詳細"
|
||||
"context_menu_title": "メニューを開きます"
|
||||
};
|
||||
|
|
|
@ -107,6 +107,5 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_privacy_notice": "プライバシーに関する通知",
|
||||
"firstrun_continue_to_login": "続ける",
|
||||
"firstrun_skip_login": "この手順をスキップ",
|
||||
"context_menu_title": "メニューを開きます",
|
||||
"pocket_learn_more": "詳細"
|
||||
"context_menu_title": "メニューを開きます"
|
||||
};
|
||||
|
|
|
@ -130,14 +130,6 @@ describe("ASRouter", () => {
|
|||
|
||||
assert.deepEqual(Router.state.messageBlockList, ["foo"]);
|
||||
});
|
||||
it("should set state.messageBlockList to the block list in ASRouterPreferences", async () => {
|
||||
setMessageProviderPref([{id: "onboarding", type: "local", exclude: ["RTAMO"]}]);
|
||||
messageBlockList = ["foo"];
|
||||
Router = new _ASRouter();
|
||||
await Router.init(channel, createFakeStorage(), dispatchStub);
|
||||
|
||||
assert.deepEqual(Router.state.messageBlockList, ["foo", "RTAMO"]);
|
||||
});
|
||||
it("should set state.messageImpressions to the messageImpressions object in persistent storage", async () => {
|
||||
// Note that messageImpressions are only kept if a message exists in router and has a .frequency property,
|
||||
// otherwise they will be cleaned up by .cleanupImpressions()
|
||||
|
|
|
@ -36,6 +36,14 @@ describe("MessageLoaderUtils", () => {
|
|||
assert.propertyVal(message, "id", "foo");
|
||||
assert.propertyVal(message, "provider", "provider123");
|
||||
});
|
||||
it("should filter out local messages listed in the `exclude` field", async () => {
|
||||
const sourceMessage = {id: "foo"};
|
||||
const provider = {id: "provider123", type: "local", messages: [sourceMessage], exclude: ["foo"]};
|
||||
|
||||
const result = await MessageLoaderUtils.loadMessagesForProvider(provider, FAKE_STORAGE);
|
||||
|
||||
assert.lengthOf(result.messages, 0);
|
||||
});
|
||||
it("should return messages for remote provider", async () => {
|
||||
const sourceMessage = {id: "foo"};
|
||||
fetchStub.resolves({ok: true, status: 200, json: () => Promise.resolve({messages: [sourceMessage]}), headers: FAKE_RESPONSE_HEADERS});
|
||||
|
@ -225,6 +233,45 @@ describe("MessageLoaderUtils", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#_loadAddonIconInURLBar", () => {
|
||||
let sandbox;
|
||||
let notificationContainerEl;
|
||||
let browser;
|
||||
let getContainerStub;
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
notificationContainerEl = {style: {}};
|
||||
browser = {ownerDocument: {getElementById() { return {}; }}};
|
||||
getContainerStub = sandbox.stub(browser.ownerDocument, "getElementById");
|
||||
});
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
it("should return for empty args", () => {
|
||||
MessageLoaderUtils._loadAddonIconInURLBar();
|
||||
assert.notCalled(getContainerStub);
|
||||
});
|
||||
it("should return if notification popup box not found", () => {
|
||||
getContainerStub.returns(null);
|
||||
MessageLoaderUtils._loadAddonIconInURLBar(browser);
|
||||
assert.calledOnce(getContainerStub);
|
||||
});
|
||||
it("should unhide notification popup box with display style as none", () => {
|
||||
getContainerStub.returns(notificationContainerEl);
|
||||
notificationContainerEl.style.display = "none";
|
||||
MessageLoaderUtils._loadAddonIconInURLBar(browser);
|
||||
assert.calledWith(browser.ownerDocument.getElementById, "notification-popup-box");
|
||||
assert.equal(notificationContainerEl.style.display, "block");
|
||||
});
|
||||
it("should unhide notification popup box with display style empty", () => {
|
||||
getContainerStub.returns(notificationContainerEl);
|
||||
notificationContainerEl.style.display = "";
|
||||
MessageLoaderUtils._loadAddonIconInURLBar(browser);
|
||||
assert.calledWith(browser.ownerDocument.getElementById, "notification-popup-box");
|
||||
assert.equal(notificationContainerEl.style.display, "block");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#installAddonFromURL", () => {
|
||||
let globals;
|
||||
let sandbox;
|
||||
|
@ -235,6 +282,7 @@ describe("MessageLoaderUtils", () => {
|
|||
sandbox = sinon.createSandbox();
|
||||
getInstallStub = sandbox.stub();
|
||||
installAddonStub = sandbox.stub();
|
||||
sandbox.stub(MessageLoaderUtils, "_loadAddonIconInURLBar").returns(null);
|
||||
globals.set("AddonManager", {
|
||||
getInstallForURL: getInstallStub,
|
||||
installAddonFromWebpage: installAddonStub,
|
||||
|
|
|
@ -141,6 +141,13 @@ describe("SubmitFormSnippet", () => {
|
|||
assert.isTrue(wrapper.state().expanded);
|
||||
assert.isTrue(wrapper.find("form").exists());
|
||||
});
|
||||
it("should submit telemetry when the action button is clicked", () => {
|
||||
assert.isFalse(wrapper.find("form").exists());
|
||||
|
||||
wrapper.find(".ASRouterButton").simulate("click");
|
||||
|
||||
assert.equal(wrapper.props().sendUserActionTelemetry.firstCall.args[0].value, "scene1-button-learn-more");
|
||||
});
|
||||
it("should submit form data when submitted", () => {
|
||||
sandbox.stub(window, "fetch").resolves(fetchOk);
|
||||
wrapper.setState({expanded: true});
|
||||
|
|
|
@ -606,7 +606,7 @@ describe("Reducers", () => {
|
|||
assert.propertyVal(state, "version", data.version);
|
||||
});
|
||||
it("should reset to the initial state on a SNIPPETS_RESET action", () => {
|
||||
const state = Snippets({initalized: true, foo: "bar"}, {type: at.SNIPPETS_RESET});
|
||||
const state = Snippets({initialized: true, foo: "bar"}, {type: at.SNIPPETS_RESET});
|
||||
assert.equal(state, INITIAL_STATE.Snippets);
|
||||
});
|
||||
it("should set the new blocklist on SNIPPET_BLOCKED", () => {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import {TopSites as OldTopSites} from "content-src/components/TopSites/TopSites";
|
||||
import React from "react";
|
||||
import {shallow} from "enzyme";
|
||||
import {_TopSites as TopSites} from "content-src/components/DiscoveryStreamComponents/TopSites/TopSites";
|
||||
|
||||
describe("Discovery Stream <TopSites>", () => {
|
||||
it("should return a wrapper around old TopSites", () => {
|
||||
const wrapper = shallow(<TopSites />);
|
||||
|
||||
const oldTopSites = wrapper.find(OldTopSites);
|
||||
const dsTopSitesWrapper = wrapper.find(".ds-top-sites");
|
||||
|
||||
assert.ok(wrapper.exists());
|
||||
assert.lengthOf(oldTopSites, 1);
|
||||
assert.lengthOf(dsTopSitesWrapper, 1);
|
||||
});
|
||||
});
|
|
@ -83,7 +83,7 @@ describe("<Search>", () => {
|
|||
it("should hand-off search when button is clicked with mouse", () => {
|
||||
const dispatch = sinon.spy();
|
||||
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
|
||||
wrapper.instance().onSearchHandoffClick({clientX: 101, clientY: 102});
|
||||
wrapper.find(".search-handoff-button").simulate("click", {clientX: 101, clientY: 102});
|
||||
assert.calledWith(dispatch, {
|
||||
data: {hiddenFocus: true},
|
||||
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
|
||||
|
@ -94,7 +94,7 @@ describe("<Search>", () => {
|
|||
it("should hand-off search when button is clicked with keyboard", () => {
|
||||
const dispatch = sinon.spy();
|
||||
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
|
||||
wrapper.instance().onSearchHandoffClick({clientX: 0, clientY: 0});
|
||||
wrapper.find(".search-handoff-button").simulate("click", {clientX: 0, clientY: 0});
|
||||
assert.calledWith(dispatch, {
|
||||
data: {hiddenFocus: false},
|
||||
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
|
||||
|
@ -102,5 +102,49 @@ describe("<Search>", () => {
|
|||
});
|
||||
assert.calledWith(dispatch, {type: "FOCUS_SEARCH"});
|
||||
});
|
||||
it("should hand-off search when user types", () => {
|
||||
const dispatch = sinon.spy();
|
||||
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
|
||||
wrapper.find(".search-handoff-button").simulate("keydown", {key: "f"});
|
||||
assert.calledWith(dispatch, {
|
||||
data: {text: "f"},
|
||||
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
|
||||
type: "HANDOFF_SEARCH_TO_AWESOMEBAR",
|
||||
});
|
||||
});
|
||||
it("should NOT hand-off search when user types with with ctrl pressed", () => {
|
||||
const dispatch = sinon.spy();
|
||||
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
|
||||
wrapper.find(".search-handoff-button").simulate("keydown", {key: "f", ctrlKey: true});
|
||||
assert.notCalled(dispatch);
|
||||
});
|
||||
it("should NOT hand-off search when user types with with alt pressed", () => {
|
||||
const dispatch = sinon.spy();
|
||||
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
|
||||
wrapper.find(".search-handoff-button").simulate("keydown", {key: "f", altKey: true});
|
||||
assert.notCalled(dispatch);
|
||||
});
|
||||
it("should NOT hand-off search when user types with with meta pressed", () => {
|
||||
const dispatch = sinon.spy();
|
||||
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
|
||||
wrapper.find(".search-handoff-button").simulate("keydown", {key: "f", metaKey: true});
|
||||
assert.notCalled(dispatch);
|
||||
});
|
||||
it("should hand-off search on paste", () => {
|
||||
const dispatch = sinon.spy();
|
||||
const wrapper = mountWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
|
||||
wrapper.instance()._searchHandoffButton = {contains: () => true};
|
||||
wrapper.instance().onSearchHandoffPaste({
|
||||
clipboardData: {
|
||||
getData: () => "some copied text",
|
||||
},
|
||||
preventDefault: () => {},
|
||||
});
|
||||
assert.calledWith(dispatch, {
|
||||
data: {text: "some copied text"},
|
||||
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
|
||||
type: "HANDOFF_SEARCH_TO_AWESOMEBAR",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -46,7 +46,7 @@ describe("DiscoveryStreamFeed", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#loadCachedData", () => {
|
||||
describe("#loadLayout", () => {
|
||||
it("should fetch data and populate the cache if it is empty", async () => {
|
||||
const resp = {layout: ["foo", "bar"]};
|
||||
const fakeCache = {};
|
||||
|
@ -55,7 +55,7 @@ describe("DiscoveryStreamFeed", () => {
|
|||
|
||||
fetchStub.resolves({ok: true, json: () => Promise.resolve(resp)});
|
||||
|
||||
await feed.loadCachedData();
|
||||
await feed.loadLayout();
|
||||
|
||||
assert.calledOnce(fetchStub);
|
||||
assert.calledWith(feed.cache.set, "layout", resp);
|
||||
|
@ -70,7 +70,7 @@ describe("DiscoveryStreamFeed", () => {
|
|||
fetchStub.resolves({ok: true, json: () => Promise.resolve(resp)});
|
||||
|
||||
clock.tick(THIRTY_MINUTES + 1);
|
||||
await feed.loadCachedData();
|
||||
await feed.loadLayout();
|
||||
|
||||
assert.calledOnce(fetchStub);
|
||||
assert.calledWith(feed.cache.set, "layout", resp);
|
||||
|
@ -82,21 +82,95 @@ describe("DiscoveryStreamFeed", () => {
|
|||
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
|
||||
|
||||
clock.tick(THIRTY_MINUTES - 1);
|
||||
await feed.loadCachedData();
|
||||
await feed.loadLayout();
|
||||
|
||||
assert.notCalled(fetchStub);
|
||||
assert.notCalled(feed.cache.set);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#loadComponentFeeds", () => {
|
||||
it("should populate feeds cache", async () => {
|
||||
const fakeComponents = {components: [{feed: {url: "foo.com"}}]};
|
||||
const fakeLayout = [fakeComponents, {components: [{}]}, {}];
|
||||
const fakeDiscoveryStream = {DiscoveryStream: {layout: fakeLayout}};
|
||||
sandbox.stub(feed.store, "getState").returns(fakeDiscoveryStream);
|
||||
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
|
||||
const fakeCache = {feeds: {"foo.com": {"lastUpdated": Date.now(), "data": "data"}}};
|
||||
sandbox.stub(feed.cache, "get").returns(Promise.resolve(fakeCache));
|
||||
|
||||
await feed.loadComponentFeeds();
|
||||
|
||||
assert.calledWith(feed.cache.set, "feeds", {"foo.com": {"data": "data", "lastUpdated": 0}});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#getComponentFeed", () => {
|
||||
it("should fetch fresh data if cache is empty", async () => {
|
||||
const fakeCache = {};
|
||||
sandbox.stub(feed.cache, "get").returns(Promise.resolve(fakeCache));
|
||||
sandbox.stub(feed, "fetchComponentFeed").returns(Promise.resolve("data"));
|
||||
|
||||
const feedResp = await feed.getComponentFeed("foo.com");
|
||||
|
||||
assert.deepEqual(feedResp.data, "data");
|
||||
});
|
||||
it("should fetch fresh data if cache is old", async () => {
|
||||
const fakeCache = {feeds: {"foo.com": {lastUpdated: Date.now()}}};
|
||||
sandbox.stub(feed.cache, "get").returns(Promise.resolve(fakeCache));
|
||||
sandbox.stub(feed, "fetchComponentFeed").returns(Promise.resolve("data"));
|
||||
clock.tick(THIRTY_MINUTES + 1);
|
||||
|
||||
const feedResp = await feed.getComponentFeed("foo.com");
|
||||
|
||||
assert.equal(feedResp.data, "data");
|
||||
});
|
||||
it("should return data from cache if it is fresh", async () => {
|
||||
const fakeCache = {feeds: {"foo.com": {lastUpdated: Date.now(), data: "data"}}};
|
||||
sandbox.stub(feed.cache, "get").returns(Promise.resolve(fakeCache));
|
||||
sandbox.stub(feed, "fetchComponentFeed").returns(Promise.resolve("old data"));
|
||||
clock.tick(THIRTY_MINUTES - 1);
|
||||
|
||||
const feedResp = await feed.getComponentFeed("foo.com");
|
||||
|
||||
assert.equal(feedResp.data, "data");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#fetchComponentFeed", () => {
|
||||
it("should return old feed if fetch failed", async () => {
|
||||
fetchStub.resolves({ok: false, json: () => Promise.resolve({})});
|
||||
const fakeCache = {feeds: {"foo.com": {lastUpdated: Date.now(), data: "old data"}}};
|
||||
sandbox.stub(feed.cache, "get").returns(Promise.resolve(fakeCache));
|
||||
clock.tick(THIRTY_MINUTES + 1);
|
||||
|
||||
const feedResp = await feed.getComponentFeed("foo.com");
|
||||
|
||||
assert.equal(feedResp.data, "old data");
|
||||
});
|
||||
it("should return new feed if fetch succeeds", async () => {
|
||||
fetchStub.resolves({ok: true, json: () => Promise.resolve("data")});
|
||||
const fakeCache = {feeds: {"foo.com": {lastUpdated: Date.now(), data: "old data"}}};
|
||||
sandbox.stub(feed.cache, "get").returns(Promise.resolve(fakeCache));
|
||||
clock.tick(THIRTY_MINUTES + 1);
|
||||
|
||||
const feedResp = await feed.getComponentFeed("foo.com");
|
||||
|
||||
assert.equal(feedResp.data, "data");
|
||||
});
|
||||
});
|
||||
|
||||
describe("#clearCache", () => {
|
||||
it("should set .layout to {}", async () => {
|
||||
it("should set .layout and .feeds to {}", async () => {
|
||||
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
|
||||
|
||||
await feed.clearCache();
|
||||
|
||||
assert.calledOnce(feed.cache.set);
|
||||
assert.calledWith(feed.cache.set, "layout", {});
|
||||
assert.calledTwice(feed.cache.set);
|
||||
const {firstCall} = feed.cache.set;
|
||||
const {secondCall} = feed.cache.set;
|
||||
assert.deepEqual(firstCall.args, ["layout", {}]);
|
||||
assert.deepEqual(secondCall.args, ["feeds", {}]);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -105,13 +179,14 @@ describe("DiscoveryStreamFeed", () => {
|
|||
assert.isFalse(feed.loaded);
|
||||
});
|
||||
it("should load data, add pref observer, and set .loaded=true if config.enabled is true", async () => {
|
||||
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
|
||||
configPrefStub.returns(JSON.stringify({enabled: true}));
|
||||
sandbox.stub(feed, "loadCachedData").returns(Promise.resolve());
|
||||
sandbox.stub(feed, "loadLayout").returns(Promise.resolve());
|
||||
sandbox.stub(global.Services.prefs, "addObserver");
|
||||
|
||||
await feed.onAction({type: at.INIT});
|
||||
|
||||
assert.calledOnce(feed.loadCachedData);
|
||||
assert.calledOnce(feed.loadLayout);
|
||||
assert.calledWith(global.Services.prefs.addObserver, CONFIG_PREF_NAME, feed);
|
||||
assert.isTrue(feed.loaded);
|
||||
});
|
||||
|
@ -129,7 +204,7 @@ describe("DiscoveryStreamFeed", () => {
|
|||
});
|
||||
|
||||
describe("#onAction: DISCOVERY_STREAM_CONFIG_CHANGE", () => {
|
||||
it("should call this.loadCachedData if config.enabled changes to true ", async () => {
|
||||
it("should call this.loadLayout if config.enabled changes to true ", async () => {
|
||||
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
|
||||
// First initialize
|
||||
await feed.onAction({type: at.INIT});
|
||||
|
@ -140,14 +215,15 @@ describe("DiscoveryStreamFeed", () => {
|
|||
configPrefStub.returns(JSON.stringify({enabled: true}));
|
||||
|
||||
sandbox.stub(feed, "clearCache").returns(Promise.resolve());
|
||||
sandbox.stub(feed, "loadCachedData").returns(Promise.resolve());
|
||||
sandbox.stub(feed, "loadLayout").returns(Promise.resolve());
|
||||
await feed.onAction({type: at.DISCOVERY_STREAM_CONFIG_CHANGE});
|
||||
|
||||
assert.calledOnce(feed.loadCachedData);
|
||||
assert.calledOnce(feed.loadLayout);
|
||||
assert.calledOnce(feed.clearCache);
|
||||
assert.isTrue(feed.loaded);
|
||||
});
|
||||
it("should clear the cache if a config change happens and config.enabled is true", async () => {
|
||||
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
|
||||
// force clear cached pref value
|
||||
feed._prefCache = {};
|
||||
configPrefStub.returns(JSON.stringify({enabled: true}));
|
||||
|
@ -157,7 +233,7 @@ describe("DiscoveryStreamFeed", () => {
|
|||
|
||||
assert.calledOnce(feed.clearCache);
|
||||
});
|
||||
it("should not call this.loadCachedData if config.enabled changes to false", async () => {
|
||||
it("should not call this.loadLayout if config.enabled changes to false", async () => {
|
||||
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
|
||||
// force clear cached pref value
|
||||
feed._prefCache = {};
|
||||
|
@ -169,10 +245,10 @@ describe("DiscoveryStreamFeed", () => {
|
|||
feed._prefCache = {};
|
||||
configPrefStub.returns(JSON.stringify({enabled: false}));
|
||||
sandbox.stub(feed, "clearCache").returns(Promise.resolve());
|
||||
sandbox.stub(feed, "loadCachedData").returns(Promise.resolve());
|
||||
sandbox.stub(feed, "loadLayout").returns(Promise.resolve());
|
||||
await feed.onAction({type: at.DISCOVERY_STREAM_CONFIG_CHANGE});
|
||||
|
||||
assert.notCalled(feed.loadCachedData);
|
||||
assert.notCalled(feed.loadLayout);
|
||||
assert.calledOnce(feed.clearCache);
|
||||
assert.isFalse(feed.loaded);
|
||||
});
|
||||
|
|
|
@ -326,6 +326,7 @@ describe("PlacesFeed", () => {
|
|||
beforeEach(() => {
|
||||
fakeUrlBar = {
|
||||
focus: sinon.spy(),
|
||||
search: sinon.spy(),
|
||||
hiddenFocus: sinon.spy(),
|
||||
removeHiddenFocus: sinon.spy(),
|
||||
addEventListener: (ev, cb) => {
|
||||
|
@ -364,9 +365,21 @@ describe("PlacesFeed", () => {
|
|||
assert.notCalled(fakeUrlBar.focus);
|
||||
assert.notCalled(feed.store.dispatch);
|
||||
|
||||
// Now call keydown listener.
|
||||
// Now call keydown listener with "Ctrl".
|
||||
feed.store.dispatch.resetHistory();
|
||||
listeners.keydown();
|
||||
listeners.keydown({key: "Ctrl"});
|
||||
assert.notCalled(fakeUrlBar.removeHiddenFocus);
|
||||
assert.notCalled(feed.store.dispatch);
|
||||
|
||||
// Now call keydown listener with "Ctrl+f".
|
||||
feed.store.dispatch.resetHistory();
|
||||
listeners.keydown({key: "f", ctrlKey: true});
|
||||
assert.notCalled(fakeUrlBar.removeHiddenFocus);
|
||||
assert.notCalled(feed.store.dispatch);
|
||||
|
||||
// Now call keydown listener with "f".
|
||||
feed.store.dispatch.resetHistory();
|
||||
listeners.keydown({key: "f"});
|
||||
assert.calledOnce(fakeUrlBar.removeHiddenFocus);
|
||||
assert.calledOnce(feed.store.dispatch);
|
||||
assert.calledWith(feed.store.dispatch, {
|
||||
|
@ -395,6 +408,27 @@ describe("PlacesFeed", () => {
|
|||
type: "SHOW_SEARCH",
|
||||
});
|
||||
});
|
||||
it("should properly handle text data passed in", () => {
|
||||
feed.handoffSearchToAwesomebar({
|
||||
_target: {browser: {ownerGlobal: {gURLBar: fakeUrlBar}}},
|
||||
data: {text: "f"},
|
||||
meta: {fromTarget: {}},
|
||||
});
|
||||
assert.calledOnce(fakeUrlBar.search);
|
||||
assert.calledWith(fakeUrlBar.search, "f");
|
||||
assert.notCalled(fakeUrlBar.hiddenFocus);
|
||||
assert.notCalled(fakeUrlBar.focus);
|
||||
assert.calledOnce(feed.store.dispatch);
|
||||
assert.calledWith(feed.store.dispatch, {
|
||||
meta: {
|
||||
from: "ActivityStream:Main",
|
||||
skipMain: true,
|
||||
to: "ActivityStream:Content",
|
||||
toTarget: {},
|
||||
},
|
||||
type: "HIDE_SEARCH",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#observe", () => {
|
||||
|
|
Загрузка…
Ссылка в новой задаче