Bug 1522379 - Add Discovery styling, AMO onboarding and bug fixes to Activity Stream r=k88hudson

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ed Lee 2019-01-24 15:34:40 +00:00
Родитель fc848c690e
Коммит 9795b2ffc2
50 изменённых файлов: 537 добавлений и 363 удалений

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

@ -48,6 +48,7 @@ for (const type of [
"DISCOVERY_STREAM_SPOCS_ENDPOINT",
"DISCOVERY_STREAM_SPOCS_UPDATE",
"DOWNLOAD_CHANGED",
"FAKE_FOCUS_SEARCH",
"FILL_SEARCH_TERM",
"HANDOFF_SEARCH_TO_AWESOMEBAR",
"HIDE_SEARCH",

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

@ -60,11 +60,15 @@ const INITIAL_STATE = {
spocs_endpoint: "",
lastUpdated: null,
data: {}, // {spocs: []}
loaded: false,
},
},
Search: {
// Pretend the search box is focused after handing off to AwesomeBar.
focus: false,
// When search hand-off is enabled, we render a big button that is styled to
// look like a search textbox. If the button is clicked, we style
// the button as if it was a focused search box and show a fake cursor but
// really focus the awesomebar without the focus styles ("hidden focus").
fakeFocus: false,
// Hide the search box after handing off to AwesomeBar and user starts typing.
hide: false,
},
@ -478,6 +482,7 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
...prevState.spocs,
lastUpdated: action.data.lastUpdated,
data: action.data.spocs,
loaded: true,
},
};
}
@ -491,8 +496,10 @@ function Search(prevState = INITIAL_STATE.Search, action) {
switch (action.type) {
case at.HIDE_SEARCH:
return Object.assign({...prevState, hide: true});
case at.FAKE_FOCUS_SEARCH:
return Object.assign({...prevState, fakeFocus: true});
case at.SHOW_SEARCH:
return Object.assign({...prevState, hide: false});
return Object.assign({...prevState, hide: false, fakeFocus: false});
default:
return prevState;
}

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

@ -159,6 +159,8 @@ export class ASRouterUISurface extends React.PureComponent {
case "CLEAR_MESSAGE":
if (action.data.id === this.state.message.id) {
this.setState({message: {}});
// Remove any styles related to the RTAMO message
document.body.classList.remove("welcome", "hide-main", "amo");
}
break;
case "CLEAR_PROVIDER":

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

@ -14,8 +14,6 @@ export class ReturnToAMO extends React.PureComponent {
onClickAddExtension() {
this.props.onAction(this.props.content.primary_button.action);
this.props.onBlock();
document.body.classList.remove("welcome", "hide-main", "amo");
}
onBlockButton() {

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

@ -115,6 +115,14 @@ export class _DiscoveryStreamBase extends React.PureComponent {
renderComponent(component) {
let rows;
const {spocs} = this.props.DiscoveryStream;
// TODO: Can we make this a bit better visually while it loads?
// If this component expects spocs,
// wait until spocs are loaded before attempting to use it.
if (component.spocs && !spocs.loaded) {
return null;
}
switch (component.type) {
case "TopSites":

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

@ -25,15 +25,12 @@ $excerpt-line-height: 20;
.img-wrapper {
width: 100%;
border: 0.5px solid $black-10;
border-radius: 4px;
}
.img {
@include image-as-background;
height: 0;
padding-top: 50%; // 2:1 aspect ratio
background-repeat: no-repeat;
background-size: cover;
}
.meta {

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

@ -1,8 +1,6 @@
.ds-hero {
.img {
border: 0.5px solid $black-10;
box-sizing: border-box;
border-radius: 4px;
@include image-as-background;
}
.ds-card {
@ -28,8 +26,16 @@
color: $grey-50;
margin: 18px 0;
padding: 20px 0;
border-top: 1px solid transparentize($grey-40, 0.64);
border-bottom: 1px solid transparentize($grey-40, 0.64);
border-top: $border-secondary;
border-bottom: $border-secondary;
&:hover .meta header {
color: $blue-60;
}
&:active .meta header {
color: $blue-70;
}
.img-wrapper {
width: 100%;
@ -38,23 +44,12 @@
.img {
height: 0;
padding-top: 50%; // 2:1 aspect ratio
background-repeat: no-repeat;
background-size: cover;
background-color: $grey-30;
}
.meta {
header {
font-size: 22px;
color: $grey-90;
&:hover {
color: $blue-60;
}
&:active {
color: $blue-70;
}
}
p {

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

@ -3,7 +3,7 @@ import React from "react";
export class HorizontalRule extends React.PureComponent {
render() {
return (
<hr />
<hr className="ds-hr" />
);
}
}

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

@ -0,0 +1,5 @@
.ds-hr {
border: 0;
height: 0;
border-top: $border-secondary;
}

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

@ -39,11 +39,9 @@ export class ListItem extends React.PureComponent {
{this.props.title}
</b>
</div>
<div className="ds-list-item-info">
{`${this.props.domain} · TODO:Topic`}
</div>
<div className="ds-list-item-info">{this.props.domain}</div>
</div>
<img className="ds-list-image" src={this.props.image_src} />
<div className="ds-list-image" style={{backgroundImage: `url(${this.props.image_src})`}} />
</a>
</li>
);

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

@ -3,7 +3,10 @@ $item-font-size: 13;
$item-line-height: 20;
.ds-list-border {
border: 1px solid $grey-40-36;
border: 0;
border-top: $border-secondary;
padding-top: 1px;
// Instead of using margin, we need to use these to override stuff that comes
// by default from <hr>.
@ -80,6 +83,10 @@ $item-line-height: 20;
&:hover::before {
background-color: var(--newtab-link-primary-color);
}
&:active::before {
background-color: $blue-70;
}
}
}
@ -88,8 +95,8 @@ $item-line-height: 20;
// Unfortunately the border needs to go _above_ the row gap as currently
// set up, which means that some refactoring will be required to do this.
.ds-list-item:nth-child(-n+3) { // all but the last three items
border-bottom: 2px solid $grey-40-36;
margin-bottom: -2px; // cancel out the 2 pixels we used for the border
border-bottom: $border-secondary;
margin-bottom: -1px; // cancel out the pixel we used for the border
padding-bottom: 2px;
}
@ -134,13 +141,26 @@ $item-line-height: 20;
}
.ds-list-image {
display: none;
width: 72px;
height: 72px;
object-fit: cover;
$image-size: 72px;
border: 0.5px solid $black-12;
box-sizing: border-box;
border-radius: 4px;
@include image-as-background;
display: none;
height: $image-size;
margin-inline-start: $item-font-size * 1px;
min-height: $image-size;
min-width: $image-size;
width: $image-size;
}
&:hover {
.ds-list-item-title {
color: var(--newtab-link-primary-color);
}
}
&:active {
.ds-list-item-title {
color: $blue-70;
}
}
}

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

@ -12,11 +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.onSearchHandoffDrop = this.onSearchHandoffDrop.bind(this);
this.onInputMount = this.onInputMount.bind(this);
this.onSearchHandoffButtonMount = this.onSearchHandoffButtonMount.bind(this);
this.cancelEvent = this.cancelEvent.bind(this);
}
handleEvent(event) {
@ -32,64 +31,36 @@ export class _Search extends React.PureComponent {
doSearchHandoff(text) {
this.props.dispatch(ac.OnlyToMain({type: at.HANDOFF_SEARCH_TO_AWESOMEBAR, data: {text}}));
this.props.dispatch({type: at.FAKE_FOCUS_SEARCH});
this.props.dispatch(ac.UserEvent({event: "SEARCH_HANDOFF"}));
if (text) {
// We don't hide the in-content search if there is no text (user hit <Enter>)
this.props.dispatch({type: at.HIDE_SEARCH});
}
}
onSearchHandoffClick(event) {
// When search hand-off is enabled, we render a big button that is styled to
// look like a search textbox. If the button is clicked with the mouse, we
// focus it. If the user types, transfer focus to awesomebar.
// If the button is clicked from the keyboard, we focus the awesomebar normally.
// This is to minimize confusion with users navigating with the keyboard and
// users using assistive technologoy.
// look like a search textbox. If the button is clicked, we style
// the button as if it was a focused search box and show a fake cursor but
// really focus the awesomebar without the focus styles ("hidden focus").
event.preventDefault();
const isKeyboardClick = event.clientX === 0 && event.clientY === 0;
if (isKeyboardClick) {
this.doSearchHandoff();
} else {
this._searchHandoffButton.focus();
}
}
onSearchHandoffKeyDown(event) {
if (event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey) {
// We only care about key strokes that will produce a character.
this.doSearchHandoff(event.key);
}
this.doSearchHandoff();
}
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();
this.doSearchHandoff(event.clipboardData.getData("Text"));
}
cancelEvent(event) {
onSearchHandoffDrop(event) {
event.preventDefault();
}
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);
let text = event.dataTransfer.getData("text");
if (text) {
this.doSearchHandoff(text);
}
}
componentWillUnmount() {
if (global.document) {
global.document.removeEventListener("paste", this.onDocumentPaste);
}
delete window.gContentSearchController;
}
@ -135,6 +106,7 @@ export class _Search extends React.PureComponent {
const wrapperClassName = [
"search-wrapper",
this.props.hide && "search-hidden",
this.props.fakeFocus && "fake-focus",
].filter(v => v).join(" ");
return (<div className={wrapperClassName}>
@ -171,10 +143,10 @@ export class _Search extends React.PureComponent {
className="search-handoff-button"
ref={this.onSearchHandoffButtonMount}
onClick={this.onSearchHandoffClick}
onKeyDown={this.onSearchHandoffKeyDown}
tabIndex="-1"
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="" onDrop={this.cancelEvent} />
<div className="fake-editable" tabIndex="-1" aria-hidden="true" contentEditable="" onDrop={this.onSearchHandoffDrop} onPaste={this.onSearchHandoffPaste} />
<div className="fake-caret" />
</button>
{/*

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

@ -160,7 +160,7 @@ $glyph-forward: url('chrome://browser/skin/forward.svg');
box-shadow: $shadow-secondary, 0 0 0 1px $black-25;
}
&:focus {
.fake-focus & {
border: $input-border-active;
box-shadow: var(--newtab-textbox-focus-boxshadow);

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

@ -1,3 +1,14 @@
// Shared styling of article images shown as background
@mixin image-as-background {
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 4px;
border: 0.5px solid $black-10;
box-sizing: border-box;
}
// Note: lineHeight and fontSize should be unitless but can be derived from pixel values
@mixin limit-visibile-lines($line-count, $line-height, $font-size) {
max-height: 1em * $line-count * $line-height / $font-size;

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

@ -71,6 +71,7 @@ body {
--newtab-card-active-outline-color: #{$grey-30};
--newtab-card-background-color: #{$white};
--newtab-card-hairline-color: #{$black-10};
--newtab-card-placeholder-color: #{$grey-30};
--newtab-card-shadow: 0 1px 4px 0 #{$grey-90-10};
// Snippets
@ -129,6 +130,7 @@ body {
--newtab-card-active-outline-color: #{$grey-60};
--newtab-card-background-color: #{$grey-70};
--newtab-card-hairline-color: #{$grey-10-10};
--newtab-card-placeholder-color: #{$grey-60};
--newtab-card-shadow: 0 1px 8px 0 #{$grey-90-20};
// Snippets

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

@ -29,7 +29,6 @@ $grey-10-95: rgba($grey-10, 0.95);
$grey-20-60: rgba($grey-20, 0.6);
$grey-20-80: rgba($grey-20, 0.8);
$grey-30-60: rgba($grey-30, 0.6);
$grey-40-36: rgba($grey-40, 0.36);
$grey-60-60: rgba($grey-60, 0.6);
$grey-60-70: rgba($grey-60, 0.7);
$grey-80-95: rgba($grey-80, 0.95);

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

@ -64,6 +64,7 @@ body {
--newtab-card-active-outline-color: #D7D7DB;
--newtab-card-background-color: #FFF;
--newtab-card-hairline-color: rgba(0, 0, 0, 0.1);
--newtab-card-placeholder-color: #D7D7DB;
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
--newtab-snippets-background-color: #FFF;
--newtab-snippets-hairline-color: transparent; }
@ -107,6 +108,7 @@ body {
--newtab-card-active-outline-color: #4A4A4F;
--newtab-card-background-color: #38383D;
--newtab-card-hairline-color: rgba(249, 249, 250, 0.1);
--newtab-card-placeholder-color: #4A4A4F;
--newtab-card-shadow: 0 1px 8px 0 rgba(12, 12, 13, 0.2);
--newtab-snippets-background-color: #38383D;
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1); }
@ -1066,10 +1068,10 @@ main {
background-position-x: right 12px; }
.search-handoff-button:hover {
box-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.25); }
.search-handoff-button:focus {
.fake-focus .search-handoff-button {
border: 1px solid var(--newtab-textbox-focus-color);
box-shadow: var(--newtab-textbox-focus-boxshadow); }
.search-handoff-button:focus .fake-caret {
.fake-focus .search-handoff-button .fake-caret {
display: block; }
.search-hidden .search-handoff-button {
opacity: 0;
@ -1845,9 +1847,13 @@ main {
grid-template-columns: repeat(3, 1fr); }
.ds-hero .img {
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
border-radius: 4px; }
box-sizing: border-box; }
.ds-hero .ds-card {
border: 0; }
@ -1865,23 +1871,20 @@ main {
color: #737373;
margin: 18px 0;
padding: 20px 0;
border-top: 1px solid rgba(177, 177, 179, 0.36);
border-bottom: 1px solid rgba(177, 177, 179, 0.36); }
border-top: 1px solid var(--newtab-border-secondary-color);
border-bottom: 1px solid var(--newtab-border-secondary-color); }
.ds-hero .wrapper:hover .meta header {
color: #0060DF; }
.ds-hero .wrapper:active .meta header {
color: #003EAA; }
.ds-hero .wrapper .img-wrapper {
width: 100%; }
.ds-hero .wrapper .img {
height: 0;
padding-top: 50%;
background-repeat: no-repeat;
background-size: cover;
background-color: #D7D7DB; }
padding-top: 50%; }
.ds-hero .wrapper .meta header {
font-size: 22px;
color: #0C0C0D; }
.ds-hero .wrapper .meta header:hover {
color: #0060DF; }
.ds-hero .wrapper .meta header:active {
color: #003EAA; }
.ds-hero .wrapper .meta p {
font-size: 13px; }
.ds-hero .wrapper .meta p.context {
@ -1952,8 +1955,15 @@ main {
grid-template-columns: repeat(4, 1fr);
grid-column-gap: 24px; }
.ds-hr {
border: 0;
height: 0;
border-top: 1px solid var(--newtab-border-secondary-color); }
.ds-list-border {
border: 1px solid rgba(177, 177, 179, 0.36);
border: 0;
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 1px;
margin-block-start: 8px;
margin-block-end: 8px; }
@ -2000,10 +2010,12 @@ main {
width: 33px; }
.ds-list-numbers .ds-list-item-link:hover::before {
background-color: var(--newtab-link-primary-color); }
.ds-list-numbers .ds-list-item-link:active::before {
background-color: #003EAA; }
.ds-list-item:nth-child(-n+3) {
border-bottom: 2px solid rgba(177, 177, 179, 0.36);
margin-bottom: -2px;
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-item {
@ -2030,13 +2042,23 @@ main {
display: flex;
flex-direction: column; }
.ds-list-item .ds-list-image {
display: none;
width: 72px;
height: 72px;
object-fit: cover;
border: 0.5px solid rgba(0, 0, 0, 0.12);
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
border-radius: 4px; }
display: none;
height: 72px;
margin-inline-start: 13px;
min-height: 72px;
min-width: 72px;
width: 72px; }
.ds-list-item:hover .ds-list-item-title {
color: var(--newtab-link-primary-color); }
.ds-list-item:active .ds-list-item-title {
color: #003EAA; }
.ds-navigation.ds-navigation-centered {
text-align: center; }
@ -2160,14 +2182,17 @@ main {
.ds-card:active header {
color: #003EAA; }
.ds-card .img-wrapper {
width: 100%;
border: 0.5px solid rgba(0, 0, 0, 0.1);
border-radius: 4px; }
width: 100%; }
.ds-card .img {
height: 0;
padding-top: 50%;
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover; }
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
height: 0;
padding-top: 50%; }
.ds-card .meta {
padding: 16px; }
.ds-card .meta .title {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -67,6 +67,7 @@ body {
--newtab-card-active-outline-color: #D7D7DB;
--newtab-card-background-color: #FFF;
--newtab-card-hairline-color: rgba(0, 0, 0, 0.1);
--newtab-card-placeholder-color: #D7D7DB;
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
--newtab-snippets-background-color: #FFF;
--newtab-snippets-hairline-color: transparent; }
@ -110,6 +111,7 @@ body {
--newtab-card-active-outline-color: #4A4A4F;
--newtab-card-background-color: #38383D;
--newtab-card-hairline-color: rgba(249, 249, 250, 0.1);
--newtab-card-placeholder-color: #4A4A4F;
--newtab-card-shadow: 0 1px 8px 0 rgba(12, 12, 13, 0.2);
--newtab-snippets-background-color: #38383D;
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1); }
@ -1069,10 +1071,10 @@ main {
background-position-x: right 12px; }
.search-handoff-button:hover {
box-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.25); }
.search-handoff-button:focus {
.fake-focus .search-handoff-button {
border: 1px solid var(--newtab-textbox-focus-color);
box-shadow: var(--newtab-textbox-focus-boxshadow); }
.search-handoff-button:focus .fake-caret {
.fake-focus .search-handoff-button .fake-caret {
display: block; }
.search-hidden .search-handoff-button {
opacity: 0;
@ -1848,9 +1850,13 @@ main {
grid-template-columns: repeat(3, 1fr); }
.ds-hero .img {
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
border-radius: 4px; }
box-sizing: border-box; }
.ds-hero .ds-card {
border: 0; }
@ -1868,23 +1874,20 @@ main {
color: #737373;
margin: 18px 0;
padding: 20px 0;
border-top: 1px solid rgba(177, 177, 179, 0.36);
border-bottom: 1px solid rgba(177, 177, 179, 0.36); }
border-top: 1px solid var(--newtab-border-secondary-color);
border-bottom: 1px solid var(--newtab-border-secondary-color); }
.ds-hero .wrapper:hover .meta header {
color: #0060DF; }
.ds-hero .wrapper:active .meta header {
color: #003EAA; }
.ds-hero .wrapper .img-wrapper {
width: 100%; }
.ds-hero .wrapper .img {
height: 0;
padding-top: 50%;
background-repeat: no-repeat;
background-size: cover;
background-color: #D7D7DB; }
padding-top: 50%; }
.ds-hero .wrapper .meta header {
font-size: 22px;
color: #0C0C0D; }
.ds-hero .wrapper .meta header:hover {
color: #0060DF; }
.ds-hero .wrapper .meta header:active {
color: #003EAA; }
.ds-hero .wrapper .meta p {
font-size: 13px; }
.ds-hero .wrapper .meta p.context {
@ -1955,8 +1958,15 @@ main {
grid-template-columns: repeat(4, 1fr);
grid-column-gap: 24px; }
.ds-hr {
border: 0;
height: 0;
border-top: 1px solid var(--newtab-border-secondary-color); }
.ds-list-border {
border: 1px solid rgba(177, 177, 179, 0.36);
border: 0;
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 1px;
margin-block-start: 8px;
margin-block-end: 8px; }
@ -2003,10 +2013,12 @@ main {
width: 33px; }
.ds-list-numbers .ds-list-item-link:hover::before {
background-color: var(--newtab-link-primary-color); }
.ds-list-numbers .ds-list-item-link:active::before {
background-color: #003EAA; }
.ds-list-item:nth-child(-n+3) {
border-bottom: 2px solid rgba(177, 177, 179, 0.36);
margin-bottom: -2px;
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-item {
@ -2033,13 +2045,23 @@ main {
display: flex;
flex-direction: column; }
.ds-list-item .ds-list-image {
display: none;
width: 72px;
height: 72px;
object-fit: cover;
border: 0.5px solid rgba(0, 0, 0, 0.12);
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
border-radius: 4px; }
display: none;
height: 72px;
margin-inline-start: 13px;
min-height: 72px;
min-width: 72px;
width: 72px; }
.ds-list-item:hover .ds-list-item-title {
color: var(--newtab-link-primary-color); }
.ds-list-item:active .ds-list-item-title {
color: #003EAA; }
.ds-navigation.ds-navigation-centered {
text-align: center; }
@ -2163,14 +2185,17 @@ main {
.ds-card:active header {
color: #003EAA; }
.ds-card .img-wrapper {
width: 100%;
border: 0.5px solid rgba(0, 0, 0, 0.1);
border-radius: 4px; }
width: 100%; }
.ds-card .img {
height: 0;
padding-top: 50%;
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover; }
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
height: 0;
padding-top: 50%; }
.ds-card .meta {
padding: 16px; }
.ds-card .meta .title {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -64,6 +64,7 @@ body {
--newtab-card-active-outline-color: #D7D7DB;
--newtab-card-background-color: #FFF;
--newtab-card-hairline-color: rgba(0, 0, 0, 0.1);
--newtab-card-placeholder-color: #D7D7DB;
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
--newtab-snippets-background-color: #FFF;
--newtab-snippets-hairline-color: transparent; }
@ -107,6 +108,7 @@ body {
--newtab-card-active-outline-color: #4A4A4F;
--newtab-card-background-color: #38383D;
--newtab-card-hairline-color: rgba(249, 249, 250, 0.1);
--newtab-card-placeholder-color: #4A4A4F;
--newtab-card-shadow: 0 1px 8px 0 rgba(12, 12, 13, 0.2);
--newtab-snippets-background-color: #38383D;
--newtab-snippets-hairline-color: rgba(255, 255, 255, 0.1); }
@ -1066,10 +1068,10 @@ main {
background-position-x: right 12px; }
.search-handoff-button:hover {
box-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.25); }
.search-handoff-button:focus {
.fake-focus .search-handoff-button {
border: 1px solid var(--newtab-textbox-focus-color);
box-shadow: var(--newtab-textbox-focus-boxshadow); }
.search-handoff-button:focus .fake-caret {
.fake-focus .search-handoff-button .fake-caret {
display: block; }
.search-hidden .search-handoff-button {
opacity: 0;
@ -1845,9 +1847,13 @@ main {
grid-template-columns: repeat(3, 1fr); }
.ds-hero .img {
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
border-radius: 4px; }
box-sizing: border-box; }
.ds-hero .ds-card {
border: 0; }
@ -1865,23 +1871,20 @@ main {
color: #737373;
margin: 18px 0;
padding: 20px 0;
border-top: 1px solid rgba(177, 177, 179, 0.36);
border-bottom: 1px solid rgba(177, 177, 179, 0.36); }
border-top: 1px solid var(--newtab-border-secondary-color);
border-bottom: 1px solid var(--newtab-border-secondary-color); }
.ds-hero .wrapper:hover .meta header {
color: #0060DF; }
.ds-hero .wrapper:active .meta header {
color: #003EAA; }
.ds-hero .wrapper .img-wrapper {
width: 100%; }
.ds-hero .wrapper .img {
height: 0;
padding-top: 50%;
background-repeat: no-repeat;
background-size: cover;
background-color: #D7D7DB; }
padding-top: 50%; }
.ds-hero .wrapper .meta header {
font-size: 22px;
color: #0C0C0D; }
.ds-hero .wrapper .meta header:hover {
color: #0060DF; }
.ds-hero .wrapper .meta header:active {
color: #003EAA; }
.ds-hero .wrapper .meta p {
font-size: 13px; }
.ds-hero .wrapper .meta p.context {
@ -1952,8 +1955,15 @@ main {
grid-template-columns: repeat(4, 1fr);
grid-column-gap: 24px; }
.ds-hr {
border: 0;
height: 0;
border-top: 1px solid var(--newtab-border-secondary-color); }
.ds-list-border {
border: 1px solid rgba(177, 177, 179, 0.36);
border: 0;
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 1px;
margin-block-start: 8px;
margin-block-end: 8px; }
@ -2000,10 +2010,12 @@ main {
width: 33px; }
.ds-list-numbers .ds-list-item-link:hover::before {
background-color: var(--newtab-link-primary-color); }
.ds-list-numbers .ds-list-item-link:active::before {
background-color: #003EAA; }
.ds-list-item:nth-child(-n+3) {
border-bottom: 2px solid rgba(177, 177, 179, 0.36);
margin-bottom: -2px;
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-item {
@ -2030,13 +2042,23 @@ main {
display: flex;
flex-direction: column; }
.ds-list-item .ds-list-image {
display: none;
width: 72px;
height: 72px;
object-fit: cover;
border: 0.5px solid rgba(0, 0, 0, 0.12);
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
border-radius: 4px; }
display: none;
height: 72px;
margin-inline-start: 13px;
min-height: 72px;
min-width: 72px;
width: 72px; }
.ds-list-item:hover .ds-list-item-title {
color: var(--newtab-link-primary-color); }
.ds-list-item:active .ds-list-item-title {
color: #003EAA; }
.ds-navigation.ds-navigation-centered {
text-align: center; }
@ -2160,14 +2182,17 @@ main {
.ds-card:active header {
color: #003EAA; }
.ds-card .img-wrapper {
width: 100%;
border: 0.5px solid rgba(0, 0, 0, 0.1);
border-radius: 4px; }
width: 100%; }
.ds-card .img {
height: 0;
padding-top: 50%;
background-color: var(--newtab-card-placeholder-color);
background-position: center;
background-repeat: no-repeat;
background-size: cover; }
background-size: cover;
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
height: 0;
padding-top: 50%; }
.ds-card .meta {
padding: 16px; }
.ds-card .meta .title {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -211,7 +211,7 @@ const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS :
// }
const actionTypes = {};
for (const type of ["ADDONS_INFO_REQUEST", "ADDONS_INFO_RESPONSE", "ARCHIVE_FROM_POCKET", "AS_ROUTER_INITIALIZED", "AS_ROUTER_PREF_CHANGED", "AS_ROUTER_TELEMETRY_USER_EVENT", "BLOCK_URL", "BOOKMARK_URL", "COPY_DOWNLOAD_LINK", "DELETE_BOOKMARK_BY_ID", "DELETE_FROM_POCKET", "DELETE_HISTORY_URL", "DIALOG_CANCEL", "DIALOG_OPEN", "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", "DISCOVERY_STREAM_SPOCS_ENDPOINT", "DISCOVERY_STREAM_SPOCS_UPDATE", "DOWNLOAD_CHANGED", "FILL_SEARCH_TERM", "HANDOFF_SEARCH_TO_AWESOMEBAR", "HIDE_SEARCH", "INIT", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_DOWNLOAD_FILE", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "OPEN_WEBEXT_SETTINGS", "PAGE_PRERENDERED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_CHANGED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PLACES_SAVED_TO_POCKET", "POCKET_CTA", "POCKET_LOGGED_IN", "POCKET_WAITING_FOR_SPOC", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "PREVIEW_REQUEST", "PREVIEW_REQUEST_CANCEL", "PREVIEW_RESPONSE", "REMOVE_DOWNLOAD_FILE", "RICH_ICON_MISSING", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_MOVE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SETTINGS_CLOSE", "SETTINGS_OPEN", "SET_PREF", "SHOW_DOWNLOAD_FILE", "SHOW_FIREFOX_ACCOUNTS", "SHOW_SEARCH", "SKIPPED_SIGNIN", "SNIPPETS_BLOCKLIST_CLEARED", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_PREVIEW_MODE", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SUBMIT_EMAIL", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_EDIT", "TOP_SITES_INSERT", "TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_PIN", "TOP_SITES_PREFS_UPDATED", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "TOTAL_BOOKMARKS_REQUEST", "TOTAL_BOOKMARKS_RESPONSE", "UNINIT", "UPDATE_PINNED_SEARCH_SHORTCUTS", "UPDATE_SEARCH_SHORTCUTS", "UPDATE_SECTION_PREFS", "WEBEXT_CLICK", "WEBEXT_DISMISS"]) {
for (const type of ["ADDONS_INFO_REQUEST", "ADDONS_INFO_RESPONSE", "ARCHIVE_FROM_POCKET", "AS_ROUTER_INITIALIZED", "AS_ROUTER_PREF_CHANGED", "AS_ROUTER_TELEMETRY_USER_EVENT", "BLOCK_URL", "BOOKMARK_URL", "COPY_DOWNLOAD_LINK", "DELETE_BOOKMARK_BY_ID", "DELETE_FROM_POCKET", "DELETE_HISTORY_URL", "DIALOG_CANCEL", "DIALOG_OPEN", "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", "DISCOVERY_STREAM_SPOCS_ENDPOINT", "DISCOVERY_STREAM_SPOCS_UPDATE", "DOWNLOAD_CHANGED", "FAKE_FOCUS_SEARCH", "FILL_SEARCH_TERM", "HANDOFF_SEARCH_TO_AWESOMEBAR", "HIDE_SEARCH", "INIT", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_DOWNLOAD_FILE", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "OPEN_WEBEXT_SETTINGS", "PAGE_PRERENDERED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_CHANGED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PLACES_SAVED_TO_POCKET", "POCKET_CTA", "POCKET_LOGGED_IN", "POCKET_WAITING_FOR_SPOC", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "PREVIEW_REQUEST", "PREVIEW_REQUEST_CANCEL", "PREVIEW_RESPONSE", "REMOVE_DOWNLOAD_FILE", "RICH_ICON_MISSING", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_MOVE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SETTINGS_CLOSE", "SETTINGS_OPEN", "SET_PREF", "SHOW_DOWNLOAD_FILE", "SHOW_FIREFOX_ACCOUNTS", "SHOW_SEARCH", "SKIPPED_SIGNIN", "SNIPPETS_BLOCKLIST_CLEARED", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_PREVIEW_MODE", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SUBMIT_EMAIL", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_EDIT", "TOP_SITES_INSERT", "TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_PIN", "TOP_SITES_PREFS_UPDATED", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "TOTAL_BOOKMARKS_REQUEST", "TOTAL_BOOKMARKS_RESPONSE", "UNINIT", "UPDATE_PINNED_SEARCH_SHORTCUTS", "UPDATE_SEARCH_SHORTCUTS", "UPDATE_SECTION_PREFS", "WEBEXT_CLICK", "WEBEXT_DISMISS"]) {
actionTypes[type] = type;
}
@ -1107,6 +1107,8 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
case "CLEAR_MESSAGE":
if (action.data.id === this.state.message.id) {
this.setState({ message: {} });
// Remove any styles related to the RTAMO message
document.body.classList.remove("welcome", "hide-main", "amo");
}
break;
case "CLEAR_PROVIDER":
@ -1766,8 +1768,6 @@ class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCompo
onClickAddExtension() {
this.props.onAction(this.props.content.primary_button.action);
this.props.onBlock();
document.body.classList.remove("welcome", "hide-main", "amo");
}
onBlockButton() {
@ -6236,7 +6236,7 @@ var PrerenderData = new _PrerenderData({
"use strict";
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Search", function() { return _Search; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Search", function() { return _Search; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Search", function() { return Search; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
@ -6260,11 +6260,10 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.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.onSearchHandoffDrop = this.onSearchHandoffDrop.bind(this);
this.onInputMount = this.onInputMount.bind(this);
this.onSearchHandoffButtonMount = this.onSearchHandoffButtonMount.bind(this);
this.cancelEvent = this.cancelEvent.bind(this);
}
handleEvent(event) {
@ -6280,63 +6279,36 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
doSearchHandoff(text) {
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].HANDOFF_SEARCH_TO_AWESOMEBAR, data: { text } }));
this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].FAKE_FOCUS_SEARCH });
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: "SEARCH_HANDOFF" }));
if (text) {
// We don't hide the in-content search if there is no text (user hit <Enter>)
this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].HIDE_SEARCH });
}
}
onSearchHandoffClick(event) {
// When search hand-off is enabled, we render a big button that is styled to
// look like a search textbox. If the button is clicked with the mouse, we
// focus it. If the user types, transfer focus to awesomebar.
// If the button is clicked from the keyboard, we focus the awesomebar normally.
// This is to minimize confusion with users navigating with the keyboard and
// users using assistive technologoy.
// look like a search textbox. If the button is clicked, we style
// the button as if it was a focused search box and show a fake cursor but
// really focus the awesomebar without the focus styles ("hidden focus").
event.preventDefault();
const isKeyboardClick = event.clientX === 0 && event.clientY === 0;
if (isKeyboardClick) {
this.doSearchHandoff();
} else {
this._searchHandoffButton.focus();
}
}
onSearchHandoffKeyDown(event) {
if (event.key.length === 1 && !event.altKey && !event.ctrlKey && !event.metaKey) {
// We only care about key strokes that will produce a character.
this.doSearchHandoff(event.key);
}
this.doSearchHandoff();
}
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();
this.doSearchHandoff(event.clipboardData.getData("Text"));
}
cancelEvent(event) {
onSearchHandoffDrop(event) {
event.preventDefault();
}
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);
let text = event.dataTransfer.getData("text");
if (text) {
this.doSearchHandoff(text);
}
}
componentWillUnmount() {
if (global.document) {
global.document.removeEventListener("paste", this.onDocumentPaste);
}
delete window.gContentSearchController;
}
@ -6378,7 +6350,7 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
* in order to execute searches in various tests
*/
render() {
const wrapperClassName = ["search-wrapper", this.props.hide && "search-hidden"].filter(v => v).join(" ");
const wrapperClassName = ["search-wrapper", this.props.hide && "search-hidden", this.props.fakeFocus && "fake-focus"].filter(v => v).join(" ");
return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
"div",
@ -6431,14 +6403,14 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
className: "search-handoff-button",
ref: this.onSearchHandoffButtonMount,
onClick: this.onSearchHandoffClick,
onKeyDown: this.onSearchHandoffKeyDown,
tabIndex: "-1",
title: this.props.intl.formatMessage({ id: "search_web_placeholder" }) },
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
"div",
{ className: "fake-textbox" },
this.props.intl.formatMessage({ id: "search_web_placeholder" })
),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "fake-editable", tabIndex: "-1", "aria-hidden": "true", contentEditable: "", onDrop: this.cancelEvent }),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "fake-editable", tabIndex: "-1", "aria-hidden": "true", contentEditable: "", onDrop: this.onSearchHandoffDrop, onPaste: this.onSearchHandoffPaste }),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "fake-caret" })
),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
@ -6451,7 +6423,6 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
}
const Search = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])()(Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_Search));
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
/* 47 */
@ -7276,7 +7247,7 @@ Hero_Hero.defaultProps = {
class HorizontalRule_HorizontalRule extends external_React_default.a.PureComponent {
render() {
return external_React_default.a.createElement("hr", null);
return external_React_default.a.createElement("hr", { className: "ds-hr" });
}
}
// EXTERNAL MODULE: ./content-src/components/DiscoveryStreamImpressionStats/ImpressionStats.jsx
@ -7338,10 +7309,10 @@ class List_ListItem extends external_React_default.a.PureComponent {
external_React_default.a.createElement(
"div",
{ className: "ds-list-item-info" },
`${this.props.domain} · TODO:Topic`
this.props.domain
)
),
external_React_default.a.createElement("img", { className: "ds-list-image", src: this.props.image_src })
external_React_default.a.createElement("div", { className: "ds-list-image", style: { backgroundImage: `url(${this.props.image_src})` } })
)
);
}
@ -7756,6 +7727,14 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
renderComponent(component) {
let rows;
const { spocs } = this.props.DiscoveryStream;
// TODO: Can we make this a bit better visually while it loads?
// If this component expects spocs,
// wait until spocs are loaded before attempting to use it.
if (component.spocs && !spocs.loaded) {
return null;
}
switch (component.type) {
case "TopSites":
@ -11365,12 +11344,16 @@ const INITIAL_STATE = {
spocs: {
spocs_endpoint: "",
lastUpdated: null,
data: {} // {spocs: []}
data: {}, // {spocs: []}
loaded: false
}
},
Search: {
// Pretend the search box is focused after handing off to AwesomeBar.
focus: false,
// When search hand-off is enabled, we render a big button that is styled to
// look like a search textbox. If the button is clicked, we style
// the button as if it was a focused search box and show a fake cursor but
// really focus the awesomebar without the focus styles ("hidden focus").
fakeFocus: false,
// Hide the search box after handing off to AwesomeBar and user starts typing.
hide: false
}
@ -11780,7 +11763,8 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
return Object.assign({}, prevState, {
spocs: Object.assign({}, prevState.spocs, {
lastUpdated: action.data.lastUpdated,
data: action.data.spocs
data: action.data.spocs,
loaded: true
})
});
}
@ -11794,8 +11778,10 @@ function Search(prevState = INITIAL_STATE.Search, action) {
switch (action.type) {
case Actions["actionTypes"].HIDE_SEARCH:
return Object.assign(Object.assign({}, prevState, { hide: true }));
case Actions["actionTypes"].FAKE_FOCUS_SEARCH:
return Object.assign(Object.assign({}, prevState, { fakeFocus: true }));
case Actions["actionTypes"].SHOW_SEARCH:
return Object.assign(Object.assign({}, prevState, { hide: false }));
return Object.assign(Object.assign({}, prevState, { hide: false, fakeFocus: false }));
default:
return prevState;
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -253,7 +253,9 @@ const MessageLoaderUtils = {
null, null, null, null, amTelemetryInfo);
await AddonManager.installAddonFromWebpage("application/x-xpinstall", browser,
systemPrincipal, install);
} catch (e) {}
} catch (e) {
Cu.reportError(e);
}
},
/**
@ -906,6 +908,16 @@ class _ASRouter {
}
}
// Ensure we switch to the Onboarding message after RTAMO addon was installed
_updateOnboardingState() {
let addonInstallObs = (subject, topic) => {
Services.obs.removeObserver(addonInstallObs, "webextension-install-notify");
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "CLEAR_MESSAGE", data: {id: "RETURN_TO_AMO_1"}});
this.blockMessageById("RETURN_TO_AMO_1");
};
Services.obs.addObserver(addonInstallObs, "webextension-install-notify");
}
_loadSnippetsWhitelistHosts() {
let additionalHosts = [];
const whitelistPrefValue = Services.prefs.getStringPref(SNIPPETS_ENDPOINT_WHITELIST, "");
@ -1025,6 +1037,7 @@ class _ASRouter {
UITour.showMenu(target.browser.ownerGlobal, action.data.args);
break;
case ra.INSTALL_ADDON_FROM_URL:
this._updateOnboardingState();
await MessageLoaderUtils.installAddonFromURL(target.browser, action.data.url);
break;
case ra.SHOW_FIREFOX_ACCOUNTS:

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

@ -218,7 +218,7 @@ const PREFS_CONFIG = new Map([
value: JSON.stringify({
enabled: false,
// This is currently an exmple layout used for dev purposes.
layout_endpoint: "https://getpocket.com/v3/newtab/layout?version=1&consumer_key=40249-e88c401e1b1f2242d9e441c4&layout_variant=control",
layout_endpoint: "https://getpocket.com/v3/newtab/layout?version=1&consumer_key=40249-e88c401e1b1f2242d9e441c4&layout_variant=basic",
}),
}],
]);

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

@ -168,6 +168,8 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
await this.cache.set("spocs", spocs);
} else {
Cu.reportError("No response for spocs_endpoint prop");
// Use old data if we have it, otherwise nothing.
spocs = spocs || {};
}
}

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

@ -283,34 +283,69 @@ class PlacesFeed {
_target.browser.ownerGlobal.gURLBar.search(`${data.label} `);
}
handoffSearchToAwesomebar({_target, data, meta}) {
const urlBar = _target.browser.ownerGlobal.gURLBar;
_getSearchPrefix() {
const searchAliases = Services.search.defaultEngine.wrappedJSObject.__internalAliases;
if (searchAliases && searchAliases.length > 0) {
return `${searchAliases[0]} `;
}
return "";
}
if (!data.text) {
// Do a normal focus of awesomebar.
urlBar.focus();
// We are done here. return early.
return;
handoffSearchToAwesomebar({_target, data, meta}) {
const searchAlias = this._getSearchPrefix();
const urlBar = _target.browser.ownerGlobal.gURLBar;
let isFirstChange = true;
if (!data || !data.text) {
urlBar.setHiddenFocus();
} else {
// Pass the provided text to the awesomebar. Prepend the @engine shortcut.
urlBar.search(`${searchAlias}${data.text}`);
isFirstChange = false;
}
// Pass the provided text to the awesomebar.
urlBar.search(data.text);
const onDone = () => {
// When done, let's cleanup everything.
this.store.dispatch(ac.OnlyToOneContent({type: at.SHOW_SEARCH}, meta.fromTarget));
urlBar.removeEventListener("mousedown", onDone);
urlBar.removeEventListener("blur", onDone);
};
const onKeydown = event => {
// If the Esc button is pressed, we are done. Show in-content search and cleanup.
if (event.key === "Escape") {
onDone();
const checkFirstChange = () => {
// Check if this is the first change since we hidden focused. If it is,
// remove hidden focus styles, prepend the search alias and hide the
// in-content search.
if (isFirstChange) {
isFirstChange = false;
urlBar.removeHiddenFocus();
urlBar.search(searchAlias);
this.store.dispatch(ac.OnlyToOneContent({type: at.HIDE_SEARCH}, meta.fromTarget));
urlBar.removeEventListener("compositionstart", checkFirstChange);
urlBar.removeEventListener("paste", checkFirstChange);
}
};
const onKeydown = ev => {
// Check if the keydown will cause a value change.
if (ev.key.length === 1 && !ev.altKey && !ev.ctrlKey && !ev.metaKey) {
checkFirstChange();
}
// If the Esc button is pressed, we are done. Show in-content search and cleanup.
if (ev.key === "Escape") {
onDone(); // eslint-disable-line no-use-before-define
}
};
const onDone = () => {
// We are done. Show in-content search again and cleanup.
this.store.dispatch(ac.OnlyToOneContent({type: at.SHOW_SEARCH}, meta.fromTarget));
urlBar.removeHiddenFocus();
urlBar.removeEventListener("keydown", onKeydown);
urlBar.removeEventListener("mousedown", onDone);
urlBar.removeEventListener("blur", onDone);
urlBar.removeEventListener("compositionstart", checkFirstChange);
urlBar.removeEventListener("paste", checkFirstChange);
};
urlBar.addEventListener("keydown", onKeydown);
urlBar.addEventListener("mousedown", onDone);
urlBar.addEventListener("blur", onDone);
urlBar.addEventListener("compositionstart", checkFirstChange);
urlBar.addEventListener("paste", checkFirstChange);
}
onAction(action) {

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

@ -93,6 +93,8 @@ prefs_home_header=Obsah domovské stránky Firefoxu
prefs_home_description=Vyberte obsah, který chcete mít na výchozí domovské stránce Firefoxu.
prefs_content_discovery_header=Domovská stránka Firefoxu
prefs_content_discovery_description=Doporučování obsahu na domovské stránce obsahu vám nabídne kvalitní a relevantní články z celého internetu.
prefs_content_discovery_button=Vypnout doporučování obsahu
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
# plural forms used in a drop down of multiple row options (1 row, 2 rows).

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

@ -91,6 +91,10 @@ section_disclaimer_topstories_buttontext=Εντάξει, το 'πιασα
# what is shown for the homepage, new windows, and new tabs.
prefs_home_header=Περιεχόμενο αρχικής σελίδας Firefox
prefs_home_description=Επιλέξτε τι περιεχόμενο θέλετε στην αρχική σελίδα του Firefox σας.
prefs_content_discovery_header=Αρχική Firefox
prefs_content_discovery_button=Απενεργοποίηση ανακάλυψης περιεχομένου
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals

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

@ -91,6 +91,9 @@ section_disclaimer_topstories_buttontext=알겠습니다.
# what is shown for the homepage, new windows, and new tabs.
prefs_home_header=Firefox 홈 콘텐츠
prefs_home_description=Firefox 홈 화면에 나올 콘텐츠를 선택하세요.
prefs_content_discovery_header=Firefox 홈
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
@ -144,7 +147,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에 저장하고 재미있게 읽어 보세요.

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

@ -73,7 +73,7 @@ search_header=Pesquisa {search_engine_name}
# LOCALIZATION NOTE (search_web_placeholder): This is shown in the searchbox when
# the user hasn't typed anything yet.
search_web_placeholder=Pesquisar na Web
search_web_placeholder=Pesquisar na web
# LOCALIZATION NOTE (section_disclaimer_topstories): This is shown below
# the topstories section title to provide additional information about

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

@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=Ok, chapì
# what is shown for the homepage, new windows, and new tabs.
prefs_home_header=Cuntegn da la pagina da partenza da Firefox
prefs_home_description=Tscherna il cuntegn che ti vuls vesair sin la pagina da partenza da Firefox.
prefs_content_discovery_header=Pagina da partenza da Firefox
prefs_content_discovery_description=La vitrina da cuntegn pussibilitescha da scuvrir artitgels relevants da gronda qualitad en il web.
prefs_content_discovery_button=Deactivar la vitrina da cuntegn
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
@ -144,7 +149,6 @@ pocket_read_more=Temas populars:
# end of the list of popular topic links.
pocket_read_even_more=Mussar dapli artitgels
pocket_more_reccommendations=Dapli propostas
pocket_learn_more=Ulteriuras infurmaziuns
pocket_how_it_works=Co ch'i funcziuna
pocket_cta_button=Obtegnair Pocket
pocket_cta_text=Memorisescha ils artitgels che ta plaschan en Pocket e procura per inspiraziun cuntinuanta cun lectura fascinanta.

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

@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=Tamam, anladım
# what is shown for the homepage, new windows, and new tabs.
prefs_home_header=Firefox giriş sayfası içeriği
prefs_home_description=Firefox giriş sayfasında görmek istediğiniz içerikleri seçin.
prefs_content_discovery_header=Firefox Başlangıç
prefs_content_discovery_description=Firefox giriş sayfasındaki içerik keşfi özelliği, internetteki kaliteli ve ilginizi çekebilecek yazıları keşfetmenizi sağlar.
prefs_content_discovery_button=İçerik keşfini kapat
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
@ -144,7 +149,6 @@ pocket_read_more=Popüler konular:
# end of the list of popular topic links.
pocket_read_even_more=Daha fazla yazı göster
pocket_more_reccommendations=Daha fazla öneri
pocket_learn_more=Daha fazla bilgi al
pocket_how_it_works=Nasıl çalışıyor?
pocket_cta_button=Pocketı edinin
pocket_cta_text=Sevdiğiniz yazıları Pocketa kaydedin, aklınız okumaya değer şeylerle doldurun.

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

@ -41,8 +41,8 @@ window.gActivityStreamStrings = {
"prefs_home_header": "Obsah domovské stránky Firefoxu",
"prefs_home_description": "Vyberte obsah, který chcete mít na výchozí domovské stránce Firefoxu.",
"prefs_content_discovery_header": "Domovská stránka Firefoxu",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_content_discovery_description": "Doporučování obsahu na domovské stránce obsahu vám nabídne kvalitní a relevantní články z celého internetu.",
"prefs_content_discovery_button": "Vypnout doporučování obsahu",
"prefs_section_rows_option": "{num} řádek;{num} řádky;{num} řádků",
"prefs_search_header": "Vyhledávání na webu",
"prefs_topsites_description": "Nejnavštěvovanější stránky",

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

@ -40,9 +40,9 @@ window.gActivityStreamStrings = {
"section_disclaimer_topstories_buttontext": "Εντάξει, το 'πιασα",
"prefs_home_header": "Περιεχόμενο αρχικής σελίδας Firefox",
"prefs_home_description": "Επιλέξτε τι περιεχόμενο θέλετε στην αρχική σελίδα του Firefox σας.",
"prefs_content_discovery_header": "Firefox Home",
"prefs_content_discovery_header": "Αρχική Firefox",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_content_discovery_button": "Απενεργοποίηση ανακάλυψης περιεχομένου",
"prefs_section_rows_option": "{num} σειρά;{num} σειρές",
"prefs_search_header": "Διαδικτυακή αναζήτηση",
"prefs_topsites_description": "Οι ιστοσελίδες που επισκέπτεστε περισσότερο",

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

@ -40,7 +40,7 @@ window.gActivityStreamStrings = {
"section_disclaimer_topstories_buttontext": "알겠습니다.",
"prefs_home_header": "Firefox 홈 콘텐츠",
"prefs_home_description": "Firefox 홈 화면에 나올 콘텐츠를 선택하세요.",
"prefs_content_discovery_header": "Firefox Home",
"prefs_content_discovery_header": "Firefox ",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_section_rows_option": "{num} 행",
@ -110,6 +110,5 @@ window.gActivityStreamStrings = {
"firstrun_privacy_notice": "개인 정보 보호 정책",
"firstrun_continue_to_login": "계속",
"firstrun_skip_login": "단계 건너뛰기",
"context_menu_title": "메뉴 열기",
"pocket_learn_more": "자세히 보기"
"context_menu_title": "메뉴 열기"
};

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

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

@ -34,7 +34,7 @@ window.gActivityStreamStrings = {
"menu_action_remove_download": "Remover do histórico",
"search_button": "Pesquisar",
"search_header": "Pesquisa {search_engine_name}",
"search_web_placeholder": "Pesquisar na Web",
"search_web_placeholder": "Pesquisar na web",
"section_disclaimer_topstories": "As histórias mais interessantes na web, selecionadas baseadas no que você lê. Do Pocket, agora parte da Mozilla.",
"section_disclaimer_topstories_linktext": "Saiba como funciona.",
"section_disclaimer_topstories_buttontext": "Ok, entendi",

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

@ -40,9 +40,9 @@ window.gActivityStreamStrings = {
"section_disclaimer_topstories_buttontext": "Ok, chapì",
"prefs_home_header": "Cuntegn da la pagina da partenza da Firefox",
"prefs_home_description": "Tscherna il cuntegn che ti vuls vesair sin la pagina da partenza da Firefox.",
"prefs_content_discovery_header": "Firefox Home",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_content_discovery_header": "Pagina da partenza da Firefox",
"prefs_content_discovery_description": "La vitrina da cuntegn pussibilitescha da scuvrir artitgels relevants da gronda qualitad en il web.",
"prefs_content_discovery_button": "Deactivar la vitrina da cuntegn",
"prefs_section_rows_option": "{num} lingia;{num} lingias",
"prefs_search_header": "Tschertga web",
"prefs_topsites_description": "Las paginas che ti visitas il pli savens",
@ -110,6 +110,5 @@ window.gActivityStreamStrings = {
"firstrun_privacy_notice": "Infurmaziuns davart la protecziun da datas",
"firstrun_continue_to_login": "Cuntinuar",
"firstrun_skip_login": "Sursiglir quest pass",
"context_menu_title": "Avrir il menu",
"pocket_learn_more": "Ulteriuras infurmaziuns"
"context_menu_title": "Avrir il menu"
};

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

@ -40,9 +40,9 @@ window.gActivityStreamStrings = {
"section_disclaimer_topstories_buttontext": "Tamam, anladım",
"prefs_home_header": "Firefox giriş sayfası içeriği",
"prefs_home_description": "Firefox giriş sayfasında görmek istediğiniz içerikleri seçin.",
"prefs_content_discovery_header": "Firefox Home",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_content_discovery_header": "Firefox Başlangıç",
"prefs_content_discovery_description": "Firefox giriş sayfasındaki içerik keşfi özelliği, internetteki kaliteli ve ilginizi çekebilecek yazıları keşfetmenizi sağlar.",
"prefs_content_discovery_button": "İçerik keşfini kapat",
"prefs_section_rows_option": "{num} satır;{num} satır",
"prefs_search_header": "Web araması",
"prefs_topsites_description": "En çok ziyaret ettiğiniz siteler",
@ -110,6 +110,5 @@ window.gActivityStreamStrings = {
"firstrun_privacy_notice": "Gizlilik Bildirimini",
"firstrun_continue_to_login": "Devam et",
"firstrun_skip_login": "Bu adımı atla",
"context_menu_title": "Menüyü aç",
"pocket_learn_more": "Daha fazla bilgi al"
"context_menu_title": "Menüyü aç"
};

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

@ -80,11 +80,12 @@ window.gActivityStreamPrerenderedState = {
"spocs": {
"spocs_endpoint": "",
"lastUpdated": null,
"data": {}
"data": {},
"loaded": false
}
},
"Search": {
"focus": false,
"fakeFocus": false,
"hide": false
}
};

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

@ -25,7 +25,7 @@ test_newtab({
},
test: async function test_hr_override() {
const hr = await ContentTaskUtils.waitForCondition(() => content.document.querySelector("hr"));
ok(content.getComputedStyle(hr).borderBottomWidth.match(/11.?\d*px/), "applied and normalized hr component width override");
ok(content.getComputedStyle(hr).borderTopWidth.match(/11.?\d*px/), "applied and normalized hr component width override");
},
});

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

@ -903,6 +903,27 @@ describe("ASRouter", () => {
assert.calledOnce(MessageLoaderUtils.installAddonFromURL);
assert.calledWithExactly(MessageLoaderUtils.installAddonFromURL, msg.target.browser, "foo.com");
});
it("should add/remove observers for `webextension-install-notify`", async () => {
sandbox.spy(global.Services.obs, "addObserver");
sandbox.spy(global.Services.obs, "removeObserver");
sandbox.spy(Router, "blockMessageById");
sandbox.stub(MessageLoaderUtils, "installAddonFromURL").resolves(null);
const msg = fakeExecuteUserAction({type: "INSTALL_ADDON_FROM_URL", data: {url: "foo.com"}});
await Router.onMessage(msg);
assert.calledOnce(global.Services.obs.addObserver);
const [cb] = global.Services.obs.addObserver.firstCall.args;
cb();
assert.calledOnce(global.Services.obs.removeObserver);
assert.calledOnce(channel.sendAsyncMessage);
assert.calledOnce(Router.blockMessageById);
assert.calledWithExactly(Router.blockMessageById, "RETURN_TO_AMO_1");
});
});
describe("#dispatch(action, target)", () => {

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

@ -682,6 +682,7 @@ describe("Reducers", () => {
spocs_endpoint: "",
data: [1, 2, 3],
lastUpdated: 123,
loaded: true,
});
});
it("should handle no data from DISCOVERY_STREAM_SPOCS_UPDATE", () => {
@ -698,8 +699,13 @@ describe("Reducers", () => {
const nextState = Search(undefined, {type: "HIDE_SEARCH"});
assert.propertyVal(nextState, "hide", true);
});
it("should set focus to true on FAKE_FOCUS_SEARCH", () => {
const nextState = Search(undefined, {type: "FAKE_FOCUS_SEARCH"});
assert.propertyVal(nextState, "fakeFocus", true);
});
it("should set focus and hide to false on SHOW_SEARCH", () => {
const nextState = Search(undefined, {type: "SHOW_SEARCH"});
assert.propertyVal(nextState, "fakeFocus", false);
assert.propertyVal(nextState, "hide", false);
});
});

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

@ -76,10 +76,10 @@ describe("<ListItem> presentation component", () => {
assert.lengthOf(anchors, 1);
});
it("should include an img with a src of props.image_src", () => {
it("should include an background image of props.image_src", () => {
const wrapper = shallow(<ListItem {...ValidListItemProps} />);
const anchors = wrapper.find(`img[src="${ValidListItemProps.image_src}"]`);
assert.lengthOf(anchors, 1);
const imageStyle = wrapper.find(".ds-list-image").prop("style");
assert.propertyVal(imageStyle, "backgroundImage", `url(${ValidListItemProps.image_src})`);
});
});

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

@ -80,60 +80,21 @@ describe("<Search>", () => {
assert.ok(wrapper.exists());
assert.equal(wrapper.find(".search-handoff-button").length, 1);
});
it("should focus search hand-off button when clicked with mouse", () => {
it("should hand-off search when button is clicked", () => {
const dispatch = sinon.spy();
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
wrapper.instance()._searchHandoffButton = {focus: sinon.spy()};
wrapper.find(".search-handoff-button").simulate("click", {clientX: 101, clientY: 102, preventDefault: () => {}});
assert.calledOnce(wrapper.instance()._searchHandoffButton.focus);
});
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.find(".search-handoff-button").simulate("click", {clientX: 0, clientY: 0, preventDefault: () => {}});
assert.calledTwice(dispatch);
wrapper.find(".search-handoff-button").simulate("click", {preventDefault: () => {}});
assert.calledThrice(dispatch);
assert.calledWith(dispatch, {
data: {text: undefined},
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
type: "HANDOFF_SEARCH_TO_AWESOMEBAR",
});
const [action] = dispatch.secondCall.args;
assert.calledWith(dispatch, {type: "FAKE_FOCUS_SEARCH"});
const [action] = dispatch.thirdCall.args;
assert.isUserEventAction(action);
assert.propertyVal(action.data, "event", "SEARCH_HANDOFF");
});
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.calledThrice(dispatch);
assert.calledWith(dispatch, {
data: {text: "f"},
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
type: "HANDOFF_SEARCH_TO_AWESOMEBAR",
});
assert.calledWith(dispatch, {type: "HIDE_SEARCH"});
const [action] = dispatch.secondCall.args;
assert.isUserEventAction(action);
assert.propertyVal(action.data, "event", "SEARCH_HANDOFF");
});
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} />);
@ -144,22 +105,35 @@ describe("<Search>", () => {
},
preventDefault: () => {},
});
assert.calledThrice(dispatch);
assert.equal(dispatch.callCount, 4);
assert.calledWith(dispatch, {
data: {text: "some copied text"},
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
type: "HANDOFF_SEARCH_TO_AWESOMEBAR",
});
assert.calledWith(dispatch, {type: "HIDE_SEARCH"});
const [action] = dispatch.secondCall.args;
const [action] = dispatch.thirdCall.args;
assert.isUserEventAction(action);
assert.propertyVal(action.data, "event", "SEARCH_HANDOFF");
});
it("should not accept drop events", () => {
const wrapper = shallowWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} />);
it("should properly handle drop events", () => {
const dispatch = sinon.spy();
const wrapper = mountWithIntl(<Search {...DEFAULT_PROPS} handoffEnabled={true} dispatch={dispatch} />);
const preventDefault = sinon.spy();
wrapper.find(".fake-editable").simulate("drop", {preventDefault});
assert.calledOnce(preventDefault);
wrapper.find(".fake-editable").simulate("drop", {
dataTransfer: {getData: () => "dropped text"},
preventDefault,
});
assert.equal(dispatch.callCount, 4);
assert.calledWith(dispatch, {
data: {text: "dropped text"},
meta: {from: "ActivityStream:Content", skipLocal: true, to: "ActivityStream:Main"},
type: "HANDOFF_SEARCH_TO_AWESOMEBAR",
});
assert.calledWith(dispatch, {type: "HIDE_SEARCH"});
const [action] = dispatch.thirdCall.args;
assert.isUserEventAction(action);
assert.propertyVal(action.data, "event", "SEARCH_HANDOFF");
});
});
});

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

@ -327,7 +327,7 @@ describe("PlacesFeed", () => {
fakeUrlBar = {
focus: sinon.spy(),
search: sinon.spy(),
hiddenFocus: sinon.spy(),
setHiddenFocus: sinon.spy(),
removeHiddenFocus: sinon.spy(),
addEventListener: (ev, cb) => {
listeners[ev] = cb;
@ -336,24 +336,41 @@ describe("PlacesFeed", () => {
};
listeners = {};
});
it("should properly handle normal focus (no text passed in)", () => {
it("should properly handle handoff with no text passed in", () => {
feed.handoffSearchToAwesomebar({
_target: {browser: {ownerGlobal: {gURLBar: fakeUrlBar}}},
data: {},
meta: {fromTarget: {}},
});
assert.calledOnce(fakeUrlBar.focus);
assert.calledOnce(fakeUrlBar.setHiddenFocus);
assert.notCalled(fakeUrlBar.search);
assert.notCalled(feed.store.dispatch);
// Now type a character.
listeners.keydown({key: "f"});
assert.calledOnce(fakeUrlBar.search);
assert.calledOnce(fakeUrlBar.removeHiddenFocus);
assert.calledOnce(feed.store.dispatch);
assert.calledWith(feed.store.dispatch, {
meta: {
from: "ActivityStream:Main",
skipMain: true,
to: "ActivityStream:Content",
toTarget: {},
},
type: "HIDE_SEARCH",
});
});
it("should properly handle text data passed in", () => {
it("should properly handle handoff with text data passed in", () => {
feed.handoffSearchToAwesomebar({
_target: {browser: {ownerGlobal: {gURLBar: fakeUrlBar}}},
data: {text: "f"},
data: {text: "foo"},
meta: {fromTarget: {}},
});
assert.calledOnce(fakeUrlBar.search);
assert.calledWith(fakeUrlBar.search, "f");
assert.calledWith(fakeUrlBar.search, "@google foo");
assert.notCalled(fakeUrlBar.focus);
assert.notCalled(fakeUrlBar.setHiddenFocus);
// Now call blur listener.
listeners.blur();
@ -371,11 +388,11 @@ describe("PlacesFeed", () => {
it("should SHOW_SEARCH on ESC keydown", () => {
feed.handoffSearchToAwesomebar({
_target: {browser: {ownerGlobal: {gURLBar: fakeUrlBar}}},
data: {text: "f"},
data: {text: "foo"},
meta: {fromTarget: {}},
});
assert.calledOnce(fakeUrlBar.search);
assert.calledWith(fakeUrlBar.search, "f");
assert.calledWith(fakeUrlBar.search, "@google foo");
assert.notCalled(fakeUrlBar.focus);
// Now call ESC keydown.
@ -391,6 +408,16 @@ describe("PlacesFeed", () => {
type: "SHOW_SEARCH",
});
});
it("should properly handle no defined search alias", () => {
global.Services.search.defaultEngine.wrappedJSObject.__internalAliases = [];
feed.handoffSearchToAwesomebar({
_target: {browser: {ownerGlobal: {gURLBar: fakeUrlBar}}},
data: {text: "foo"},
meta: {fromTarget: {}},
});
assert.calledOnce(fakeUrlBar.search);
assert.calledWith(fakeUrlBar.search, "foo");
});
});
describe("#observe", () => {

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

@ -225,7 +225,13 @@ const TEST_GLOBAL = {
search: {
init(cb) { cb(); },
getVisibleEngines: () => [{identifier: "google"}, {identifier: "bing"}],
defaultEngine: {identifier: "google", searchForm: "https://www.google.com/search?q=&ie=utf-8&oe=utf-8&client=firefox-b"},
defaultEngine: {
identifier: "google",
searchForm: "https://www.google.com/search?q=&ie=utf-8&oe=utf-8&client=firefox-b",
wrappedJSObject: {
__internalAliases: ["@google"],
},
},
currentEngine: {identifier: "google", searchForm: "https://www.google.com/search?q=&ie=utf-8&oe=utf-8&client=firefox-b"},
},
scriptSecurityManager: {