Bug 1555507 - Add modal escaping, simple prerendering and bug fixes to Activity Stream r=k88hudson

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ed Lee 2019-05-30 15:04:19 +00:00
parent cc371c6881
commit bd822928e5
446 changed files with 2519 additions and 8614 deletions

View file

@ -57,7 +57,6 @@ browser/components/pocket/content/panels/js/vendor/**
# Ignore newtab files
# Kept in sync with browser/components/newtab/.eslintignore
browser/components/newtab/bin/prerender.js
browser/components/newtab/data/
browser/components/newtab/logs/
browser/components/newtab/prerendered/

View file

@ -1,4 +1,3 @@
bin/prerender.js
data/
logs/
prerendered/

View file

@ -7,8 +7,6 @@ npm-debug.log
.gitignore
/.git/
/bin/prerender.js
/bin/prerender.js.map
/data/locales.json
/dist/
/logs/

View file

@ -31,14 +31,12 @@ const IS_PRIVILEGED_PROCESS = Services.appinfo.remoteType === E10SUtils.PRIVILEG
const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA;
const PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS = "browser.tabs.remote.separatePrivilegedContentProcess";
const PREF_ACTIVITY_STREAM_PRERENDER_ENABLED = "browser.newtabpage.activity-stream.prerender";
const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
function AboutNewTabService() {
Services.obs.addObserver(this, TOPIC_APP_QUIT);
Services.obs.addObserver(this, TOPIC_LOCALES_CHANGE);
Services.prefs.addObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this);
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
if (!IS_RELEASE_OR_BETA) {
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
}
@ -90,7 +88,6 @@ AboutNewTabService.prototype = {
_newTabURL: ABOUT_URL,
_activityStreamEnabled: false,
_activityStreamPrerender: false,
_activityStreamPath: "",
_activityStreamDebug: false,
_privilegedAboutContentProcess: false,
@ -110,9 +107,6 @@ AboutNewTabService.prototype = {
this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS);
this.updatePrerenderedPath();
this.notifyChange();
} else if (data === PREF_ACTIVITY_STREAM_PRERENDER_ENABLED) {
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
this.notifyChange();
} else if (!IS_RELEASE_OR_BETA && data === PREF_ACTIVITY_STREAM_DEBUG) {
this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
this.updatePrerenderedPath();
@ -158,10 +152,6 @@ AboutNewTabService.prototype = {
`${BASE_URL}data/content/activity-stream.bundle.js`,
];
if (this._activityStreamPrerender) {
scripts.unshift(`${BASE_URL}prerendered/static/activity-stream-initial-state.js`);
}
for (let script of scripts) {
Services.scriptloader.loadSubScript(script, win); // Synchronous call
}
@ -217,7 +207,6 @@ AboutNewTabService.prototype = {
this._activityStreamEnabled = false;
}
this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS);
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
if (!IS_RELEASE_OR_BETA) {
this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
}
@ -245,13 +234,11 @@ AboutNewTabService.prototype = {
get defaultURL() {
// Generate the desired activity stream resource depending on state, e.g.,
// resource://activity-stream/prerendered/ar/activity-stream.html
// resource://activity-stream/prerendered/en-US/activity-stream-prerendered.html
// resource://activity-stream/prerendered/static/activity-stream-debug.html
return [
"resource://activity-stream/prerendered/",
this._activityStreamPath,
"activity-stream",
this._activityStreamPrerender ? "-prerendered" : "",
// Debug version loads dev scripts but noscripts separately loads scripts
this._activityStreamDebug && !this._privilegedAboutContentProcess ? "-debug" : "",
this._privilegedAboutContentProcess ? "-noscripts" : "",
@ -262,15 +249,10 @@ AboutNewTabService.prototype = {
/*
* Returns the about:welcome URL
*
* This is calculated in the same way the default URL is, except that we don't
* allow prerendering.
* This is calculated in the same way the default URL is.
*/
get welcomeURL() {
const prerenderEnabled = this._activityStreamPrerender;
this._activityStreamPrerender = false;
const url = this.defaultURL;
this._activityStreamPrerender = prerenderEnabled;
return url;
return this.defaultURL;
},
get newTabURL() {
@ -301,10 +283,6 @@ AboutNewTabService.prototype = {
return this._activityStreamEnabled;
},
get activityStreamPrerender() {
return this._activityStreamPrerender;
},
get activityStreamDebug() {
return this._activityStreamDebug;
},
@ -352,7 +330,6 @@ AboutNewTabService.prototype = {
Services.obs.removeObserver(this, TOPIC_APP_QUIT);
Services.obs.removeObserver(this, TOPIC_LOCALES_CHANGE);
Services.prefs.removeObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this);
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
if (!IS_RELEASE_OR_BETA) {
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
}

View file

@ -3,9 +3,6 @@ const fs = require("fs");
const {mkdir} = require("shelljs");
const path = require("path");
// Note: this file is generated by webpack from content-src/activity-stream-prerender.jsx
const {prerender} = require("./prerender");
const {CENTRAL_LOCALES, DEFAULT_LOCALE} = require("./locales");
// Note: DEFAULT_OPTIONS.baseUrl should match BASE_URL in aboutNewTabService.js
@ -64,11 +61,9 @@ function getTextDirection(locale) {
* {str} options.baseUrl The base URL for all local assets
* {bool} options.debug Should we use dev versions of JS libraries?
* {bool} options.noscripts Should we include scripts in the prerendered files?
* @param {str} html The prerendered HTML created with React.renderToString (optional)
* @return {str} An HTML document as a string
*/
function templateHTML(options, html) {
const isPrerendered = !!html;
function templateHTML(options) {
const debugString = options.debug ? "-dev" : "";
const scripts = [
"chrome://browser/content/contentSearchUI.js",
@ -82,9 +77,6 @@ function templateHTML(options, html) {
`${options.baseUrl}prerendered/${options.locale}/activity-stream-strings.js`,
`${options.baseUrl}data/content/activity-stream.bundle.js`,
];
if (isPrerendered) {
scripts.unshift(`${options.baseUrl}prerendered/static/activity-stream-initial-state.js`);
}
// Add spacing and script tags
const scriptRender = `\n${scripts.map(script => ` <script src="${script}"></script>`).join("\n")}`;
@ -101,7 +93,7 @@ function templateHTML(options, html) {
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root">${isPrerendered ? html : "<!-- Regular React Rendering -->"}</div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>${options.noscripts ? "" : scriptRender}
</body>
</html>
@ -135,25 +127,20 @@ window.${name} = ${JSON.stringify(state, null, 2)};
* @param {string} name Something to identify in the console
* @param {string} destPath Path to write the files to
* @param {Map} filesMap Mapping of a string file name to templater
* @param {Object} prerenderData Contains the html and state
* @param {Object} options Various options for the templater
*/
function writeFiles(name, destPath, filesMap, {html, state}, options) {
function writeFiles(name, destPath, filesMap, options) {
for (const [file, templater] of filesMap) {
fs.writeFileSync(path.join(destPath, file), templater({html, options, state}));
fs.writeFileSync(path.join(destPath, file), templater({options}));
}
console.log("\x1b[32m", `${name}`, "\x1b[0m");
}
const STATIC_FILES = new Map([
["activity-stream-debug.html", ({options}) => templateHTML(options)],
["activity-stream-initial-state.js", ({state}) => templateJs("gActivityStreamPrerenderedState", "static", state)],
["activity-stream-prerendered-debug.html", ({html, options}) => templateHTML(options, html)],
]);
const LOCALIZED_FILES = new Map([
["activity-stream-prerendered.html", ({html, options}) => templateHTML(options, html)],
["activity-stream-prerendered-noscripts.html", ({html, options}) => templateHTML(Object.assign({}, options, {noscripts: true}), html)],
["activity-stream-strings.js", ({options: {locale, strings}}) => templateJs("gActivityStreamStrings", locale, strings)],
["activity-stream.html", ({options}) => templateHTML(options)],
["activity-stream-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))],
@ -200,7 +187,6 @@ function main() { // eslint-disable-line max-statements
continue;
}
const prerenderData = prerender(locale, strings);
const options = Object.assign({}, baseOptions, {
direction: getTextDirection(locale),
locale,
@ -210,13 +196,13 @@ function main() { // eslint-disable-line max-statements
// Put locale-specific files in their own directory
const localePath = path.join(prerenderedPath, "locales", locale);
mkdir("-p", localePath);
writeFiles(locale, localePath, LOCALIZED_FILES, prerenderData, options);
writeFiles(locale, localePath, LOCALIZED_FILES, options);
// Only write static files once for the default locale
if (locale === DEFAULT_LOCALE) {
const staticPath = path.join(prerenderedPath, "static");
mkdir("-p", staticPath);
writeFiles(`${locale} (static)`, staticPath, STATIC_FILES, prerenderData,
writeFiles(`${locale} (static)`, staticPath, STATIC_FILES,
Object.assign({}, options, {debug: true}));
// Save the default strings to compare against other locales' strings

View file

@ -72,7 +72,6 @@ for (const type of [
"OPEN_NEW_WINDOW",
"OPEN_PRIVATE_WINDOW",
"OPEN_WEBEXT_SETTINGS",
"PAGE_PRERENDERED",
"PLACES_BOOKMARK_ADDED",
"PLACES_BOOKMARK_REMOVED",
"PLACES_HISTORY_CLEARED",

View file

@ -15,17 +15,10 @@ if (typeof Services !== "undefined") {
// Borrow the high-resolution timer from the hidden window....
// eslint-disable-next-line block-scoped-var
usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
} else if (typeof performance !== "undefined") {
} else {
// we must be running in content space
// eslint-disable-next-line no-undef
usablePerfObj = performance;
} else {
// This is a dummy object so this file doesn't crash in the node prerendering
// task.
usablePerfObj = {
now() {},
mark() {},
};
}
function _PerfService(options) {

View file

@ -1,126 +0,0 @@
class _PrerenderData {
constructor(options) {
this.initialPrefs = options.initialPrefs;
this.initialSections = options.initialSections;
this._setValidation(options.validation);
}
get validation() {
return this._validation;
}
set validation(value) {
this._setValidation(value);
}
get invalidatingPrefs() {
return this._invalidatingPrefs;
}
// This is needed so we can use it in the constructor
_setValidation(value = []) {
this._validation = value;
this._invalidatingPrefs = value.reduce((result, next) => {
if (typeof next === "string") {
result.push(next);
return result;
} else if (next && next.oneOf) {
return result.concat(next.oneOf);
} else if (next && next.indexedDB) {
return result.concat(next.indexedDB);
} else if (next && next.jsonPrefs) {
return result.concat(next.jsonPrefs);
}
throw new Error("Your validation configuration is not properly configured");
}, []);
}
_isPrefEnabled(prefObj) {
try {
let data = JSON.parse(prefObj);
return (data && data.enabled) ? true : false; // eslint-disable-line no-unneeded-ternary
} catch (e) {
return false;
}
}
arePrefsValid(getPref, indexedDBPrefs) {
for (const prefs of this.validation) {
// {oneOf: ["foo", "bar"]}
if (prefs && prefs.oneOf && !prefs.oneOf.some(name => getPref(name) === this.initialPrefs[name])) {
return false;
// {indexedDB: ["foo", "bar"]}
} else if (indexedDBPrefs && prefs && prefs.indexedDB) {
const anyModifiedPrefs = prefs.indexedDB.some(prefName => indexedDBPrefs.some(pref => pref && pref[prefName]));
if (anyModifiedPrefs) {
return false;
}
// {jsonPrefs: ["foo", "bar"]}
} else if (prefs && prefs.jsonPrefs) {
const isPrefModified =
prefs.jsonPrefs.some(name => this._isPrefEnabled(getPref(name)) !== this.initialPrefs[name].enabled);
if (isPrefModified) {
return false;
}
// "foo"
} else if (getPref(prefs) !== this.initialPrefs[prefs]) {
return false;
}
}
return true;
}
}
this.PrerenderData = new _PrerenderData({
initialPrefs: {
"feeds.topsites": true,
"showSearch": true,
"topSitesRows": 1,
"feeds.section.topstories": true,
"feeds.section.highlights": true,
"sectionOrder": "topsites,topstories,highlights",
"collapsed": false,
"discoverystream.config": {"enabled": false},
},
// Prefs listed as invalidating will prevent the prerendered version
// of AS from being used if their value is something other than what is listed
// here. This is required because some preferences cause the page layout to be
// too different for the prerendered version to be used. Unfortunately, this
// will result in users who have modified some of their preferences not being
// able to get the benefits of prerendering.
validation: [
"feeds.topsites",
"showSearch",
"topSitesRows",
"sectionOrder",
// This means if either of these are set to their default values,
// prerendering can be used.
{oneOf: ["feeds.section.topstories", "feeds.section.highlights"]},
// If any component has the following preference set to `true` it will
// invalidate the prerendered version.
{indexedDB: ["collapsed"]},
// For below prefs, parse value to check enabled property. If enabled property
// differs from initial prefs enabled value, prerendering cannot be used
{jsonPrefs: ["discoverystream.config"]},
],
initialSections: [
{
enabled: true,
icon: "pocket",
id: "topstories",
order: 1,
title: {id: "header_recommended_by", values: {provider: "Pocket"}},
},
{
enabled: true,
id: "highlights",
icon: "highlights",
order: 2,
title: {id: "header_highlights"},
},
],
});
this._PrerenderData = _PrerenderData;
const EXPORTED_SYMBOLS = ["PrerenderData", "_PrerenderData"];

View file

@ -1,45 +0,0 @@
import {INITIAL_STATE, reducers} from "common/Reducers.jsm";
import {actionTypes as at} from "common/Actions.jsm";
import {Base} from "content-src/components/Base/Base";
import {initStore} from "content-src/lib/init-store";
import {PrerenderData} from "common/PrerenderData.jsm";
import {Provider} from "react-redux";
import React from "react";
import ReactDOMServer from "react-dom/server";
/**
* prerenderStore - Generate a store with the initial state required for a prerendered page
*
* @return {obj} A store
*/
export function prerenderStore() {
const store = initStore(reducers, INITIAL_STATE);
store.dispatch({type: at.PREFS_INITIAL_VALUES, data: PrerenderData.initialPrefs});
PrerenderData.initialSections.forEach(data => store.dispatch({type: at.SECTION_REGISTER, data}));
return store;
}
export function prerender(locale, strings,
renderToString = ReactDOMServer.renderToString) {
const store = prerenderStore();
const html = renderToString(
<Provider store={store}>
<Base
isPrerendered={true}
locale={locale}
strings={strings} />
</Provider>);
// If this happens, it means pre-rendering is effectively disabled, so we
// need to sound the alarms:
if (!html || !html.length) {
throw new Error("no HTML returned");
}
return {
html,
state: store.getState(),
store,
};
}

View file

@ -7,21 +7,15 @@ import React from "react";
import ReactDOM from "react-dom";
import {reducers} from "common/Reducers.jsm";
const store = initStore(reducers, global.gActivityStreamPrerenderedState);
const store = initStore(reducers);
new DetectUserSessionStart(store).sendEventOrAddListener();
// If we are starting in a prerendered state, we must wait until the first render
// to request state rehydration (see Base.jsx). If we are NOT in a prerendered state,
// we can request it immedately.
if (!global.gActivityStreamPrerenderedState) {
store.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST}));
}
store.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST}));
ReactDOM.hydrate(<Provider store={store}>
<Base
isFirstrun={global.document.location.href === "about:welcome"}
isPrerendered={!!global.gActivityStreamPrerenderedState}
locale={global.document.documentElement.lang}
strings={global.gActivityStreamStrings} />
</Provider>, document.getElementById("root"));

View file

@ -1,7 +1,7 @@
import {addLocaleData, IntlProvider} from "react-intl";
import {actionCreators as ac} from "common/Actions.jsm";
import {OUTGOING_MESSAGE_NAME as AS_GENERAL_OUTGOING_MESSAGE_NAME} from "content-src/lib/init-store";
import {generateMessages} from "./rich-text-strings";
import {generateBundles} from "./rich-text-strings";
import {ImpressionsWrapper} from "./components/ImpressionsWrapper/ImpressionsWrapper";
import {LocalizationProvider} from "fluent-react";
import {NEWTAB_DARK_THEME} from "content-src/lib/constants";
@ -257,7 +257,7 @@ export class ASRouterUISurface extends React.PureComponent {
shouldSendImpressionOnUpdate={shouldSendImpressionOnUpdate}
// This helps with testing
document={this.props.document}>
<LocalizationProvider messages={generateMessages(content)}>
<LocalizationProvider bundles={generateBundles(content)}>
<SnippetComponent
{...this.state.message}
UISurface="NEWTAB_FOOTER_BAR"
@ -298,7 +298,7 @@ export class ASRouterUISurface extends React.PureComponent {
} else if (message.template === "return_to_amo_overlay") {
global.document.body.classList.add("amo");
return (
<LocalizationProvider messages={generateMessages({"amo_html": message.content.text})}>
<LocalizationProvider messages={generateBundles({"amo_html": message.content.text})}>
<ReturnToAMO
{...message}
UISurface="NEWTAB_OVERLAY"

View file

@ -24,9 +24,13 @@ export class ModalOverlayWrapper extends React.PureComponent {
render() {
const {props} = this;
let className = props.unstyled ? "" : "modalOverlayInner active";
if (props.innerClassName) {
className += ` ${props.innerClassName}`;
}
return (<React.Fragment>
<div className="modalOverlayOuter active" onClick={props.onClose} role="presentation" />
<div className={`modalOverlayInner active ${props.innerClassName || ""}`}
<div className="modalOverlayOuter active" onClick={props.onClose} onKeyDown={this.onKeyDown} role="presentation" />
<div className={className}
aria-labelledby={props.headerId}
id={props.id}
role="dialog">

View file

@ -9,6 +9,7 @@
height: 100%;
position: fixed;
top: 0;
left: 0;
width: 100%;
display: none;
z-index: 1100;
@ -20,10 +21,10 @@
.modalOverlayInner {
width: 960px;
height: 570px;
position: fixed;
top: calc(50% - 285px); // halfway down minus half the height of the modal
top: 20%;
left: calc(50% - 480px); // halfway across minus half the width of the modal
max-height: calc(100% - 100px);
background: $white;
box-shadow: 0 1px 15px 0 $black-30;
border-radius: 4px;
@ -75,6 +76,7 @@
.footer {
border-top: 1px solid $grey-30;
border-radius: 4px;
height: 70px;
width: 100%;
position: absolute;

View file

@ -1,4 +1,4 @@
import {MessageContext} from "fluent";
import {FluentBundle} from "fluent";
/**
* Properties that allow rich text MUST be added to this list.
@ -21,10 +21,10 @@ export const RICH_TEXT_KEYS = Object.keys(RICH_TEXT_CONFIG);
* Generates an array of messages suitable for fluent's localization provider
* including all needed strings for rich text.
* @param {object} content A .content object from an ASR message (i.e. message.content)
* @returns {MessageContext[]} A array containing the fluent message context
* @returns {FluentBundle[]} A array containing the fluent message context
*/
export function generateMessages(content) {
const cx = new MessageContext("en-US");
export function generateBundles(content) {
const bundle = new FluentBundle("en-US");
RICH_TEXT_KEYS.forEach(key => {
const attrs = RICH_TEXT_CONFIG[key];
@ -34,7 +34,7 @@ export function generateMessages(content) {
const attr = attrsToTry.pop();
string = content[attr];
}
cx.addMessages(`${key} = ${string}`);
bundle.addMessages(`${key} = ${string}`);
});
return [cx];
return [bundle];
}

View file

@ -59,7 +59,7 @@ export class OnboardingMessage extends React.PureComponent {
const {props} = this;
const {button_label, header} = props.extraTemplateStrings;
return (
<ModalOverlay {...props} button_label={button_label} title={header}>
<ModalOverlay {...props} button_label={button_label} title={header} >
<div className="onboardingMessageContainer">
{props.bundle.map(message => (
<OnboardingCard key={message.id}

View file

@ -4,6 +4,7 @@
grid-template-columns: auto auto auto;
padding-left: 30px;
padding-right: 30px;
min-height: 500px;
// at 850px, the cards go from vertical layout to horizontal layout
@media(max-width: 850px) {

View file

@ -539,7 +539,7 @@ export class ASRouterAdminInner extends React.PureComponent {
}
const errors = this.refs.targetingParamsEval && this.refs.targetingParamsEval.innerText.length;
return (
<ModalOverlay title="New targeting parameters" button_label={errors ? "Cancel" : "Done"} onDoneButton={this.onPasteTargetingParams}>
<ModalOverlay innerStyle="pasteModal" title="New targeting parameters" button_label={errors ? "Cancel" : "Done"} onDismissBundle={this.onPasteTargetingParams}>
<div className="onboardingMessage">
<p>
<textarea onChange={this.onNewTargetingParams} value={this.state.newStringTargetingParameters} rows="20" cols="60" />

View file

@ -219,4 +219,8 @@
.ds-component {
margin-bottom: 20px;
}
.modalOverlayInner {
height: 80%;
}
}

View file

@ -6,7 +6,6 @@ import {ConfirmDialog} from "content-src/components/ConfirmDialog/ConfirmDialog"
import {connect} from "react-redux";
import {DiscoveryStreamBase} from "content-src/components/DiscoveryStreamBase/DiscoveryStreamBase";
import {ErrorBoundary} from "content-src/components/ErrorBoundary/ErrorBoundary";
import {PrerenderData} from "common/PrerenderData.jsm";
import React from "react";
import {Search} from "content-src/components/Search/Search";
import {Sections} from "content-src/components/Sections/Sections";
@ -47,16 +46,6 @@ export class _Base extends React.PureComponent {
}
}
componentDidMount() {
// Request state AFTER the first render to ensure we don't cause the
// prerendered DOM to be unmounted. Otherwise, NEW_TAB_STATE_REQUEST is
// dispatched right after the store is ready.
if (this.props.isPrerendered) {
this.props.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST}));
this.props.dispatch(ac.AlsoToMain({type: at.PAGE_PRERENDERED}));
}
}
componentWillUnmount() {
this.updateTheme();
}
@ -80,10 +69,9 @@ export class _Base extends React.PureComponent {
render() {
const {props} = this;
const {App, locale, strings} = props;
const {initialized} = App;
const isDevtoolsEnabled = props.Prefs.values["asrouter.devtoolsEnabled"];
if (!props.isPrerendered && !initialized) {
if (!App.initialized) {
return null;
}
@ -134,7 +122,6 @@ export class BaseContent extends React.PureComponent {
const {initialized} = App;
const prefs = props.Prefs.values;
const shouldBeFixedToTop = PrerenderData.arePrefsValid(name => prefs[name]);
const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled;
let filteredSections = props.Sections;
@ -149,7 +136,6 @@ export class BaseContent extends React.PureComponent {
"outer-wrapper",
isDiscoveryStream && "ds-outer-wrapper-search-alignment",
isDiscoveryStream && "ds-outer-wrapper-breakpoint-override",
shouldBeFixedToTop && "fixed-to-top",
prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search",
prefs.showSearch && noSectionsEnabled && "only-search",
].filter(v => v).join(" ");

View file

@ -5,10 +5,6 @@
min-height: 100vh;
padding: ($section-spacing + $section-vertical-padding) $base-gutter $base-gutter;
&.fixed-to-top {
display: block;
}
&.only-search {
display: block;
padding-top: 134px;

View file

@ -37,7 +37,9 @@ export class ContextMenu extends React.PureComponent {
}
render() {
return (<span role="menu" className="context-menu" onClick={this.onClick} onKeyDown={this.onClick} tabIndex="0" >
// Disabling focus on the menu span allows the first tab to focus on the first menu item instead of the wrapper.
// eslint-disable-next-line jsx-a11y/interactive-supports-focus
return (<span role="menu" className="context-menu" onClick={this.onClick} onKeyDown={this.onClick} >
<ul className="context-menu-list">
{this.props.options.map((option, i) => (option.type === "separator" ?
(<li key={i} className="separator" />) :

View file

@ -1,5 +1,6 @@
.impression-observer {
position: absolute;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;

View file

@ -4,6 +4,7 @@ import {CollapsibleSection} from "content-src/components/CollapsibleSection/Coll
import {ComponentPerfTimer} from "content-src/components/ComponentPerfTimer/ComponentPerfTimer";
import {connect} from "react-redux";
import {injectIntl} from "react-intl";
import {ModalOverlayWrapper} from "../../asrouter/components/ModalOverlay/ModalOverlay";
import React from "react";
import {SearchShortcutsForm} from "./SearchShortcutsForm";
import {TOP_SITES_MAX_SITES_PER_ROW} from "common/Reducers.jsm";
@ -139,26 +140,24 @@ export class _TopSites extends React.PureComponent {
<div className="edit-topsites-wrapper">
{editForm &&
<div className="edit-topsites">
<div className="modal-overlay" onClick={this.onEditFormClose} role="presentation" />
<div className="modal">
<ModalOverlayWrapper unstyled={true} onClose={this.onEditFormClose} innerClassName="modal" >
<TopSiteForm
site={props.TopSites.rows[editForm.index]}
onClose={this.onEditFormClose}
dispatch={this.props.dispatch}
intl={this.props.intl}
{...editForm} />
</div>
</ModalOverlayWrapper>
</div>
}
{showSearchShortcutsForm &&
<div className="edit-search-shortcuts">
<div className="modal-overlay" onClick={this.onSearchShortcutsFormClose} role="presentation" />
<div className="modal">
<ModalOverlayWrapper unstyled={true} onClose={this.onSearchShortcutsFormClose} innerClassName="modal" >
<SearchShortcutsForm
TopSites={props.TopSites}
onClose={this.onSearchShortcutsFormClose}
dispatch={this.props.dispatch} />
</div>
</ModalOverlayWrapper>
</div>
}
</div>

View file

@ -6,7 +6,7 @@ import {applyMiddleware, combineReducers, createStore} from "redux";
export const MERGE_STORE_ACTION = "NEW_TAB_INITIAL_STATE";
export const OUTGOING_MESSAGE_NAME = "ActivityStream:ContentToMain";
export const INCOMING_MESSAGE_NAME = "ActivityStream:MainToContent";
export const EARLY_QUEUED_ACTIONS = [at.SAVE_SESSION_PERF_DATA, at.PAGE_PRERENDERED];
export const EARLY_QUEUED_ACTIONS = [at.SAVE_SESSION_PERF_DATA];
/**
* A higher-order function which returns a reducer that, on MERGE_STORE action,
@ -114,10 +114,9 @@ export const queueEarlyMessageMiddleware = store => next => action => {
* @param {object} intialState (optional) The initial state of the store, if desired
* @return {object} A redux store
*/
export function initStore(reducers, initialState) {
export function initStore(reducers) {
const store = createStore(
mergeStateReducer(combineReducers(reducers)),
initialState,
global.RPMAddMessageListener && applyMiddleware(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware)
);

View file

@ -363,8 +363,6 @@ input[type='text'], input[type='search'] {
flex-grow: 1;
min-height: 100vh;
padding: 30px 32px 32px; }
.outer-wrapper.fixed-to-top {
display: block; }
.outer-wrapper.only-search {
display: block;
padding-top: 134px; }
@ -1787,6 +1785,8 @@ main {
border: 1px solid var(--newtab-border-secondary-color); }
.asrouter-admin .ds-component {
margin-bottom: 20px; }
.asrouter-admin .modalOverlayInner {
height: 80%; }
.pocket-logged-in-cta {
font-size: 13px;
@ -2736,6 +2736,7 @@ main {
.impression-observer {
position: absolute;
top: 0;
width: 100%;
height: 100%;
pointer-events: none; }
@ -2895,6 +2896,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
height: 100%;
position: fixed;
top: 0;
left: 0;
width: 100%;
display: none;
z-index: 1100; }
@ -2903,10 +2905,10 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
.modalOverlayInner {
width: 960px;
height: 570px;
position: fixed;
top: calc(50% - 285px);
top: 20%;
left: calc(50% - 480px);
max-height: calc(100% - 100px);
background: #FFF;
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
border-radius: 4px;
@ -2944,6 +2946,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
margin-top: 30px; } }
.modalOverlayInner .footer {
border-top: 1px solid #D7D7DB;
border-radius: 4px;
height: 70px;
width: 100%;
position: absolute;
@ -3318,7 +3321,8 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
grid-column-gap: 21px;
grid-template-columns: auto auto auto;
padding-left: 30px;
padding-right: 30px; }
padding-right: 30px;
min-height: 500px; }
@media (max-width: 850px) {
.onboardingMessageContainer {
grid-template-columns: none;

View file

@ -366,8 +366,6 @@ input[type='text'], input[type='search'] {
flex-grow: 1;
min-height: 100vh;
padding: 30px 32px 32px; }
.outer-wrapper.fixed-to-top {
display: block; }
.outer-wrapper.only-search {
display: block;
padding-top: 134px; }
@ -1790,6 +1788,8 @@ main {
border: 1px solid var(--newtab-border-secondary-color); }
.asrouter-admin .ds-component {
margin-bottom: 20px; }
.asrouter-admin .modalOverlayInner {
height: 80%; }
.pocket-logged-in-cta {
font-size: 13px;
@ -2739,6 +2739,7 @@ main {
.impression-observer {
position: absolute;
top: 0;
width: 100%;
height: 100%;
pointer-events: none; }
@ -2898,6 +2899,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
height: 100%;
position: fixed;
top: 0;
left: 0;
width: 100%;
display: none;
z-index: 1100; }
@ -2906,10 +2908,10 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
.modalOverlayInner {
width: 960px;
height: 570px;
position: fixed;
top: calc(50% - 285px);
top: 20%;
left: calc(50% - 480px);
max-height: calc(100% - 100px);
background: #FFF;
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
border-radius: 4px;
@ -2947,6 +2949,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
margin-top: 30px; } }
.modalOverlayInner .footer {
border-top: 1px solid #D7D7DB;
border-radius: 4px;
height: 70px;
width: 100%;
position: absolute;
@ -3321,7 +3324,8 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
grid-column-gap: 21px;
grid-template-columns: auto auto auto;
padding-left: 30px;
padding-right: 30px; }
padding-right: 30px;
min-height: 500px; }
@media (max-width: 850px) {
.onboardingMessageContainer {
grid-template-columns: none;

View file

@ -363,8 +363,6 @@ input[type='text'], input[type='search'] {
flex-grow: 1;
min-height: 100vh;
padding: 30px 32px 32px; }
.outer-wrapper.fixed-to-top {
display: block; }
.outer-wrapper.only-search {
display: block;
padding-top: 134px; }
@ -1787,6 +1785,8 @@ main {
border: 1px solid var(--newtab-border-secondary-color); }
.asrouter-admin .ds-component {
margin-bottom: 20px; }
.asrouter-admin .modalOverlayInner {
height: 80%; }
.pocket-logged-in-cta {
font-size: 13px;
@ -2736,6 +2736,7 @@ main {
.impression-observer {
position: absolute;
top: 0;
width: 100%;
height: 100%;
pointer-events: none; }
@ -2895,6 +2896,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
height: 100%;
position: fixed;
top: 0;
left: 0;
width: 100%;
display: none;
z-index: 1100; }
@ -2903,10 +2905,10 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
.modalOverlayInner {
width: 960px;
height: 570px;
position: fixed;
top: calc(50% - 285px);
top: 20%;
left: calc(50% - 480px);
max-height: calc(100% - 100px);
background: #FFF;
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
border-radius: 4px;
@ -2944,6 +2946,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
margin-top: 30px; } }
.modalOverlayInner .footer {
border-top: 1px solid #D7D7DB;
border-radius: 4px;
height: 70px;
width: 100%;
position: absolute;
@ -3318,7 +3321,8 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
grid-column-gap: 21px;
grid-template-columns: auto auto auto;
padding-left: 30px;
padding-right: 30px; }
padding-right: 30px;
min-height: 500px; }
@media (max-width: 850px) {
.onboardingMessageContainer {
grid-template-columns: none;

File diff suppressed because one or more lines are too long

View file

@ -254,7 +254,6 @@ and losing focus. | :one:
| `block` | [Optional] An integer to record the 0-based index when user blocks a Pocket tile. | :one:
| `pocket` | [Optional] An integer to record the 0-based index when user saves a Pocket tile to Pocket. | :one:
| `user_prefs` | [Required] The encoded integer of user's preferences. | :one: & :four:
| `is_prerendered` | [Required] A boolean to signify whether the page is prerendered or not | :one:
| `is_preloaded` | [Required] A boolean to signify whether the page is preloaded or not | :one:
| `icon_type` | [Optional] ("tippytop", "rich_icon", "screenshot_with_icon", "screenshot", "no_image") | :one:
| `region` | [Optional] A string maps to pref "browser.search.region", which is essentially the two letter ISO 3166-1 country code populated by the Firefox search service. Note that: 1). it reports "OTHER" for those regions with smaller Firefox user base (less than 10000) so that users cannot be uniquely identified; 2). it reports "UNSET" if this pref is missing; 3). it reports "EMPTY" if the value of this pref is an empty string. | :one:

View file

@ -537,9 +537,6 @@ perf: {
// Whether the page is preloaded or not.
"is_preloaded": [true|false],
// Whether the page is prerendered or not.
"is_prerendered": [true|false]
}
```

View file

@ -53,3 +53,8 @@ Services.prefs.setBoolPref("browser.newtabpage.activity-stream.asrouter.devtools
**4. Go to `about:newtab#devtools`**
There should be a "cfr-remote" provider listed.
## Using the staging server for Remote CFR
If your message is published in the staging environment the easiest way to test is using the [Remote Settings Devtools](https://github.com/mozilla/remote-settings-devtools/releases) addon. You can install this by going to `about:debugging` and using the `Load Temporary Addon` feature.
The devtools allow you to switch your profile between production and staging and takes care of correctly flipping all the required preferences.

View file

@ -2,18 +2,12 @@
Adding telemetry generally involves a few steps:
1. - [ ] File a "user story issue" [in ping-centre](https://github.com/mozilla/ping-centre) about who wants what question answered. This will be used to track server-side data handling implementation (ETL, dashboard implementation...).
> As an engineer, I see the distribution of times between triggering a new tab load by tab menu entry, plus button or keyboard shortcut and when the visibility event is fired on that page, so that I can understand how long it takes before the page becomes visible and how close to instantaneous that feels.
1. - [ ] File or update your existing client-side implementation bug so that it points to the "user story issue".
1. - [ ] Talk to Marina (@emtwo) about the dashboard you're hoping to see from the data you're adding, and work with her to create a data model (or request her review on it after the fact).
1. - [ ] Update `system-addon/test/schemas/pings.js` with a commented JOI schema of your changes, and add tests to system-addon/test/unit/TelemetryFeed.test.js to exercise the ping creation.
1. - [ ] Update [data_events.md](data_events.md) with an example of the data in question
1. - [ ] Update any fields that you've added, deleted, or changed in [data_dictionary.md](data_dictionary.md)
1. - [ ] Get review from Nan (@ncloudioj) and/or Marina (@emtwo) on the data schema and the documentation changes.
1. - [ ] Request `data-review` of your documentation changes from a [data steward](https://wiki.mozilla.org/Firefox/Data_Collection) to ensure suitability for collection controlled by the opt-out `datareporting.healthreport.uploadEnabled` pref. Download and fill out the [data review request form](https://github.com/mozilla/data-review/blob/master/request.md) and then attach it as a text file on Bugzilla so you can r? a data steward. We've been working with Francois Marier (:francois / @fmarier), so he's a good candidate as he's likely to have the most context.
1. - [ ] Implement as usual...
1. - [ ] After landing the implementation, check with Nan (@ncloudioj) to make sure the pings are making it to the database
1. - [ ] Update the [ping-centre](https://github.com/mozilla/ping-centre/issues) user story issue for the dashboard, stating that the data should now be available for implementation, and removing any `blocked` tag if appropriate.
1. File a "user story" bug about who wants what question answered. This will be used to track the client-side implementation as well as the data review request. If the server side changes are needed, ask Nan (:nanj / @ncloudio) if in doubt, bugs will be filed separately as dependencies.
1. Implement as usual...
1. Update `system-addon/test/schemas/pings.js` with a commented JOI schema of your changes, and add tests to system-addon/test/unit/TelemetryFeed.test.js to exercise the ping creation.
1. Update [data_events.md](data_events.md) with an example of the data in question.
1. Update any fields that you've added, deleted, or changed in [data_dictionary.md](data_dictionary.md).
1. Get review from Nan on the data schema and the documentation changes.
1. Request `data-review` of your documentation changes from a [data steward](https://wiki.mozilla.org/Firefox/Data_Collection) to ensure suitability for collection controlled by the opt-out `datareporting.healthreport.uploadEnabled` pref. Download and fill out the [data review request form](https://github.com/mozilla/data-review/blob/master/request.md) and then attach it as a text file on Bugzilla so you can r? a data steward. We've been working with Chris H-C (:chutten) for the Firefox specific telemetry, and Kenny Long (kenny@getpocket.com) for the Pocket specific telemetry, they are the best candidates for the review work as they know well about the context.
1. After landing the implementation, check with Nan to make sure the pings are making it to the database.
1. Once data flows in, you can build dashboard for the new telemetry on [Redash](https://sql.telemetry.mozilla.org/dashboards). If you're looking for some help about Redash or dashboard building, Nan is the guy for that.

View file

@ -27,9 +27,7 @@ browser.jar:
#else
res/activity-stream/css/activity-stream.css (./css/activity-stream-linux.css)
#endif
res/activity-stream/prerendered/static/activity-stream-initial-state.js (./prerendered/static/activity-stream-initial-state.js)
#ifndef RELEASE_OR_BETA
res/activity-stream/prerendered/static/activity-stream-debug.html (./prerendered/static/activity-stream-debug.html)
res/activity-stream/prerendered/static/activity-stream-prerendered-debug.html (./prerendered/static/activity-stream-prerendered-debug.html)
#endif
res/activity-stream/prerendered/ (./prerendered/locales/*)

View file

@ -1085,7 +1085,7 @@ defaultLayoutResp = {
{
"type": "CardGrid",
"header": {
"title": "Tech 🖥",
"title": "Tech 💻",
},
"feed": {
"embed_reference": null,

View file

@ -24,7 +24,7 @@ XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => new TextDecoder());
XPCOMUtils.defineLazyGetter(this, "baseAttachmentsURL", async () => {
const server = Services.prefs.getCharPref("services.settings.server");
const serverInfo = await (await fetch(`${server}/`)).json();
const serverInfo = await (await fetch(`${server}/`, {credentials: "omit"})).json();
const {capabilities: {attachments: {base_url}}} = serverInfo;
return base_url;
});

View file

@ -5,7 +5,6 @@
const {actionCreators: ac, actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm");
const {Prefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm");
const {PrerenderData} = ChromeUtils.import("resource://activity-stream/common/PrerenderData.jsm");
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
@ -20,27 +19,11 @@ this.PrefsFeed = class PrefsFeed {
this._prefs = new Prefs();
}
// If any of the prefs are set to something other than what the
// prerendered version of AS expects, we can't use it.
async _setPrerenderPref() {
const indexedDBPrefs = await this._storage.getAll();
const prefsAreValid = PrerenderData.arePrefsValid(pref => this._prefs.get(pref), indexedDBPrefs);
this._prefs.set("prerender", prefsAreValid);
}
_checkPrerender(name) {
if (PrerenderData.invalidatingPrefs.includes(name)) {
this._setPrerenderPref();
}
}
onPrefChanged(name, value) {
const prefItem = this._prefMap.get(name);
if (prefItem) {
this.store.dispatch(ac[prefItem.skipBroadcast ? "OnlyToMain" : "BroadcastToContent"]({type: at.PREF_CHANGED, data: {name, value}}));
}
this._checkPrerender(name);
}
init() {
@ -78,8 +61,6 @@ this.PrefsFeed = class PrefsFeed {
// Set the initial state of all prefs in redux
this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values}));
this._setPrerenderPref();
}
removeListeners() {
@ -90,7 +71,6 @@ this.PrefsFeed = class PrefsFeed {
const name = id === "topsites" ? id : `feeds.section.${id}`;
try {
await this._storage.set(name, value);
this._setPrerenderPref();
} catch (e) {
Cu.reportError("Could not set section preferences.");
}

View file

@ -316,7 +316,6 @@ this.TelemetryFeed = class TelemetryFeed {
perf: {
load_trigger_type,
is_preloaded: false,
is_prerendered: false,
},
};
@ -409,22 +408,6 @@ this.TelemetryFeed = class TelemetryFeed {
});
}
/**
* handlePagePrerendered - Set the session as prerendered
*
* @param {string} portID the portID of the target session
*/
handlePagePrerendered(portID) {
const session = this.sessions.get(portID);
if (!session) {
// It's possible the tab was never visible in which case, there was no user session.
return;
}
session.perf.is_prerendered = true;
}
/**
* handleNewTabInit - Handle NEW_TAB_INIT, which creates a new session and sets the a flag
* for session.perf based on whether or not this new tab is preloaded
@ -742,9 +725,6 @@ this.TelemetryFeed = class TelemetryFeed {
case at.NEW_TAB_UNLOAD:
this.endSession(au.getPortIdOfSender(action));
break;
case at.PAGE_PRERENDERED:
this.handlePagePrerendered(au.getPortIdOfSender(action));
break;
case at.SAVE_SESSION_PERF_DATA:
this.saveSessionPerfData(au.getPortIdOfSender(action), action.data);
break;

View file

@ -35,7 +35,7 @@ module.exports = function inject(src) {
if (this.cacheable) {
this.cacheable();
}
const regex = createRequireStringRegex(loaderUtils.parseQuery(this.query));
const regex = createRequireStringRegex(loaderUtils.getOptions(this) || {});
return `module.exports = function inject(injections) {
var module = {exports: {}};

View file

@ -93,6 +93,7 @@ prefs_home_header=Cynnwys Cartref Firefox
prefs_home_description=Dewis pa gynnwys rydych eisiau ar eich sgrin Firefox Cartref.
prefs_content_discovery_header=Cartref Firefox
prefs_content_discovery_description=Mae Darganfod Cynnwys yng Nghartref Firefox yn caniatáu i chi ddarganfod erthyglau perthnasol o ansawdd uchel ar draws y we.
prefs_content_discovery_button=Diffodd Ddarganfod Cynnwys
@ -190,14 +191,14 @@ section_menu_action_privacy_notice=Hysbysiad Preifatrwydd
# LOCALIZATION NOTE (firstrun_*). These strings are displayed only once, on the
# firstrun of the browser, they give an introduction to Firefox and Sync.
firstrun_title=Mynd â Firefox gyda Chi
firstrun_content=Cewch eich nodau tudalen, hanes, cyfrineiriau a gosodiadau eraill ar eich holl ddyfeisiau.
firstrun_content=Cael eich nodau tudalen, hanes, cyfrineiriau a gosodiadau eraill ar eich holl ddyfeisiau.
firstrun_learn_more_link=Dysgu rhagor am Gyfrif Firefox
# LOCALIZATION NOTE (firstrun_form_header and firstrun_form_sub_header):
# firstrun_form_sub_header is a continuation of firstrun_form_header, they are one sentence.
# firstrun_form_header is displayed more boldly as the call to action.
firstrun_form_header=Rhowch eich e-bost
firstrun_form_sub_header=i barhau i Firefox Sync
firstrun_form_sub_header=ac ymlaen i Firefox Sync
firstrun_email_input_placeholder=E-bost
firstrun_invalid_input=Mae angen e-bost dilys

View file

@ -31,7 +31,7 @@ type_label_downloaded=Descaregou
menu_action_bookmark=Azonzi a-i segnalibbri
menu_action_remove_bookmark=Scancella segnalibbro
menu_action_open_new_window=Arvi in neuvo barcon
menu_action_open_private_window=Arvi in neuvo barcon privou
menu_action_open_private_window=Arvi in neuvo barcon privòu
menu_action_dismiss=Scancella
menu_action_delete=Scancella da-a stöia
menu_action_pin=Azonzi a-a bacheca
@ -78,7 +78,7 @@ search_web_placeholder=Çerca inta Ræ
# LOCALIZATION NOTE (section_disclaimer_topstories): This is shown below
# the topstories section title to provide additional information about
# how the stories are selected.
section_disclaimer_topstories=E stöie ciù interesanti do Web, seleçionæ in baze a quello che ti lezi. Pigiæ da Pocket, che oua o l'é parte de Mozilla.
section_disclaimer_topstories=E stöie ciù interesanti do Web, seleçionæ in baze a quello che ti lezi. Pigiæ da Pocket, che òua o l'é parte de Mozilla.
section_disclaimer_topstories_linktext=Descòvri comme fonçionn-a.
# LOCALIZATION NOTE (section_disclaimer_topstories_buttontext): The text of
# the button used to acknowledge, and hide this disclaimer in the future.
@ -93,6 +93,7 @@ prefs_home_header=Pagina iniçiâ de Firefox
prefs_home_description=Çerni i contegnui che ti veu vedde inta pagina iniçiâ de Firefox.
prefs_content_discovery_header=Pagina iniçiâ de Firefox
prefs_content_discovery_button=Dizabilita a descoverta de neuvi contegnui
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
@ -166,7 +167,7 @@ manual_migration_explanation2=Preuva Firefox con i segnalibbri, a stöia e-e par
manual_migration_cancel_button=No graçie
# LOCALIZATION NOTE (manual_migration_import_button): This message is shown on a button that starts the process
# of importing another browsers profile profile into Firefox.
manual_migration_import_button=Inpòrta oua
manual_migration_import_button=Inpòrta òua
# LOCALIZATION NOTE (error_fallback_default_*): This message and suggested
# action link are shown in each section of UI that fails to render

View file

@ -186,7 +186,7 @@ section_menu_action_add_topsite=Adaugă site de top
section_menu_action_add_search_engine=Adaugă motor de căutare
section_menu_action_move_up=Mută în sus
section_menu_action_move_down=Mută în jos
section_menu_action_privacy_notice=Politica de confidențialitate
section_menu_action_privacy_notice=Declarație de confidențialitate
# LOCALIZATION NOTE (firstrun_*). These strings are displayed only once, on the
# firstrun of the browser, they give an introduction to Firefox and Sync.
@ -207,7 +207,7 @@ firstrun_invalid_input=Necesită o adresă de e-mail validă
# {privacy} is equal to firstrun_privacy_notice. {terms} and {privacy} are clickable links.
firstrun_extra_legal_links=Prin continuare, ești de acord cu {terms} și {privacy}.
firstrun_terms_of_service=Termenii de utilizare a serviciului
firstrun_privacy_notice=Politica de confidențialitate
firstrun_privacy_notice=Declarație de confidențialitate
firstrun_continue_to_login=Continuă
firstrun_skip_login=Omite acest pas

View file

@ -14,7 +14,7 @@ cd /activity-stream && npm install . && npm run buildmc
# Build latest m-c with Activity Stream changes
cd /mozilla-central && ./mach build \
&& ./mach lint -l codespell browser/components/newtab \
&& ./mach lint browser/components/newtab \
&& ./mach test browser/components/newtab/test/browser --headless \
&& ./mach test browser/components/newtab/test/xpcshell \
&& ./mach test --log-tbpl test_run_log \

View file

@ -44,11 +44,6 @@ interface nsIAboutNewTabService : nsISupports
*/
readonly attribute bool activityStreamEnabled;
/**
* Returns true if the the prerendering pref for activity stream is true
*/
readonly attribute bool activityStreamPrerender;
/**
* Returns true if the the debug pref for activity stream is true
*/

File diff suppressed because it is too large Load diff

View file

@ -7,36 +7,36 @@
"url": "https://github.com/mozilla/activity-stream/issues"
},
"dependencies": {
"fluent": "0.6.4",
"fluent-react": "0.7.0",
"fluent": "0.12.0",
"fluent-react": "0.8.4",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-intl": "2.8.0",
"react-intl": "2.9.0",
"react-redux": "7.0.3",
"redux": "4.0.1",
"reselect": "4.0.0"
},
"devDependencies": {
"@babel/core": "7.4.4",
"@babel/core": "7.4.5",
"@babel/plugin-proposal-async-generator-functions": "7.2.0",
"@babel/preset-react": "7.0.0",
"acorn": "6.1.1",
"babel-eslint": "10.0.1",
"babel-loader": "8.0.5",
"babel-loader": "8.0.6",
"babel-plugin-jsm-to-commonjs": "0.5.0",
"babel-plugin-jsm-to-esmodules": "0.6.0",
"chai": "4.2.0",
"chai-json-schema": "1.5.0",
"chai-json-schema": "1.5.1",
"cpx": "1.5.0",
"enzyme": "3.9.0",
"enzyme-adapter-react-16": "1.12.1",
"enzyme-adapter-react-16": "1.13.2",
"eslint": "5.16.0",
"eslint-plugin-fetch-options": "0.0.4",
"eslint-plugin-import": "2.17.2",
"eslint-plugin-fetch-options": "0.0.5",
"eslint-plugin-import": "2.17.3",
"eslint-plugin-jsx-a11y": "6.2.1",
"eslint-plugin-mozilla": "1.2.1",
"eslint-plugin-no-unsanitized": "3.0.2",
"eslint-plugin-react": "7.12.4",
"eslint-plugin-react": "7.13.0",
"eslint-plugin-react-hooks": "1.6.0",
"istanbul-instrumenter-loader": "3.0.1",
"joi-browser": "13.4.0",
@ -49,11 +49,11 @@
"karma-sinon": "1.0.5",
"karma-sourcemap-loader": "0.3.7",
"karma-webpack": "3.0.5",
"loader-utils": "0.2.16",
"loader-utils": "1.2.3",
"minimist": "1.2.0",
"mocha": "6.1.4",
"mock-raf": "1.0.1",
"node-fetch": "2.5.0",
"node-fetch": "2.6.0",
"node-sass": "4.12.0",
"npm-run-all": "4.1.5",
"pontoon-to-json": "2.0.0",
@ -61,12 +61,12 @@
"raw-loader": "2.0.0",
"react-test-renderer": "16.8.6",
"rimraf": "2.6.3",
"sass": "1.19.0",
"sass": "1.20.1",
"sass-lint": "1.13.1",
"shelljs": "0.8.3",
"sinon": "7.3.2",
"webpack": "4.30.0",
"webpack-cli": "3.3.1",
"webpack": "4.32.2",
"webpack-cli": "3.3.2",
"yamscripts": "0.1.0"
},
"engines": {
@ -99,7 +99,7 @@
"bundle:locales": "pontoon-to-json --src $npm_package_config_locales_dir --dest data",
"bundle:webpack": "webpack --config webpack.system-addon.config.js",
"bundle:css": "node-sass content-src/styles -o css",
"bundle:html": "rimraf prerendered && webpack --config webpack.prerender.config.js && node ./bin/render-activity-stream-html.js",
"bundle:html": "rimraf prerendered && node ./bin/render-activity-stream-html.js",
"buildmc": "npm-run-all buildmc:*",
"prebuildmc": "rimraf $npm_package_config_mc_dir/browser/components/newtab/",
"buildmc:bundle": "npm run bundle",

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head>
<body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div>
<div id="root"><!-- Regular React Rendering --></div>
<div id="root"></div>
<div id="footer-asrouter-container" role="presentation"></div>
</body>
</html>

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show more