forked from mirrors/gecko-dev
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:
parent
cc371c6881
commit
bd822928e5
446 changed files with 2519 additions and 8614 deletions
|
|
@ -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/
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
bin/prerender.js
|
data/
|
||||||
data/
|
logs/
|
||||||
logs/
|
prerendered/
|
||||||
prerendered/
|
|
||||||
vendor/
|
vendor/
|
||||||
|
|
|
||||||
|
|
@ -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/
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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"];
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -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"));
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -219,4 +219,8 @@
|
||||||
.ds-component {
|
.ds-component {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modalOverlayInner {
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(" ");
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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" />) :
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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/*)
|
||||||
|
|
|
||||||
|
|
@ -1085,7 +1085,7 @@ defaultLayoutResp = {
|
||||||
{
|
{
|
||||||
"type": "CardGrid",
|
"type": "CardGrid",
|
||||||
"header": {
|
"header": {
|
||||||
"title": "Tech 🖥",
|
"title": "Tech 💻",
|
||||||
},
|
},
|
||||||
"feed": {
|
"feed": {
|
||||||
"embed_reference": null,
|
"embed_reference": null,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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: {}};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 browser’s profile profile into Firefox.
|
# of importing another browser’s 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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 \
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
861
browser/components/newtab/package-lock.json
generated
861
browser/components/newtab/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
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
Loading…
Reference in a new issue