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 # Ignore newtab files
# Kept in sync with browser/components/newtab/.eslintignore # Kept in sync with browser/components/newtab/.eslintignore
browser/components/newtab/bin/prerender.js
browser/components/newtab/data/ browser/components/newtab/data/
browser/components/newtab/logs/ browser/components/newtab/logs/
browser/components/newtab/prerendered/ browser/components/newtab/prerendered/

View file

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

View file

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

View file

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

View file

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

View file

@ -15,17 +15,10 @@ if (typeof Services !== "undefined") {
// Borrow the high-resolution timer from the hidden window.... // Borrow the high-resolution timer from the hidden window....
// eslint-disable-next-line block-scoped-var // eslint-disable-next-line block-scoped-var
usablePerfObj = Services.appShell.hiddenDOMWindow.performance; usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
} else if (typeof performance !== "undefined") { } else {
// we must be running in content space // we must be running in content space
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
usablePerfObj = performance; 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) { 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 ReactDOM from "react-dom";
import {reducers} from "common/Reducers.jsm"; import {reducers} from "common/Reducers.jsm";
const store = initStore(reducers, global.gActivityStreamPrerenderedState); const store = initStore(reducers);
new DetectUserSessionStart(store).sendEventOrAddListener(); new DetectUserSessionStart(store).sendEventOrAddListener();
// If we are starting in a prerendered state, we must wait until the first render store.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST}));
// 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}));
}
ReactDOM.hydrate(<Provider store={store}> ReactDOM.hydrate(<Provider store={store}>
<Base <Base
isFirstrun={global.document.location.href === "about:welcome"} isFirstrun={global.document.location.href === "about:welcome"}
isPrerendered={!!global.gActivityStreamPrerenderedState}
locale={global.document.documentElement.lang} locale={global.document.documentElement.lang}
strings={global.gActivityStreamStrings} /> strings={global.gActivityStreamStrings} />
</Provider>, document.getElementById("root")); </Provider>, document.getElementById("root"));

View file

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

View file

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

View file

@ -9,6 +9,7 @@
height: 100%; height: 100%;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0;
width: 100%; width: 100%;
display: none; display: none;
z-index: 1100; z-index: 1100;
@ -20,10 +21,10 @@
.modalOverlayInner { .modalOverlayInner {
width: 960px; width: 960px;
height: 570px;
position: fixed; 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 left: calc(50% - 480px); // halfway across minus half the width of the modal
max-height: calc(100% - 100px);
background: $white; background: $white;
box-shadow: 0 1px 15px 0 $black-30; box-shadow: 0 1px 15px 0 $black-30;
border-radius: 4px; border-radius: 4px;
@ -75,6 +76,7 @@
.footer { .footer {
border-top: 1px solid $grey-30; border-top: 1px solid $grey-30;
border-radius: 4px;
height: 70px; height: 70px;
width: 100%; width: 100%;
position: absolute; 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. * 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 * Generates an array of messages suitable for fluent's localization provider
* including all needed strings for rich text. * including all needed strings for rich text.
* @param {object} content A .content object from an ASR message (i.e. message.content) * @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) { export function generateBundles(content) {
const cx = new MessageContext("en-US"); const bundle = new FluentBundle("en-US");
RICH_TEXT_KEYS.forEach(key => { RICH_TEXT_KEYS.forEach(key => {
const attrs = RICH_TEXT_CONFIG[key]; const attrs = RICH_TEXT_CONFIG[key];
@ -34,7 +34,7 @@ export function generateMessages(content) {
const attr = attrsToTry.pop(); const attr = attrsToTry.pop();
string = content[attr]; 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 {props} = this;
const {button_label, header} = props.extraTemplateStrings; const {button_label, header} = props.extraTemplateStrings;
return ( return (
<ModalOverlay {...props} button_label={button_label} title={header}> <ModalOverlay {...props} button_label={button_label} title={header} >
<div className="onboardingMessageContainer"> <div className="onboardingMessageContainer">
{props.bundle.map(message => ( {props.bundle.map(message => (
<OnboardingCard key={message.id} <OnboardingCard key={message.id}

View file

@ -4,6 +4,7 @@
grid-template-columns: auto auto auto; grid-template-columns: auto auto auto;
padding-left: 30px; padding-left: 30px;
padding-right: 30px; padding-right: 30px;
min-height: 500px;
// at 850px, the cards go from vertical layout to horizontal layout // at 850px, the cards go from vertical layout to horizontal layout
@media(max-width: 850px) { @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; const errors = this.refs.targetingParamsEval && this.refs.targetingParamsEval.innerText.length;
return ( 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"> <div className="onboardingMessage">
<p> <p>
<textarea onChange={this.onNewTargetingParams} value={this.state.newStringTargetingParameters} rows="20" cols="60" /> <textarea onChange={this.onNewTargetingParams} value={this.state.newStringTargetingParameters} rows="20" cols="60" />

View file

@ -219,4 +219,8 @@
.ds-component { .ds-component {
margin-bottom: 20px; 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 {connect} from "react-redux";
import {DiscoveryStreamBase} from "content-src/components/DiscoveryStreamBase/DiscoveryStreamBase"; import {DiscoveryStreamBase} from "content-src/components/DiscoveryStreamBase/DiscoveryStreamBase";
import {ErrorBoundary} from "content-src/components/ErrorBoundary/ErrorBoundary"; import {ErrorBoundary} from "content-src/components/ErrorBoundary/ErrorBoundary";
import {PrerenderData} from "common/PrerenderData.jsm";
import React from "react"; import React from "react";
import {Search} from "content-src/components/Search/Search"; import {Search} from "content-src/components/Search/Search";
import {Sections} from "content-src/components/Sections/Sections"; 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() { componentWillUnmount() {
this.updateTheme(); this.updateTheme();
} }
@ -80,10 +69,9 @@ export class _Base extends React.PureComponent {
render() { render() {
const {props} = this; const {props} = this;
const {App, locale, strings} = props; const {App, locale, strings} = props;
const {initialized} = App;
const isDevtoolsEnabled = props.Prefs.values["asrouter.devtoolsEnabled"]; const isDevtoolsEnabled = props.Prefs.values["asrouter.devtoolsEnabled"];
if (!props.isPrerendered && !initialized) { if (!App.initialized) {
return null; return null;
} }
@ -134,7 +122,6 @@ export class BaseContent extends React.PureComponent {
const {initialized} = App; const {initialized} = App;
const prefs = props.Prefs.values; const prefs = props.Prefs.values;
const shouldBeFixedToTop = PrerenderData.arePrefsValid(name => prefs[name]);
const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled; const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled;
let filteredSections = props.Sections; let filteredSections = props.Sections;
@ -149,7 +136,6 @@ export class BaseContent extends React.PureComponent {
"outer-wrapper", "outer-wrapper",
isDiscoveryStream && "ds-outer-wrapper-search-alignment", isDiscoveryStream && "ds-outer-wrapper-search-alignment",
isDiscoveryStream && "ds-outer-wrapper-breakpoint-override", isDiscoveryStream && "ds-outer-wrapper-breakpoint-override",
shouldBeFixedToTop && "fixed-to-top",
prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search", prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search",
prefs.showSearch && noSectionsEnabled && "only-search", prefs.showSearch && noSectionsEnabled && "only-search",
].filter(v => v).join(" "); ].filter(v => v).join(" ");

View file

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

View file

@ -37,7 +37,9 @@ export class ContextMenu extends React.PureComponent {
} }
render() { 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"> <ul className="context-menu-list">
{this.props.options.map((option, i) => (option.type === "separator" ? {this.props.options.map((option, i) => (option.type === "separator" ?
(<li key={i} className="separator" />) : (<li key={i} className="separator" />) :

View file

@ -1,5 +1,6 @@
.impression-observer { .impression-observer {
position: absolute; position: absolute;
top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
pointer-events: none; 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 {ComponentPerfTimer} from "content-src/components/ComponentPerfTimer/ComponentPerfTimer";
import {connect} from "react-redux"; import {connect} from "react-redux";
import {injectIntl} from "react-intl"; import {injectIntl} from "react-intl";
import {ModalOverlayWrapper} from "../../asrouter/components/ModalOverlay/ModalOverlay";
import React from "react"; import React from "react";
import {SearchShortcutsForm} from "./SearchShortcutsForm"; import {SearchShortcutsForm} from "./SearchShortcutsForm";
import {TOP_SITES_MAX_SITES_PER_ROW} from "common/Reducers.jsm"; 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"> <div className="edit-topsites-wrapper">
{editForm && {editForm &&
<div className="edit-topsites"> <div className="edit-topsites">
<div className="modal-overlay" onClick={this.onEditFormClose} role="presentation" /> <ModalOverlayWrapper unstyled={true} onClose={this.onEditFormClose} innerClassName="modal" >
<div className="modal">
<TopSiteForm <TopSiteForm
site={props.TopSites.rows[editForm.index]} site={props.TopSites.rows[editForm.index]}
onClose={this.onEditFormClose} onClose={this.onEditFormClose}
dispatch={this.props.dispatch} dispatch={this.props.dispatch}
intl={this.props.intl} intl={this.props.intl}
{...editForm} /> {...editForm} />
</div> </ModalOverlayWrapper>
</div> </div>
} }
{showSearchShortcutsForm && {showSearchShortcutsForm &&
<div className="edit-search-shortcuts"> <div className="edit-search-shortcuts">
<div className="modal-overlay" onClick={this.onSearchShortcutsFormClose} role="presentation" /> <ModalOverlayWrapper unstyled={true} onClose={this.onSearchShortcutsFormClose} innerClassName="modal" >
<div className="modal">
<SearchShortcutsForm <SearchShortcutsForm
TopSites={props.TopSites} TopSites={props.TopSites}
onClose={this.onSearchShortcutsFormClose} onClose={this.onSearchShortcutsFormClose}
dispatch={this.props.dispatch} /> dispatch={this.props.dispatch} />
</div> </ModalOverlayWrapper>
</div> </div>
} }
</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 MERGE_STORE_ACTION = "NEW_TAB_INITIAL_STATE";
export const OUTGOING_MESSAGE_NAME = "ActivityStream:ContentToMain"; export const OUTGOING_MESSAGE_NAME = "ActivityStream:ContentToMain";
export const INCOMING_MESSAGE_NAME = "ActivityStream:MainToContent"; 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, * 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 * @param {object} intialState (optional) The initial state of the store, if desired
* @return {object} A redux store * @return {object} A redux store
*/ */
export function initStore(reducers, initialState) { export function initStore(reducers) {
const store = createStore( const store = createStore(
mergeStateReducer(combineReducers(reducers)), mergeStateReducer(combineReducers(reducers)),
initialState,
global.RPMAddMessageListener && applyMiddleware(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware) global.RPMAddMessageListener && applyMiddleware(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware)
); );

View file

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

View file

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

View file

@ -363,8 +363,6 @@ input[type='text'], input[type='search'] {
flex-grow: 1; flex-grow: 1;
min-height: 100vh; min-height: 100vh;
padding: 30px 32px 32px; } padding: 30px 32px 32px; }
.outer-wrapper.fixed-to-top {
display: block; }
.outer-wrapper.only-search { .outer-wrapper.only-search {
display: block; display: block;
padding-top: 134px; } padding-top: 134px; }
@ -1787,6 +1785,8 @@ main {
border: 1px solid var(--newtab-border-secondary-color); } border: 1px solid var(--newtab-border-secondary-color); }
.asrouter-admin .ds-component { .asrouter-admin .ds-component {
margin-bottom: 20px; } margin-bottom: 20px; }
.asrouter-admin .modalOverlayInner {
height: 80%; }
.pocket-logged-in-cta { .pocket-logged-in-cta {
font-size: 13px; font-size: 13px;
@ -2736,6 +2736,7 @@ main {
.impression-observer { .impression-observer {
position: absolute; position: absolute;
top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
pointer-events: none; } pointer-events: none; }
@ -2895,6 +2896,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
height: 100%; height: 100%;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0;
width: 100%; width: 100%;
display: none; display: none;
z-index: 1100; } z-index: 1100; }
@ -2903,10 +2905,10 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
.modalOverlayInner { .modalOverlayInner {
width: 960px; width: 960px;
height: 570px;
position: fixed; position: fixed;
top: calc(50% - 285px); top: 20%;
left: calc(50% - 480px); left: calc(50% - 480px);
max-height: calc(100% - 100px);
background: #FFF; background: #FFF;
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3); box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
border-radius: 4px; border-radius: 4px;
@ -2944,6 +2946,7 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
margin-top: 30px; } } margin-top: 30px; } }
.modalOverlayInner .footer { .modalOverlayInner .footer {
border-top: 1px solid #D7D7DB; border-top: 1px solid #D7D7DB;
border-radius: 4px;
height: 70px; height: 70px;
width: 100%; width: 100%;
position: absolute; position: absolute;
@ -3318,7 +3321,8 @@ body[lwt-newtab-brighttext] .scene2Icon .icon-light-theme {
grid-column-gap: 21px; grid-column-gap: 21px;
grid-template-columns: auto auto auto; grid-template-columns: auto auto auto;
padding-left: 30px; padding-left: 30px;
padding-right: 30px; } padding-right: 30px;
min-height: 500px; }
@media (max-width: 850px) { @media (max-width: 850px) {
.onboardingMessageContainer { .onboardingMessageContainer {
grid-template-columns: none; 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: | `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: | `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: | `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: | `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: | `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: | `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. // Whether the page is preloaded or not.
"is_preloaded": [true|false], "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`** **4. Go to `about:newtab#devtools`**
There should be a "cfr-remote" provider listed. 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: 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...). 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...
> 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. 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. - [ ] File or update your existing client-side implementation bug so that it points to the "user story issue". 1. Update any fields that you've added, deleted, or changed in [data_dictionary.md](data_dictionary.md).
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. Get review from Nan on the data schema and the documentation changes.
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. 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. - [ ] Update [data_events.md](data_events.md) with an example of the data in question 1. After landing the implementation, check with Nan to make sure the pings are making it to the database.
1. - [ ] Update any fields that you've added, deleted, or changed in [data_dictionary.md](data_dictionary.md) 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.
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.

View file

@ -27,9 +27,7 @@ browser.jar:
#else #else
res/activity-stream/css/activity-stream.css (./css/activity-stream-linux.css) res/activity-stream/css/activity-stream.css (./css/activity-stream-linux.css)
#endif #endif
res/activity-stream/prerendered/static/activity-stream-initial-state.js (./prerendered/static/activity-stream-initial-state.js)
#ifndef RELEASE_OR_BETA #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-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 #endif
res/activity-stream/prerendered/ (./prerendered/locales/*) res/activity-stream/prerendered/ (./prerendered/locales/*)

View file

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

View file

@ -24,7 +24,7 @@ XPCOMUtils.defineLazyGetter(this, "gTextDecoder", () => new TextDecoder());
XPCOMUtils.defineLazyGetter(this, "baseAttachmentsURL", async () => { XPCOMUtils.defineLazyGetter(this, "baseAttachmentsURL", async () => {
const server = Services.prefs.getCharPref("services.settings.server"); 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; const {capabilities: {attachments: {base_url}}} = serverInfo;
return base_url; return base_url;
}); });

View file

@ -5,7 +5,6 @@
const {actionCreators: ac, actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm"); const {actionCreators: ac, actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm");
const {Prefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamPrefs.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"); const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils", ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
@ -20,27 +19,11 @@ this.PrefsFeed = class PrefsFeed {
this._prefs = new Prefs(); 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) { onPrefChanged(name, value) {
const prefItem = this._prefMap.get(name); const prefItem = this._prefMap.get(name);
if (prefItem) { if (prefItem) {
this.store.dispatch(ac[prefItem.skipBroadcast ? "OnlyToMain" : "BroadcastToContent"]({type: at.PREF_CHANGED, data: {name, value}})); this.store.dispatch(ac[prefItem.skipBroadcast ? "OnlyToMain" : "BroadcastToContent"]({type: at.PREF_CHANGED, data: {name, value}}));
} }
this._checkPrerender(name);
} }
init() { init() {
@ -78,8 +61,6 @@ this.PrefsFeed = class PrefsFeed {
// Set the initial state of all prefs in redux // Set the initial state of all prefs in redux
this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values})); this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values}));
this._setPrerenderPref();
} }
removeListeners() { removeListeners() {
@ -90,7 +71,6 @@ this.PrefsFeed = class PrefsFeed {
const name = id === "topsites" ? id : `feeds.section.${id}`; const name = id === "topsites" ? id : `feeds.section.${id}`;
try { try {
await this._storage.set(name, value); await this._storage.set(name, value);
this._setPrerenderPref();
} catch (e) { } catch (e) {
Cu.reportError("Could not set section preferences."); Cu.reportError("Could not set section preferences.");
} }

View file

@ -316,7 +316,6 @@ this.TelemetryFeed = class TelemetryFeed {
perf: { perf: {
load_trigger_type, load_trigger_type,
is_preloaded: false, 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 * 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 * 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: case at.NEW_TAB_UNLOAD:
this.endSession(au.getPortIdOfSender(action)); this.endSession(au.getPortIdOfSender(action));
break; break;
case at.PAGE_PRERENDERED:
this.handlePagePrerendered(au.getPortIdOfSender(action));
break;
case at.SAVE_SESSION_PERF_DATA: case at.SAVE_SESSION_PERF_DATA:
this.saveSessionPerfData(au.getPortIdOfSender(action), action.data); this.saveSessionPerfData(au.getPortIdOfSender(action), action.data);
break; break;

View file

@ -35,7 +35,7 @@ module.exports = function inject(src) {
if (this.cacheable) { if (this.cacheable) {
this.cacheable(); this.cacheable();
} }
const regex = createRequireStringRegex(loaderUtils.parseQuery(this.query)); const regex = createRequireStringRegex(loaderUtils.getOptions(this) || {});
return `module.exports = function inject(injections) { return `module.exports = function inject(injections) {
var module = {exports: {}}; 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_home_description=Dewis pa gynnwys rydych eisiau ar eich sgrin Firefox Cartref.
prefs_content_discovery_header=Cartref Firefox 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_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 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 # LOCALIZATION NOTE (firstrun_*). These strings are displayed only once, on the
# firstrun of the browser, they give an introduction to Firefox and Sync. # firstrun of the browser, they give an introduction to Firefox and Sync.
firstrun_title=Mynd â Firefox gyda Chi 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 firstrun_learn_more_link=Dysgu rhagor am Gyfrif Firefox
# LOCALIZATION NOTE (firstrun_form_header and firstrun_form_sub_header): # 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_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 is displayed more boldly as the call to action.
firstrun_form_header=Rhowch eich e-bost 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_email_input_placeholder=E-bost
firstrun_invalid_input=Mae angen e-bost dilys 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_bookmark=Azonzi a-i segnalibbri
menu_action_remove_bookmark=Scancella segnalibbro menu_action_remove_bookmark=Scancella segnalibbro
menu_action_open_new_window=Arvi in neuvo barcon 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_dismiss=Scancella
menu_action_delete=Scancella da-a stöia menu_action_delete=Scancella da-a stöia
menu_action_pin=Azonzi a-a bacheca 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 # LOCALIZATION NOTE (section_disclaimer_topstories): This is shown below
# the topstories section title to provide additional information about # the topstories section title to provide additional information about
# how the stories are selected. # 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. section_disclaimer_topstories_linktext=Descòvri comme fonçionn-a.
# LOCALIZATION NOTE (section_disclaimer_topstories_buttontext): The text of # LOCALIZATION NOTE (section_disclaimer_topstories_buttontext): The text of
# the button used to acknowledge, and hide this disclaimer in the future. # 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_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_header=Pagina iniçiâ de Firefox
prefs_content_discovery_button=Dizabilita a descoverta de neuvi contegnui prefs_content_discovery_button=Dizabilita a descoverta de neuvi contegnui
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of # 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 manual_migration_cancel_button=No graçie
# LOCALIZATION NOTE (manual_migration_import_button): This message is shown on a button that starts the process # 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. # 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 # LOCALIZATION NOTE (error_fallback_default_*): This message and suggested
# action link are shown in each section of UI that fails to render # 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_add_search_engine=Adaugă motor de căutare
section_menu_action_move_up=Mută în sus section_menu_action_move_up=Mută în sus
section_menu_action_move_down=Mută în jos 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 # LOCALIZATION NOTE (firstrun_*). These strings are displayed only once, on the
# firstrun of the browser, they give an introduction to Firefox and Sync. # 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. # {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_extra_legal_links=Prin continuare, ești de acord cu {terms} și {privacy}.
firstrun_terms_of_service=Termenii de utilizare a serviciului 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_continue_to_login=Continuă
firstrun_skip_login=Omite acest pas 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 # Build latest m-c with Activity Stream changes
cd /mozilla-central && ./mach build \ 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/browser --headless \
&& ./mach test browser/components/newtab/test/xpcshell \ && ./mach test browser/components/newtab/test/xpcshell \
&& ./mach test --log-tbpl test_run_log \ && ./mach test --log-tbpl test_run_log \

View file

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

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
<script src="chrome://browser/content/contentSearchUI.js"></script> <script src="chrome://browser/content/contentSearchUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script> <script src="chrome://browser/content/contentTheme.js"></script>

View file

@ -10,7 +10,7 @@
</head> </head>
<body class="activity-stream"> <body class="activity-stream">
<div id="header-asrouter-container" role="presentation"></div> <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> <div id="footer-asrouter-container" role="presentation"></div>
</body> </body>
</html> </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