Skip to content

Instantly share code, notes, and snippets.

@dmose
Created March 15, 2019 18:26
Show Gist options
  • Save dmose/a7f8cb2947619df8769a6422af341a01 to your computer and use it in GitHub Desktop.
Save dmose/a7f8cb2947619df8769a6422af341a01 to your computer and use it in GitHub Desktop.
diff --git a/browser/components/newtab/data/content/activity-stream.bundle.js b/browser/components/newtab/data/content/activity-stream.bundle.js
index 2c8a24112f129..133c9c703030f 100644
--- a/browser/components/newtab/data/content/activity-stream.bundle.js
+++ b/browser/components/newtab/data/content/activity-stream.bundle.js
@@ -115,30 +115,27 @@ __webpack_require__.r(__webpack_exports__);
-
const store = Object(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_6__["initStore"])(common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_10__["reducers"], global.gActivityStreamPrerenderedState);
const asrouterContent = new content_src_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_2__["ASRouterContent"]();
-
-new content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_4__["DetectUserSessionStart"](store).sendEventOrAddListener();
-
-// If we are starting in a prerendered state, we must wait until the first render
+new content_src_lib_detect_user_session_start__WEBPACK_IMPORTED_MODULE_4__["DetectUserSessionStart"](store).sendEventOrAddListener(); // If we are starting in a prerendered state, we must wait until the first render
// to request state rehydration (see Base.jsx). If we are NOT in a prerendered state,
// we can request it immedately.
+
if (!global.gActivityStreamPrerenderedState) {
- store.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST }));
+ store.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
+ }));
}
-Object(content_src_lib_asroutercontent__WEBPACK_IMPORTED_MODULE_5__["enableASRouterContent"])(store, asrouterContent);
-
-react_dom__WEBPACK_IMPORTED_MODULE_9___default.a.hydrate(react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- react_redux__WEBPACK_IMPORTED_MODULE_7__["Provider"],
- { store: store },
- react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_3__["Base"], {
- isFirstrun: global.document.location.href === "about:welcome",
- isPrerendered: !!global.gActivityStreamPrerenderedState,
- locale: global.document.documentElement.lang,
- strings: global.gActivityStreamStrings })
-), document.getElementById("root"));
+Object(content_src_lib_asroutercontent__WEBPACK_IMPORTED_MODULE_5__["enableASRouterContent"])(store, asrouterContent);
+react_dom__WEBPACK_IMPORTED_MODULE_9___default.a.hydrate(react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_redux__WEBPACK_IMPORTED_MODULE_7__["Provider"], {
+ store: store
+}, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Base_Base__WEBPACK_IMPORTED_MODULE_3__["Base"], {
+ isFirstrun: global.document.location.href === "about:welcome",
+ isPrerendered: !!global.gActivityStreamPrerenderedState,
+ locale: global.document.documentElement.lang,
+ strings: global.gActivityStreamStrings
+})), document.getElementById("root"));
Object(content_src_lib_snippets__WEBPACK_IMPORTED_MODULE_1__["addSnippetsSubscriber"])(store);
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -194,15 +191,13 @@ var CONTENT_MESSAGE_TYPE = "ActivityStream:Content";
var PRELOAD_MESSAGE_TYPE = "ActivityStream:PreloadedBrowser";
var UI_CODE = 1;
var BACKGROUND_PROCESS = 2;
-
/**
* globalImportContext - Are we in UI code (i.e. react, a dom) or some kind of background process?
* Use this in action creators if you need different logic
* for ui/background processes.
*/
-const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS : UI_CODE;
-// Export for tests
+const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS : UI_CODE; // Export for tests
// Create an object that avoids accidental differing key/value pairs:
// {
@@ -213,25 +208,28 @@ const actionTypes = {};
for (const type of ["ADDONS_INFO_REQUEST", "ADDONS_INFO_RESPONSE", "ARCHIVE_FROM_POCKET", "AS_ROUTER_INITIALIZED", "AS_ROUTER_PREF_CHANGED", "AS_ROUTER_TELEMETRY_USER_EVENT", "BLOCK_URL", "BOOKMARK_URL", "COPY_DOWNLOAD_LINK", "DELETE_BOOKMARK_BY_ID", "DELETE_FROM_POCKET", "DELETE_HISTORY_URL", "DIALOG_CANCEL", "DIALOG_OPEN", "DISCOVERY_STREAM_CONFIG_CHANGE", "DISCOVERY_STREAM_CONFIG_SETUP", "DISCOVERY_STREAM_CONFIG_SET_VALUE", "DISCOVERY_STREAM_FEEDS_UPDATE", "DISCOVERY_STREAM_IMPRESSION_STATS", "DISCOVERY_STREAM_LAYOUT_RESET", "DISCOVERY_STREAM_LAYOUT_UPDATE", "DISCOVERY_STREAM_OPT_OUT", "DISCOVERY_STREAM_SPOCS_ENDPOINT", "DISCOVERY_STREAM_SPOCS_UPDATE", "DISCOVERY_STREAM_SPOC_IMPRESSION", "DOWNLOAD_CHANGED", "FAKE_FOCUS_SEARCH", "FILL_SEARCH_TERM", "HANDOFF_SEARCH_TO_AWESOMEBAR", "HIDE_SEARCH", "INIT", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_DOWNLOAD_FILE", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "OPEN_WEBEXT_SETTINGS", "PAGE_PRERENDERED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINKS_CHANGED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PLACES_SAVED_TO_POCKET", "POCKET_CTA", "POCKET_LOGGED_IN", "POCKET_WAITING_FOR_SPOC", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "PREVIEW_REQUEST", "PREVIEW_REQUEST_CANCEL", "PREVIEW_RESPONSE", "REMOVE_DOWNLOAD_FILE", "RICH_ICON_MISSING", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_MOVE", "SECTION_OPTIONS_CHANGED", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SETTINGS_CLOSE", "SETTINGS_OPEN", "SET_PREF", "SHOW_DOWNLOAD_FILE", "SHOW_FIREFOX_ACCOUNTS", "SHOW_SEARCH", "SKIPPED_SIGNIN", "SNIPPETS_BLOCKLIST_CLEARED", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_PREVIEW_MODE", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SUBMIT_EMAIL", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_EDIT", "TOP_SITES_INSERT", "TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_PIN", "TOP_SITES_PREFS_UPDATED", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "TOTAL_BOOKMARKS_REQUEST", "TOTAL_BOOKMARKS_RESPONSE", "UNINIT", "UPDATE_PINNED_SEARCH_SHORTCUTS", "UPDATE_SEARCH_SHORTCUTS", "UPDATE_SECTION_PREFS", "WEBEXT_CLICK", "WEBEXT_DISMISS"]) {
actionTypes[type] = type;
-}
-
-// These are acceptable actions for AS Router messages to have. They can show up
+} // These are acceptable actions for AS Router messages to have. They can show up
// as call-to-action buttons in snippets, onboarding tour, etc.
+
+
const ASRouterActions = {};
for (const type of ["INSTALL_ADDON_FROM_URL", "OPEN_APPLICATIONS_MENU", "OPEN_PRIVATE_BROWSER_WINDOW", "OPEN_URL", "OPEN_ABOUT_PAGE", "OPEN_PREFERENCES_PAGE", "SHOW_FIREFOX_ACCOUNTS", "PIN_CURRENT_TAB"]) {
ASRouterActions[type] = type;
-}
-
-// Helper function for creating routed actions between content and main
+} // Helper function for creating routed actions between content and main
// Not intended to be used by consumers
+
+
function _RouteMessage(action, options) {
- const meta = action.meta ? Object.assign({}, action.meta) : {};
+ const meta = action.meta ? { ...action.meta
+ } : {};
+
if (!options || !options.from || !options.to) {
throw new Error("Routed Messages must have options as the second parameter, and must at least include a .from and .to property.");
- }
- // For each of these fields, if they are passed as an option,
+ } // For each of these fields, if they are passed as an option,
// add them to the action. If they are not defined, remove them.
+
+
["from", "to", "toTarget", "fromTarget", "skipMain", "skipLocal"].forEach(o => {
if (typeof options[o] !== "undefined") {
meta[o] = options[o];
@@ -239,9 +237,10 @@ function _RouteMessage(action, options) {
delete meta[o];
}
});
- return Object.assign({}, action, { meta });
+ return { ...action,
+ meta
+ };
}
-
/**
* AlsoToMain - Creates a message that will be dispatched locally and also sent to the Main process.
*
@@ -251,6 +250,8 @@ function _RouteMessage(action, options) {
* @param {string} fromTarget The id of the content port from which the action originated. (optional)
* @return {object} An action with added .meta properties
*/
+
+
function AlsoToMain(action, fromTarget, skipLocal) {
return _RouteMessage(action, {
from: CONTENT_MESSAGE_TYPE,
@@ -259,7 +260,6 @@ function AlsoToMain(action, fromTarget, skipLocal) {
skipLocal
});
}
-
/**
* OnlyToMain - Creates a message that will be sent to the Main process and skip the local reducer.
*
@@ -268,23 +268,25 @@ function AlsoToMain(action, fromTarget, skipLocal) {
* @param {string} fromTarget The id of the content port from which the action originated. (optional)
* @return {object} An action with added .meta properties
*/
+
+
function OnlyToMain(action, fromTarget) {
return AlsoToMain(action, fromTarget, true);
}
-
/**
* BroadcastToContent - Creates a message that will be dispatched to main and sent to ALL content processes.
*
* @param {object} action Any redux action (required)
* @return {object} An action with added .meta properties
*/
+
+
function BroadcastToContent(action) {
return _RouteMessage(action, {
from: MAIN_MESSAGE_TYPE,
to: CONTENT_MESSAGE_TYPE
});
}
-
/**
* AlsoToOneContent - Creates a message that will be will be dispatched to the main store
* and also sent to a particular Content process.
@@ -294,10 +296,13 @@ function BroadcastToContent(action) {
* @param {bool} skipMain Used by OnlyToOneContent to skip the main process
* @return {object} An action with added .meta properties
*/
+
+
function AlsoToOneContent(action, target, skipMain) {
if (!target) {
throw new Error("You must provide a target ID as the second parameter of AlsoToOneContent. If you want to send to all content processes, use BroadcastToContent");
}
+
return _RouteMessage(action, {
from: MAIN_MESSAGE_TYPE,
to: CONTENT_MESSAGE_TYPE,
@@ -305,7 +310,6 @@ function AlsoToOneContent(action, target, skipMain) {
skipMain
});
}
-
/**
* OnlyToOneContent - Creates a message that will be sent to a particular Content process
* and skip the main reducer.
@@ -314,23 +318,25 @@ function AlsoToOneContent(action, target, skipMain) {
* @param {string} target The id of a content port
* @return {object} An action with added .meta properties
*/
+
+
function OnlyToOneContent(action, target) {
return AlsoToOneContent(action, target, true);
}
-
/**
* AlsoToPreloaded - Creates a message that dispatched to the main reducer and also sent to the preloaded tab.
*
* @param {object} action Any redux action (required)
* @return {object} An action with added .meta properties
*/
+
+
function AlsoToPreloaded(action) {
return _RouteMessage(action, {
from: MAIN_MESSAGE_TYPE,
to: PRELOAD_MESSAGE_TYPE
});
}
-
/**
* UserEvent - A telemetry ping indicating a user action. This should only
* be sent from the UI during a user session.
@@ -338,13 +344,14 @@ function AlsoToPreloaded(action) {
* @param {object} data Fields to include in the ping (source, etc.)
* @return {object} An AlsoToMain action
*/
+
+
function UserEvent(data) {
return AlsoToMain({
type: actionTypes.TELEMETRY_USER_EVENT,
data
});
}
-
/**
* ASRouterUserEvent - A telemetry ping indicating a user action from AS router. This should only
* be sent from the UI during a user session.
@@ -352,13 +359,14 @@ function UserEvent(data) {
* @param {object} data Fields to include in the ping (source, etc.)
* @return {object} An AlsoToMain action
*/
+
+
function ASRouterUserEvent(data) {
return AlsoToMain({
type: actionTypes.AS_ROUTER_TELEMETRY_USER_EVENT,
data
});
}
-
/**
* UndesiredEvent - A telemetry ping indicating an undesired state.
*
@@ -366,6 +374,8 @@ function ASRouterUserEvent(data) {
* @param {int} importContext (For testing) Override the import context for testing.
* @return {object} An action. For UI code, a AlsoToMain action.
*/
+
+
function UndesiredEvent(data, importContext = globalImportContext) {
const action = {
type: actionTypes.TELEMETRY_UNDESIRED_EVENT,
@@ -373,7 +383,6 @@ function UndesiredEvent(data, importContext = globalImportContext) {
};
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
-
/**
* PerfEvent - A telemetry ping indicating a performance-related event.
*
@@ -381,6 +390,8 @@ function UndesiredEvent(data, importContext = globalImportContext) {
* @param {int} importContext (For testing) Override the import context for testing.
* @return {object} An action. For UI code, a AlsoToMain action.
*/
+
+
function PerfEvent(data, importContext = globalImportContext) {
const action = {
type: actionTypes.TELEMETRY_PERFORMANCE_EVENT,
@@ -388,7 +399,6 @@ function PerfEvent(data, importContext = globalImportContext) {
};
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
-
/**
* ImpressionStats - A telemetry ping indicating an impression stats.
*
@@ -396,6 +406,8 @@ function PerfEvent(data, importContext = globalImportContext) {
* @param {int} importContext (For testing) Override the import context for testing.
* #return {object} An action. For UI code, a AlsoToMain action.
*/
+
+
function ImpressionStats(data, importContext = globalImportContext) {
const action = {
type: actionTypes.TELEMETRY_IMPRESSION_STATS,
@@ -403,7 +415,6 @@ function ImpressionStats(data, importContext = globalImportContext) {
};
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
-
/**
* DiscoveryStreamImpressionStats - A telemetry ping indicating an impression stats in Discovery Stream.
*
@@ -411,6 +422,8 @@ function ImpressionStats(data, importContext = globalImportContext) {
* @param {int} importContext (For testing) Override the import context for testing.
* #return {object} An action. For UI code, a AlsoToMain action.
*/
+
+
function DiscoveryStreamImpressionStats(data, importContext = globalImportContext) {
const action = {
type: actionTypes.DISCOVERY_STREAM_IMPRESSION_STATS,
@@ -420,7 +433,13 @@ function DiscoveryStreamImpressionStats(data, importContext = globalImportContex
}
function SetPref(name, value, importContext = globalImportContext) {
- const action = { type: actionTypes.SET_PREF, data: { name, value } };
+ const action = {
+ type: actionTypes.SET_PREF,
+ data: {
+ name,
+ value
+ }
+ };
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
@@ -428,7 +447,11 @@ function WebExtEvent(type, data, importContext = globalImportContext) {
if (!data || !data.source) {
throw new Error("WebExtEvent actions should include a property \"source\", the id of the webextension that should receive the event.");
}
- const action = { type, data };
+
+ const action = {
+ type,
+ data
+ };
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
@@ -447,50 +470,61 @@ var actionCreators = {
SetPref,
WebExtEvent,
DiscoveryStreamImpressionStats
-};
-
-// These are helpers to test for certain kinds of actions
+}; // These are helpers to test for certain kinds of actions
var actionUtils = {
isSendToMain(action) {
if (!action.meta) {
return false;
}
+
return action.meta.to === MAIN_MESSAGE_TYPE && action.meta.from === CONTENT_MESSAGE_TYPE;
},
+
isBroadcastToContent(action) {
if (!action.meta) {
return false;
}
+
if (action.meta.to === CONTENT_MESSAGE_TYPE && !action.meta.toTarget) {
return true;
}
+
return false;
},
+
isSendToOneContent(action) {
if (!action.meta) {
return false;
}
+
if (action.meta.to === CONTENT_MESSAGE_TYPE && action.meta.toTarget) {
return true;
}
+
return false;
},
+
isSendToPreloaded(action) {
if (!action.meta) {
return false;
}
+
return action.meta.to === PRELOAD_MESSAGE_TYPE && action.meta.from === MAIN_MESSAGE_TYPE;
},
+
isFromMain(action) {
if (!action.meta) {
return false;
}
+
return action.meta.from === MAIN_MESSAGE_TYPE && action.meta.to === CONTENT_MESSAGE_TYPE;
},
+
getPortIdOfSender(action) {
return action.meta && action.meta.fromTarget || null;
},
+
_RouteMessage
};
@@ -505,7 +539,9 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SnippetsProvider", function() { return SnippetsProvider; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addSnippetsSubscriber", function() { return addSnippetsSubscriber; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
+
+function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
const DATABASE_NAME = "snippets_db";
const DATABASE_VERSION = 1;
@@ -515,8 +551,6 @@ const SNIPPETS_UPDATE_INTERVAL_MS = 14400000; // 4 hours.
const SNIPPETS_ENABLED_EVENT = "Snippets:Enabled";
const SNIPPETS_DISABLED_EVENT = "Snippets:Disabled";
-
-
/**
* SnippetsMap - A utility for cacheing values related to the snippet. It has
* the same interface as a Map, but is optionally backed by
@@ -525,6 +559,7 @@ const SNIPPETS_DISABLED_EVENT = "Snippets:Disabled";
* previously cached data, if necessary.
*
*/
+
class SnippetsMap extends Map {
constructor(dispatch) {
super();
@@ -544,14 +579,17 @@ class SnippetsMap extends Map {
clear() {
super.clear();
- this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SNIPPETS_BLOCKLIST_CLEARED }));
+
+ this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SNIPPETS_BLOCKLIST_CLEARED
+ }));
+
return this._dbTransaction(db => db.clear());
}
get blockList() {
return this.get("blockList") || [];
}
-
/**
* blockSnippetById - Blocks a snippet given an id
*
@@ -559,6 +597,8 @@ class SnippetsMap extends Map {
* @return {Promise} Resolves when the id has been written to indexedDB,
* or immediately if the snippetMap is not connected
*/
+
+
blockSnippetById(id) {
var _this = this;
@@ -566,10 +606,19 @@ class SnippetsMap extends Map {
if (!id) {
return;
}
- const { blockList } = _this;
+
+ const {
+ blockList
+ } = _this;
+
if (!blockList.includes(id)) {
blockList.push(id);
- _this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SNIPPETS_BLOCKLIST_UPDATED, data: id }));
+
+ _this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SNIPPETS_BLOCKLIST_UPDATED,
+ data: id
+ }));
+
yield _this.set("blockList", blockList);
}
})();
@@ -578,13 +627,20 @@ class SnippetsMap extends Map {
disableOnboarding() {}
showFirefoxAccounts() {
- this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SHOW_FIREFOX_ACCOUNTS }));
+ this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SHOW_FIREFOX_ACCOUNTS
+ }));
}
getTotalBookmarksCount() {
return new Promise(resolve => {
- this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOTAL_BOOKMARKS_REQUEST }));
- global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({ data: action }) {
+ this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOTAL_BOOKMARKS_REQUEST
+ }));
+
+ global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({
+ data: action
+ }) {
if (action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOTAL_BOOKMARKS_RESPONSE) {
resolve(action.data);
global.RPMRemoveMessageListener("ActivityStream:MainToContent", onMessage);
@@ -595,8 +651,13 @@ class SnippetsMap extends Map {
getAddonsInfo() {
return new Promise(resolve => {
- this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].ADDONS_INFO_REQUEST }));
- global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({ data: action }) {
+ this._dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].ADDONS_INFO_REQUEST
+ }));
+
+ global.RPMAddMessageListener("ActivityStream:MainToContent", function onMessage({
+ data: action
+ }) {
if (action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].ADDONS_INFO_RESPONSE) {
resolve(action.data);
global.RPMRemoveMessageListener("ActivityStream:MainToContent", onMessage);
@@ -604,7 +665,6 @@ class SnippetsMap extends Map {
});
});
}
-
/**
* connect - Attaches an indexedDB back-end to the Map so that any set values
* are also cached in a store. It also restores any existing values
@@ -612,21 +672,20 @@ class SnippetsMap extends Map {
*
* @return {type} description
*/
+
+
connect() {
var _this2 = this;
return _asyncToGenerator(function* () {
// Open the connection
- const db = yield _this2._openDB();
+ const db = yield _this2._openDB(); // Restore any existing values
- // Restore any existing values
- yield _this2._restoreFromDb(db);
+ yield _this2._restoreFromDb(db); // Attach a reference to the db
- // Attach a reference to the db
_this2._db = db;
})();
}
-
/**
* _dbTransaction - Returns a db transaction wrapped with the given modifier
* function as a Promise. If the db has not been connected,
@@ -636,15 +695,20 @@ class SnippetsMap extends Map {
* @return {obj} A Promise that resolves when the transaction has
* completed or errored
*/
+
+
_dbTransaction(modifier) {
if (!this._db) {
return Promise.resolve();
}
+
return new Promise((resolve, reject) => {
const transaction = modifier(this._db.transaction(SNIPPETS_OBJECTSTORE_NAME, "readwrite").objectStore(SNIPPETS_OBJECTSTORE_NAME));
- transaction.onsuccess = event => resolve();
+ transaction.onsuccess = event => resolve();
/* istanbul ignore next */
+
+
transaction.onerror = event => reject(transaction.error);
});
}
@@ -652,8 +716,8 @@ class SnippetsMap extends Map {
_openDB() {
return new Promise((resolve, reject) => {
const openRequest = indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
-
/* istanbul ignore next */
+
openRequest.onerror = event => {
// Try to delete the old database so that we can start this process over
// next time.
@@ -663,6 +727,7 @@ class SnippetsMap extends Map {
openRequest.onupgradeneeded = event => {
const db = event.target.result;
+
if (!db.objectStoreNames.contains(SNIPPETS_OBJECTSTORE_NAME)) {
db.createObjectStore(SNIPPETS_OBJECTSTORE_NAME);
}
@@ -670,10 +735,13 @@ class SnippetsMap extends Map {
openRequest.onsuccess = event => {
let db = event.target.result;
-
/* istanbul ignore next */
+
db.onerror = err => console.error(err); // eslint-disable-line no-console
+
/* istanbul ignore next */
+
+
db.onversionchange = versionChangeEvent => versionChangeEvent.target.close();
resolve(db);
@@ -684,25 +752,28 @@ class SnippetsMap extends Map {
_restoreFromDb(db) {
return new Promise((resolve, reject) => {
let cursorRequest;
+
try {
cursorRequest = db.transaction(SNIPPETS_OBJECTSTORE_NAME).objectStore(SNIPPETS_OBJECTSTORE_NAME).openCursor();
} catch (err) {
// istanbul ignore next
- reject(err);
- // istanbul ignore next
+ reject(err); // istanbul ignore next
+
return;
}
-
/* istanbul ignore next */
+
+
cursorRequest.onerror = event => reject(event);
cursorRequest.onsuccess = event => {
- let cursor = event.target.result;
- // Populate the cache from the persistent storage.
+ let cursor = event.target.result; // Populate the cache from the persistent storage.
+
if (cursor) {
if (cursor.value !== "blockList") {
this.set(cursor.key, cursor.value);
}
+
cursor.continue();
} else {
// We are done.
@@ -711,13 +782,14 @@ class SnippetsMap extends Map {
};
});
}
-}
+}
/**
* SnippetsProvider - Initializes a SnippetsMap and loads snippets from a
* remote location, or else default snippets if the remote
* snippets cannot be retrieved.
*/
+
class SnippetsProvider {
constructor(dispatch) {
// Initialize the Snippets Map and attaches it to a global so that
@@ -740,20 +812,24 @@ class SnippetsProvider {
if (cachedVersion !== _this3.appData.version) {
_this3.snippetsMap.clear();
- }
+ } // Has enough time passed for us to require an update?
+
- // Has enough time passed for us to require an update?
const lastUpdate = _this3.snippetsMap.get("snippets-last-update");
+
const needsUpdate = !(lastUpdate >= 0) || Date.now() - lastUpdate > SNIPPETS_UPDATE_INTERVAL_MS;
if (needsUpdate && _this3.appData.snippetsURL) {
_this3.snippetsMap.set("snippets-last-update", Date.now());
+
try {
const response = yield fetch(_this3.appData.snippetsURL);
+
if (response.status === 200) {
const payload = yield response.text();
_this3.snippetsMap.set("snippets", payload);
+
_this3.snippetsMap.set("snippets-cached-version", _this3.appData.version);
}
} catch (e) {
@@ -769,25 +845,25 @@ class SnippetsProvider {
if (!snippetsEl) {
throw new Error(`No element was found with id '${this.elementId}'.`);
- }
+ } // This could happen if fetching failed
+
- // This could happen if fetching failed
if (!payload) {
throw new Error("No remote snippets were found in gSnippetsMap.");
}
if (typeof payload !== "string") {
throw new Error("Snippet payload was incorrectly formatted");
- }
-
- // Note that injecting snippets can throw if they're invalid XML.
+ } // Note that injecting snippets can throw if they're invalid XML.
// eslint-disable-next-line no-unsanitized/property
- snippetsEl.innerHTML = payload;
- this._logIfDevtools("Successfully added snippets.");
- // Scripts injected by innerHTML are inactive, so we have to relocate them
+ snippetsEl.innerHTML = payload;
+
+ this._logIfDevtools("Successfully added snippets."); // Scripts injected by innerHTML are inactive, so we have to relocate them
// through DOM manipulation to activate their contents.
+
+
for (const scriptEl of snippetsEl.getElementsByTagName("script")) {
const relocatedScript = document.createElement("script");
relocatedScript.text = scriptEl.text;
@@ -802,15 +878,14 @@ class SnippetsProvider {
document.getElementById("snippets-container").style.display = "none";
}
}
- }
+ } // istanbul ignore next
+
- // istanbul ignore next
_logIfDevtools(text) {
if (this.devtoolsEnabled) {
console.log("Legacy snippets:", text); // eslint-disable-line no-console
}
}
-
/**
* init - Fetch the snippet payload and show snippets
*
@@ -820,6 +895,8 @@ class SnippetsProvider {
* @param {str} options.elementId The id of the element in which to inject snippets
* @param {bool} options.connect Should gSnippetsMap connect to indexedDB?
*/
+
+
init(options) {
var _this4 = this;
@@ -831,59 +908,61 @@ class SnippetsProvider {
devtoolsEnabled: false
}, options);
- _this4._logIfDevtools("Initializing...");
+ _this4._logIfDevtools("Initializing..."); // Add listener so we know when snippets are blocked on other pages
+
- // Add listener so we know when snippets are blocked on other pages
if (global.RPMAddMessageListener) {
global.RPMAddMessageListener("ActivityStream:MainToContent", _this4._onAction);
- }
-
- // TODO: Requires enabling indexedDB on newtab
+ } // TODO: Requires enabling indexedDB on newtab
// Restore the snippets map from indexedDB
+
+
if (_this4.connect) {
try {
yield _this4.snippetsMap.connect();
} catch (e) {
console.error(e); // eslint-disable-line no-console
}
- }
+ } // Cache app data values so they can be accessible from gSnippetsMap
+
- // Cache app data values so they can be accessible from gSnippetsMap
for (const key of Object.keys(_this4.appData)) {
if (key === "blockList") {
_this4.snippetsMap.set("blockList", _this4.appData[key]);
} else {
_this4.snippetsMap.set(`appData.${key}`, _this4.appData[key]);
}
- }
+ } // Refresh snippets, if enough time has passed.
+
- // Refresh snippets, if enough time has passed.
- yield _this4._refreshSnippets();
+ yield _this4._refreshSnippets(); // Try showing remote snippets, falling back to defaults if necessary.
- // Try showing remote snippets, falling back to defaults if necessary.
try {
_this4._showRemoteSnippets();
} catch (e) {
_this4._logIfDevtools("Problem inserting remote snippets!");
+
console.error(e); // eslint-disable-line no-console
}
window.dispatchEvent(new Event(SNIPPETS_ENABLED_EVENT));
-
_this4.initialized = true;
+
_this4._logIfDevtools("Finished initializing.");
})();
}
uninit() {
window.dispatchEvent(new Event(SNIPPETS_DISABLED_EVENT));
+
if (global.RPMRemoveMessageListener) {
global.RPMRemoveMessageListener("ActivityStream:MainToContent", this._onAction);
}
+
this.initialized = false;
}
-}
+}
/**
* addSnippetsSubscriber - Creates a SnippetsProvider that Initializes
* when the store has received the appropriate
@@ -892,14 +971,14 @@ class SnippetsProvider {
* @param {obj} store The redux store
* @return {obj} Returns the snippets instance, asrouterContent instance and unsubscribe function
*/
+
function addSnippetsSubscriber(store) {
const snippets = new SnippetsProvider(store.dispatch);
-
let initializing = false;
-
- store.subscribe(_asyncToGenerator(function* () {
+ store.subscribe(
+ /*#__PURE__*/
+ _asyncToGenerator(function* () {
const state = store.getState();
-
/**
* Sorry this code is so complicated. It will be removed soon.
* This is what the different values actually mean:
@@ -914,26 +993,29 @@ function addSnippetsSubscriber(store) {
*/
/** If we should initialize snippets... */
- if (state.Prefs.values["feeds.snippets"] && state.ASRouter.initialized && state.ASRouter.allowLegacySnippets && !state.Prefs.values.disableSnippets && state.Snippets.initialized && !snippets.initialized &&
- // Don't call init multiple times
+
+ if (state.Prefs.values["feeds.snippets"] && state.ASRouter.initialized && state.ASRouter.allowLegacySnippets && !state.Prefs.values.disableSnippets && state.Snippets.initialized && !snippets.initialized && // Don't call init multiple times
!initializing && location.href !== "about:welcome" && location.hash !== "#asrouter") {
initializing = true;
- yield snippets.init({ appData: state.Snippets, devtoolsEnabled: state.Prefs.values["asrouter.devtoolsEnabled"] });
+ yield snippets.init({
+ appData: state.Snippets,
+ devtoolsEnabled: state.Prefs.values["asrouter.devtoolsEnabled"]
+ });
initializing = false;
-
/** If we should remove snippets... */
} else if ((state.Prefs.values["feeds.snippets"] === false || state.Prefs.values.disableSnippets === true || state.ASRouter.initialized && !state.ASRouter.allowLegacySnippets) && snippets.initialized) {
// Remove snippets
- snippets.uninit();
- // istanbul ignore if
+ snippets.uninit(); // istanbul ignore if
+
if (state.Prefs.values["asrouter.devtoolsEnabled"]) {
console.log("Legacy snippets removed"); // eslint-disable-line no-console
}
}
- }));
+ })); // Returned for testing purposes
- // Returned for testing purposes
- return { snippets };
+ return {
+ snippets
+ };
}
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -961,8 +1043,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _templates_ReturnToAMO_ReturnToAMO__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(15);
/* harmony import */ var _templates_template_manifest__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(56);
/* harmony import */ var _templates_StartupOverlay_StartupOverlay__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(23);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -979,48 +1060,90 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
const ASR_CONTAINER_ID = "asr-newtab-container";
-
const ASRouterUtils = {
addListener(listener) {
global.RPMAddMessageListener(INCOMING_MESSAGE_NAME, listener);
},
+
removeListener(listener) {
global.RPMRemoveMessageListener(INCOMING_MESSAGE_NAME, listener);
},
+
sendMessage(action) {
global.RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
},
+
blockById(id, options) {
- ASRouterUtils.sendMessage({ type: "BLOCK_MESSAGE_BY_ID", data: Object.assign({ id }, options) });
+ ASRouterUtils.sendMessage({
+ type: "BLOCK_MESSAGE_BY_ID",
+ data: {
+ id,
+ ...options
+ }
+ });
},
+
dismissById(id) {
- ASRouterUtils.sendMessage({ type: "DISMISS_MESSAGE_BY_ID", data: { id } });
+ ASRouterUtils.sendMessage({
+ type: "DISMISS_MESSAGE_BY_ID",
+ data: {
+ id
+ }
+ });
},
+
dismissBundle(bundle) {
- ASRouterUtils.sendMessage({ type: "DISMISS_BUNDLE", data: { bundle } });
+ ASRouterUtils.sendMessage({
+ type: "DISMISS_BUNDLE",
+ data: {
+ bundle
+ }
+ });
},
+
executeAction(button_action) {
ASRouterUtils.sendMessage({
type: "USER_ACTION",
data: button_action
});
},
+
unblockById(id) {
- ASRouterUtils.sendMessage({ type: "UNBLOCK_MESSAGE_BY_ID", data: { id } });
+ ASRouterUtils.sendMessage({
+ type: "UNBLOCK_MESSAGE_BY_ID",
+ data: {
+ id
+ }
+ });
},
+
unblockBundle(bundle) {
- ASRouterUtils.sendMessage({ type: "UNBLOCK_BUNDLE", data: { bundle } });
+ ASRouterUtils.sendMessage({
+ type: "UNBLOCK_BUNDLE",
+ data: {
+ bundle
+ }
+ });
},
+
overrideMessage(id) {
- ASRouterUtils.sendMessage({ type: "OVERRIDE_MESSAGE", data: { id } });
+ ASRouterUtils.sendMessage({
+ type: "OVERRIDE_MESSAGE",
+ data: {
+ id
+ }
+ });
},
+
sendTelemetry(ping) {
const payload = common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__["actionCreators"].ASRouterUserEvent(ping);
global.RPMSendAsyncMessage(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_2__["OUTGOING_MESSAGE_NAME"], payload);
},
+
getPreviewEndpoint() {
if (window.location.href.includes("endpoint")) {
const params = new URLSearchParams(window.location.href.slice(window.location.href.indexOf("endpoint")));
+
try {
const endpoint = new URL(params.get("endpoint"));
return {
@@ -1032,9 +1155,9 @@ const ASRouterUtils = {
return null;
}
-};
-// Note: nextProps/prevProps refer to props passed to <ImpressionsWrapper />, not <ASRouterUISurface />
+}; // Note: nextProps/prevProps refer to props passed to <ImpressionsWrapper />, not <ASRouterUISurface />
+
function shouldSendImpressionOnUpdate(nextProps, prevProps) {
return nextProps.message.id && (!prevProps.message || prevProps.message.id !== nextProps.message.id);
}
@@ -1046,20 +1169,29 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
this.sendClick = this.sendClick.bind(this);
this.sendImpression = this.sendImpression.bind(this);
this.sendUserActionTelemetry = this.sendUserActionTelemetry.bind(this);
- this.state = { message: {}, bundle: {} };
+ this.state = {
+ message: {},
+ bundle: {}
+ };
}
sendUserActionTelemetry(extraProps = {}) {
- const { message, bundle } = this.state;
+ const {
+ message,
+ bundle
+ } = this.state;
+
if (!message && !extraProps.message_id) {
throw new Error(`You must provide a message_id for bundled messages`);
}
+
const eventType = `${message.provider || bundle.provider}_user_event`;
- ASRouterUtils.sendTelemetry(Object.assign({
+ ASRouterUtils.sendTelemetry({
message_id: message.id || extraProps.message_id,
source: extraProps.id,
- action: eventType
- }, extraProps));
+ action: eventType,
+ ...extraProps
+ });
}
sendImpression(extraProps) {
@@ -1067,13 +1199,19 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
return;
}
- ASRouterUtils.sendMessage({ type: "IMPRESSION", data: this.state.message });
- this.sendUserActionTelemetry(Object.assign({ event: "IMPRESSION" }, extraProps));
- }
-
- // If link has a `metric` data attribute send it as part of the `value`
+ ASRouterUtils.sendMessage({
+ type: "IMPRESSION",
+ data: this.state.message
+ });
+ this.sendUserActionTelemetry({
+ event: "IMPRESSION",
+ ...extraProps
+ });
+ } // If link has a `metric` data attribute send it as part of the `value`
// telemetry field which can have arbitrary values.
// Used for router messages with links as part of the content.
+
+
sendClick(event) {
const metric = {
value: event.target.dataset.metric,
@@ -1083,16 +1221,24 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
};
const action = {
type: event.target.dataset.action,
- data: { args: event.target.dataset.args }
+ data: {
+ args: event.target.dataset.args
+ }
};
+
if (action.type) {
ASRouterUtils.executeAction(action);
}
+
if (!this.state.message.content.do_not_autoblock && !event.target.dataset.do_not_autoblock) {
ASRouterUtils.blockById(this.state.message.id);
}
+
if (this.state.message.provider !== "preview") {
- this.sendUserActionTelemetry(Object.assign({ event: "CLICK_BUTTON" }, metric));
+ this.sendUserActionTelemetry({
+ event: "CLICK_BUTTON",
+ ...metric
+ });
}
}
@@ -1109,51 +1255,91 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
}
triggerOnboarding() {
- ASRouterUtils.sendMessage({ type: "TRIGGER", data: { trigger: { id: "showOnboarding" } } });
+ ASRouterUtils.sendMessage({
+ type: "TRIGGER",
+ data: {
+ trigger: {
+ id: "showOnboarding"
+ }
+ }
+ });
}
- onMessageFromParent({ data: action }) {
+ onMessageFromParent({
+ data: action
+ }) {
switch (action.type) {
case "SET_MESSAGE":
- this.setState({ message: action.data });
+ this.setState({
+ message: action.data
+ });
break;
+
case "SET_BUNDLED_MESSAGES":
- this.setState({ bundle: action.data });
+ this.setState({
+ bundle: action.data
+ });
break;
+
case "CLEAR_MESSAGE":
if (action.data.id === this.state.message.id) {
- this.setState({ message: {} });
- // Remove any styles related to the RTAMO message
+ this.setState({
+ message: {}
+ }); // Remove any styles related to the RTAMO message
+
document.body.classList.remove("welcome", "hide-main", "amo");
}
+
break;
+
case "CLEAR_PROVIDER":
if (action.data.id === this.state.message.provider) {
- this.setState({ message: {} });
+ this.setState({
+ message: {}
+ });
}
+
break;
+
case "CLEAR_BUNDLE":
if (this.state.bundle.bundle) {
- this.setState({ bundle: {} });
+ this.setState({
+ bundle: {}
+ });
}
+
break;
+
case "CLEAR_ALL":
- this.setState({ message: {}, bundle: {} });
+ this.setState({
+ message: {},
+ bundle: {}
+ });
}
}
componentWillMount() {
// Add locale data for StartupOverlay because it uses react-intl
Object(react_intl__WEBPACK_IMPORTED_MODULE_0__["addLocaleData"])(global.document.documentElement.lang);
-
const endpoint = ASRouterUtils.getPreviewEndpoint();
- ASRouterUtils.addListener(this.onMessageFromParent);
+ ASRouterUtils.addListener(this.onMessageFromParent); // If we are loading about:welcome we want to trigger the onboarding messages
- // If we are loading about:welcome we want to trigger the onboarding messages
if (this.props.document.location.href === "about:welcome") {
- ASRouterUtils.sendMessage({ type: "TRIGGER", data: { trigger: { id: "firstRun" } } });
+ ASRouterUtils.sendMessage({
+ type: "TRIGGER",
+ data: {
+ trigger: {
+ id: "firstRun"
+ }
+ }
+ });
} else {
- ASRouterUtils.sendMessage({ type: "SNIPPETS_REQUEST", data: { endpoint } });
+ ASRouterUtils.sendMessage({
+ type: "SNIPPETS_REQUEST",
+ data: {
+ endpoint
+ }
+ });
}
}
@@ -1165,30 +1351,28 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
if (this.state.bundle.template === "onboarding" || this.state.message.template === "fxa_overlay" || this.state.message.template === "return_to_amo_overlay") {
return null;
}
- const SnippetComponent = _templates_template_manifest__WEBPACK_IMPORTED_MODULE_10__["SnippetsTemplates"][this.state.message.template];
- const { content } = this.state.message;
- return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(
- _components_ImpressionsWrapper_ImpressionsWrapper__WEBPACK_IMPORTED_MODULE_4__["ImpressionsWrapper"],
- {
- id: "NEWTAB_FOOTER_BAR",
- message: this.state.message,
- sendImpression: this.sendImpression,
- shouldSendImpressionOnUpdate: shouldSendImpressionOnUpdate
- // This helps with testing
- , document: this.props.document },
- react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(
- fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"],
- { messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])(content) },
- react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(SnippetComponent, _extends({}, this.state.message, {
- UISurface: "NEWTAB_FOOTER_BAR",
- onBlock: this.onBlockById(this.state.message.id),
- onDismiss: this.onDismissById(this.state.message.id),
- onAction: ASRouterUtils.executeAction,
- sendClick: this.sendClick,
- sendUserActionTelemetry: this.sendUserActionTelemetry }))
- )
- );
+ const SnippetComponent = _templates_template_manifest__WEBPACK_IMPORTED_MODULE_10__["SnippetsTemplates"][this.state.message.template];
+ const {
+ content
+ } = this.state.message;
+ return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(_components_ImpressionsWrapper_ImpressionsWrapper__WEBPACK_IMPORTED_MODULE_4__["ImpressionsWrapper"], {
+ id: "NEWTAB_FOOTER_BAR",
+ message: this.state.message,
+ sendImpression: this.sendImpression,
+ shouldSendImpressionOnUpdate: shouldSendImpressionOnUpdate // This helps with testing
+ ,
+ document: this.props.document
+ }, react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"], {
+ messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])(content)
+ }, react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(SnippetComponent, _extends({}, this.state.message, {
+ UISurface: "NEWTAB_FOOTER_BAR",
+ onBlock: this.onBlockById(this.state.message.id),
+ onDismiss: this.onDismissById(this.state.message.id),
+ onAction: ASRouterUtils.executeAction,
+ sendClick: this.sendClick,
+ sendUserActionTelemetry: this.sendUserActionTelemetry
+ }))));
}
renderOnboarding() {
@@ -1197,35 +1381,42 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
UISurface: "NEWTAB_OVERLAY",
onAction: ASRouterUtils.executeAction,
onDoneButton: this.dismissBundle(this.state.bundle.bundle),
- sendUserActionTelemetry: this.sendUserActionTelemetry }));
+ sendUserActionTelemetry: this.sendUserActionTelemetry
+ }));
}
+
return null;
}
renderFirstRunOverlay() {
- const { message } = this.state;
+ const {
+ message
+ } = this.state;
+
if (message.template === "fxa_overlay") {
global.document.body.classList.add("fxa");
- return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(
- react_intl__WEBPACK_IMPORTED_MODULE_0__["IntlProvider"],
- { locale: global.document.documentElement.lang, messages: global.gActivityStreamStrings },
- react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(_templates_StartupOverlay_StartupOverlay__WEBPACK_IMPORTED_MODULE_11__["StartupOverlay"], {
- onReady: this.triggerOnboarding,
- onBlock: this.onDismissById(message.id),
- dispatch: this.props.activityStreamStore.dispatch,
- store: this.props.activityStreamStore })
- );
+ return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["IntlProvider"], {
+ locale: global.document.documentElement.lang,
+ messages: global.gActivityStreamStrings
+ }, react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(_templates_StartupOverlay_StartupOverlay__WEBPACK_IMPORTED_MODULE_11__["StartupOverlay"], {
+ onReady: this.triggerOnboarding,
+ onBlock: this.onDismissById(message.id),
+ dispatch: this.props.activityStreamStore.dispatch,
+ store: this.props.activityStreamStore
+ }));
} else if (message.template === "return_to_amo_overlay") {
global.document.body.classList.add("amo");
- return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(
- fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"],
- { messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])({ "amo_html": message.content.text }) },
- react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(_templates_ReturnToAMO_ReturnToAMO__WEBPACK_IMPORTED_MODULE_9__["ReturnToAMO"], _extends({}, message, {
- onReady: this.triggerOnboarding,
- onBlock: this.onDismissById(message.id),
- onAction: ASRouterUtils.executeAction }))
- );
+ return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_5__["LocalizationProvider"], {
+ messages: Object(_rich_text_strings__WEBPACK_IMPORTED_MODULE_3__["generateMessages"])({
+ "amo_html": message.content.text
+ })
+ }, react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(_templates_ReturnToAMO_ReturnToAMO__WEBPACK_IMPORTED_MODULE_9__["ReturnToAMO"], _extends({}, message, {
+ onReady: this.triggerOnboarding,
+ onBlock: this.onDismissById(message.id),
+ onAction: ASRouterUtils.executeAction
+ })));
}
+
return null;
}
@@ -1234,36 +1425,30 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_7___default.a.Pur
return null;
}
- return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(
- "div",
- { className: "snippets-preview-banner" },
- react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement("span", { className: "icon icon-small-spacer icon-info" }),
- react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(
- "span",
- null,
- "Preview Purposes Only"
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement("div", {
+ className: "snippets-preview-banner"
+ }, react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement("span", {
+ className: "icon icon-small-spacer icon-info"
+ }), react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement("span", null, "Preview Purposes Only"));
}
render() {
- const { message, bundle } = this.state;
+ const {
+ message,
+ bundle
+ } = this.state;
+
if (!message.id && !bundle.template) {
return null;
}
- return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(
- react__WEBPACK_IMPORTED_MODULE_7___default.a.Fragment,
- null,
- this.renderPreviewBanner(),
- this.renderFirstRunOverlay(),
- this.renderOnboarding(),
- this.renderSnippets()
- );
- }
-}
-ASRouterUISurface.defaultProps = { document: global.document };
+ return react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_7___default.a.Fragment, null, this.renderPreviewBanner(), this.renderFirstRunOverlay(), this.renderOnboarding(), this.renderSnippets());
+ }
+}
+ASRouterUISurface.defaultProps = {
+ document: global.document
+};
class ASRouterContent {
constructor() {
this.initialized = false;
@@ -1272,6 +1457,7 @@ class ASRouterContent {
_mount() {
this.containerElement = global.document.getElementById(ASR_CONTAINER_ID);
+
if (!this.containerElement) {
this.containerElement = global.document.createElement("div");
this.containerElement.id = ASR_CONTAINER_ID;
@@ -1279,7 +1465,9 @@ class ASRouterContent {
global.document.body.appendChild(this.containerElement);
}
- react_dom__WEBPACK_IMPORTED_MODULE_8___default.a.render(react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(ASRouterUISurface, { activityStreamStore: this._activityStreamStore }), this.containerElement);
+ react_dom__WEBPACK_IMPORTED_MODULE_8___default.a.render(react__WEBPACK_IMPORTED_MODULE_7___default.a.createElement(ASRouterUISurface, {
+ activityStreamStore: this._activityStreamStore
+ }), this.containerElement);
}
_unmount() {
@@ -1288,16 +1476,20 @@ class ASRouterContent {
init(store) {
this._activityStreamStore = store;
+
this._mount();
+
this.initialized = true;
}
uninit() {
if (this.initialized) {
this._unmount();
+
this.initialized = false;
}
}
+
}
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -1326,13 +1518,10 @@ __webpack_require__.r(__webpack_exports__);
/* eslint-env mozilla/frame-script */
-
-
const MERGE_STORE_ACTION = "NEW_TAB_INITIAL_STATE";
const OUTGOING_MESSAGE_NAME = "ActivityStream:ContentToMain";
const INCOMING_MESSAGE_NAME = "ActivityStream:MainToContent";
const EARLY_QUEUED_ACTIONS = [common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_SESSION_PERF_DATA, common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].PAGE_PRERENDERED];
-
/**
* A higher-order function which returns a reducer that, on MERGE_STORE action,
* will return the action.data object merged into the previous state.
@@ -1349,24 +1538,30 @@ const EARLY_QUEUED_ACTIONS = [common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["a
* into the previous state, and the result
* of calling mainReducer otherwise.
*/
+
function mergeStateReducer(mainReducer) {
return (prevState, action) => {
if (action.type === MERGE_STORE_ACTION) {
- return Object.assign({}, prevState, action.data);
+ return { ...prevState,
+ ...action.data
+ };
}
return mainReducer(prevState, action);
};
}
-
/**
* messageMiddleware - Middleware that looks for SentToMain type actions, and sends them if necessary
*/
+
+
const messageMiddleware = store => next => action => {
const skipLocal = action.meta && action.meta.skipLocal;
+
if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToMain(action)) {
RPMSendAsyncMessage(OUTGOING_MESSAGE_NAME, action);
}
+
if (!skipLocal) {
next(action);
}
@@ -1388,11 +1583,13 @@ const rehydrationMiddleware = store => next => action => {
if (isMergeStoreAction) {
store._didRehydrate = true;
return next(action);
- }
+ } // If init happened after our request was made, we need to re-request
+
- // If init happened after our request was made, we need to re-request
if (store._didRequestInitialState && action.type === common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].INIT) {
- return next(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST }));
+ return next(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
+ }));
}
if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isBroadcastToContent(action) || common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToOneContent(action) || common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isSendToPreloaded(action)) {
@@ -1404,7 +1601,6 @@ const rehydrationMiddleware = store => next => action => {
return next(action);
};
-
/**
* This middleware queues up all the EARLY_QUEUED_ACTIONS until it receives
* the first action from main. This is useful for those actions for main which
@@ -1412,26 +1608,28 @@ const rehydrationMiddleware = store => next => action => {
* that it gets sent before the main is ready to receive it. Conversely, any
* actions allowed early are accepted to be ignorable or re-sendable.
*/
+
const queueEarlyMessageMiddleware = store => next => action => {
if (store._receivedFromMain) {
next(action);
} else if (common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionUtils"].isFromMain(action)) {
next(action);
- store._receivedFromMain = true;
- // Sending out all the early actions as main is ready now
+ store._receivedFromMain = true; // Sending out all the early actions as main is ready now
+
if (store._earlyActionQueue) {
store._earlyActionQueue.forEach(next);
+
store._earlyActionQueue = [];
}
} else if (EARLY_QUEUED_ACTIONS.includes(action.type)) {
store._earlyActionQueue = store._earlyActionQueue || [];
+
store._earlyActionQueue.push(action);
} else {
// Let any other type of action go through
next(action);
}
};
-
/**
* initStore - Create a store and listen for incoming actions
*
@@ -1439,9 +1637,9 @@ const queueEarlyMessageMiddleware = store => next => action => {
* @param {object} intialState (optional) The initial state of the store, if desired
* @return {object} A redux store
*/
+
function initStore(reducers, initialState) {
const store = Object(redux__WEBPACK_IMPORTED_MODULE_1__["createStore"])(mergeStateReducer(Object(redux__WEBPACK_IMPORTED_MODULE_1__["combineReducers"])(reducers)), initialState, global.RPMAddMessageListener && Object(redux__WEBPACK_IMPORTED_MODULE_1__["applyMiddleware"])(rehydrationMiddleware, queueEarlyMessageMiddleware, messageMiddleware));
-
store._didRehydrate = false;
store._didRequestInitialState = false;
@@ -1451,6 +1649,7 @@ function initStore(reducers, initialState) {
store.dispatch(msg.data);
} catch (ex) {
console.error("Content msg:", msg, "Dispatch error: ", ex); // eslint-disable-line no-console
+
dump(`Content msg: ${JSON.stringify(msg)}\nDispatch error: ${ex}\n${ex.stack}`);
}
});
@@ -1476,12 +1675,12 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "generateMessages", function() { return generateMessages; });
/* harmony import */ var fluent__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(57);
-
/**
* Properties that allow rich text MUST be added to this list.
* key: the localization_id that should be used
* value: a property or array of properties on the message.content object
*/
+
const RICH_TEXT_CONFIG = {
"text": ["text", "scene1_text"],
"success_text": "success_text",
@@ -1491,26 +1690,26 @@ const RICH_TEXT_CONFIG = {
"privacy_html": "scene2_privacy_html",
"disclaimer_html": "scene2_disclaimer_html"
};
-
const RICH_TEXT_KEYS = Object.keys(RICH_TEXT_CONFIG);
-
/**
* Generates an array of messages suitable for fluent's localization provider
* including all needed strings for rich text.
* @param {object} content A .content object from an ASR message (i.e. message.content)
* @returns {MessageContext[]} A array containing the fluent message context
*/
+
function generateMessages(content) {
const cx = new fluent__WEBPACK_IMPORTED_MODULE_0__["MessageContext"]("en-US");
-
RICH_TEXT_KEYS.forEach(key => {
const attrs = RICH_TEXT_CONFIG[key];
const attrsToTry = Array.isArray(attrs) ? [...attrs] : [attrs];
let string = "";
+
while (!string && attrsToTry.length) {
const attr = attrsToTry.pop();
string = content[attr];
}
+
cx.addMessages(`${key} = ${string}`);
});
return [cx];
@@ -1528,34 +1727,38 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-
const VISIBLE = "visible";
const VISIBILITY_CHANGE_EVENT = "visibilitychange";
-
/**
* Component wrapper used to send telemetry pings on every impression.
*/
+
class ImpressionsWrapper extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
// This sends an event when a user sees a set of new content. If content
// changes while the page is hidden (i.e. preloaded or on a hidden tab),
// only send the event if the page becomes visible again.
sendImpressionOrAddListener() {
if (this.props.document.visibilityState === VISIBLE) {
- this.props.sendImpression({ id: this.props.id });
+ this.props.sendImpression({
+ id: this.props.id
+ });
} else {
// We should only ever send the latest impression stats ping, so remove any
// older listeners.
if (this._onVisibilityChange) {
this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
- }
+ } // When the page becomes visible, send the impression stats ping if the section isn't collapsed.
+
- // When the page becomes visible, send the impression stats ping if the section isn't collapsed.
this._onVisibilityChange = () => {
if (this.props.document.visibilityState === VISIBLE) {
- this.props.sendImpression({ id: this.props.id });
+ this.props.sendImpression({
+ id: this.props.id
+ });
this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
};
+
this.props.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
}
@@ -1581,8 +1784,8 @@ class ImpressionsWrapper extends react__WEBPACK_IMPORTED_MODULE_0___default.a.Pu
render() {
return this.props.children;
}
-}
+}
ImpressionsWrapper.defaultProps = {
document: global.document,
sendOnMount: true
@@ -1611,7 +1814,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(13);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -1623,7 +1826,9 @@ class OnboardingCard extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCo
}
onClick() {
- const { props } = this;
+ const {
+ props
+ } = this;
const ping = {
event: "CLICK_BUTTON",
message_id: props.id,
@@ -1634,66 +1839,46 @@ class OnboardingCard extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCo
}
render() {
- const { content } = this.props;
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "div",
- { className: "onboardingMessage" },
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", { className: `onboardingMessageImage ${content.icon}` }),
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "div",
- { className: "onboardingContent" },
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "span",
- null,
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "h3",
- null,
- " ",
- content.title,
- " "
- ),
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "p",
- null,
- " ",
- content.text,
- " "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "span",
- null,
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "button",
- { tabIndex: "1", className: "button onboardingButton", onClick: this.onClick },
- " ",
- content.primary_button.label,
- " "
- )
- )
- )
- );
+ const {
+ content
+ } = this.props;
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+ className: "onboardingMessage"
+ }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+ className: `onboardingMessageImage ${content.icon}`
+ }), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+ className: "onboardingContent"
+ }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("h3", null, " ", content.title, " "), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("p", null, " ", content.text, " ")), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("button", {
+ tabIndex: "1",
+ className: "button onboardingButton",
+ onClick: this.onClick
+ }, " ", content.primary_button.label, " "))));
}
+
}
class OnboardingMessage extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
render() {
- const { props } = this;
- const { button_label, header } = props.extraTemplateStrings;
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- _components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_0__["ModalOverlay"],
- _extends({}, props, { button_label: button_label, title: header }),
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "div",
- { className: "onboardingMessageContainer" },
- props.bundle.map(message => react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(OnboardingCard, _extends({ key: message.id,
- sendUserActionTelemetry: props.sendUserActionTelemetry,
- onAction: props.onAction,
- UISurface: props.UISurface
- }, message)))
- )
- );
+ const {
+ props
+ } = this;
+ const {
+ button_label,
+ header
+ } = props.extraTemplateStrings;
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_0__["ModalOverlay"], _extends({}, props, {
+ button_label: button_label,
+ title: header
+ }), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+ className: "onboardingMessageContainer"
+ }, props.bundle.map(message => react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(OnboardingCard, _extends({
+ key: message.id,
+ sendUserActionTelemetry: props.sendUserActionTelemetry,
+ onAction: props.onAction,
+ UISurface: props.UISurface
+ }, message)))));
}
+
}
/***/ }),
@@ -1706,50 +1891,42 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-
class ModalOverlay extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
componentWillMount() {
- this.setState({ active: true });
+ this.setState({
+ active: true
+ });
document.body.classList.add("modal-open");
}
componentWillUnmount() {
document.body.classList.remove("modal-open");
- this.setState({ active: false });
+ this.setState({
+ active: false
+ });
}
render() {
- const { active } = this.state;
- const { title, button_label } = this.props;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", { className: `modalOverlayOuter ${active ? "active" : ""}` }),
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- { className: `modalOverlayInner ${active ? "active" : ""}` },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "h2",
- null,
- " ",
- title,
- " "
- ),
- this.props.children,
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- { className: "footer" },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "button",
- { tabIndex: "2", onClick: this.props.onDoneButton, className: "button primary modalButton" },
- " ",
- button_label,
- " "
- )
- )
- )
- );
+ const {
+ active
+ } = this.state;
+ const {
+ title,
+ button_label
+ } = this.props;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: `modalOverlayOuter ${active ? "active" : ""}`
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: `modalOverlayInner ${active ? "active" : ""}`
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", null, " ", title, " "), this.props.children, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "footer"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
+ tabIndex: "2",
+ onClick: this.props.onDoneButton,
+ className: "button primary modalButton"
+ }, " ", button_label, " "))));
}
+
}
/***/ }),
@@ -1770,7 +1947,6 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _components_RichText_RichText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(16);
-
class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
constructor(props) {
super(props);
@@ -1792,74 +1968,45 @@ class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCompo
}
renderText() {
- const customElement = react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("img", { src: this.props.content.addon_icon, width: "20px", height: "20px" });
+ const customElement = react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("img", {
+ src: this.props.content.addon_icon,
+ width: "20px",
+ height: "20px"
+ });
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_RichText_RichText__WEBPACK_IMPORTED_MODULE_1__["RichText"], {
- customElements: { icon: customElement },
+ customElements: {
+ icon: customElement
+ },
amo_html: this.props.content.text,
- localization_id: "amo_html" });
+ localization_id: "amo_html"
+ });
}
render() {
- const { content } = this.props;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- { className: "ReturnToAMOOverlay" },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "h2",
- null,
- " ",
- content.header,
- " "
- ),
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- { className: "ReturnToAMOContainer" },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- { className: "ReturnToAMOAddonContents" },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "p",
- null,
- " ",
- content.title,
- " "
- ),
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "div",
- { className: "ReturnToAMOText" },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "span",
- null,
- " ",
- this.renderText(),
- " "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "button",
- { onClick: this.onClickAddExtension, className: "puffy blue ReturnToAMOAddExtension" },
- " ",
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", { className: "icon icon-add" }),
- " ",
- content.primary_button.label,
- " "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", { className: "ReturnToAMOIcon" })
- ),
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "button",
- { onClick: this.onBlockButton, className: "default grey ReturnToAMOGetStarted" },
- " ",
- content.secondary_button.label,
- " "
- )
- )
- );
+ const {
+ content
+ } = this.props;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "ReturnToAMOOverlay"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", null, " ", content.header, " "), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "ReturnToAMOContainer"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "ReturnToAMOAddonContents"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, " ", content.title, " "), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "ReturnToAMOText"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", null, " ", this.renderText(), " ")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
+ onClick: this.onClickAddExtension,
+ className: "puffy blue ReturnToAMOAddExtension"
+ }, " ", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
+ className: "icon icon-add"
+ }), " ", content.primary_button.label, " ")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "ReturnToAMOIcon"
+ })), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
+ onClick: this.onBlockButton,
+ className: "default grey ReturnToAMOGetStarted"
+ }, " ", content.secondary_button.label, " ")));
}
+
}
/***/ }),
@@ -1875,14 +2022,13 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _rich_text_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
/* harmony import */ var _template_utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(17);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
+ // Elements allowed in snippet content
-// Elements allowed in snippet content
const ALLOWED_TAGS = {
b: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("b", null),
i: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("i", null),
@@ -1891,48 +2037,46 @@ const ALLOWED_TAGS = {
em: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("em", null),
br: react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("br", null)
};
-
/**
* Transform an object (tag name: {url}) into (tag name: anchor) where the url
* is used as href, in order to render links inside a Fluent.Localized component.
*/
+
function convertLinks(links, sendClick, doNotAutoBlock, openNewWindow = false) {
if (links) {
return Object.keys(links).reduce((acc, linkTag) => {
- const { action } = links[linkTag];
- // Setting the value to false will not include the attribute in the anchor
- const url = action ? false : Object(_template_utils__WEBPACK_IMPORTED_MODULE_3__["safeURI"])(links[linkTag].url);
+ const {
+ action
+ } = links[linkTag]; // Setting the value to false will not include the attribute in the anchor
- acc[linkTag] = react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("a", { href: url,
+ const url = action ? false : Object(_template_utils__WEBPACK_IMPORTED_MODULE_3__["safeURI"])(links[linkTag].url);
+ acc[linkTag] = react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("a", {
+ href: url,
target: openNewWindow ? "_blank" : "",
"data-metric": links[linkTag].metric,
"data-action": action,
"data-args": links[linkTag].args,
"data-do_not_autoblock": doNotAutoBlock,
- onClick: sendClick });
+ onClick: sendClick
+ });
return acc;
}, {});
}
return null;
}
-
/**
* Message wrapper used to sanitize markup and render HTML.
*/
+
function RichText(props) {
if (!_rich_text_strings__WEBPACK_IMPORTED_MODULE_2__["RICH_TEXT_KEYS"].includes(props.localization_id)) {
throw new Error(`ASRouter: ${props.localization_id} is not a valid rich text property. If you want it to be processed, you need to add it to asrouter/rich-text-strings.js`);
}
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- fluent_react__WEBPACK_IMPORTED_MODULE_0__["Localized"],
- _extends({ id: props.localization_id }, ALLOWED_TAGS, props.customElements, convertLinks(props.links, props.sendClick, props.doNotAutoBlock, props.openNewWindow)),
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "span",
- null,
- props.text
- )
- );
+
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(fluent_react__WEBPACK_IMPORTED_MODULE_0__["Localized"], _extends({
+ id: props.localization_id
+ }, ALLOWED_TAGS, props.customElements, convertLinks(props.links, props.sendClick, props.doNotAutoBlock, props.openNewWindow)), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, props.text));
}
/***/ }),
@@ -1946,11 +2090,16 @@ function safeURI(url) {
if (!url) {
return "";
}
- const { protocol } = new URL(url);
+
+ const {
+ protocol
+ } = new URL(url);
const isAllowed = ["http:", "https:", "data:", "resource:", "chrome:"].includes(protocol);
+
if (!isAllowed) {
console.warn(`The protocol ${protocol} is not allowed for template URLs.`); // eslint-disable-line no-console
}
+
return isAllowed ? url : "";
}
@@ -1999,8 +2148,9 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_redux__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_3__);
-function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
+function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
@@ -2015,7 +2165,6 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
this.initScene = this.initScene.bind(this);
this.removeOverlay = this.removeOverlay.bind(this);
this.onInputInvalid = this.onInputInvalid.bind(this);
-
this.state = {
emailInput: "",
overlayRemoved: false,
@@ -2033,15 +2182,36 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
try {
_this.didFetch = true;
const fxaParams = "entrypoint=activity-stream-firstrun&utm_source=activity-stream&utm_campaign=firstrun&form_type=email";
- const response = yield fetch(`${_this.props.fxa_endpoint}/metrics-flow?${fxaParams}`, { credentials: "omit" });
+ const response = yield fetch(`${_this.props.fxa_endpoint}/metrics-flow?${fxaParams}`, {
+ credentials: "omit"
+ });
+
if (response.status === 200) {
- const { flowId, flowBeginTime } = yield response.json();
- _this.setState({ flowId, flowBeginTime });
+ const {
+ flowId,
+ flowBeginTime
+ } = yield response.json();
+
+ _this.setState({
+ flowId,
+ flowBeginTime
+ });
} else {
- _this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT, data: { event: "FXA_METRICS_FETCH_ERROR", value: response.status } }));
+ _this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT,
+ data: {
+ event: "FXA_METRICS_FETCH_ERROR",
+ value: response.status
+ }
+ }));
}
} catch (error) {
- _this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT, data: { event: "FXA_METRICS_ERROR" } }));
+ _this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT,
+ data: {
+ event: "FXA_METRICS_ERROR"
+ }
+ }));
}
}
})();
@@ -2055,7 +2225,9 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
// Timeout to allow the scene to render once before attaching the attribute
// to trigger the animation.
setTimeout(() => {
- this.setState({ show: true });
+ this.setState({
+ show: true
+ });
this.props.onReady();
}, 10);
}
@@ -2063,39 +2235,55 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
removeOverlay() {
window.removeEventListener("visibilitychange", this.removeOverlay);
document.body.classList.remove("hide-main", "fxa");
- this.setState({ show: false });
+ this.setState({
+ show: false
+ });
this.props.onBlock();
setTimeout(() => {
// Allow scrolling and fully remove overlay after animation finishes.
document.body.classList.remove("welcome");
- this.setState({ overlayRemoved: true });
+ this.setState({
+ overlayRemoved: true
+ });
}, 400);
}
onInputChange(e) {
let error = e.target.previousSibling;
- this.setState({ emailInput: e.target.value });
+ this.setState({
+ emailInput: e.target.value
+ });
error.classList.remove("active");
e.target.classList.remove("invalid");
}
onSubmit() {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent(Object.assign({ event: "SUBMIT_EMAIL" }, this._getFormInfo())));
-
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: "SUBMIT_EMAIL",
+ ...this._getFormInfo()
+ }));
window.addEventListener("visibilitychange", this.removeOverlay);
}
clickSkip() {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent(Object.assign({ event: "SKIPPED_SIGNIN" }, this._getFormInfo())));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: "SKIPPED_SIGNIN",
+ ...this._getFormInfo()
+ }));
this.removeOverlay();
}
-
/**
* Report to telemetry additional information about the form submission.
*/
+
+
_getFormInfo() {
- const value = { has_flow_params: this.state.flowId.length > 0 };
- return { value };
+ const value = {
+ has_flow_params: this.state.flowId.length > 0
+ };
+ return {
+ value
+ };
}
onInputInvalid(e) {
@@ -2103,6 +2291,7 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
error.classList.add("active");
e.target.classList.add("invalid");
e.preventDefault(); // Override built-in form validation popup
+
e.target.focus();
}
@@ -2113,105 +2302,135 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
return null;
}
- let termsLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "a",
- { href: `${this.props.fxa_endpoint}/legal/terms`, target: "_blank", rel: "noopener noreferrer" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_terms_of_service" })
- );
- let privacyLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "a",
- { href: `${this.props.fxa_endpoint}/legal/privacy`, target: "_blank", rel: "noopener noreferrer" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_privacy_notice" })
- );
-
- return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: `overlay-wrapper ${this.state.show ? "show" : ""}` },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", { className: "background" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "firstrun-scene" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "fxaccounts-container" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "firstrun-left-divider" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "h1",
- { className: "firstrun-title" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_title" })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "p",
- { className: "firstrun-content" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_content" })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "a",
- { className: "firstrun-link", href: "https://www.mozilla.org/firefox/features/sync/", target: "_blank", rel: "noopener noreferrer" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_learn_more_link" })
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "firstrun-sign-in" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "p",
- { className: "form-header" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_form_header" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "sub-header" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_form_sub_header" })
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "form",
- { method: "get", action: this.props.fxa_endpoint, target: "_blank", rel: "noopener noreferrer", onSubmit: this.onSubmit },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "service", type: "hidden", value: "sync" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "action", type: "hidden", value: "email" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "context", type: "hidden", value: "fx_desktop_v3" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "entrypoint", type: "hidden", value: "activity-stream-firstrun" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "utm_source", type: "hidden", value: "activity-stream" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "utm_campaign", type: "hidden", value: "firstrun" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "flow_id", type: "hidden", value: this.state.flowId }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { name: "flow_begin_time", type: "hidden", value: this.state.flowBeginTime }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "error" },
- this.props.intl.formatMessage({ id: "firstrun_invalid_input" })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", { className: "email-input", name: "email", type: "email", required: "true", onInvalid: this.onInputInvalid, placeholder: this.props.intl.formatMessage({ id: "firstrun_email_input_placeholder" }), onChange: this.onInputChange }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "extra-links" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
- id: "firstrun_extra_legal_links",
- values: {
- terms: termsLink,
- privacy: privacyLink
- } })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "button",
- { className: "continue-button", type: "submit" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_continue_to_login" })
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "button",
- { className: "skip-button", disabled: !!this.state.emailInput, onClick: this.clickSkip },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "firstrun_skip_login" })
- )
- )
- )
- )
- );
- }
-}
-
-const getState = state => ({ fxa_endpoint: state.Prefs.values.fxa_endpoint });
+ let termsLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
+ href: `${this.props.fxa_endpoint}/legal/terms`,
+ target: "_blank",
+ rel: "noopener noreferrer"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_terms_of_service"
+ }));
+ let privacyLink = react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
+ href: `${this.props.fxa_endpoint}/legal/privacy`,
+ target: "_blank",
+ rel: "noopener noreferrer"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_privacy_notice"
+ }));
+ return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: `overlay-wrapper ${this.state.show ? "show" : ""}`
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "background"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "firstrun-scene"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "fxaccounts-container"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "firstrun-left-divider"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("h1", {
+ className: "firstrun-title"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_title"
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", {
+ className: "firstrun-content"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_content"
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
+ className: "firstrun-link",
+ href: "https://www.mozilla.org/firefox/features/sync/",
+ target: "_blank",
+ rel: "noopener noreferrer"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_learn_more_link"
+ }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "firstrun-sign-in"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", {
+ className: "form-header"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_form_header"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "sub-header"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_form_sub_header"
+ }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("form", {
+ method: "get",
+ action: this.props.fxa_endpoint,
+ target: "_blank",
+ rel: "noopener noreferrer",
+ onSubmit: this.onSubmit
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "service",
+ type: "hidden",
+ value: "sync"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "action",
+ type: "hidden",
+ value: "email"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "context",
+ type: "hidden",
+ value: "fx_desktop_v3"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "entrypoint",
+ type: "hidden",
+ value: "activity-stream-firstrun"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "utm_source",
+ type: "hidden",
+ value: "activity-stream"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "utm_campaign",
+ type: "hidden",
+ value: "firstrun"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "flow_id",
+ type: "hidden",
+ value: this.state.flowId
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ name: "flow_begin_time",
+ type: "hidden",
+ value: this.state.flowBeginTime
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "error"
+ }, this.props.intl.formatMessage({
+ id: "firstrun_invalid_input"
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("input", {
+ className: "email-input",
+ name: "email",
+ type: "email",
+ required: "true",
+ onInvalid: this.onInputInvalid,
+ placeholder: this.props.intl.formatMessage({
+ id: "firstrun_email_input_placeholder"
+ }),
+ onChange: this.onInputChange
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "extra-links"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_extra_legal_links",
+ values: {
+ terms: termsLink,
+ privacy: privacyLink
+ }
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+ className: "continue-button",
+ type: "submit"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_continue_to_login"
+ }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+ className: "skip-button",
+ disabled: !!this.state.emailInput,
+ onClick: this.clickSkip
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "firstrun_skip_login"
+ }))))));
+ }
+
+}
+
+const getState = state => ({
+ fxa_endpoint: state.Prefs.values.fxa_endpoint
+});
+
const StartupOverlay = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(getState)(Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_StartupOverlay));
/***/ }),
@@ -2245,8 +2464,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_10__);
/* harmony import */ var content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(47);
/* harmony import */ var content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(49);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -2262,22 +2480,27 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
let didLogDevtoolsHelpText = false;
-
-const PrefsButton = Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(props => react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- "div",
- { className: "prefs-button" },
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("button", { className: "icon icon-settings", onClick: props.onClick, title: props.intl.formatMessage({ id: "settings_pane_button_label" }) })
-));
-
-// Add the locale data for pluralization and relative-time formatting for now,
+const PrefsButton = Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(props => react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
+ className: "prefs-button"
+}, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("button", {
+ className: "icon icon-settings",
+ onClick: props.onClick,
+ title: props.intl.formatMessage({
+ id: "settings_pane_button_label"
+ })
+}))); // Add the locale data for pluralization and relative-time formatting for now,
// this just uses english locale data. We can make this more sophisticated if
// more features are needed.
-function addLocaleDataForReactIntl(locale) {
- Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["addLocaleData"])([{ locale, parentLocale: "en" }]);
-}
-// Returns a function will not be continuously triggered when called. The
+function addLocaleDataForReactIntl(locale) {
+ Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["addLocaleData"])([{
+ locale,
+ parentLocale: "en"
+ }]);
+} // Returns a function will not be continuously triggered when called. The
// function will be triggered if called again after `wait` milliseconds.
+
+
function debounce(func, wait) {
let timer;
return (...args) => {
@@ -2296,8 +2519,11 @@ function debounce(func, wait) {
class _Base extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComponent {
componentWillMount() {
- const { locale } = this.props;
+ const {
+ locale
+ } = this.props;
addLocaleDataForReactIntl(locale);
+
if (this.props.isFirstrun) {
global.document.body.classList.add("welcome", "hide-main");
}
@@ -2308,8 +2534,12 @@ class _Base extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComponent
// 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(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST }));
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].PAGE_PRERENDERED }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_STATE_REQUEST
+ }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].PAGE_PRERENDERED
+ }));
}
}
@@ -2322,24 +2552,32 @@ class _Base extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComponent
}
updateTheme() {
- const bodyClassName = ["activity-stream",
- // If we skipped the about:welcome overlay and removed the CSS classes
+ const bodyClassName = ["activity-stream", // If we skipped the about:welcome overlay and removed the CSS classes
// we don't want to add them back to the Activity Stream view
document.body.classList.contains("welcome") ? "welcome" : "", document.body.classList.contains("hide-main") ? "hide-main" : ""].filter(v => v).join(" ");
global.document.body.className = bodyClassName;
}
render() {
- const { props } = this;
- const { App, locale, strings } = props;
- const { initialized } = App;
-
+ const {
+ props
+ } = this;
+ const {
+ App,
+ locale,
+ strings
+ } = props;
+ const {
+ initialized
+ } = App;
const prefs = props.Prefs.values;
+
if (prefs["asrouter.devtoolsEnabled"]) {
if (window.location.hash.startsWith("#asrouter") || window.location.hash.startsWith("#devtools")) {
return react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ASRouterAdmin_ASRouterAdmin__WEBPACK_IMPORTED_MODULE_2__["ASRouterAdmin"], null);
} else if (!didLogDevtoolsHelpText) {
console.log("Activity Stream devtools enabled. To access visit %cabout:newtab#devtools", "font-weight: bold"); // eslint-disable-line no-console
+
didLogDevtoolsHelpText = true;
}
}
@@ -2348,24 +2586,23 @@ class _Base extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComponent
return null;
}
- return react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- react_intl__WEBPACK_IMPORTED_MODULE_1__["IntlProvider"],
- { locale: locale, messages: strings },
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"],
- { className: "base-content-fallback" },
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(BaseContent, this.props)
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["IntlProvider"], {
+ locale: locale,
+ messages: strings
+ }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"], {
+ className: "base-content-fallback"
+ }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(BaseContent, this.props)));
}
-}
+}
class BaseContent extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComponent {
constructor(props) {
super(props);
this.openPreferences = this.openPreferences.bind(this);
this.onWindowScroll = debounce(this.onWindowScroll.bind(this), 5);
- this.state = { fixedSearch: false };
+ this.state = {
+ fixedSearch: false
+ };
}
componentDidMount() {
@@ -2378,72 +2615,62 @@ class BaseContent extends react__WEBPACK_IMPORTED_MODULE_10___default.a.PureComp
onWindowScroll() {
const SCROLL_THRESHOLD = 34;
+
if (global.scrollY > SCROLL_THRESHOLD && !this.state.fixedSearch) {
- this.setState({ fixedSearch: true });
+ this.setState({
+ fixedSearch: true
+ });
} else if (global.scrollY <= SCROLL_THRESHOLD && this.state.fixedSearch) {
- this.setState({ fixedSearch: false });
+ this.setState({
+ fixedSearch: false
+ });
}
}
openPreferences() {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SETTINGS_OPEN }));
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: "OPEN_NEWTAB_PREFS" }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SETTINGS_OPEN
+ }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: "OPEN_NEWTAB_PREFS"
+ }));
}
render() {
- const { props } = this;
- const { App } = props;
- const { initialized } = App;
+ const {
+ props
+ } = this;
+ const {
+ App
+ } = props;
+ const {
+ initialized
+ } = App;
const prefs = props.Prefs.values;
-
const shouldBeFixedToTop = common_PrerenderData_jsm__WEBPACK_IMPORTED_MODULE_9__["PrerenderData"].arePrefsValid(name => prefs[name]);
const noSectionsEnabled = !prefs["feeds.topsites"] && props.Sections.filter(section => section.enabled).length === 0;
const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled;
const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
-
const outerClassName = ["outer-wrapper", isDiscoveryStream && "ds-outer-wrapper-search-alignment", isDiscoveryStream && "ds-outer-wrapper-breakpoint-override", shouldBeFixedToTop && "fixed-to-top", prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search", prefs.showSearch && noSectionsEnabled && "only-search"].filter(v => v).join(" ");
-
- return react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- "div",
- { className: outerClassName },
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- "main",
- null,
- prefs.showSearch && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- "div",
- { className: "non-collapsible-section" },
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"],
- null,
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_11__["Search"], _extends({ showLogo: noSectionsEnabled, handoffEnabled: searchHandoffEnabled }, props.Search))
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- "div",
- { className: `body-wrapper${initialized ? " on" : ""}` },
- !isDiscoveryStream && !prefs.migrationExpired && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- "div",
- { className: "non-collapsible-section" },
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ManualMigration_ManualMigration__WEBPACK_IMPORTED_MODULE_8__["ManualMigration"], null)
- ),
- isDiscoveryStream ? react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(
- content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"],
- { className: "borderless-error" },
- prefs.darkModeMessage && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_DarkModeMessage_DarkModeMessage__WEBPACK_IMPORTED_MODULE_5__["DarkModeMessage"], null),
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_6__["DiscoveryStreamBase"], null)
- ) : react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_12__["Sections"], null),
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(PrefsButton, { onClick: this.openPreferences })
- ),
- react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ConfirmDialog_ConfirmDialog__WEBPACK_IMPORTED_MODULE_3__["ConfirmDialog"], null)
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
+ className: outerClassName
+ }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("main", null, prefs.showSearch && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
+ className: "non-collapsible-section"
+ }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"], null, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_Search_Search__WEBPACK_IMPORTED_MODULE_11__["Search"], _extends({
+ showLogo: noSectionsEnabled,
+ handoffEnabled: searchHandoffEnabled
+ }, props.Search)))), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
+ className: `body-wrapper${initialized ? " on" : ""}`
+ }, !isDiscoveryStream && !prefs.migrationExpired && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement("div", {
+ className: "non-collapsible-section"
+ }, react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ManualMigration_ManualMigration__WEBPACK_IMPORTED_MODULE_8__["ManualMigration"], null)), isDiscoveryStream ? react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_7__["ErrorBoundary"], {
+ className: "borderless-error"
+ }, prefs.darkModeMessage && react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_DarkModeMessage_DarkModeMessage__WEBPACK_IMPORTED_MODULE_5__["DarkModeMessage"], null), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_6__["DiscoveryStreamBase"], null)) : react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_12__["Sections"], null), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(PrefsButton, {
+ onClick: this.openPreferences
+ })), react__WEBPACK_IMPORTED_MODULE_10___default.a.createElement(content_src_components_ConfirmDialog_ConfirmDialog__WEBPACK_IMPORTED_MODULE_3__["ConfirmDialog"], null))));
}
-}
+}
const Base = Object(react_redux__WEBPACK_IMPORTED_MODULE_4__["connect"])(state => ({
App: state.App,
Prefs: state.Prefs,
@@ -2470,7 +2697,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(10);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _SimpleHashRouter__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(27);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -2479,18 +2706,18 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
-const Row = props => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- _extends({ className: "message-item" }, props),
- props.children
-);
+const Row = props => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", _extends({
+ className: "message-item"
+}, props), props.children);
function relativeTime(timestamp) {
if (!timestamp) {
return "";
}
+
const seconds = Math.floor((Date.now() - timestamp) / 1000);
const minutes = Math.floor((Date.now() - timestamp) / 60000);
+
if (seconds < 2) {
return "just now";
} else if (seconds < 60) {
@@ -2500,6 +2727,7 @@ function relativeTime(timestamp) {
} else if (minutes < 600) {
return `${minutes} minutes ago`;
}
+
return new Date(timestamp).toLocaleString();
}
@@ -2509,6 +2737,7 @@ const LAYOUT_VARIANTS = {
"dev-test-all": "A little bit of everything. Good layout for testing all components",
"dev-test-feeds": "Stress testing for slow feeds"
};
+
class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
constructor(props) {
super(props);
@@ -2521,7 +2750,13 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
}
setConfigValue(name, value) {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_CONFIG_SET_VALUE, data: { name, value } }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_CONFIG_SET_VALUE,
+ data: {
+ name,
+ value
+ }
+ }));
}
onEnableToggle(event) {
@@ -2530,49 +2765,18 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
changeEndpointVariant(event) {
const endpoint = this.props.state.config.layout_endpoint;
+
if (endpoint) {
this.setConfigValue("layout_endpoint", endpoint.replace(/layout_variant=.+/, `layout_variant=${event.target.value}`));
}
}
renderComponent(width, component) {
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- Row,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Type"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- component.type
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- Row,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Width"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- width
- )
- ),
- component.feed && this.renderFeed(component.feed)
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Type"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, component.type)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Width"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, width)), component.feed && this.renderFeed(component.feed)));
}
isCurrentVariant(id) {
@@ -2582,147 +2786,67 @@ class DiscoveryStreamAdmin extends react__WEBPACK_IMPORTED_MODULE_4___default.a.
}
renderFeed(feed) {
- const { feeds } = this.props.state;
+ const {
+ feeds
+ } = this.props.state;
+
if (!feed.url) {
return null;
}
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- Row,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Feed url"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- feed.url
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- Row,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Data last fetched"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- relativeTime(feeds.data[feed.url] ? feeds.data[feed.url].lastUpdated : null) || "(no data)"
- )
- )
- );
+
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Feed url"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, feed.url)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Data last fetched"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, relativeTime(feeds.data[feed.url] ? feeds.data[feed.url].lastUpdated : null) || "(no data)")));
}
render() {
- const { isOptedOut } = this;
-
- const { config, lastUpdated, layout } = this.props.state;
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "dsEnabled" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "checkbox", checked: config.enabled, onChange: this.onEnableToggle }),
- " enabled",
- isOptedOut ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- { className: "optOutNote" },
- "(Note: User has opted-out. Check this box to reset)"
- ) : ""
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h3",
- null,
- "Endpoint variant"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "p",
- null,
- "You can also change this manually by changing this pref: ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "code",
- null,
- "browser.newtabpage.activity-stream.discoverystream.config"
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- { style: config.enabled ? null : { opacity: 0.5 } },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- Object.keys(LAYOUT_VARIANTS).map(id => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- Row,
- { key: id },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "radio", value: id, checked: this.isCurrentVariant(id), onChange: this.changeEndpointVariant })
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- id
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- LAYOUT_VARIANTS[id]
- )
- ))
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h3",
- null,
- "Caching info"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- { style: config.enabled ? null : { opacity: 0.5 } },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- Row,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Data last fetched"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- relativeTime(lastUpdated) || "(no data)"
- )
- )
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h3",
- null,
- "Layout"
- ),
- layout.map((row, rowIndex) => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { key: `row-${rowIndex}` },
- row.components.map((component, componentIndex) => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { key: `component-${componentIndex}`, className: "ds-component" },
- this.renderComponent(row.width, component)
- ))
- ))
- );
+ const {
+ isOptedOut
+ } = this;
+ const {
+ config,
+ lastUpdated,
+ layout
+ } = this.props.state;
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "dsEnabled"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "checkbox",
+ checked: config.enabled,
+ onChange: this.onEnableToggle
+ }), " enabled", isOptedOut ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ className: "optOutNote"
+ }, "(Note: User has opted-out. Check this box to reset)") : ""), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Endpoint variant"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", null, "You can also change this manually by changing this pref: ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("code", null, "browser.newtabpage.activity-stream.discoverystream.config")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", {
+ style: config.enabled ? null : {
+ opacity: 0.5
+ }
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, Object.keys(LAYOUT_VARIANTS).map(id => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, {
+ key: id
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "radio",
+ value: id,
+ checked: this.isCurrentVariant(id),
+ onChange: this.changeEndpointVariant
+ })), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, id), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, LAYOUT_VARIANTS[id]))))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Caching info"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", {
+ style: config.enabled ? null : {
+ opacity: 0.5
+ }
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(Row, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Data last fetched"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, relativeTime(lastUpdated) || "(no data)")))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h3", null, "Layout"), layout.map((row, rowIndex) => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ key: `row-${rowIndex}`
+ }, row.components.map((component, componentIndex) => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ key: `component-${componentIndex}`,
+ className: "ds-component"
+ }, this.renderComponent(row.width, component))))));
}
+
}
class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
@@ -2755,22 +2879,34 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
};
}
- onMessage({ data: action }) {
+ onMessage({
+ data: action
+ }) {
if (action.type === "ADMIN_SET_STATE") {
this.setState(action.data);
+
if (!this.state.stringTargetingParameters) {
const stringTargetingParameters = {};
+
for (const param of Object.keys(action.data.targetingParameters)) {
stringTargetingParameters[param] = JSON.stringify(action.data.targetingParameters[param], null, 2);
}
- this.setState({ stringTargetingParameters });
+
+ this.setState({
+ stringTargetingParameters
+ });
}
}
}
componentWillMount() {
const endpoint = _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].getPreviewEndpoint();
- _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({ type: "ADMIN_CONNECT_STATE", data: { endpoint } });
+ _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
+ type: "ADMIN_CONNECT_STATE",
+ data: {
+ endpoint
+ }
+ });
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].addListener(this.onMessage);
}
@@ -2788,6 +2924,7 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
let bundle = this.findOtherBundledMessagesOfSameTemplate(msg.template);
return () => _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].blockBundle(bundle);
}
+
return () => _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].blockById(msg.id);
}
@@ -2797,6 +2934,7 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
let bundle = this.findOtherBundledMessagesOfSameTemplate(msg.template);
return () => _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].unblockBundle(bundle);
}
+
return () => _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].unblockById(msg.id);
}
@@ -2805,19 +2943,25 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
}
expireCache() {
- _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({ type: "EXPIRE_QUERY_CACHE" });
+ _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
+ type: "EXPIRE_QUERY_CACHE"
+ });
}
resetPref() {
- _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({ type: "RESET_PROVIDER_PREF" });
+ _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
+ type: "RESET_PROVIDER_PREF"
+ });
}
handleExpressionEval() {
const context = {};
+
for (const param of Object.keys(this.state.stringTargetingParameters)) {
const value = this.state.stringTargetingParameters[param];
context[param] = value ? JSON.parse(value) : null;
}
+
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
type: "EVALUATE_JEXL_EXPRESSION",
data: {
@@ -2828,18 +2972,28 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
}
onChangeTargetingParameters(event) {
- const { name } = event.target;
- const { value } = event.target;
-
- this.setState(({ stringTargetingParameters }) => {
+ const {
+ name
+ } = event.target;
+ const {
+ value
+ } = event.target;
+ this.setState(({
+ stringTargetingParameters
+ }) => {
let targetingParametersError = null;
- const updatedParameters = Object.assign({}, stringTargetingParameters);
+ const updatedParameters = { ...stringTargetingParameters
+ };
updatedParameters[name] = value;
+
try {
JSON.parse(value);
} catch (e) {
console.log(`Error parsing value of parameter ${name}`); // eslint-disable-line no-console
- targetingParametersError = { id: name };
+
+ targetingParametersError = {
+ id: name
+ };
}
return {
@@ -2854,72 +3008,106 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
handleEnabledToggle(event) {
const provider = this.state.providerPrefs.find(p => p.id === event.target.dataset.provider);
const userPrefInfo = this.state.userPrefs;
-
const isUserEnabled = provider.id in userPrefInfo ? userPrefInfo[provider.id] : true;
const isSystemEnabled = provider.enabled;
const isEnabling = event.target.checked;
if (isEnabling) {
if (!isUserEnabled) {
- _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({ type: "SET_PROVIDER_USER_PREF", data: { id: provider.id, value: true } });
+ _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
+ type: "SET_PROVIDER_USER_PREF",
+ data: {
+ id: provider.id,
+ value: true
+ }
+ });
}
+
if (!isSystemEnabled) {
- _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({ type: "ENABLE_PROVIDER", data: provider.id });
+ _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
+ type: "ENABLE_PROVIDER",
+ data: provider.id
+ });
}
} else {
- _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({ type: "DISABLE_PROVIDER", data: provider.id });
+ _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
+ type: "DISABLE_PROVIDER",
+ data: provider.id
+ });
}
- this.setState({ messageFilter: "all" });
+ this.setState({
+ messageFilter: "all"
+ });
}
handleUserPrefToggle(event) {
- const action = { type: "SET_PROVIDER_USER_PREF", data: { id: event.target.dataset.provider, value: event.target.checked } };
+ const action = {
+ type: "SET_PROVIDER_USER_PREF",
+ data: {
+ id: event.target.dataset.provider,
+ value: event.target.checked
+ }
+ };
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage(action);
- this.setState({ messageFilter: "all" });
+ this.setState({
+ messageFilter: "all"
+ });
}
onChangeMessageFilter(event) {
- this.setState({ messageFilter: event.target.value });
- }
+ this.setState({
+ messageFilter: event.target.value
+ });
+ } // Simulate a copy event that sets to clipboard all targeting paramters and values
+
- // Simulate a copy event that sets to clipboard all targeting paramters and values
onCopyTargetingParams(event) {
- const stringTargetingParameters = Object.assign({}, this.state.stringTargetingParameters);
+ const stringTargetingParameters = { ...this.state.stringTargetingParameters
+ };
+
for (const key of Object.keys(stringTargetingParameters)) {
// If the value is not set the parameter will be lost when we stringify
if (stringTargetingParameters[key] === undefined) {
stringTargetingParameters[key] = null;
}
}
+
const setClipboardData = e => {
e.preventDefault();
e.clipboardData.setData("text", JSON.stringify(stringTargetingParameters, null, 2));
document.removeEventListener("copy", setClipboardData);
- this.setState({ copiedToClipboard: true });
+ this.setState({
+ copiedToClipboard: true
+ });
};
document.addEventListener("copy", setClipboardData);
-
document.execCommand("copy");
- }
+ } // Copy all clipboard data to targeting parameters
+
- // Copy all clipboard data to targeting parameters
onPasteTargetingParams(event) {
- this.setState(({ pasteFromClipboard }) => ({
+ this.setState(({
+ pasteFromClipboard
+ }) => ({
pasteFromClipboard: !pasteFromClipboard,
newStringTargetingParameters: ""
}));
}
onNewTargetingParams(event) {
- this.setState({ newStringTargetingParameters: event.target.value });
+ this.setState({
+ newStringTargetingParameters: event.target.value
+ });
event.target.classList.remove("errorState");
this.refs.targetingParamsEval.innerText = "";
try {
const stringTargetingParameters = JSON.parse(event.target.value);
- this.setState({ stringTargetingParameters });
+ this.setState({
+ stringTargetingParameters
+ });
} catch (e) {
event.target.classList.add("errorState");
this.refs.targetingParamsEval.innerText = e.message;
@@ -2930,702 +3118,341 @@ class ASRouterAdminInner extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
const isCurrent = msg.id === this.state.lastMessageId;
const isBlocked = this.state.messageBlockList.includes(msg.id) || this.state.messageBlockList.includes(msg.campaign);
const impressions = this.state.messageImpressions[msg.id] ? this.state.messageImpressions[msg.id].length : 0;
-
let itemClassName = "message-item";
+
if (isCurrent) {
itemClassName += " current";
}
+
if (isBlocked) {
itemClassName += " blocked";
}
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- { className: itemClassName, key: msg.id },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "message-id" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- null,
- msg.id,
- " ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("br", null)
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: `button ${isBlocked ? "" : " primary"}`, onClick: isBlocked ? this.handleUnblock(msg) : this.handleBlock(msg) },
- isBlocked ? "Unblock" : "Block"
- ),
- isBlocked ? null : react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: "button", onClick: this.handleOverride(msg.id) },
- "Show"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("br", null),
- "(",
- impressions,
- " impressions)"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "message-summary" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "pre",
- null,
- JSON.stringify(msg, null, 2)
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", {
+ className: itemClassName,
+ key: msg.id
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "message-id"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", null, msg.id, " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("br", null))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: `button ${isBlocked ? "" : " primary"}`,
+ onClick: isBlocked ? this.handleUnblock(msg) : this.handleBlock(msg)
+ }, isBlocked ? "Unblock" : "Block"), isBlocked ? null : react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "button",
+ onClick: this.handleOverride(msg.id)
+ }, "Show"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("br", null), "(", impressions, " impressions)"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "message-summary"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("pre", null, JSON.stringify(msg, null, 2))));
}
renderMessages() {
if (!this.state.messages) {
return null;
}
+
const messagesToShow = this.state.messageFilter === "all" ? this.state.messages : this.state.messages.filter(message => message.provider === this.state.messageFilter);
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- messagesToShow.map(msg => this.renderMessageItem(msg))
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, messagesToShow.map(msg => this.renderMessageItem(msg))));
}
renderMessageFilter() {
if (!this.state.providers) {
return null;
}
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "p",
- null,
- "Show messages from ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "select",
- { value: this.state.messageFilter, onChange: this.onChangeMessageFilter },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "option",
- { value: "all" },
- "all providers"
- ),
- this.state.providers.map(provider => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "option",
- { key: provider.id, value: provider.id },
- provider.id
- ))
- )
- );
+
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", null, "Show messages from ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("select", {
+ value: this.state.messageFilter,
+ onChange: this.onChangeMessageFilter
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("option", {
+ value: "all"
+ }, "all providers"), this.state.providers.map(provider => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("option", {
+ key: provider.id,
+ value: provider.id
+ }, provider.id))));
}
renderTableHead() {
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "thead",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- { className: "message-item" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", { className: "min" }),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Provider ID"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- "Source"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Cohort"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Last Updated"
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", {
+ className: "message-item"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Provider ID"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, "Source"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Cohort"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Last Updated")));
}
renderProviders() {
const providersConfig = this.state.providerPrefs;
const providerInfo = this.state.providers;
const userPrefInfo = this.state.userPrefs;
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, this.renderTableHead(), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, providersConfig.map((provider, i) => {
+ const isTestProvider = provider.id === "snippets_local_testing";
+ const info = providerInfo.find(p => p.id === provider.id) || {};
+ const isUserEnabled = provider.id in userPrefInfo ? userPrefInfo[provider.id] : true;
+ const isSystemEnabled = isTestProvider || provider.enabled;
+ let label = "local";
+
+ if (provider.type === "remote") {
+ label = react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", null, "endpoint (", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+ className: "providerUrl",
+ target: "_blank",
+ href: info.url,
+ rel: "noopener noreferrer"
+ }, info.url), ")");
+ } else if (provider.type === "remote-settings") {
+ label = `remote settings (${provider.bucket})`;
+ }
+
+ let reasonsDisabled = [];
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- null,
- this.renderTableHead(),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- providersConfig.map((provider, i) => {
- const isTestProvider = provider.id === "snippets_local_testing";
- const info = providerInfo.find(p => p.id === provider.id) || {};
- const isUserEnabled = provider.id in userPrefInfo ? userPrefInfo[provider.id] : true;
- const isSystemEnabled = isTestProvider || provider.enabled;
-
- let label = "local";
- if (provider.type === "remote") {
- label = react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- null,
- "endpoint (",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "a",
- { className: "providerUrl", target: "_blank", href: info.url, rel: "noopener noreferrer" },
- info.url
- ),
- ")"
- );
- } else if (provider.type === "remote-settings") {
- label = `remote settings (${provider.bucket})`;
- }
+ if (!isSystemEnabled) {
+ reasonsDisabled.push("system pref");
+ }
- let reasonsDisabled = [];
- if (!isSystemEnabled) {
- reasonsDisabled.push("system pref");
- }
- if (!isUserEnabled) {
- reasonsDisabled.push("user pref");
- }
- if (reasonsDisabled.length) {
- label = `disabled via ${reasonsDisabled.join(", ")}`;
- }
-
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- { className: "message-item", key: i },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- isTestProvider ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "checkbox", disabled: true, readOnly: true, checked: true }) : react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "checkbox", "data-provider": provider.id, checked: isUserEnabled && isSystemEnabled, onChange: this.handleEnabledToggle })
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- provider.id
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- { className: `sourceLabel${isUserEnabled && isSystemEnabled ? "" : " isDisabled"}` },
- label
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- provider.cohort
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { style: { whiteSpace: "nowrap" } },
- info.lastUpdated ? new Date(info.lastUpdated).toLocaleString() : ""
- )
- );
- })
- )
- );
+ if (!isUserEnabled) {
+ reasonsDisabled.push("user pref");
+ }
+
+ if (reasonsDisabled.length) {
+ label = `disabled via ${reasonsDisabled.join(", ")}`;
+ }
+
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", {
+ className: "message-item",
+ key: i
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, isTestProvider ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "checkbox",
+ disabled: true,
+ readOnly: true,
+ checked: true
+ }) : react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "checkbox",
+ "data-provider": provider.id,
+ checked: isUserEnabled && isSystemEnabled,
+ onChange: this.handleEnabledToggle
+ })), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, provider.id), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ className: `sourceLabel${isUserEnabled && isSystemEnabled ? "" : " isDisabled"}`
+ }, label)), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, provider.cohort), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ style: {
+ whiteSpace: "nowrap"
+ }
+ }, info.lastUpdated ? new Date(info.lastUpdated).toLocaleString() : ""));
+ })));
}
renderPasteModal() {
if (!this.state.pasteFromClipboard) {
return null;
}
+
const errors = this.refs.targetingParamsEval && this.refs.targetingParamsEval.innerText.length;
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- _asrouter_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_3__["ModalOverlay"],
- { title: "New targeting parameters", button_label: errors ? "Cancel" : "Done", onDoneButton: this.onPasteTargetingParams },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "onboardingMessage" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "p",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("textarea", { onChange: this.onNewTargetingParams, value: this.state.newStringTargetingParameters, autoFocus: true, rows: "20", cols: "60" })
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", { ref: "targetingParamsEval" })
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(_asrouter_components_ModalOverlay_ModalOverlay__WEBPACK_IMPORTED_MODULE_3__["ModalOverlay"], {
+ title: "New targeting parameters",
+ button_label: errors ? "Cancel" : "Done",
+ onDoneButton: this.onPasteTargetingParams
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "onboardingMessage"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("textarea", {
+ onChange: this.onNewTargetingParams,
+ value: this.state.newStringTargetingParameters,
+ autoFocus: true,
+ rows: "20",
+ cols: "60"
+ })), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", {
+ ref: "targetingParamsEval"
+ })));
}
renderTargetingParameters() {
// There was no error and the result is truthy
const success = this.state.evaluationStatus.success && !!this.state.evaluationStatus.result;
const result = JSON.stringify(this.state.evaluationStatus.result, null, 2) || "(Empty result)";
-
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- "Evaluate JEXL expression"
- )
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "p",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("textarea", { ref: "expressionInput", rows: "10", cols: "60", placeholder: "Evaluate JEXL expressions and mock parameters by changing their values below" })
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "p",
- null,
- "Status: ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- { ref: "evaluationStatus" },
- success ? "✅" : "❌",
- ", Result: ",
- result
- )
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: "ASRouterButton secondary", onClick: this.handleExpressionEval },
- "Evaluate"
- )
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- "Modify targeting parameters"
- )
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: "ASRouterButton secondary", onClick: this.onCopyTargetingParams, disabled: this.state.copiedToClipboard },
- this.state.copiedToClipboard ? "Parameters copied!" : "Copy parameters"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: "ASRouterButton secondary", onClick: this.onPasteTargetingParams, disabled: this.state.pasteFromClipboard },
- "Paste parameters"
- )
- )
- ),
- this.state.stringTargetingParameters && Object.keys(this.state.stringTargetingParameters).map((param, i) => {
- const value = this.state.stringTargetingParameters[param];
- const errorState = this.state.targetingParametersError && this.state.targetingParametersError.id === param;
- const className = errorState ? "errorState" : "";
- const inputComp = (value && value.length) > 30 ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("textarea", { name: param, className: className, value: value, rows: "10", cols: "60", onChange: this.onChangeTargetingParameters }) : react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { name: param, className: className, value: value, onChange: this.onChangeTargetingParameters });
-
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- { key: i },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- param
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- inputComp
- )
- );
- })
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Evaluate JEXL expression"))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("textarea", {
+ ref: "expressionInput",
+ rows: "10",
+ cols: "60",
+ placeholder: "Evaluate JEXL expressions and mock parameters by changing their values below"
+ })), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", null, "Status: ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ ref: "evaluationStatus"
+ }, success ? "✅" : "❌", ", Result: ", result))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "ASRouterButton secondary",
+ onClick: this.handleExpressionEval
+ }, "Evaluate"))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Modify targeting parameters"))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "ASRouterButton secondary",
+ onClick: this.onCopyTargetingParams,
+ disabled: this.state.copiedToClipboard
+ }, this.state.copiedToClipboard ? "Parameters copied!" : "Copy parameters"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "ASRouterButton secondary",
+ onClick: this.onPasteTargetingParams,
+ disabled: this.state.pasteFromClipboard
+ }, "Paste parameters"))), this.state.stringTargetingParameters && Object.keys(this.state.stringTargetingParameters).map((param, i) => {
+ const value = this.state.stringTargetingParameters[param];
+ const errorState = this.state.targetingParametersError && this.state.targetingParametersError.id === param;
+ const className = errorState ? "errorState" : "";
+ const inputComp = (value && value.length) > 30 ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("textarea", {
+ name: param,
+ className: className,
+ value: value,
+ rows: "10",
+ cols: "60",
+ onChange: this.onChangeTargetingParameters
+ }) : react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ name: param,
+ className: className,
+ value: value,
+ onChange: this.onChangeTargetingParameters
+ });
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", {
+ key: i
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, param), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, inputComp));
+ })));
}
onChangeAttributionParameters(event) {
- const { name, value } = event.target;
-
- this.setState(({ attributionParameters }) => {
- const updatedParameters = Object.assign({}, attributionParameters);
+ const {
+ name,
+ value
+ } = event.target;
+ this.setState(({
+ attributionParameters
+ }) => {
+ const updatedParameters = { ...attributionParameters
+ };
updatedParameters[name] = value;
-
- return { attributionParameters: updatedParameters };
+ return {
+ attributionParameters: updatedParameters
+ };
});
}
setAttribution(e) {
- _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({ type: "FORCE_ATTRIBUTION", data: this.state.attributionParameters });
+ _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_1__["ASRouterUtils"].sendMessage({
+ type: "FORCE_ATTRIBUTION",
+ data: this.state.attributionParameters
+ });
}
renderPocketStory(story) {
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- { className: "message-item", key: story.guid },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "message-id" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- null,
- story.guid,
- " ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("br", null)
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "message-summary" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "pre",
- null,
- JSON.stringify(story, null, 2)
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", {
+ className: "message-item",
+ key: story.guid
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "message-id"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", null, story.guid, " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("br", null))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "message-summary"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("pre", null, JSON.stringify(story, null, 2))));
}
renderPocketStories() {
- const { rows } = this.props.Sections.find(Section => Section.id === "topstories") || {};
-
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- rows && rows.map(story => this.renderPocketStory(story))
- )
- );
+ const {
+ rows
+ } = this.props.Sections.find(Section => Section.id === "topstories") || {};
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, rows && rows.map(story => this.renderPocketStory(story))));
}
renderDiscoveryStream() {
- const { config } = this.props.DiscoveryStream;
-
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tbody",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- { className: "message-item" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Enabled"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- config.enabled ? "yes" : "no"
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- { className: "message-item" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- { className: "min" },
- "Endpoint"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- config.endpoint || "(empty)"
- )
- )
- )
- )
- );
+ const {
+ config
+ } = this.props.DiscoveryStream;
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tbody", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", {
+ className: "message-item"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Enabled"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, config.enabled ? "yes" : "no")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", {
+ className: "message-item"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", {
+ className: "min"
+ }, "Endpoint"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, config.endpoint || "(empty)")))));
}
renderAttributionParamers() {
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- " Attribution Parameters "
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "p",
- null,
- " This forces the browser to set some attribution parameters, useful for testing the Return To AMO feature. Clicking on 'Force Attribution', with the default values in each field, will demo the Return To AMO flow with the addon called 'Iridium for Youtube'. If you wish to try different attribution parameters, enter them in the text boxes. If you wish to try a different addon with the Return To AMO flow, make sure the 'content' text box has the addon GUID, then click 'Force Attribution'."
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "table",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "b",
- null,
- " Source "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- " ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "text", name: "source", placeholder: "addons.mozilla.org", value: this.state.attributionParameters.source, onChange: this.onChangeAttributionParameters }),
- " "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "b",
- null,
- " Campaign "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- " ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "text", name: "campaign", placeholder: "non-fx-button", value: this.state.attributionParameters.campaign, onChange: this.onChangeAttributionParameters }),
- " "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "b",
- null,
- " Content "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- " ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "text", name: "content", placeholder: "[email protected]", value: this.state.attributionParameters.content, onChange: this.onChangeAttributionParameters }),
- " "
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "tr",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "td",
- null,
- " ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: "ASRouterButton primary button", onClick: this.setAttribution },
- " Force Attribution "
- ),
- " "
- )
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, " Attribution Parameters "), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", null, " This forces the browser to set some attribution parameters, useful for testing the Return To AMO feature. Clicking on 'Force Attribution', with the default values in each field, will demo the Return To AMO flow with the addon called 'Iridium for Youtube'. If you wish to try different attribution parameters, enter them in the text boxes. If you wish to try a different addon with the Return To AMO flow, make sure the 'content' text box has the addon GUID, then click 'Force Attribution'."), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("table", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("b", null, " Source ")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "text",
+ name: "source",
+ placeholder: "addons.mozilla.org",
+ value: this.state.attributionParameters.source,
+ onChange: this.onChangeAttributionParameters
+ }), " ")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("b", null, " Campaign ")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "text",
+ name: "campaign",
+ placeholder: "non-fx-button",
+ value: this.state.attributionParameters.campaign,
+ onChange: this.onChangeAttributionParameters
+ }), " ")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("b", null, " Content ")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "text",
+ name: "content",
+ placeholder: "[email protected]",
+ value: this.state.attributionParameters.content,
+ onChange: this.onChangeAttributionParameters
+ }), " ")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("td", null, " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "ASRouterButton primary button",
+ onClick: this.setAttribution
+ }, " Force Attribution "), " "))));
}
getSection() {
const [section] = this.props.location.routes;
+
switch (section) {
case "targeting":
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- "Targeting Utilities"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: "button", onClick: this.expireCache },
- "Expire Cache"
- ),
- " (This expires the cache in ASR Targeting for bookmarks and top sites)",
- this.renderTargetingParameters(),
- this.renderAttributionParamers()
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Targeting Utilities"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "button",
+ onClick: this.expireCache
+ }, "Expire Cache"), " (This expires the cache in ASR Targeting for bookmarks and top sites)", this.renderTargetingParameters(), this.renderAttributionParamers());
+
case "pocket":
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- "Pocket"
- ),
- this.renderPocketStories()
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Pocket"), this.renderPocketStories());
+
case "ds":
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- "Discovery Stream"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(DiscoveryStreamAdmin, { state: this.props.DiscoveryStream, otherPrefs: this.props.Prefs.values, dispatch: this.props.dispatch })
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Discovery Stream"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(DiscoveryStreamAdmin, {
+ state: this.props.DiscoveryStream,
+ otherPrefs: this.props.Prefs.values,
+ dispatch: this.props.dispatch
+ }));
+
default:
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment,
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- "Message Providers ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { title: "Restore all provider settings that ship with Firefox", className: "button", onClick: this.resetPref },
- "Restore default prefs"
- )
- ),
- this.state.providers ? this.renderProviders() : null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h2",
- null,
- "Messages"
- ),
- this.renderMessageFilter(),
- this.renderMessages(),
- this.renderPasteModal()
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_4___default.a.Fragment, null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Message Providers ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ title: "Restore all provider settings that ship with Firefox",
+ className: "button",
+ onClick: this.resetPref
+ }, "Restore default prefs")), this.state.providers ? this.renderProviders() : null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h2", null, "Messages"), this.renderMessageFilter(), this.renderMessages(), this.renderPasteModal());
}
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "asrouter-admin" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "aside",
- { className: "sidebar" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "ul",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "li",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "a",
- { href: "#devtools" },
- "General"
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "li",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "a",
- { href: "#devtools-targeting" },
- "Targeting"
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "li",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "a",
- { href: "#devtools-pocket" },
- "Pocket"
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "li",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "a",
- { href: "#devtools-ds" },
- "Discovery Stream"
- )
- )
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "main",
- { className: "main-panel" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "h1",
- null,
- "AS Router Admin"
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "p",
- { className: "helpLink" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", { className: "icon icon-small-spacer icon-info" }),
- " ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- null,
- "Need help using these tools? Check out our ",
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "a",
- { target: "blank", href: "https://github.com/mozilla/activity-stream/blob/master/content-src/asrouter/docs/debugging-docs.md" },
- "documentation"
- )
- )
- ),
- this.getSection()
- )
- );
- }
-}
-
-const _ASRouterAdmin = props => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- _SimpleHashRouter__WEBPACK_IMPORTED_MODULE_5__["SimpleHashRouter"],
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(ASRouterAdminInner, props)
-);
-const ASRouterAdmin = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(state => ({ Sections: state.Sections, DiscoveryStream: state.DiscoveryStream, Prefs: state.Prefs }))(_ASRouterAdmin);
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "asrouter-admin"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("aside", {
+ className: "sidebar"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("ul", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+ href: "#devtools"
+ }, "General")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+ href: "#devtools-targeting"
+ }, "Targeting")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+ href: "#devtools-pocket"
+ }, "Pocket")), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+ href: "#devtools-ds"
+ }, "Discovery Stream")))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("main", {
+ className: "main-panel"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("h1", null, "AS Router Admin"), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("p", {
+ className: "helpLink"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ className: "icon icon-small-spacer icon-info"
+ }), " ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", null, "Need help using these tools? Check out our ", react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+ target: "blank",
+ href: "https://github.com/mozilla/activity-stream/blob/master/content-src/asrouter/docs/debugging-docs.md"
+ }, "documentation"))), this.getSection()));
+ }
+
+}
+const _ASRouterAdmin = props => react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(_SimpleHashRouter__WEBPACK_IMPORTED_MODULE_5__["SimpleHashRouter"], null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(ASRouterAdminInner, props));
+const ASRouterAdmin = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])(state => ({
+ Sections: state.Sections,
+ DiscoveryStream: state.DiscoveryStream,
+ Prefs: state.Prefs
+}))(_ASRouterAdmin);
/***/ }),
/* 27 */
@@ -3637,16 +3464,19 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-
class SimpleHashRouter extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
constructor(props) {
super(props);
this.onHashChange = this.onHashChange.bind(this);
- this.state = { hash: global.location.hash };
+ this.state = {
+ hash: global.location.hash
+ };
}
onHashChange() {
- this.setState({ hash: global.location.hash });
+ this.setState({
+ hash: global.location.hash
+ });
}
componentWillMount() {
@@ -3666,6 +3496,7 @@ class SimpleHashRouter extends react__WEBPACK_IMPORTED_MODULE_0___default.a.Pure
}
});
}
+
}
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -3688,7 +3519,6 @@ __webpack_require__.r(__webpack_exports__);
-
/**
* ConfirmDialog component.
* One primary action button, one cancel button.
@@ -3708,6 +3538,7 @@ __webpack_require__.r(__webpack_exports__);
* confirm_button_string_id: "menu_action_delete"
* },
*/
+
class _ConfirmDialog extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
constructor(props) {
super(props);
@@ -3716,8 +3547,13 @@ class _ConfirmDialog extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureCo
}
_handleCancelBtn() {
- this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DIALOG_CANCEL });
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DIALOG_CANCEL, source: this.props.data.eventSource }));
+ this.props.dispatch({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DIALOG_CANCEL
+ });
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DIALOG_CANCEL,
+ source: this.props.data.eventSource
+ }));
}
_handleConfirmBtn() {
@@ -3731,15 +3567,11 @@ class _ConfirmDialog extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureCo
return null;
}
- return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- null,
- message_body.map(msg => react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "p",
- { key: msg },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], { id: msg })
- ))
- );
+ return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", null, message_body.map(msg => react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", {
+ key: msg
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], {
+ id: msg
+ }))));
}
render() {
@@ -3747,38 +3579,32 @@ class _ConfirmDialog extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureCo
return null;
}
- return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "confirmation-dialog" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", { className: "modal-overlay", onClick: this._handleCancelBtn }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "modal" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "section",
- { className: "modal-message" },
- this.props.data.icon && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", { className: `icon icon-spacer icon-${this.props.data.icon}` }),
- this._renderModalMessage()
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "section",
- { className: "actions" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "button",
- { onClick: this._handleCancelBtn },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], { id: this.props.data.cancel_button_string_id })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "button",
- { className: "done", onClick: this._handleConfirmBtn },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], { id: this.props.data.confirm_button_string_id })
- )
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "confirmation-dialog"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "modal-overlay",
+ onClick: this._handleCancelBtn
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "modal"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("section", {
+ className: "modal-message"
+ }, this.props.data.icon && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: `icon icon-spacer icon-${this.props.data.icon}`
+ }), this._renderModalMessage()), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("section", {
+ className: "actions"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+ onClick: this._handleCancelBtn
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], {
+ id: this.props.data.cancel_button_string_id
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+ className: "done",
+ onClick: this._handleConfirmBtn
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], {
+ id: this.props.data.confirm_button_string_id
+ })))));
}
-}
+}
const ConfirmDialog = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])(state => state.Dialog)(_ConfirmDialog);
/***/ }),
@@ -3797,7 +3623,6 @@ __webpack_require__.r(__webpack_exports__);
-
class _DarkModeMessage extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComponent {
constructor(props) {
super(props);
@@ -3807,7 +3632,9 @@ class _DarkModeMessage extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Pure
handleSwitch() {
// Switch to default new tab version
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_OPT_OUT }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_OPT_OUT
+ }));
}
handleCancel() {
@@ -3816,45 +3643,21 @@ class _DarkModeMessage extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Pure
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- { className: "ds-message-container" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "p",
- null,
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", { className: "icon icon-info" }),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "span",
- null,
- "This version of New Tab doesn't support dark mode yet."
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- { className: "ds-message-actions actions" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "button",
- { onClick: this.handleCancel },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "span",
- null,
- "Got it"
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "button",
- { className: "dismiss", onClick: this.handleSwitch },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "span",
- null,
- "Use older version"
- )
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "ds-message-container"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", {
+ className: "icon icon-info"
+ }), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", null, "This version of New Tab doesn't support dark mode yet.")), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "ds-message-actions actions"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("button", {
+ onClick: this.handleCancel
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", null, "Got it")), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("button", {
+ className: "dismiss",
+ onClick: this.handleSwitch
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", null, "Use older version"))));
}
-}
+}
const DarkModeMessage = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])()(_DarkModeMessage);
/***/ }),
@@ -3880,23 +3683,40 @@ __webpack_require__.r(__webpack_exports__);
-
const DEFAULT_SITE_MENU_OPTIONS = ["CheckPinTopSite", "EditTopSite", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"];
-
class _LinkMenu extends react__WEBPACK_IMPORTED_MODULE_5___default.a.PureComponent {
getOptions() {
- const { props } = this;
- const { site, index, source, isPrivateBrowsingEnabled, siteInfo, platform } = props;
+ const {
+ props
+ } = this;
+ const {
+ site,
+ index,
+ source,
+ isPrivateBrowsingEnabled,
+ siteInfo,
+ platform
+ } = props; // Handle special case of default site
- // Handle special case of default site
const propOptions = !site.isDefault || site.searchTopSite ? props.options : DEFAULT_SITE_MENU_OPTIONS;
-
const options = propOptions.map(o => content_src_lib_link_menu_options__WEBPACK_IMPORTED_MODULE_4__["LinkMenuOptions"][o](site, index, source, isPrivateBrowsingEnabled, siteInfo, platform)).map(option => {
- const { action, impression, id, string_id, type, userEvent } = option;
+ const {
+ action,
+ impression,
+ id,
+ string_id,
+ type,
+ userEvent
+ } = option;
+
if (!type && id) {
- option.label = props.intl.formatMessage({ id: string_id || id });
+ option.label = props.intl.formatMessage({
+ id: string_id || id
+ });
+
option.onClick = () => {
props.dispatch(action);
+
if (userEvent) {
const userEventData = Object.assign({
event: userEvent,
@@ -3905,17 +3725,18 @@ class _LinkMenu extends react__WEBPACK_IMPORTED_MODULE_5___default.a.PureCompone
}, siteInfo);
props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent(userEventData));
}
+
if (impression && props.shouldSendImpressionStats) {
props.dispatch(impression);
}
};
}
- return option;
- });
- // This is for accessibility to support making each item tabbable.
+ return option;
+ }); // This is for accessibility to support making each item tabbable.
// We want to know which item is the first and which item
// is the last, so we can close the context menu accordingly.
+
options[0].first = true;
options[options.length - 1].last = true;
return options;
@@ -3925,11 +3746,17 @@ class _LinkMenu extends react__WEBPACK_IMPORTED_MODULE_5___default.a.PureCompone
return react__WEBPACK_IMPORTED_MODULE_5___default.a.createElement(content_src_components_ContextMenu_ContextMenu__WEBPACK_IMPORTED_MODULE_2__["ContextMenu"], {
onUpdate: this.props.onUpdate,
onShow: this.props.onShow,
- options: this.getOptions() });
+ options: this.getOptions()
+ });
}
+
}
-const getState = state => ({ isPrivateBrowsingEnabled: state.Prefs.values.isPrivateBrowsingEnabled, platform: state.Prefs.values.platform });
+const getState = state => ({
+ isPrivateBrowsingEnabled: state.Prefs.values.isPrivateBrowsingEnabled,
+ platform: state.Prefs.values.platform
+});
+
const LinkMenu = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])(getState)(Object(react_intl__WEBPACK_IMPORTED_MODULE_3__["injectIntl"])(_LinkMenu));
/***/ }),
@@ -3943,7 +3770,6 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-
class ContextMenu extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
constructor(props) {
super(props);
@@ -3981,18 +3807,23 @@ class ContextMenu extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCompo
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "span",
- { className: "context-menu", onClick: this.onClick },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "ul",
- { role: "menu", className: "context-menu-list" },
- this.props.options.map((option, i) => option.type === "separator" ? react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("li", { key: i, className: "separator" }) : option.type !== "empty" && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ContextMenuItem, { key: i, option: option, hideContext: this.hideContext }))
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
+ className: "context-menu",
+ onClick: this.onClick
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("ul", {
+ role: "menu",
+ className: "context-menu-list"
+ }, this.props.options.map((option, i) => option.type === "separator" ? react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("li", {
+ key: i,
+ className: "separator"
+ }) : option.type !== "empty" && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ContextMenuItem, {
+ key: i,
+ option: option,
+ hideContext: this.hideContext
+ }))));
}
-}
+}
class ContextMenuItem extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
constructor(props) {
super(props);
@@ -4006,7 +3837,10 @@ class ContextMenuItem extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureC
}
onKeyDown(event) {
- const { option } = this.props;
+ const {
+ option
+ } = this.props;
+
switch (event.key) {
case "Tab":
// tab goes down in context menu, shift + tab goes up in context menu
@@ -4015,7 +3849,9 @@ class ContextMenuItem extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureC
if (event.shiftKey && option.first || !event.shiftKey && option.last) {
this.props.hideContext();
}
+
break;
+
case "Enter":
this.props.hideContext();
option.onClick();
@@ -4024,18 +3860,22 @@ class ContextMenuItem extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureC
}
render() {
- const { option } = this.props;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "li",
- { role: "menuitem", className: "context-menu-item" },
- react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(
- "a",
- { onClick: this.onClick, onKeyDown: this.onKeyDown, tabIndex: "0", className: option.disabled ? "disabled" : "" },
- option.icon && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", { className: `icon icon-spacer icon-${option.icon}` }),
- option.label
- )
- );
+ const {
+ option
+ } = this.props;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("li", {
+ role: "menuitem",
+ className: "context-menu-item"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
+ onClick: this.onClick,
+ onKeyDown: this.onKeyDown,
+ tabIndex: "0",
+ className: option.disabled ? "disabled" : ""
+ }, option.icon && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("span", {
+ className: `icon icon-spacer icon-${option.icon}`
+ }), option.label));
}
+
}
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -4055,7 +3895,10 @@ const _OpenInPrivateWindow = site => ({
icon: "new-window-private",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].OPEN_PRIVATE_WINDOW,
- data: { url: site.url, referrer: site.referrer }
+ data: {
+ url: site.url,
+ referrer: site.referrer
+ }
}),
userEvent: "OPEN_PRIVATE_WINDOW"
});
@@ -4064,23 +3907,30 @@ const GetPlatformString = platform => {
switch (platform) {
case "win":
return "menu_action_show_file_windows";
+
case "macosx":
return "menu_action_show_file_mac_os";
+
case "linux":
return "menu_action_show_file_linux";
+
default:
return "menu_action_show_file_default";
}
};
-
/**
* List of functions that return items that can be included as menu options in a
* LinkMenu. All functions take the site as the first parameter, and optionally
* the index of the site.
*/
+
const LinkMenuOptions = {
- Separator: () => ({ type: "separator" }),
- EmptyItem: () => ({ type: "empty" }),
+ Separator: () => ({
+ type: "separator"
+ }),
+ EmptyItem: () => ({
+ type: "empty"
+ }),
RemoveBookmark: site => ({
id: "menu_action_remove_bookmark",
icon: "bookmark-added",
@@ -4095,7 +3945,11 @@ const LinkMenuOptions = {
icon: "bookmark-hollow",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].BOOKMARK_URL,
- data: { url: site.url, title: site.title, type: site.type }
+ data: {
+ url: site.url,
+ title: site.title,
+ type: site.type
+ }
}),
userEvent: "BOOKMARK_ADD"
}),
@@ -4117,16 +3971,21 @@ const LinkMenuOptions = {
icon: "dismiss",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].BLOCK_URL,
- data: { url: site.open_url || site.url, pocket_id: site.pocket_id }
+ data: {
+ url: site.open_url || site.url,
+ pocket_id: site.pocket_id
+ }
}),
impression: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].ImpressionStats({
source: eventSource,
block: 0,
- tiles: [{ id: site.guid, pos: index }]
+ tiles: [{
+ id: site.guid,
+ pos: index
+ }]
}),
userEvent: "BLOCK"
}),
-
// This is an option for web extentions which will result in remove items from
// memory and notify the web extenion, rather than using the built-in block list.
WebExtDismiss: (site, index, eventSource) => ({
@@ -4145,7 +4004,18 @@ const LinkMenuOptions = {
action: {
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DIALOG_OPEN,
data: {
- onConfirm: [common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DELETE_HISTORY_URL, data: { url: site.url, pocket_id: site.pocket_id, forceBlock: site.bookmarkGuid } }), common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent(Object.assign({ event: "DELETE", source: eventSource, action_position: index }, siteInfo))],
+ onConfirm: [common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DELETE_HISTORY_URL,
+ data: {
+ url: site.url,
+ pocket_id: site.pocket_id,
+ forceBlock: site.bookmarkGuid
+ }
+ }), common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent(Object.assign({
+ event: "DELETE",
+ source: eventSource,
+ action_position: index
+ }, siteInfo))],
eventSource,
body_string_id: ["confirm_history_delete_p1", "confirm_history_delete_notice_p2"],
confirm_button_string_id: "menu_action_delete",
@@ -4160,7 +4030,9 @@ const LinkMenuOptions = {
icon: "search",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SHOW_DOWNLOAD_FILE,
- data: { url: site.url }
+ data: {
+ url: site.url
+ }
})
}),
OpenFile: site => ({
@@ -4168,7 +4040,9 @@ const LinkMenuOptions = {
icon: "open-file",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].OPEN_DOWNLOAD_FILE,
- data: { url: site.url }
+ data: {
+ url: site.url
+ }
})
}),
CopyDownloadLink: site => ({
@@ -4176,7 +4050,9 @@ const LinkMenuOptions = {
icon: "copy",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].COPY_DOWNLOAD_LINK,
- data: { url: site.url }
+ data: {
+ url: site.url
+ }
})
}),
GoToDownloadPage: site => ({
@@ -4184,7 +4060,9 @@ const LinkMenuOptions = {
icon: "download",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].OPEN_LINK,
- data: { url: site.referrer }
+ data: {
+ url: site.referrer
+ }
}),
disabled: !site.referrer
}),
@@ -4193,18 +4071,28 @@ const LinkMenuOptions = {
icon: "delete",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].REMOVE_DOWNLOAD_FILE,
- data: { url: site.url }
+ data: {
+ url: site.url
+ }
})
}),
- PinTopSite: ({ url, searchTopSite, label }, index) => ({
+ PinTopSite: ({
+ url,
+ searchTopSite,
+ label
+ }, index) => ({
id: "menu_action_pin",
icon: "pin",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_PIN,
data: {
- site: Object.assign({
- url
- }, searchTopSite && { searchTopSite, label }),
+ site: {
+ url,
+ ...(searchTopSite && {
+ searchTopSite,
+ label
+ })
+ },
index
}
}),
@@ -4215,7 +4103,11 @@ const LinkMenuOptions = {
icon: "unpin",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_UNPIN,
- data: { site: { url: site.url } }
+ data: {
+ site: {
+ url: site.url
+ }
+ }
}),
userEvent: "UNPIN"
}),
@@ -4224,12 +4116,20 @@ const LinkMenuOptions = {
icon: "pocket-save",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_TO_POCKET,
- data: { site: { url: site.url, title: site.title } }
+ data: {
+ site: {
+ url: site.url,
+ title: site.title
+ }
+ }
}),
impression: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].ImpressionStats({
source: eventSource,
pocket: 0,
- tiles: [{ id: site.guid, pos: index }]
+ tiles: [{
+ id: site.guid,
+ pos: index
+ }]
}),
userEvent: "SAVE_TO_POCKET"
}),
@@ -4238,7 +4138,9 @@ const LinkMenuOptions = {
icon: "delete",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DELETE_FROM_POCKET,
- data: { pocket_id: site.pocket_id }
+ data: {
+ pocket_id: site.pocket_id
+ }
}),
userEvent: "DELETE_FROM_POCKET"
}),
@@ -4247,7 +4149,9 @@ const LinkMenuOptions = {
icon: "check",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].ARCHIVE_FROM_POCKET,
- data: { pocket_id: site.pocket_id }
+ data: {
+ pocket_id: site.pocket_id
+ }
}),
userEvent: "ARCHIVE_FROM_POCKET"
}),
@@ -4256,7 +4160,9 @@ const LinkMenuOptions = {
icon: "edit",
action: {
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_EDIT,
- data: { index }
+ data: {
+ index
+ }
}
}),
CheckBookmark: site => site.bookmarkGuid ? LinkMenuOptions.RemoveBookmark(site) : LinkMenuOptions.AddBookmark(site),
@@ -4279,17 +4185,14 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-
const VISIBLE = "visible";
-const VISIBILITY_CHANGE_EVENT = "visibilitychange";
-
-// Per analytical requirement, we set the minimal intersection ratio to
+const VISIBILITY_CHANGE_EVENT = "visibilitychange"; // Per analytical requirement, we set the minimal intersection ratio to
// 0.5, and an impression is identified when the wrapped item has at least
// 50% visibility.
//
// This constant is exported for unit test
-const INTERSECTION_RATIO = 0.5;
+const INTERSECTION_RATIO = 0.5;
/**
* Impression wrapper for Discovery Stream related React components.
*
@@ -4305,6 +4208,7 @@ const INTERSECTION_RATIO = 0.5;
* * Batching is not yet implemented, hence it might send multiple
* impression pings separately
*/
+
class ImpressionStats extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
// This checks if the given cards are the same as those in the last impression ping.
// If so, it should not send the same impression ping again.
@@ -4323,24 +4227,36 @@ class ImpressionStats extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureC
}
_dispatchImpressionStats() {
- const { props } = this;
+ const {
+ props
+ } = this;
const cards = props.rows;
if (this.props.campaignId) {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_SPOC_IMPRESSION, data: { campaignId: this.props.campaignId } }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].DISCOVERY_STREAM_SPOC_IMPRESSION,
+ data: {
+ campaignId: this.props.campaignId
+ }
+ }));
}
if (this._needsImpressionStats(cards)) {
props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].DiscoveryStreamImpressionStats({
source: props.source.toUpperCase(),
- tiles: cards.map(link => ({ id: link.id, pos: link.pos }))
+ tiles: cards.map(link => ({
+ id: link.id,
+ pos: link.pos
+ }))
}));
this.impressionCardGuids = cards.map(link => link.id);
}
}
setImpressionObserverOrAddListener() {
- const { props } = this;
+ const {
+ props
+ } = this;
if (!props.dispatch) {
return;
@@ -4361,10 +4277,10 @@ class ImpressionStats extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureC
props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
};
+
props.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
}
-
/**
* Set an impression observer for the wrapped component. It makes use of
* the Intersection Observer API to detect if the wrapped component is
@@ -4373,8 +4289,12 @@ class ImpressionStats extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureC
* See more details about Intersection Observer API at:
* https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
*/
+
+
setImpressionObserver() {
- const { props } = this;
+ const {
+ props
+ } = this;
if (!props.rows.length) {
return;
@@ -4383,11 +4303,14 @@ class ImpressionStats extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureC
this._handleIntersect = entries => {
if (entries.some(entry => entry.isIntersecting && entry.intersectionRatio >= INTERSECTION_RATIO)) {
this._dispatchImpressionStats();
+
this.impressionObserver.unobserve(this.refs.impression);
}
};
- const options = { threshold: INTERSECTION_RATIO };
+ const options = {
+ threshold: INTERSECTION_RATIO
+ };
this.impressionObserver = new props.IntersectionObserver(this._handleIntersect, options);
this.impressionObserver.observe(this.refs.impression);
}
@@ -4408,20 +4331,20 @@ class ImpressionStats extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureC
if (this._handleIntersect && this.impressionObserver) {
this.impressionObserver.unobserve(this.refs.impression);
}
+
if (this._onVisibilityChange) {
this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "div",
- { ref: "impression", className: "impression-observer" },
- this.props.children
- );
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+ ref: "impression",
+ className: "impression-observer"
+ }, this.props.children);
}
-}
+}
ImpressionStats.defaultProps = {
IntersectionObserver: global.IntersectionObserver,
document: global.document,
@@ -4452,7 +4375,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(59);
/* harmony import */ var _TopSiteForm__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(61);
/* harmony import */ var _TopSite__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(43);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -4470,26 +4393,32 @@ function topSiteIconType(link) {
if (link.customScreenshotURL) {
return "custom_screenshot";
}
+
if (link.tippyTopIcon || link.faviconRef === "tippytop") {
return "tippytop";
}
+
if (link.faviconSize >= _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__["MIN_RICH_FAVICON_SIZE"]) {
return "rich_icon";
}
+
if (link.screenshot && link.faviconSize >= _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__["MIN_CORNER_FAVICON_SIZE"]) {
return "screenshot_with_icon";
}
+
if (link.screenshot) {
return "screenshot";
}
+
return "no_image";
}
-
/**
* Iterates through TopSites and counts types of images.
* @param acc Accumulator for reducer.
* @param topsite Entry in TopSites.
*/
+
+
function countTopSitesIconsTypes(topSites) {
const countTopSitesTypes = (acc, link) => {
acc[topSiteIconType(link)]++;
@@ -4512,16 +4441,18 @@ class _TopSites extends react__WEBPACK_IMPORTED_MODULE_6___default.a.PureCompone
this.onEditFormClose = this.onEditFormClose.bind(this);
this.onSearchShortcutsFormClose = this.onSearchShortcutsFormClose.bind(this);
}
-
/**
* Dispatch session statistics about the quality of TopSites icons and pinned count.
*/
+
+
_dispatchTopSitesStats() {
const topSites = this._getVisibleTopSites();
+
const topSitesIconsStats = countTopSitesIconsTypes(topSites);
const topSitesPinned = topSites.filter(site => !!site.isPinned).length;
- const searchShortcuts = topSites.filter(site => !!site.searchTopSite).length;
- // Dispatch telemetry event with the count of TopSites images types.
+ const searchShortcuts = topSites.filter(site => !!site.searchTopSite).length; // Dispatch telemetry event with the count of TopSites images types.
+
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_SESSION_PERF_DATA,
data: {
@@ -4531,17 +4462,19 @@ class _TopSites extends react__WEBPACK_IMPORTED_MODULE_6___default.a.PureCompone
}
}));
}
-
/**
* Return the TopSites that are visible based on prefs and window width.
*/
+
+
_getVisibleTopSites() {
// We hide 2 sites per row when not in the wide layout.
- let sitesPerRow = common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_8__["TOP_SITES_MAX_SITES_PER_ROW"];
- // $break-point-widest = 1072px (from _variables.scss)
+ let sitesPerRow = common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_8__["TOP_SITES_MAX_SITES_PER_ROW"]; // $break-point-widest = 1072px (from _variables.scss)
+
if (!global.matchMedia(`(min-width: 1072px)`).matches) {
sitesPerRow -= 2;
}
+
return this.props.TopSites.rows.slice(0, this.props.TopSitesRows * sitesPerRow);
}
@@ -4558,7 +4491,9 @@ class _TopSites extends react__WEBPACK_IMPORTED_MODULE_6___default.a.PureCompone
source: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__["TOP_SITES_SOURCE"],
event: "TOP_SITES_EDIT_CLOSE"
}));
- this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_CANCEL_EDIT });
+ this.props.dispatch({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_CANCEL_EDIT
+ });
}
onSearchShortcutsFormClose() {
@@ -4566,72 +4501,78 @@ class _TopSites extends react__WEBPACK_IMPORTED_MODULE_6___default.a.PureCompone
source: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__["TOP_SITES_SOURCE"],
event: "SEARCH_EDIT_CLOSE"
}));
- this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL });
+ this.props.dispatch({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL
+ });
}
render() {
- const { props } = this;
- const { editForm, showSearchShortcutsForm } = props.TopSites;
+ const {
+ props
+ } = this;
+ const {
+ editForm,
+ showSearchShortcutsForm
+ } = props.TopSites;
const extraMenuOptions = ["AddTopSite"];
+
if (props.Prefs.values["improvesearch.topSiteSearchShortcuts"]) {
extraMenuOptions.push("AddSearchShortcut");
}
- return react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
- content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__["ComponentPerfTimer"],
- { id: "topsites", initialized: props.TopSites.initialized, dispatch: props.dispatch },
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
- content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__["CollapsibleSection"],
- {
- className: "top-sites",
- icon: "topsites",
- id: "topsites",
- title: { id: "header_top_sites" },
- extraMenuOptions: extraMenuOptions,
- showPrefName: "feeds.topsites",
- eventSource: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__["TOP_SITES_SOURCE"],
- collapsed: props.TopSites.pref ? props.TopSites.pref.collapsed : undefined,
- isFirst: props.isFirst,
- isLast: props.isLast,
- dispatch: props.dispatch },
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(_TopSite__WEBPACK_IMPORTED_MODULE_10__["TopSiteList"], { TopSites: props.TopSites, TopSitesRows: props.TopSitesRows, dispatch: props.dispatch, intl: props.intl, topSiteIconType: topSiteIconType }),
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
- "div",
- { className: "edit-topsites-wrapper" },
- editForm && react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
- "div",
- { className: "edit-topsites" },
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", { className: "modal-overlay", onClick: this.onEditFormClose }),
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
- "div",
- { className: "modal" },
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(_TopSiteForm__WEBPACK_IMPORTED_MODULE_9__["TopSiteForm"], _extends({
- site: props.TopSites.rows[editForm.index],
- onClose: this.onEditFormClose,
- dispatch: this.props.dispatch,
- intl: this.props.intl
- }, editForm))
- )
- ),
- showSearchShortcutsForm && react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
- "div",
- { className: "edit-search-shortcuts" },
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", { className: "modal-overlay", onClick: this.onSearchShortcutsFormClose }),
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
- "div",
- { className: "modal" },
- react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(_SearchShortcutsForm__WEBPACK_IMPORTED_MODULE_7__["SearchShortcutsForm"], {
- TopSites: props.TopSites,
- onClose: this.onSearchShortcutsFormClose,
- dispatch: this.props.dispatch })
- )
- )
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_3__["ComponentPerfTimer"], {
+ id: "topsites",
+ initialized: props.TopSites.initialized,
+ dispatch: props.dispatch
+ }, react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_2__["CollapsibleSection"], {
+ className: "top-sites",
+ icon: "topsites",
+ id: "topsites",
+ title: {
+ id: "header_top_sites"
+ },
+ extraMenuOptions: extraMenuOptions,
+ showPrefName: "feeds.topsites",
+ eventSource: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_1__["TOP_SITES_SOURCE"],
+ collapsed: props.TopSites.pref ? props.TopSites.pref.collapsed : undefined,
+ isFirst: props.isFirst,
+ isLast: props.isLast,
+ dispatch: props.dispatch
+ }, react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(_TopSite__WEBPACK_IMPORTED_MODULE_10__["TopSiteList"], {
+ TopSites: props.TopSites,
+ TopSitesRows: props.TopSitesRows,
+ dispatch: props.dispatch,
+ intl: props.intl,
+ topSiteIconType: topSiteIconType
+ }), react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", {
+ className: "edit-topsites-wrapper"
+ }, editForm && react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", {
+ className: "edit-topsites"
+ }, react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", {
+ className: "modal-overlay",
+ onClick: this.onEditFormClose
+ }), react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", {
+ className: "modal"
+ }, react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(_TopSiteForm__WEBPACK_IMPORTED_MODULE_9__["TopSiteForm"], _extends({
+ site: props.TopSites.rows[editForm.index],
+ onClose: this.onEditFormClose,
+ dispatch: this.props.dispatch,
+ intl: this.props.intl
+ }, editForm)))), showSearchShortcutsForm && react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", {
+ className: "edit-search-shortcuts"
+ }, react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", {
+ className: "modal-overlay",
+ onClick: this.onSearchShortcutsFormClose
+ }), react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("div", {
+ className: "modal"
+ }, react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(_SearchShortcutsForm__WEBPACK_IMPORTED_MODULE_7__["SearchShortcutsForm"], {
+ TopSites: props.TopSites,
+ onClose: this.onSearchShortcutsFormClose,
+ dispatch: this.props.dispatch
+ }))))));
}
-}
+}
const TopSites = Object(react_redux__WEBPACK_IMPORTED_MODULE_4__["connect"])(state => ({
TopSites: state.TopSites,
Prefs: state.Prefs,
@@ -4651,12 +4592,12 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MIN_RICH_FAVICON_SIZE", function() { return MIN_RICH_FAVICON_SIZE; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MIN_CORNER_FAVICON_SIZE", function() { return MIN_CORNER_FAVICON_SIZE; });
const TOP_SITES_SOURCE = "TOP_SITES";
-const TOP_SITES_CONTEXT_MENU_OPTIONS = ["CheckPinTopSite", "EditTopSite", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl", "DeleteUrl"];
-// the special top site for search shortcut experiment can only have the option to unpin (which removes) the topsite
-const TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS = ["CheckPinTopSite", "Separator", "BlockUrl"];
-// minimum size necessary to show a rich icon instead of a screenshot
-const MIN_RICH_FAVICON_SIZE = 96;
-// minimum size necessary to show any icon in the top left corner with a screenshot
+const TOP_SITES_CONTEXT_MENU_OPTIONS = ["CheckPinTopSite", "EditTopSite", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl", "DeleteUrl"]; // the special top site for search shortcut experiment can only have the option to unpin (which removes) the topsite
+
+const TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS = ["CheckPinTopSite", "Separator", "BlockUrl"]; // minimum size necessary to show a rich icon instead of a screenshot
+
+const MIN_RICH_FAVICON_SIZE = 96; // minimum size necessary to show any icon in the top left corner with a screenshot
+
const MIN_CORNER_FAVICON_SIZE = 16;
/***/ }),
@@ -4681,16 +4622,11 @@ __webpack_require__.r(__webpack_exports__);
-
const VISIBLE = "visible";
const VISIBILITY_CHANGE_EVENT = "visibilitychange";
function getFormattedMessage(message) {
- return typeof message === "string" ? react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- null,
- message
- ) : react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], message);
+ return typeof message === "string" ? react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", null, message) : react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], message);
}
class _CollapsibleSection extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
@@ -4704,7 +4640,12 @@ class _CollapsibleSection extends react__WEBPACK_IMPORTED_MODULE_3___default.a.P
this.onMenuButtonMouseEnter = this.onMenuButtonMouseEnter.bind(this);
this.onMenuButtonMouseLeave = this.onMenuButtonMouseLeave.bind(this);
this.onMenuUpdate = this.onMenuUpdate.bind(this);
- this.state = { enableAnimation: true, isAnimating: false, menuButtonHover: false, showContextMenu: false };
+ this.state = {
+ enableAnimation: true,
+ isAnimating: false,
+ menuButtonHover: false,
+ showContextMenu: false
+ };
this.setContextMenuButtonRef = this.setContextMenuButtonRef.bind(this);
}
@@ -4741,8 +4682,11 @@ class _CollapsibleSection extends react__WEBPACK_IMPORTED_MODULE_3___default.a.P
enableOrDisableAnimation() {
// Only animate the collapse/expand for visible tabs.
const visible = this.props.document.visibilityState === VISIBLE;
+
if (this.state.enableAnimation !== visible) {
- this.setState({ enableAnimation: visible });
+ this.setState({
+ enableAnimation: visible
+ });
}
}
@@ -4757,14 +4701,17 @@ class _CollapsibleSection extends react__WEBPACK_IMPORTED_MODULE_3___default.a.P
// If props.collapsed is undefined handler shouldn't do anything.
if (!this.sectionBody || this.props.collapsed === undefined) {
return;
- }
+ } // Get the current height of the body so max-height transitions can work
+
- // Get the current height of the body so max-height transitions can work
this.setState({
isAnimating: true,
maxHeight: `${this._getSectionBodyHeight()}px`
});
- const { action, userEvent } = content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_5__["SectionMenuOptions"].CheckCollapsed(this.props);
+ const {
+ action,
+ userEvent
+ } = content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_5__["SectionMenuOptions"].CheckCollapsed(this.props);
this.props.dispatch(action);
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__["actionCreators"].UserEvent({
event: userEvent,
@@ -4774,155 +4721,176 @@ class _CollapsibleSection extends react__WEBPACK_IMPORTED_MODULE_3___default.a.P
_getSectionBodyHeight() {
const div = this.sectionBody;
+
if (div.style.display === "none") {
// If the div isn't displayed, we can't get it's height. So we display it
// to get the height (it doesn't show up because max-height is set to 0px
// in CSS). We don't undo this because we are about to expand the section.
div.style.display = "block";
}
+
return div.scrollHeight;
}
onTransitionEnd(event) {
// Only update the animating state for our own transition (not a child's)
if (event.target === event.currentTarget) {
- this.setState({ isAnimating: false });
+ this.setState({
+ isAnimating: false
+ });
}
}
renderIcon() {
- const { icon } = this.props;
+ const {
+ icon
+ } = this.props;
+
if (icon && icon.startsWith("moz-extension://")) {
- return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", { className: "icon icon-small-spacer", style: { backgroundImage: `url('${icon}')` } });
+ return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "icon icon-small-spacer",
+ style: {
+ backgroundImage: `url('${icon}')`
+ }
+ });
}
- return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", { className: `icon icon-small-spacer icon-${icon || "webextension"}` });
+
+ return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: `icon icon-small-spacer icon-${icon || "webextension"}`
+ });
}
onMenuButtonClick(event) {
event.preventDefault();
- this.setState({ showContextMenu: true });
+ this.setState({
+ showContextMenu: true
+ });
}
onMenuButtonMouseEnter() {
- this.setState({ menuButtonHover: true });
+ this.setState({
+ menuButtonHover: true
+ });
}
onMenuButtonMouseLeave() {
- this.setState({ menuButtonHover: false });
+ this.setState({
+ menuButtonHover: false
+ });
}
onMenuUpdate(showContextMenu) {
- this.setState({ showContextMenu });
+ this.setState({
+ showContextMenu
+ });
}
render() {
const isCollapsible = this.props.collapsed !== undefined;
- const { enableAnimation, isAnimating, maxHeight, menuButtonHover, showContextMenu } = this.state;
- const { id, eventSource, collapsed, learnMore, title, extraMenuOptions, showPrefName, privacyNoticeURL, dispatch, isFirst, isLast, isWebExtension } = this.props;
+ const {
+ enableAnimation,
+ isAnimating,
+ maxHeight,
+ menuButtonHover,
+ showContextMenu
+ } = this.state;
+ const {
+ id,
+ eventSource,
+ collapsed,
+ learnMore,
+ title,
+ extraMenuOptions,
+ showPrefName,
+ privacyNoticeURL,
+ dispatch,
+ isFirst,
+ isLast,
+ isWebExtension
+ } = this.props;
const active = menuButtonHover || showContextMenu;
let bodyStyle;
+
if (isAnimating && !collapsed) {
- bodyStyle = { maxHeight };
+ bodyStyle = {
+ maxHeight
+ };
} else if (!isAnimating && collapsed) {
- bodyStyle = { display: "none" };
+ bodyStyle = {
+ display: "none"
+ };
}
- return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "section",
- {
- className: `collapsible-section ${this.props.className}${enableAnimation ? " animation-enabled" : ""}${collapsed ? " collapsed" : ""}${active ? " active" : ""}`
- // Note: data-section-id is used for web extension api tests in mozilla central
- , "data-section-id": id },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "section-top-bar" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "h3",
- { className: "section-title" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "click-target-container" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "click-target", onClick: this.onHeaderClick },
- this.renderIcon(),
- getFormattedMessage(title)
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "click-target", onClick: this.onHeaderClick },
- isCollapsible && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", { className: `collapsible-arrow icon ${collapsed ? "icon-arrowhead-forward-small" : "icon-arrowhead-down-small"}` })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "learn-more-link-wrapper" },
- learnMore && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "learn-more-link" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "a",
- { href: learnMore.link.href },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], { id: learnMore.link.id })
- )
- )
- )
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "button",
- {
- className: "context-menu-button icon",
- title: this.props.intl.formatMessage({ id: "context_menu_title" }),
- onClick: this.onMenuButtonClick,
- ref: this.setContextMenuButtonRef },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "span",
- { className: "sr-only" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], { id: "section_context_menu_button_sr" })
- )
- ),
- showContextMenu && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(content_src_components_SectionMenu_SectionMenu__WEBPACK_IMPORTED_MODULE_4__["SectionMenu"], {
- id: id,
- extraOptions: extraMenuOptions,
- eventSource: eventSource,
- showPrefName: showPrefName,
- privacyNoticeURL: privacyNoticeURL,
- collapsed: collapsed,
- onUpdate: this.onMenuUpdate,
- isFirst: isFirst,
- isLast: isLast,
- dispatch: dispatch,
- isWebExtension: isWebExtension })
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_2__["ErrorBoundary"],
- { className: "section-body-fallback" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- {
- className: `section-body${isAnimating ? " animating" : ""}`,
- onTransitionEnd: this.onTransitionEnd,
- ref: this.onBodyMount,
- style: bodyStyle },
- this.props.children
- )
- )
- );
+
+ return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("section", {
+ className: `collapsible-section ${this.props.className}${enableAnimation ? " animation-enabled" : ""}${collapsed ? " collapsed" : ""}${active ? " active" : ""}` // Note: data-section-id is used for web extension api tests in mozilla central
+ ,
+ "data-section-id": id
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "section-top-bar"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("h3", {
+ className: "section-title"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "click-target-container"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "click-target",
+ onClick: this.onHeaderClick
+ }, this.renderIcon(), getFormattedMessage(title)), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "click-target",
+ onClick: this.onHeaderClick
+ }, isCollapsible && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: `collapsible-arrow icon ${collapsed ? "icon-arrowhead-forward-small" : "icon-arrowhead-down-small"}`
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "learn-more-link-wrapper"
+ }, learnMore && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "learn-more-link"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("a", {
+ href: learnMore.link.href
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
+ id: learnMore.link.id
+ })))))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+ className: "context-menu-button icon",
+ title: this.props.intl.formatMessage({
+ id: "context_menu_title"
+ }),
+ onClick: this.onMenuButtonClick,
+ ref: this.setContextMenuButtonRef
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "sr-only"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
+ id: "section_context_menu_button_sr"
+ }))), showContextMenu && react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(content_src_components_SectionMenu_SectionMenu__WEBPACK_IMPORTED_MODULE_4__["SectionMenu"], {
+ id: id,
+ extraOptions: extraMenuOptions,
+ eventSource: eventSource,
+ showPrefName: showPrefName,
+ privacyNoticeURL: privacyNoticeURL,
+ collapsed: collapsed,
+ onUpdate: this.onMenuUpdate,
+ isFirst: isFirst,
+ isLast: isLast,
+ dispatch: dispatch,
+ isWebExtension: isWebExtension
+ }))), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_2__["ErrorBoundary"], {
+ className: "section-body-fallback"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: `section-body${isAnimating ? " animating" : ""}`,
+ onTransitionEnd: this.onTransitionEnd,
+ ref: this.onBodyMount,
+ style: bodyStyle
+ }, this.props.children)));
}
-}
+}
_CollapsibleSection.defaultProps = {
document: global.document || {
addEventListener: () => {},
removeEventListener: () => {},
visibilityState: "hidden"
},
- Prefs: { values: {} }
+ Prefs: {
+ values: {}
+ }
};
-
const CollapsibleSection = Object(react_intl__WEBPACK_IMPORTED_MODULE_0__["injectIntl"])(_CollapsibleSection);
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -4940,18 +4908,18 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-
class ErrorBoundaryFallback extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
constructor(props) {
super(props);
this.windowObj = this.props.windowObj || window;
this.onClick = this.onClick.bind(this);
}
-
/**
* Since we only get here if part of the page has crashed, do a
* forced reload to give us the best chance at recovering.
*/
+
+
onClick() {
this.windowObj.location.reload(true);
}
@@ -4959,47 +4927,45 @@ class ErrorBoundaryFallback extends react__WEBPACK_IMPORTED_MODULE_1___default.a
render() {
const defaultClass = "as-error-fallback";
let className;
+
if ("className" in this.props) {
className = `${this.props.className} ${defaultClass}`;
} else {
className = defaultClass;
- }
+ } // href="#" to force normal link styling stuff (eg cursor on hover)
- // href="#" to force normal link styling stuff (eg cursor on hover)
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "div",
- { className: className },
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
- defaultMessage: "Oops, something went wrong loading this content.",
- id: "error_fallback_default_info" })
- ),
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "span",
- null,
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "a",
- { href: "#", className: "reload-button", onClick: this.onClick },
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
- defaultMessage: "Refresh page to try again.",
- id: "error_fallback_default_refresh_suggestion" })
- )
- )
- );
- }
-}
-ErrorBoundaryFallback.defaultProps = { className: "as-error-fallback" };
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", {
+ className: className
+ }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
+ defaultMessage: "Oops, something went wrong loading this content.",
+ id: "error_fallback_default_info"
+ })), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("a", {
+ href: "#",
+ className: "reload-button",
+ onClick: this.onClick
+ }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
+ defaultMessage: "Refresh page to try again.",
+ id: "error_fallback_default_refresh_suggestion"
+ }))));
+ }
+
+}
+ErrorBoundaryFallback.defaultProps = {
+ className: "as-error-fallback"
+};
class ErrorBoundary extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
constructor(props) {
super(props);
- this.state = { hasError: false };
+ this.state = {
+ hasError: false
+ };
}
componentDidCatch(error, info) {
- this.setState({ hasError: true });
+ this.setState({
+ hasError: true
+ });
}
render() {
@@ -5007,11 +4973,15 @@ class ErrorBoundary extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
return this.props.children;
}
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(this.props.FallbackComponent, { className: this.props.className });
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(this.props.FallbackComponent, {
+ className: this.props.className
+ });
}
-}
-ErrorBoundary.defaultProps = { FallbackComponent: ErrorBoundaryFallback };
+}
+ErrorBoundary.defaultProps = {
+ FallbackComponent: ErrorBoundaryFallback
+};
/***/ }),
/* 38 */
@@ -5033,30 +5003,40 @@ __webpack_require__.r(__webpack_exports__);
-
const DEFAULT_SECTION_MENU_OPTIONS = ["MoveUp", "MoveDown", "Separator", "RemoveSection", "CheckCollapsed", "Separator", "ManageSection"];
const WEBEXT_SECTION_MENU_OPTIONS = ["MoveUp", "MoveDown", "Separator", "CheckCollapsed", "Separator", "ManageWebExtension"];
-
class _SectionMenu extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
getOptions() {
- const { props } = this;
+ const {
+ props
+ } = this;
+ const propOptions = props.isWebExtension ? [...WEBEXT_SECTION_MENU_OPTIONS] : [...DEFAULT_SECTION_MENU_OPTIONS]; // Prepend custom options and a separator
- const propOptions = props.isWebExtension ? [...WEBEXT_SECTION_MENU_OPTIONS] : [...DEFAULT_SECTION_MENU_OPTIONS];
- // Prepend custom options and a separator
if (props.extraOptions) {
propOptions.splice(0, 0, ...props.extraOptions, "Separator");
- }
- // Insert privacy notice before the last option ("ManageSection")
+ } // Insert privacy notice before the last option ("ManageSection")
+
+
if (props.privacyNoticeURL) {
propOptions.splice(-1, 0, "PrivacyNotice");
}
const options = propOptions.map(o => content_src_lib_section_menu_options__WEBPACK_IMPORTED_MODULE_4__["SectionMenuOptions"][o](props)).map(option => {
- const { action, id, type, userEvent } = option;
+ const {
+ action,
+ id,
+ type,
+ userEvent
+ } = option;
+
if (!type && id) {
- option.label = props.intl.formatMessage({ id });
+ option.label = props.intl.formatMessage({
+ id
+ });
+
option.onClick = () => {
props.dispatch(action);
+
if (userEvent) {
props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
event: userEvent,
@@ -5065,12 +5045,12 @@ class _SectionMenu extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComp
}
};
}
- return option;
- });
- // This is for accessibility to support making each item tabbable.
+ return option;
+ }); // This is for accessibility to support making each item tabbable.
// We want to know which item is the first and which item
// is the last, so we can close the context menu accordingly.
+
options[0].first = true;
options[options.length - 1].last = true;
return options;
@@ -5079,10 +5059,11 @@ class _SectionMenu extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComp
render() {
return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(content_src_components_ContextMenu_ContextMenu__WEBPACK_IMPORTED_MODULE_1__["ContextMenu"], {
onUpdate: this.props.onUpdate,
- options: this.getOptions() });
+ options: this.getOptions()
+ });
}
-}
+}
const SectionMenu = Object(react_intl__WEBPACK_IMPORTED_MODULE_2__["injectIntl"])(_SectionMenu);
/***/ }),
@@ -5094,19 +5075,24 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SectionMenuOptions", function() { return SectionMenuOptions; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
-
/**
* List of functions that return items that can be included as menu options in a
* SectionMenu. All functions take the section as the only parameter.
*/
+
const SectionMenuOptions = {
- Separator: () => ({ type: "separator" }),
+ Separator: () => ({
+ type: "separator"
+ }),
MoveUp: section => ({
id: "section_menu_action_move_up",
icon: "arrowhead-up",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SECTION_MOVE,
- data: { id: section.id, direction: -1 }
+ data: {
+ id: section.id,
+ direction: -1
+ }
}),
userEvent: "MENU_MOVE_UP",
disabled: !!section.isFirst
@@ -5116,7 +5102,10 @@ const SectionMenuOptions = {
icon: "arrowhead-down",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SECTION_MOVE,
- data: { id: section.id, direction: +1 }
+ data: {
+ id: section.id,
+ direction: +1
+ }
}),
userEvent: "MENU_MOVE_DOWN",
disabled: !!section.isLast
@@ -5130,36 +5119,64 @@ const SectionMenuOptions = {
CollapseSection: section => ({
id: "section_menu_action_collapse_section",
icon: "minimize",
- action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].UPDATE_SECTION_PREFS, data: { id: section.id, value: { collapsed: true } } }),
+ action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].UPDATE_SECTION_PREFS,
+ data: {
+ id: section.id,
+ value: {
+ collapsed: true
+ }
+ }
+ }),
userEvent: "MENU_COLLAPSE"
}),
ExpandSection: section => ({
id: "section_menu_action_expand_section",
icon: "maximize",
- action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].UPDATE_SECTION_PREFS, data: { id: section.id, value: { collapsed: false } } }),
+ action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].UPDATE_SECTION_PREFS,
+ data: {
+ id: section.id,
+ value: {
+ collapsed: false
+ }
+ }
+ }),
userEvent: "MENU_EXPAND"
}),
ManageSection: section => ({
id: "section_menu_action_manage_section",
icon: "settings",
- action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SETTINGS_OPEN }),
+ action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SETTINGS_OPEN
+ }),
userEvent: "MENU_MANAGE"
}),
ManageWebExtension: section => ({
id: "section_menu_action_manage_webext",
icon: "settings",
- action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].OPEN_WEBEXT_SETTINGS, data: section.id })
+ action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].OPEN_WEBEXT_SETTINGS,
+ data: section.id
+ })
}),
AddTopSite: section => ({
id: "section_menu_action_add_topsite",
icon: "add",
- action: { type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_EDIT, data: { index: -1 } },
+ action: {
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_EDIT,
+ data: {
+ index: -1
+ }
+ },
userEvent: "MENU_ADD_TOPSITE"
}),
AddSearchShortcut: section => ({
id: "section_menu_action_add_search_engine",
icon: "search",
- action: { type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL },
+ action: {
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL
+ },
userEvent: "MENU_ADD_SEARCH"
}),
PrivacyNotice: section => ({
@@ -5167,7 +5184,9 @@ const SectionMenuOptions = {
icon: "info",
action: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].OPEN_LINK,
- data: { url: section.privacyNoticeURL }
+ data: {
+ url: section.privacyNoticeURL
+ }
}),
userEvent: "MENU_PRIVACY_NOTICE"
}),
@@ -5187,18 +5206,15 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_2__);
-
-
-// Currently record only a fixed set of sections. This will prevent data
+ // Currently record only a fixed set of sections. This will prevent data
// from custom sections from showing up or from topstories.
-const RECORDED_SECTIONS = ["highlights", "topsites"];
+const RECORDED_SECTIONS = ["highlights", "topsites"];
class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Component {
constructor(props) {
- super(props);
- // Just for test dependency injection:
- this.perfSvc = this.props.perfSvc || common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__["perfService"];
+ super(props); // Just for test dependency injection:
+ this.perfSvc = this.props.perfSvc || common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__["perfService"];
this._sendBadStateEvent = this._sendBadStateEvent.bind(this);
this._sendPaintedEvent = this._sendPaintedEvent.bind(this);
this._reportMissingData = false;
@@ -5221,7 +5237,6 @@ class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Co
this._maybeSendPaintedEvent();
}
-
/**
* Call the given callback after the upcoming frame paints.
*
@@ -5242,6 +5257,8 @@ class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Co
*
* @returns void
*/
+
+
_afterFramePaint(callback) {
requestAnimationFrame(() => setTimeout(callback, 0));
}
@@ -5253,8 +5270,8 @@ class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Co
// Remember to report back when data is available.
this._reportMissingData = true;
} else if (this._reportMissingData) {
- this._reportMissingData = false;
- // Report how long it took for component to become initialized.
+ this._reportMissingData = false; // Report how long it took for component to become initialized.
+
this._sendBadStateEvent();
}
}
@@ -5263,53 +5280,57 @@ class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Co
// If we've already handled a timestamp, don't do it again.
if (this._timestampHandled || !this.props.initialized) {
return;
- }
-
- // And if we haven't, we're doing so now, so remember that. Even if
+ } // And if we haven't, we're doing so now, so remember that. Even if
// something goes wrong in the callback, we can't try again, as we'd be
// sending back the wrong data, and we have to do it here, so that other
// calls to this method while waiting for the next frame won't also try to
// handle it.
+
+
this._timestampHandled = true;
+
this._afterFramePaint(this._sendPaintedEvent);
}
-
/**
* Triggered by call to render. Only first call goes through due to
* `_recordedFirstRender`.
*/
+
+
_ensureFirstRenderTsRecorded() {
// Used as t0 for recording how long component took to initialize.
if (!this._recordedFirstRender) {
- this._recordedFirstRender = true;
- // topsites_first_render_ts, highlights_first_render_ts.
+ this._recordedFirstRender = true; // topsites_first_render_ts, highlights_first_render_ts.
+
const key = `${this.props.id}_first_render_ts`;
this.perfSvc.mark(key);
}
}
-
/**
* Creates `TELEMETRY_UNDESIRED_EVENT` with timestamp in ms
* of how much longer the data took to be ready for display than it would
* have been the ideal case.
* https://github.com/mozilla/ping-centre/issues/98
*/
+
+
_sendBadStateEvent() {
// highlights_data_ready_ts, topsites_data_ready_ts.
const dataReadyKey = `${this.props.id}_data_ready_ts`;
this.perfSvc.mark(dataReadyKey);
try {
- const firstRenderKey = `${this.props.id}_first_render_ts`;
- // value has to be Int32.
+ const firstRenderKey = `${this.props.id}_first_render_ts`; // value has to be Int32.
+
const value = parseInt(this.perfSvc.getMostRecentAbsMarkStartByName(dataReadyKey) - this.perfSvc.getMostRecentAbsMarkStartByName(firstRenderKey), 10);
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_SESSION_PERF_DATA,
// highlights_data_late_by_ms, topsites_data_late_by_ms.
- data: { [`${this.props.id}_data_late_by_ms`]: value }
+ data: {
+ [`${this.props.id}_data_late_by_ms`]: value
+ }
}));
- } catch (ex) {
- // If this failed, it's likely because the `privacy.resistFingerprinting`
+ } catch (ex) {// If this failed, it's likely because the `privacy.resistFingerprinting`
// pref is true.
}
}
@@ -5318,22 +5339,20 @@ class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Co
// Record first_painted event but only send if topsites.
if (this.props.id !== "topsites") {
return;
- }
+ } // topsites_first_painted_ts.
+
- // topsites_first_painted_ts.
const key = `${this.props.id}_first_painted_ts`;
this.perfSvc.mark(key);
try {
const data = {};
data[key] = this.perfSvc.getMostRecentAbsMarkStartByName(key);
-
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_SESSION_PERF_DATA,
data
}));
- } catch (ex) {
- // If this failed, it's likely because the `privacy.resistFingerprinting`
+ } catch (ex) {// If this failed, it's likely because the `privacy.resistFingerprinting`
// pref is true. We should at least not blow up, and should continue
// to set this._timestampHandled to avoid going through this again.
}
@@ -5342,10 +5361,13 @@ class ComponentPerfTimer extends react__WEBPACK_IMPORTED_MODULE_2___default.a.Co
render() {
if (RECORDED_SECTIONS.includes(this.props.id)) {
this._ensureFirstRenderTsRecorded();
+
this._maybeSendBadStateEvent();
}
+
return this.props.children;
}
+
}
/***/ }),
@@ -5362,13 +5384,15 @@ if (typeof ChromeUtils !== "undefined") {
// Use a var here instead of let outside to avoid creating a locally scoped
// variable that hides the global, which we modify for testing.
// eslint-disable-next-line no-var, vars-on-top
- var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+ var {
+ Services
+ } = ChromeUtils.import("resource://gre/modules/Services.jsm");
}
let usablePerfObj;
-
/* istanbul ignore else */
// eslint-disable-next-line block-scoped-var
+
if (typeof Services !== "undefined") {
// Borrow the high-resolution timer from the hidden window....
// eslint-disable-next-line block-scoped-var
@@ -5382,7 +5406,9 @@ if (typeof Services !== "undefined") {
// task.
usablePerfObj = {
now() {},
+
mark() {}
+
};
}
@@ -5395,8 +5421,6 @@ function _PerfService(options) {
this._perf = usablePerfObj;
}
}
-
-
_PerfService.prototype = {
/**
* Calls the underlying mark() method on the appropriate Window.performance
@@ -5480,8 +5504,8 @@ _PerfService.prototype = {
let mostRecentEntry = entries[entries.length - 1];
return this._perf.timeOrigin + mostRecentEntry.startTime;
}
-};
+};
var perfService = new _PerfService();
/***/ }),
@@ -5504,41 +5528,40 @@ __webpack_require__.r(__webpack_exports__);
class SelectableSearchShortcut extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComponent {
render() {
- const { shortcut, selected } = this.props;
- const imageStyle = { backgroundImage: `url("${shortcut.tippyTopIcon}")` };
- return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- { className: "top-site-outer search-shortcut" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("input", { type: "checkbox", id: shortcut.keyword, name: shortcut.keyword, checked: selected, onChange: this.props.onChange }),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "label",
- { htmlFor: shortcut.keyword },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- { className: "top-site-inner" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "span",
- null,
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- { className: "tile" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", { className: "top-site-icon rich-icon", style: imageStyle, "data-fallback": "@" }),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", { className: "top-site-icon search-topsite" })
- ),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- { className: "title" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "span",
- { dir: "auto" },
- shortcut.keyword
- )
- )
- )
- )
- )
- );
+ const {
+ shortcut,
+ selected
+ } = this.props;
+ const imageStyle = {
+ backgroundImage: `url("${shortcut.tippyTopIcon}")`
+ };
+ return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "top-site-outer search-shortcut"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("input", {
+ type: "checkbox",
+ id: shortcut.keyword,
+ name: shortcut.keyword,
+ checked: selected,
+ onChange: this.props.onChange
+ }), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("label", {
+ htmlFor: shortcut.keyword
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "top-site-inner"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "tile"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "top-site-icon rich-icon",
+ style: imageStyle,
+ "data-fallback": "@"
+ }), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "top-site-icon search-topsite"
+ })), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "title"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", {
+ dir: "auto"
+ }, shortcut.keyword))))));
}
+
}
class SearchShortcutsForm extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComponent {
@@ -5546,27 +5569,40 @@ class SearchShortcutsForm extends react__WEBPACK_IMPORTED_MODULE_2___default.a.P
super(props);
this.handleChange = this.handleChange.bind(this);
this.onCancelButtonClick = this.onCancelButtonClick.bind(this);
- this.onSaveButtonClick = this.onSaveButtonClick.bind(this);
+ this.onSaveButtonClick = this.onSaveButtonClick.bind(this); // clone the shortcuts and add them to the state so we can add isSelected property
- // clone the shortcuts and add them to the state so we can add isSelected property
const shortcuts = [];
- const { rows, searchShortcuts } = props.TopSites;
+ const {
+ rows,
+ searchShortcuts
+ } = props.TopSites;
searchShortcuts.forEach(shortcut => {
- shortcuts.push(Object.assign({}, shortcut, {
+ shortcuts.push({ ...shortcut,
isSelected: !!rows.find(row => row && row.isPinned && row.searchTopSite && row.label === shortcut.keyword)
- }));
+ });
});
- this.state = { shortcuts };
+ this.state = {
+ shortcuts
+ };
}
handleChange(event) {
- const { target } = event;
- const { name, checked } = target;
+ const {
+ target
+ } = event;
+ const {
+ name,
+ checked
+ } = target;
this.setState(prevState => {
const shortcuts = prevState.shortcuts.slice();
- let shortcut = shortcuts.find(({ keyword }) => keyword === name);
+ let shortcut = shortcuts.find(({
+ keyword
+ }) => keyword === name);
shortcut.isSelected = checked;
- return { shortcuts };
+ return {
+ shortcuts
+ };
});
}
@@ -5576,46 +5612,52 @@ class SearchShortcutsForm extends react__WEBPACK_IMPORTED_MODULE_2___default.a.P
}
onSaveButtonClick(ev) {
- ev.preventDefault();
+ ev.preventDefault(); // Check if there were any changes and act accordingly
- // Check if there were any changes and act accordingly
- const { rows } = this.props.TopSites;
+ const {
+ rows
+ } = this.props.TopSites;
const pinQueue = [];
const unpinQueue = [];
this.state.shortcuts.forEach(shortcut => {
const alreadyPinned = rows.find(row => row && row.isPinned && row.searchTopSite && row.label === shortcut.keyword);
+
if (shortcut.isSelected && !alreadyPinned) {
pinQueue.push(this._searchTopSite(shortcut));
} else if (!shortcut.isSelected && alreadyPinned) {
- unpinQueue.push({ url: alreadyPinned.url, searchVendor: shortcut.shortURL });
+ unpinQueue.push({
+ url: alreadyPinned.url,
+ searchVendor: shortcut.shortURL
+ });
}
- });
+ }); // Tell the feed to do the work.
- // Tell the feed to do the work.
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].UPDATE_PINNED_SEARCH_SHORTCUTS,
data: {
addedShortcuts: pinQueue,
deletedShortcuts: unpinQueue
}
- }));
+ })); // Send the Telemetry pings.
- // Send the Telemetry pings.
pinQueue.forEach(shortcut => {
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
source: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_3__["TOP_SITES_SOURCE"],
event: "SEARCH_EDIT_ADD",
- value: { search_vendor: shortcut.searchVendor }
+ value: {
+ search_vendor: shortcut.searchVendor
+ }
}));
});
unpinQueue.forEach(shortcut => {
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
source: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_3__["TOP_SITES_SOURCE"],
event: "SEARCH_EDIT_DELETE",
- value: { search_vendor: shortcut.searchVendor }
+ value: {
+ search_vendor: shortcut.searchVendor
+ }
}));
});
-
this.props.onClose();
}
@@ -5629,39 +5671,36 @@ class SearchShortcutsForm extends react__WEBPACK_IMPORTED_MODULE_2___default.a.P
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "form",
- { className: "topsite-form" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- { className: "search-shortcuts-container" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "h3",
- { className: "section-title" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "section_menu_action_add_search_engine" })
- ),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "div",
- null,
- this.state.shortcuts.map(shortcut => react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(SelectableSearchShortcut, { key: shortcut.keyword, shortcut: shortcut, selected: shortcut.isSelected, onChange: this.handleChange }))
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "section",
- { className: "actions" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "button",
- { className: "cancel", type: "button", onClick: this.onCancelButtonClick },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "topsites_form_cancel_button" })
- ),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "button",
- { className: "done", type: "submit", onClick: this.onSaveButtonClick },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "topsites_form_save_button" })
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("form", {
+ className: "topsite-form"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", {
+ className: "search-shortcuts-container"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("h3", {
+ className: "section-title"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "section_menu_action_add_search_engine"
+ })), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("div", null, this.state.shortcuts.map(shortcut => react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(SelectableSearchShortcut, {
+ key: shortcut.keyword,
+ shortcut: shortcut,
+ selected: shortcut.isSelected,
+ onChange: this.handleChange
+ })))), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("section", {
+ className: "actions"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("button", {
+ className: "cancel",
+ type: "button",
+ onClick: this.onCancelButtonClick
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "topsites_form_cancel_button"
+ })), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("button", {
+ className: "done",
+ type: "submit",
+ onClick: this.onSaveButtonClick
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "topsites_form_save_button"
+ }))));
}
+
}
/***/ }),
@@ -5684,8 +5723,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(44);
/* harmony import */ var common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(59);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -5697,15 +5735,18 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
constructor(props) {
super(props);
- this.state = { screenshotImage: null };
+ this.state = {
+ screenshotImage: null
+ };
this.onDragEvent = this.onDragEvent.bind(this);
this.onKeyPress = this.onKeyPress.bind(this);
}
-
/*
* Helper to determine whether the drop zone should allow a drop. We only allow
* dropping top sites for now.
*/
+
+
_allowDrop(e) {
return e.dataTransfer.types.includes("text/topsite-index");
}
@@ -5717,7 +5758,9 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
if (this.dragged) {
event.preventDefault();
}
+
break;
+
case "dragstart":
this.dragged = true;
event.dataTransfer.effectAllowed = "move";
@@ -5725,9 +5768,11 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
event.target.blur();
this.props.onDragEvent(event, this.props.index, this.props.link, this.props.title);
break;
+
case "dragend":
this.props.onDragEvent(event);
break;
+
case "dragenter":
case "dragover":
case "drop":
@@ -5735,18 +5780,20 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
event.preventDefault();
this.props.onDragEvent(event, this.props.index);
}
+
break;
+
case "mousedown":
// Block the scroll wheel from appearing for middle clicks on search top sites
if (event.button === 1 && this.props.link.searchTopSite) {
event.preventDefault();
- }
- // Reset at the first mouse event of a potential drag
+ } // Reset at the first mouse event of a potential drag
+
+
this.dragged = false;
break;
}
}
-
/**
* Helper to obtain the next state based on nextProps and prevState.
*
@@ -5758,34 +5805,42 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
*
* See https://github.com/airbnb/enzyme/blob/master/packages/enzyme-adapter-react-16/package.json#L43.
*/
+
+
static getNextStateFromProps(nextProps, prevState) {
- const { screenshot } = nextProps.link;
+ const {
+ screenshot
+ } = nextProps.link;
const imageInState = content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__["ScreenshotUtils"].isRemoteImageLocal(prevState.screenshotImage, screenshot);
+
if (imageInState) {
return null;
- }
-
- // Since image was updated, attempt to revoke old image blob URL, if it exists.
- content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__["ScreenshotUtils"].maybeRevokeBlobObjectURL(prevState.screenshotImage);
+ } // Since image was updated, attempt to revoke old image blob URL, if it exists.
- return { screenshotImage: content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__["ScreenshotUtils"].createLocalImageObject(screenshot) };
- }
- // NOTE: Remove this function when we update React to >= 16.3 since React will
+ content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__["ScreenshotUtils"].maybeRevokeBlobObjectURL(prevState.screenshotImage);
+ return {
+ screenshotImage: content_src_lib_screenshot_utils__WEBPACK_IMPORTED_MODULE_5__["ScreenshotUtils"].createLocalImageObject(screenshot)
+ };
+ } // NOTE: Remove this function when we update React to >= 16.3 since React will
// call getDerivedStateFromProps automatically. We will also need to
// rename getNextStateFromProps to getDerivedStateFromProps.
+
+
componentWillMount() {
const nextState = TopSiteLink.getNextStateFromProps(this.props, this.state);
+
if (nextState) {
this.setState(nextState);
}
- }
-
- // NOTE: Remove this function when we update React to >= 16.3 since React will
+ } // NOTE: Remove this function when we update React to >= 16.3 since React will
// call getDerivedStateFromProps automatically. We will also need to
// rename getNextStateFromProps to getDerivedStateFromProps.
+
+
componentWillReceiveProps(nextProps) {
const nextState = TopSiteLink.getNextStateFromProps(nextProps, this.state);
+
if (nextState) {
this.setState(nextState);
}
@@ -5805,9 +5860,20 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
}
render() {
- const { children, className, defaultStyle, isDraggable, link, onClick, title } = this.props;
+ const {
+ children,
+ className,
+ defaultStyle,
+ isDraggable,
+ link,
+ onClick,
+ title
+ } = this.props;
const topSiteOuterClassName = `top-site-outer${className ? ` ${className}` : ""}${link.isDragged ? " dragged" : ""}${link.searchTopSite ? " search-shortcut" : ""}`;
- const { tippyTopIcon, faviconSize } = link;
+ const {
+ tippyTopIcon,
+ faviconSize
+ } = link;
const [letterFallback] = title;
let imageClassName;
let imageStyle;
@@ -5815,6 +5881,7 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
let smallFaviconStyle;
let smallFaviconFallback;
let hasScreenshotImage = this.state.screenshotImage && this.state.screenshotImage.url;
+
if (defaultStyle) {
// force no styles (letter fallback) even if the link has imagery
smallFaviconFallback = false;
@@ -5824,7 +5891,9 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
backgroundColor: link.backgroundColor,
backgroundImage: `url(${tippyTopIcon})`
};
- smallFaviconStyle = { backgroundImage: `url(${tippyTopIcon})` };
+ smallFaviconStyle = {
+ backgroundImage: `url(${tippyTopIcon})`
+ };
} else if (link.customScreenshotURL) {
// assume high quality custom screenshot and use rich icon styles and class names
imageClassName = "top-site-icon rich-icon";
@@ -5842,12 +5911,15 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
} else {
// styles and class names for top sites with screenshot + small icon in top left corner
imageClassName = `screenshot${hasScreenshotImage ? " active" : ""}`;
- imageStyle = { backgroundImage: hasScreenshotImage ? `url(${this.state.screenshotImage.url})` : "none" };
+ imageStyle = {
+ backgroundImage: hasScreenshotImage ? `url(${this.state.screenshotImage.url})` : "none"
+ }; // only show a favicon in top left if it's greater than 16x16
- // only show a favicon in top left if it's greater than 16x16
if (faviconSize >= _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__["MIN_CORNER_FAVICON_SIZE"]) {
showSmallFavicon = true;
- smallFaviconStyle = { backgroundImage: `url(${link.favicon})` };
+ smallFaviconStyle = {
+ backgroundImage: `url(${link.favicon})`
+ };
} else if (hasScreenshotImage) {
// Don't show a small favicon if there is no screenshot, because that
// would result in two fallback icons
@@ -5855,7 +5927,9 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
smallFaviconFallback = true;
}
}
+
let draggableProps = {};
+
if (isDraggable) {
draggableProps = {
onClick: this.onDragEvent,
@@ -5864,71 +5938,82 @@ class TopSiteLink extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureCompo
onMouseDown: this.onDragEvent
};
}
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "li",
- _extends({ className: topSiteOuterClassName, onDrop: this.onDragEvent, onDragOver: this.onDragEvent, onDragEnter: this.onDragEvent, onDragLeave: this.onDragEvent }, draggableProps),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "top-site-inner" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "a",
- { href: link.searchTopSite ? undefined : link.url, tabIndex: "0", onKeyPress: this.onKeyPress, onClick: onClick, draggable: true },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "tile", "aria-hidden": true, "data-fallback": letterFallback },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: imageClassName, style: imageStyle }),
- link.searchTopSite && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "top-site-icon search-topsite" }),
- showSmallFavicon && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
- className: "top-site-icon default-icon",
- "data-fallback": smallFaviconFallback && letterFallback,
- style: smallFaviconStyle })
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: `title ${link.isPinned ? "pinned" : ""}` },
- link.isPinned && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "icon icon-pin-small" }),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- { dir: "auto" },
- title
- )
- )
- ),
- children
- )
- );
+
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("li", _extends({
+ className: topSiteOuterClassName,
+ onDrop: this.onDragEvent,
+ onDragOver: this.onDragEvent,
+ onDragEnter: this.onDragEvent,
+ onDragLeave: this.onDragEvent
+ }, draggableProps), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "top-site-inner"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("a", {
+ href: link.searchTopSite ? undefined : link.url,
+ tabIndex: "0",
+ onKeyPress: this.onKeyPress,
+ onClick: onClick,
+ draggable: true
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "tile",
+ "aria-hidden": true,
+ "data-fallback": letterFallback
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: imageClassName,
+ style: imageStyle
+ }), link.searchTopSite && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "top-site-icon search-topsite"
+ }), showSmallFavicon && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "top-site-icon default-icon",
+ "data-fallback": smallFaviconFallback && letterFallback,
+ style: smallFaviconStyle
+ })), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: `title ${link.isPinned ? "pinned" : ""}`
+ }, link.isPinned && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "icon icon-pin-small"
+ }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ dir: "auto"
+ }, title))), children));
}
+
}
TopSiteLink.defaultProps = {
title: "",
link: {},
isDraggable: true
};
-
class TopSite extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
constructor(props) {
super(props);
- this.state = { showContextMenu: false };
+ this.state = {
+ showContextMenu: false
+ };
this.onLinkClick = this.onLinkClick.bind(this);
this.onMenuButtonClick = this.onMenuButtonClick.bind(this);
this.onMenuUpdate = this.onMenuUpdate.bind(this);
}
-
/**
* Report to telemetry additional information about the item.
*/
+
+
_getTelemetryInfo() {
- const value = { icon_type: this.props.link.iconType };
- // Filter out "not_pinned" type for being the default
+ const value = {
+ icon_type: this.props.link.iconType
+ }; // Filter out "not_pinned" type for being the default
+
if (this.props.link.isPinned) {
value.card_type = "pinned";
}
+
if (this.props.link.searchTopSite) {
// Set the card_type as "search" regardless of its pinning status
value.card_type = "search";
value.search_vendor = this.props.link.hostname;
}
- return { value };
+
+ return {
+ value
+ };
}
userEvent(event) {
@@ -5940,21 +6025,37 @@ class TopSite extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
}
onLinkClick(event) {
- this.userEvent("CLICK");
-
- // Specially handle a top site link click for "typed" frecency bonus as
+ this.userEvent("CLICK"); // Specially handle a top site link click for "typed" frecency bonus as
// specified as a property on the link.
+
event.preventDefault();
- const { altKey, button, ctrlKey, metaKey, shiftKey } = event;
+ const {
+ altKey,
+ button,
+ ctrlKey,
+ metaKey,
+ shiftKey
+ } = event;
+
if (!this.props.link.searchTopSite) {
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].OPEN_LINK,
- data: Object.assign(this.props.link, { event: { altKey, button, ctrlKey, metaKey, shiftKey } })
+ data: Object.assign(this.props.link, {
+ event: {
+ altKey,
+ button,
+ ctrlKey,
+ metaKey,
+ shiftKey
+ }
+ })
}));
} else {
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].FILL_SEARCH_TERM,
- data: { label: this.props.link.label }
+ data: {
+ label: this.props.link.label
+ }
}));
}
}
@@ -5962,50 +6063,62 @@ class TopSite extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
onMenuButtonClick(event) {
event.preventDefault();
this.props.onActivate(this.props.index);
- this.setState({ showContextMenu: true });
+ this.setState({
+ showContextMenu: true
+ });
}
onMenuUpdate(showContextMenu) {
- this.setState({ showContextMenu });
+ this.setState({
+ showContextMenu
+ });
}
render() {
- const { props } = this;
- const { link } = props;
+ const {
+ props
+ } = this;
+ const {
+ link
+ } = props;
const isContextMenuOpen = this.state.showContextMenu && props.activeIndex === props.index;
const title = link.label || link.hostname;
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- TopSiteLink,
- _extends({}, props, { onClick: this.onLinkClick, onDragEvent: this.props.onDragEvent, className: `${props.className || ""}${isContextMenuOpen ? " active" : ""}`, title: title }),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- null,
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- { className: "context-menu-button icon", title: this.props.intl.formatMessage({ id: "context_menu_title" }), onClick: this.onMenuButtonClick },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- { className: "sr-only" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "context_menu_button_sr", values: { title } })
- )
- ),
- isContextMenuOpen && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(content_src_components_LinkMenu_LinkMenu__WEBPACK_IMPORTED_MODULE_3__["LinkMenu"], {
- dispatch: props.dispatch,
- index: props.index,
- onUpdate: this.onMenuUpdate,
- options: link.searchTopSite ? _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__["TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS"] : _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__["TOP_SITES_CONTEXT_MENU_OPTIONS"],
- site: link,
- siteInfo: this._getTelemetryInfo(),
- source: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__["TOP_SITES_SOURCE"] })
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(TopSiteLink, _extends({}, props, {
+ onClick: this.onLinkClick,
+ onDragEvent: this.props.onDragEvent,
+ className: `${props.className || ""}${isContextMenuOpen ? " active" : ""}`,
+ title: title
+ }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "context-menu-button icon",
+ title: this.props.intl.formatMessage({
+ id: "context_menu_title"
+ }),
+ onClick: this.onMenuButtonClick
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ className: "sr-only"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "context_menu_button_sr",
+ values: {
+ title
+ }
+ }))), isContextMenuOpen && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(content_src_components_LinkMenu_LinkMenu__WEBPACK_IMPORTED_MODULE_3__["LinkMenu"], {
+ dispatch: props.dispatch,
+ index: props.index,
+ onUpdate: this.onMenuUpdate,
+ options: link.searchTopSite ? _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__["TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS"] : _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__["TOP_SITES_CONTEXT_MENU_OPTIONS"],
+ site: link,
+ siteInfo: this._getTelemetryInfo(),
+ source: _TopSitesConstants__WEBPACK_IMPORTED_MODULE_2__["TOP_SITES_SOURCE"]
+ })));
}
+
}
TopSite.defaultProps = {
link: {},
+
onActivate() {}
-};
+};
class TopSitePlaceholder extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
constructor(props) {
super(props);
@@ -6013,20 +6126,28 @@ class TopSitePlaceholder extends react__WEBPACK_IMPORTED_MODULE_4___default.a.Pu
}
onEditButtonClick() {
- this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_EDIT, data: { index: this.props.index } });
+ this.props.dispatch({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_EDIT,
+ data: {
+ index: this.props.index
+ }
+ });
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- TopSiteLink,
- _extends({}, this.props, { className: `placeholder ${this.props.className || ""}`, isDraggable: false }),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", { className: "context-menu-button edit-button icon",
- title: this.props.intl.formatMessage({ id: "edit_topsites_edit_button" }),
- onClick: this.onEditButtonClick })
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(TopSiteLink, _extends({}, this.props, {
+ className: `placeholder ${this.props.className || ""}`,
+ isDraggable: false
+ }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "context-menu-button edit-button icon",
+ title: this.props.intl.formatMessage({
+ id: "edit_topsites_edit_button"
+ }),
+ onClick: this.onEditButtonClick
+ }));
}
-}
+}
class _TopSiteList extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
static get DEFAULT_STATE() {
return {
@@ -6049,6 +6170,7 @@ class _TopSiteList extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComp
if (this.state.draggedSite) {
const prevTopSites = this.props.TopSites && this.props.TopSites.rows;
const newTopSites = nextProps.TopSites && nextProps.TopSites.rows;
+
if (prevTopSites && prevTopSites[this.state.draggedIndex] && prevTopSites[this.state.draggedIndex].url === this.state.draggedSite.url && (!newTopSites[this.state.draggedIndex] || newTopSites[this.state.draggedIndex].url !== this.state.draggedSite.url)) {
// We got the new order from the redux store via props. We can clear state now.
this.setState(_TopSiteList.DEFAULT_STATE);
@@ -6076,36 +6198,50 @@ class _TopSiteList extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComp
});
this.userEvent("DRAG", index);
break;
+
case "dragend":
if (!this.dropped) {
// If there was no drop event, reset the state to the default.
this.setState(_TopSiteList.DEFAULT_STATE);
}
+
break;
+
case "dragenter":
if (index === this.state.draggedIndex) {
- this.setState({ topSitesPreview: null });
+ this.setState({
+ topSitesPreview: null
+ });
} else {
- this.setState({ topSitesPreview: this._makeTopSitesPreview(index) });
+ this.setState({
+ topSitesPreview: this._makeTopSitesPreview(index)
+ });
}
+
break;
+
case "drop":
if (index !== this.state.draggedIndex) {
this.dropped = true;
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TOP_SITES_INSERT,
data: {
- site: Object.assign({
+ site: {
url: this.state.draggedSite.url,
label: this.state.draggedTitle,
- customScreenshotURL: this.state.draggedSite.customScreenshotURL
- }, this.state.draggedSite.searchTopSite && { searchTopSite: true }),
+ customScreenshotURL: this.state.draggedSite.customScreenshotURL,
+ // Only if the search topsites experiment is enabled
+ ...(this.state.draggedSite.searchTopSite && {
+ searchTopSite: true
+ })
+ },
index,
draggedFromIndex: this.state.draggedIndex
}
}));
this.userEvent("DROP", index);
}
+
break;
}
}
@@ -6116,17 +6252,23 @@ class _TopSiteList extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComp
topSites.length = this.props.TopSitesRows * common_Reducers_jsm__WEBPACK_IMPORTED_MODULE_6__["TOP_SITES_MAX_SITES_PER_ROW"];
return topSites;
}
-
/**
* Make a preview of the topsites that will be the result of dropping the currently
* dragged site at the specified index.
*/
+
+
_makeTopSitesPreview(index) {
const topSites = this._getTopSites();
+
topSites[this.state.draggedIndex] = null;
const pinnedOnly = topSites.map(site => site && site.isPinned ? site : null);
const unpinned = topSites.filter(site => site && !site.isPinned);
- const siteToInsert = Object.assign({}, this.state.draggedSite, { isPinned: true, isDragged: true });
+ const siteToInsert = Object.assign({}, this.state.draggedSite, {
+ isPinned: true,
+ isDragged: true
+ });
+
if (!pinnedOnly[index]) {
pinnedOnly[index] = siteToInsert;
} else {
@@ -6134,22 +6276,26 @@ class _TopSiteList extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComp
// hole left by the site being dragged.
let holeIndex = index;
const indexStep = index > this.state.draggedIndex ? -1 : 1;
+
while (pinnedOnly[holeIndex]) {
holeIndex += indexStep;
- }
+ } // Shift towards the hole.
+
- // Shift towards the hole.
const shiftingStep = index > this.state.draggedIndex ? 1 : -1;
+
while (holeIndex !== index) {
const nextIndex = holeIndex + shiftingStep;
pinnedOnly[holeIndex] = pinnedOnly[nextIndex];
holeIndex = nextIndex;
}
+
pinnedOnly[index] = siteToInsert;
- }
+ } // Fill in the remaining holes with unpinned sites.
+
- // Fill in the remaining holes with unpinned sites.
const preview = pinnedOnly;
+
for (let i = 0; i < preview.length; i++) {
if (!preview[i]) {
preview[i] = unpinned.shift() || null;
@@ -6160,51 +6306,59 @@ class _TopSiteList extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComp
}
onActivate(index) {
- this.setState({ activeIndex: index });
+ this.setState({
+ activeIndex: index
+ });
}
render() {
- const { props } = this;
+ const {
+ props
+ } = this;
+
const topSites = this.state.topSitesPreview || this._getTopSites();
+
const topSitesUI = [];
const commonProps = {
onDragEvent: this.onDragEvent,
dispatch: props.dispatch,
intl: props.intl
- };
- // We assign a key to each placeholder slot. We need it to be independent
+ }; // We assign a key to each placeholder slot. We need it to be independent
// of the slot index (i below) so that the keys used stay the same during
// drag and drop reordering and the underlying DOM nodes are reused.
// This mostly (only?) affects linux so be sure to test on linux before changing.
- let holeIndex = 0;
- // On narrow viewports, we only show 6 sites per row. We'll mark the rest as
+ let holeIndex = 0; // On narrow viewports, we only show 6 sites per row. We'll mark the rest as
// .hide-for-narrow to hide in CSS via @media query.
+
const maxNarrowVisibleIndex = props.TopSitesRows * 6;
for (let i = 0, l = topSites.length; i < l; i++) {
- const link = topSites[i] && Object.assign({}, topSites[i], { iconType: this.props.topSiteIconType(topSites[i]) });
+ const link = topSites[i] && Object.assign({}, topSites[i], {
+ iconType: this.props.topSiteIconType(topSites[i])
+ });
const slotProps = {
key: link ? link.url : holeIndex++,
index: i
};
+
if (i >= maxNarrowVisibleIndex) {
slotProps.className = "hide-for-narrow";
}
+
topSitesUI.push(!link ? react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(TopSitePlaceholder, _extends({}, slotProps, commonProps)) : react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(TopSite, _extends({
link: link,
activeIndex: this.state.activeIndex,
onActivate: this.onActivate
}, slotProps, commonProps)));
}
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "ul",
- { className: `top-sites-list${this.state.draggedSite ? " dnd-active" : ""}` },
- topSitesUI
- );
+
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("ul", {
+ className: `top-sites-list${this.state.draggedSite ? " dnd-active" : ""}`
+ }, topSitesUI);
}
-}
+}
const TopSiteList = Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_TopSiteList);
/***/ }),
@@ -6236,10 +6390,17 @@ const ScreenshotUtils = {
if (!remoteImage) {
return null;
}
+
if (this.isBlob(false, remoteImage)) {
- return { url: global.URL.createObjectURL(remoteImage.data), path: remoteImage.path };
+ return {
+ url: global.URL.createObjectURL(remoteImage.data),
+ path: remoteImage.path
+ };
}
- return { url: remoteImage };
+
+ return {
+ url: remoteImage
+ };
},
// Revokes the object URL of the image if the local image is a blob.
@@ -6255,12 +6416,13 @@ const ScreenshotUtils = {
// Both remoteImage and localImage are present.
if (remoteImage && localImage) {
return this.isBlob(false, remoteImage) ? localImage.path === remoteImage.path : localImage.url === remoteImage;
- }
-
- // This will only handle the remaining three possible outcomes.
+ } // This will only handle the remaining three possible outcomes.
// (i.e. everything except when both image and localImage are present)
+
+
return !remoteImage && !localImage;
}
+
};
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -6283,7 +6445,6 @@ __webpack_require__.r(__webpack_exports__);
-
/**
* Manual migration component used to start the profile import wizard.
* Message is presented temporarily and will go away if:
@@ -6292,6 +6453,7 @@ __webpack_require__.r(__webpack_exports__);
* 3. After 3 active days
* 4. User clicks "Cancel" on the import wizard (currently not implemented).
*/
+
class _ManualMigration extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureComponent {
constructor(props) {
super(props);
@@ -6300,43 +6462,45 @@ class _ManualMigration extends react__WEBPACK_IMPORTED_MODULE_3___default.a.Pure
}
onLaunchTour() {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_START }));
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_START }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_START
+ }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_START
+ }));
}
onCancelTour() {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_CANCEL }));
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_CANCEL }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_CANCEL
+ }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].MIGRATION_CANCEL
+ }));
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "manual-migration-container" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "p",
- null,
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", { className: "icon icon-import" }),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], { id: "manual_migration_explanation2" })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "div",
- { className: "manual-migration-actions actions" },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "button",
- { className: "dismiss", onClick: this.onCancelTour },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], { id: "manual_migration_cancel_button" })
- ),
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(
- "button",
- { onClick: this.onLaunchTour },
- react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], { id: "manual_migration_import_button" })
- )
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "manual-migration-container"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("span", {
+ className: "icon icon-import"
+ }), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], {
+ id: "manual_migration_explanation2"
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("div", {
+ className: "manual-migration-actions actions"
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+ className: "dismiss",
+ onClick: this.onCancelTour
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], {
+ id: "manual_migration_cancel_button"
+ })), react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement("button", {
+ onClick: this.onLaunchTour
+ }, react__WEBPACK_IMPORTED_MODULE_3___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], {
+ id: "manual_migration_import_button"
+ }))));
}
-}
+}
const ManualMigration = Object(react_redux__WEBPACK_IMPORTED_MODULE_1__["connect"])()(_ManualMigration);
/***/ }),
@@ -6351,6 +6515,7 @@ class _PrerenderData {
constructor(options) {
this.initialPrefs = options.initialPrefs;
this.initialSections = options.initialSections;
+
this._setValidation(options.validation);
}
@@ -6364,9 +6529,9 @@ class _PrerenderData {
get invalidatingPrefs() {
return this._invalidatingPrefs;
- }
+ } // This is needed so we can use it in the constructor
+
- // This is needed so we can use it in the constructor
_setValidation(value = []) {
this._validation = value;
this._invalidatingPrefs = value.reduce((result, next) => {
@@ -6380,6 +6545,7 @@ class _PrerenderData {
} else if (next && next.jsonPrefs) {
return result.concat(next.jsonPrefs);
}
+
throw new Error("Your validation configuration is not properly configured");
}, []);
}
@@ -6397,27 +6563,29 @@ class _PrerenderData {
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"]}
+ 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"]}
+ } // {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"
+ } // "foo"
+
} else if (getPref(prefs) !== this.initialPrefs[prefs]) {
return false;
}
}
+
return true;
}
+
}
var PrerenderData = new _PrerenderData({
initialPrefs: {
@@ -6429,7 +6597,9 @@ var PrerenderData = new _PrerenderData({
"feeds.section.highlights": true,
"sectionOrder": "topsites,topstories,highlights",
"collapsed": false,
- "discoverystream.config": { "enabled": 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
@@ -6437,28 +6607,38 @@ var PrerenderData = new _PrerenderData({
// 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,
+ 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
+ {
+ 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
+ {
+ 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"] }],
+ {
+ jsonPrefs: ["discoverystream.config"]
+ }],
initialSections: [{
enabled: true,
icon: "pocket",
id: "topstories",
order: 1,
- title: { id: "header_recommended_by", values: { provider: "Pocket" } }
+ title: {
+ id: "header_recommended_by",
+ values: {
+ provider: "Pocket"
+ }
+ }
}, {
enabled: true,
id: "highlights",
icon: "highlights",
order: 2,
- title: { id: "header_highlights" }
+ title: {
+ id: "header_highlights"
+ }
}]
});
@@ -6486,7 +6666,6 @@ __webpack_require__.r(__webpack_exports__);
-
class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent {
constructor(props) {
super(props);
@@ -6501,7 +6680,9 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
handleEvent(event) {
// Also track search events with our own telemetry
if (event.detail.type === "Search") {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: "SEARCH" }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: "SEARCH"
+ }));
}
}
@@ -6510,11 +6691,23 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
}
doSearchHandoff(text) {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].HANDOFF_SEARCH_TO_AWESOMEBAR, data: { text } }));
- this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].FAKE_FOCUS_SEARCH });
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: "SEARCH_HANDOFF" }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].HANDOFF_SEARCH_TO_AWESOMEBAR,
+ data: {
+ text
+ }
+ }));
+ this.props.dispatch({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].FAKE_FOCUS_SEARCH
+ });
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({
+ event: "SEARCH_HANDOFF"
+ }));
+
if (text) {
- this.props.dispatch({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].HIDE_SEARCH });
+ this.props.dispatch({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].HIDE_SEARCH
+ });
}
}
@@ -6535,6 +6728,7 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
onSearchHandoffDrop(event) {
event.preventDefault();
let text = event.dataTransfer.getData("text");
+
if (text) {
this.doSearchHandoff(text);
}
@@ -6551,18 +6745,16 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
// can add the appropriate telemetry probes for search. Without the correct
// name, certain tests like browser_UsageTelemetry_content.js will fail
// (See github ticket #2348 for more details)
- const healthReportKey = content_src_lib_constants__WEBPACK_IMPORTED_MODULE_3__["IS_NEWTAB"] ? "newtab" : "abouthome";
-
- // The "searchSource" needs to be "newtab" or "homepage" and is sent with
+ const healthReportKey = content_src_lib_constants__WEBPACK_IMPORTED_MODULE_3__["IS_NEWTAB"] ? "newtab" : "abouthome"; // The "searchSource" needs to be "newtab" or "homepage" and is sent with
// the search data and acts as context for the search request (See
// nsISearchEngine.getSubmission). It is necessary so that search engine
// plugins can correctly atribute referrals. (See github ticket #3321 for
// more details)
- const searchSource = content_src_lib_constants__WEBPACK_IMPORTED_MODULE_3__["IS_NEWTAB"] ? "newtab" : "homepage";
- // gContentSearchController needs to exist as a global so that tests for
+ const searchSource = content_src_lib_constants__WEBPACK_IMPORTED_MODULE_3__["IS_NEWTAB"] ? "newtab" : "homepage"; // gContentSearchController needs to exist as a global so that tests for
// the existing about:home can find it; and so it allows these tests to pass.
// In the future, when activity stream is default about:home, this can be renamed
+
window.gContentSearchController = new ContentSearchUIController(input, input.parentNode, healthReportKey, searchSource);
addEventListener("ContentSearchClient", this);
} else {
@@ -6575,85 +6767,87 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
// Keep a reference to the button for use during "paste" event handling.
this._searchHandoffButton = button;
}
-
/*
* Do not change the ID on the input field, as legacy newtab code
* specifically looks for the id 'newtab-search-text' on input fields
* in order to execute searches in various tests
*/
+
+
render() {
const wrapperClassName = ["search-wrapper", this.props.hide && "search-hidden", this.props.fakeFocus && "fake-focus"].filter(v => v).join(" ");
-
- return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: wrapperClassName },
- this.props.showLogo && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "logo-and-wordmark" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "logo" }),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "wordmark" })
- ),
- !this.props.handoffEnabled && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "search-inner-wrapper" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "label",
- { htmlFor: "newtab-search-text", className: "search-label" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- { className: "sr-only" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "search_web_placeholder" })
- )
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
- id: "newtab-search-text",
- maxLength: "256",
- placeholder: this.props.intl.formatMessage({ id: "search_web_placeholder" }),
- ref: this.onInputMount,
- title: this.props.intl.formatMessage({ id: "search_web_placeholder" }),
- type: "search" }),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- {
- id: "searchSubmit",
- className: "search-button",
- onClick: this.onSearchClick,
- title: this.props.intl.formatMessage({ id: "search_button" }) },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "span",
- { className: "sr-only" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "search_button" })
- )
- )
- ),
- this.props.handoffEnabled && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "search-inner-wrapper" },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "button",
- {
- className: "search-handoff-button",
- ref: this.onSearchHandoffButtonMount,
- onClick: this.onSearchHandoffClick,
- tabIndex: "-1",
- title: this.props.intl.formatMessage({ id: "search_web_placeholder" }) },
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(
- "div",
- { className: "fake-textbox" },
- this.props.intl.formatMessage({ id: "search_web_placeholder" })
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "search", className: "fake-editable", tabIndex: "-1", "aria-hidden": "true", onDrop: this.onSearchHandoffDrop, onPaste: this.onSearchHandoffPaste }),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "fake-caret" })
- ),
- react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
- type: "search",
- style: { display: "none" },
- ref: this.onInputMount })
- )
- );
+ return react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: wrapperClassName
+ }, this.props.showLogo && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "logo-and-wordmark"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "logo"
+ }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "wordmark"
+ })), !this.props.handoffEnabled && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "search-inner-wrapper"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("label", {
+ htmlFor: "newtab-search-text",
+ className: "search-label"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ className: "sr-only"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "search_web_placeholder"
+ }))), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ id: "newtab-search-text",
+ maxLength: "256",
+ placeholder: this.props.intl.formatMessage({
+ id: "search_web_placeholder"
+ }),
+ ref: this.onInputMount,
+ title: this.props.intl.formatMessage({
+ id: "search_web_placeholder"
+ }),
+ type: "search"
+ }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ id: "searchSubmit",
+ className: "search-button",
+ onClick: this.onSearchClick,
+ title: this.props.intl.formatMessage({
+ id: "search_button"
+ })
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("span", {
+ className: "sr-only"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "search_button"
+ })))), this.props.handoffEnabled && react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "search-inner-wrapper"
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("button", {
+ className: "search-handoff-button",
+ ref: this.onSearchHandoffButtonMount,
+ onClick: this.onSearchHandoffClick,
+ tabIndex: "-1",
+ title: this.props.intl.formatMessage({
+ id: "search_web_placeholder"
+ })
+ }, react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "fake-textbox"
+ }, this.props.intl.formatMessage({
+ id: "search_web_placeholder"
+ })), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "search",
+ className: "fake-editable",
+ tabIndex: "-1",
+ "aria-hidden": "true",
+ onDrop: this.onSearchHandoffDrop,
+ onPaste: this.onSearchHandoffPaste
+ }), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", {
+ className: "fake-caret"
+ })), react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
+ type: "search",
+ style: {
+ display: "none"
+ },
+ ref: this.onInputMount
+ })));
}
-}
+}
const Search = Object(react_redux__WEBPACK_IMPORTED_MODULE_2__["connect"])()(Object(react_intl__WEBPACK_IMPORTED_MODULE_1__["injectIntl"])(_Search));
/***/ }),
@@ -6690,8 +6884,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_8__);
/* harmony import */ var content_src_components_Topics_Topics__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(52);
/* harmony import */ var content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(34);
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -6710,45 +6903,53 @@ const CARDS_PER_ROW_DEFAULT = 3;
const CARDS_PER_ROW_COMPACT_WIDE = 4;
function getFormattedMessage(message) {
- return typeof message === "string" ? react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "span",
- null,
- message
- ) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], message);
+ return typeof message === "string" ? react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", null, message) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], message);
}
class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
get numRows() {
- const { rowsPref, maxRows, Prefs } = this.props;
+ const {
+ rowsPref,
+ maxRows,
+ Prefs
+ } = this.props;
return rowsPref ? Prefs.values[rowsPref] : maxRows;
}
_dispatchImpressionStats() {
- const { props } = this;
+ const {
+ props
+ } = this;
let cardsPerRow = CARDS_PER_ROW_DEFAULT;
+
if (props.compactCards && global.matchMedia(`(min-width: 1072px)`).matches) {
// If the section has compact cards and the viewport is wide enough, we show
// 4 columns instead of 3.
// $break-point-widest = 1072px (from _variables.scss)
cardsPerRow = CARDS_PER_ROW_COMPACT_WIDE;
}
+
const maxCards = cardsPerRow * this.numRows;
const cards = props.rows.slice(0, maxCards);
if (this.needsImpressionStats(cards)) {
props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].ImpressionStats({
source: props.eventSource,
- tiles: cards.map(link => ({ id: link.guid }))
+ tiles: cards.map(link => ({
+ id: link.guid
+ }))
}));
this.impressionCardGuids = cards.map(link => link.guid);
}
- }
-
- // This sends an event when a user sees a set of new content. If content
+ } // This sends an event when a user sees a set of new content. If content
// changes while the page is hidden (i.e. preloaded or on a hidden tab),
// only send the event if the page becomes visible again.
+
+
sendImpressionStatsOrAddListener() {
- const { props } = this;
+ const {
+ props
+ } = this;
if (!props.shouldSendImpressionStats || !props.dispatch) {
return;
@@ -6761,17 +6962,19 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
// older listeners.
if (this._onVisibilityChange) {
props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
- }
+ } // When the page becomes visible, send the impression stats ping if the section isn't collapsed.
+
- // When the page becomes visible, send the impression stats ping if the section isn't collapsed.
this._onVisibilityChange = () => {
if (props.document.visibilityState === VISIBLE) {
if (!this.props.pref.collapsed) {
this._dispatchImpressionStats();
}
+
props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
};
+
props.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
}
@@ -6787,16 +6990,16 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
}
componentDidUpdate(prevProps) {
- const { props } = this;
+ const {
+ props
+ } = this;
const isCollapsed = props.pref.collapsed;
const wasCollapsed = prevProps.pref.collapsed;
- if (
- // Don't send impression stats for the empty state
- props.rows.length && (
- // We only want to send impression stats if the content of the cards has changed
+
+ if ( // Don't send impression stats for the empty state
+ props.rows.length && ( // We only want to send impression stats if the content of the cards has changed
// and the section is not collapsed...
- props.rows !== prevProps.rows && !isCollapsed ||
- // or if we are expanding a section that was collapsed.
+ props.rows !== prevProps.rows && !isCollapsed || // or if we are expanding a section that was collapsed.
wasCollapsed && !isCollapsed)) {
this.sendImpressionStatsOrAddListener();
}
@@ -6824,70 +7027,87 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
}
return false;
- }
-
- // The NEW_TAB_REHYDRATED event is used to inform feeds that their
+ } // The NEW_TAB_REHYDRATED event is used to inform feeds that their
// data has been consumed e.g. for counting the number of tabs that
// have rendered that data.
+
+
sendNewTabRehydrated(initialized) {
if (initialized && !this.renderNotified) {
- this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_REHYDRATED, data: {} }));
+ this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
+ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].NEW_TAB_REHYDRATED,
+ data: {}
+ }));
this.renderNotified = true;
}
}
render() {
const {
- id, eventSource, title, icon, rows, Pocket, topics,
- emptyState, dispatch, compactCards, read_more_endpoint,
- contextMenuOptions, initialized, learnMore,
- pref, privacyNoticeURL, isFirst, isLast
+ id,
+ eventSource,
+ title,
+ icon,
+ rows,
+ Pocket,
+ topics,
+ emptyState,
+ dispatch,
+ compactCards,
+ read_more_endpoint,
+ contextMenuOptions,
+ initialized,
+ learnMore,
+ pref,
+ privacyNoticeURL,
+ isFirst,
+ isLast
} = this.props;
-
const waitingForSpoc = id === "topstories" && this.props.Pocket.waitingForSpoc;
const maxCardsPerRow = compactCards ? CARDS_PER_ROW_COMPACT_WIDE : CARDS_PER_ROW_DEFAULT;
- const { numRows } = this;
+ const {
+ numRows
+ } = this;
const maxCards = maxCardsPerRow * numRows;
const maxCardsOnNarrow = CARDS_PER_ROW_DEFAULT * numRows;
-
- const { pocketCta, isUserLoggedIn } = Pocket || {};
- const { useCta } = pocketCta || {};
-
- // Don't display anything until we have a definitve result from Pocket,
+ const {
+ pocketCta,
+ isUserLoggedIn
+ } = Pocket || {};
+ const {
+ useCta
+ } = pocketCta || {}; // Don't display anything until we have a definitve result from Pocket,
// to avoid a flash of logged out state while we render.
- const isPocketLoggedInDefined = isUserLoggedIn === true || isUserLoggedIn === false;
+ const isPocketLoggedInDefined = isUserLoggedIn === true || isUserLoggedIn === false;
const hasTopics = topics && topics.length > 0;
-
- const shouldShowPocketCta = id === "topstories" && useCta && isUserLoggedIn === false;
-
- // Show topics only for top stories and if it has loaded with topics.
+ const shouldShowPocketCta = id === "topstories" && useCta && isUserLoggedIn === false; // Show topics only for top stories and if it has loaded with topics.
// The classs .top-stories-bottom-container ensures content doesn't shift as things load.
- const shouldShowTopics = id === "topstories" && hasTopics && (useCta && isUserLoggedIn === true || !useCta && isPocketLoggedInDefined);
- // We use topics to determine language support for read more.
- const shouldShowReadMore = read_more_endpoint && hasTopics;
-
- const realRows = rows.slice(0, maxCards);
+ const shouldShowTopics = id === "topstories" && hasTopics && (useCta && isUserLoggedIn === true || !useCta && isPocketLoggedInDefined); // We use topics to determine language support for read more.
- // The empty state should only be shown after we have initialized and there is no content.
+ const shouldShowReadMore = read_more_endpoint && hasTopics;
+ const realRows = rows.slice(0, maxCards); // The empty state should only be shown after we have initialized and there is no content.
// Otherwise, we should show placeholders.
- const shouldShowEmptyState = initialized && !rows.length;
+ const shouldShowEmptyState = initialized && !rows.length;
const cards = [];
+
if (!shouldShowEmptyState) {
for (let i = 0; i < maxCards; i++) {
- const link = realRows[i];
- // On narrow viewports, we only show 3 cards per row. We'll mark the rest as
+ const link = realRows[i]; // On narrow viewports, we only show 3 cards per row. We'll mark the rest as
// .hide-for-narrow to hide in CSS via @media query.
+
const className = i >= maxCardsOnNarrow ? "hide-for-narrow" : "";
- let usePlaceholder = !link;
- // If we are in the third card and waiting for spoc,
+ let usePlaceholder = !link; // If we are in the third card and waiting for spoc,
// use the placeholder.
+
if (!usePlaceholder && i === 2 && waitingForSpoc) {
usePlaceholder = true;
}
- cards.push(!usePlaceholder ? react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__["Card"], { key: i,
+
+ cards.push(!usePlaceholder ? react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__["Card"], {
+ key: i,
index: i,
className: className,
dispatch: dispatch,
@@ -6895,75 +7115,66 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
contextMenuOptions: contextMenuOptions,
eventSource: eventSource,
shouldSendImpressionStats: this.props.shouldSendImpressionStats,
- isWebExtension: this.props.isWebExtension }) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__["PlaceholderCard"], { key: i, className: className }));
+ isWebExtension: this.props.isWebExtension
+ }) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__["PlaceholderCard"], {
+ key: i,
+ className: className
+ }));
}
}
- const sectionClassName = ["section", compactCards ? "compact-cards" : "normal-cards"].join(" ");
-
- // <Section> <-- React component
+ const sectionClassName = ["section", compactCards ? "compact-cards" : "normal-cards"].join(" "); // <Section> <-- React component
// <section> <-- HTML5 element
- return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_4__["ComponentPerfTimer"],
- this.props,
- react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_3__["CollapsibleSection"],
- { className: sectionClassName, icon: icon,
- title: title,
- id: id,
- eventSource: eventSource,
- collapsed: this.props.pref.collapsed,
- showPrefName: pref && pref.feed || id,
- privacyNoticeURL: privacyNoticeURL,
- Prefs: this.props.Prefs,
- isFirst: isFirst,
- isLast: isLast,
- learnMore: learnMore,
- dispatch: this.props.dispatch,
- isWebExtension: this.props.isWebExtension },
- !shouldShowEmptyState && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "ul",
- { className: "section-list", style: { padding: 0 } },
- cards
- ),
- shouldShowEmptyState && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "div",
- { className: "section-empty-state" },
- react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "div",
- { className: "empty-state" },
- emptyState.icon && emptyState.icon.startsWith("moz-extension://") ? react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", { className: "empty-state-icon icon", style: { "background-image": `url('${emptyState.icon}')` } }) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", { className: `empty-state-icon icon icon-${emptyState.icon}` }),
- react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "p",
- { className: "empty-state-message" },
- getFormattedMessage(emptyState.message)
- )
- )
- ),
- id === "topstories" && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "div",
- { className: "top-stories-bottom-container" },
- shouldShowTopics && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "div",
- { className: "wrapper-topics" },
- react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Topics_Topics__WEBPACK_IMPORTED_MODULE_9__["Topics"], { topics: this.props.topics })
- ),
- shouldShowPocketCta && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "div",
- { className: "wrapper-cta" },
- react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_PocketLoggedInCta_PocketLoggedInCta__WEBPACK_IMPORTED_MODULE_7__["PocketLoggedInCta"], null)
- ),
- react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "div",
- { className: "wrapper-more-recommendations" },
- shouldShowReadMore && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_MoreRecommendations_MoreRecommendations__WEBPACK_IMPORTED_MODULE_6__["MoreRecommendations"], { read_more_endpoint: read_more_endpoint })
- )
- )
- )
- );
+
+ return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_4__["ComponentPerfTimer"], this.props, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_3__["CollapsibleSection"], {
+ className: sectionClassName,
+ icon: icon,
+ title: title,
+ id: id,
+ eventSource: eventSource,
+ collapsed: this.props.pref.collapsed,
+ showPrefName: pref && pref.feed || id,
+ privacyNoticeURL: privacyNoticeURL,
+ Prefs: this.props.Prefs,
+ isFirst: isFirst,
+ isLast: isLast,
+ learnMore: learnMore,
+ dispatch: this.props.dispatch,
+ isWebExtension: this.props.isWebExtension
+ }, !shouldShowEmptyState && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("ul", {
+ className: "section-list",
+ style: {
+ padding: 0
+ }
+ }, cards), shouldShowEmptyState && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+ className: "section-empty-state"
+ }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+ className: "empty-state"
+ }, emptyState.icon && emptyState.icon.startsWith("moz-extension://") ? react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", {
+ className: "empty-state-icon icon",
+ style: {
+ "background-image": `url('${emptyState.icon}')`
+ }
+ }) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("span", {
+ className: `empty-state-icon icon icon-${emptyState.icon}`
+ }), react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("p", {
+ className: "empty-state-message"
+ }, getFormattedMessage(emptyState.message)))), id === "topstories" && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+ className: "top-stories-bottom-container"
+ }, shouldShowTopics && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+ className: "wrapper-topics"
+ }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_Topics_Topics__WEBPACK_IMPORTED_MODULE_9__["Topics"], {
+ topics: this.props.topics
+ })), shouldShowPocketCta && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+ className: "wrapper-cta"
+ }, react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_PocketLoggedInCta_PocketLoggedInCta__WEBPACK_IMPORTED_MODULE_7__["PocketLoggedInCta"], null)), react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+ className: "wrapper-more-recommendations"
+ }, shouldShowReadMore && react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_MoreRecommendations_MoreRecommendations__WEBPACK_IMPORTED_MODULE_6__["MoreRecommendations"], {
+ read_more_endpoint: read_more_endpoint
+ })))));
}
-}
+}
Section.defaultProps = {
document: global.document,
rows: [],
@@ -6971,15 +7182,19 @@ Section.defaultProps = {
pref: {},
title: ""
};
-
-const SectionIntl = Object(react_redux__WEBPACK_IMPORTED_MODULE_5__["connect"])(state => ({ Prefs: state.Prefs, Pocket: state.Pocket }))(Object(react_intl__WEBPACK_IMPORTED_MODULE_2__["injectIntl"])(Section));
-
+const SectionIntl = Object(react_redux__WEBPACK_IMPORTED_MODULE_5__["connect"])(state => ({
+ Prefs: state.Prefs,
+ Pocket: state.Pocket
+}))(Object(react_intl__WEBPACK_IMPORTED_MODULE_2__["injectIntl"])(Section));
class _Sections extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
renderSections() {
const sections = [];
const enabledSections = this.props.Sections.filter(section => section.enabled);
- const { sectionOrder, "feeds.topsites": showTopSites } = this.props.Prefs.values;
- // Enabled sections doesn't include Top Sites, so we add it if enabled.
+ const {
+ sectionOrder,
+ "feeds.topsites": showTopSites
+ } = this.props.Prefs.values; // Enabled sections doesn't include Top Sites, so we add it if enabled.
+
const expectedCount = enabledSections.length + ~~showTopSites;
for (const sectionId of sectionOrder.split(",")) {
@@ -6988,28 +7203,32 @@ class _Sections extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureCompone
isFirst: sections.length === 0,
isLast: sections.length === expectedCount - 1
};
+
if (sectionId === "topsites" && showTopSites) {
sections.push(react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_TopSites_TopSites__WEBPACK_IMPORTED_MODULE_10__["TopSites"], commonProps));
} else {
const section = enabledSections.find(s => s.id === sectionId);
+
if (section) {
sections.push(react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(SectionIntl, _extends({}, section, commonProps)));
}
}
}
+
return sections;
}
render() {
- return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
- "div",
- { className: "sections-list" },
- this.renderSections()
- );
+ return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement("div", {
+ className: "sections-list"
+ }, this.renderSections());
}
-}
-const Sections = Object(react_redux__WEBPACK_IMPORTED_MODULE_5__["connect"])(state => ({ Sections: state.Sections, Prefs: state.Prefs }))(_Sections);
+}
+const Sections = Object(react_redux__WEBPACK_IMPORTED_MODULE_5__["connect"])(state => ({
+ Sections: state.Sections,
+ Prefs: state.Prefs
+}))(_Sections);
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
@@ -7025,19 +7244,24 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-
class MoreRecommendations extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
render() {
- const { read_more_endpoint } = this.props;
+ const {
+ read_more_endpoint
+ } = this.props;
+
if (read_more_endpoint) {
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "a",
- { className: "more-recommendations", href: read_more_endpoint },
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], { id: "pocket_more_reccommendations" })
- );
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("a", {
+ className: "more-recommendations",
+ href: read_more_endpoint
+ }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
+ id: "pocket_more_reccommendations"
+ }));
}
+
return null;
}
+
}
/***/ }),
@@ -7057,32 +7281,31 @@ __webpack_require__.r(__webpack_exports__);
-
class _PocketLoggedInCta extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureComponent {
render() {
- const { pocketCta } = this.props.Pocket;
- return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "span",
- { className: "pocket-logged-in-cta" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "a",
- { className: "pocket-cta-button", href: pocketCta.ctaUrl ? pocketCta.ctaUrl : "https://getpocket.com/" },
- pocketCta.ctaButton ? pocketCta.ctaButton : react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "pocket_cta_button" })
- ),
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "a",
- { href: pocketCta.ctaUrl ? pocketCta.ctaUrl : "https://getpocket.com/" },
- react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
- "span",
- { className: "cta-text" },
- pocketCta.ctaText ? pocketCta.ctaText : react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], { id: "pocket_cta_text" })
- )
- )
- );
- }
-}
-
-const PocketLoggedInCta = Object(react_redux__WEBPACK_IMPORTED_MODULE_0__["connect"])(state => ({ Pocket: state.Pocket }))(_PocketLoggedInCta);
+ const {
+ pocketCta
+ } = this.props.Pocket;
+ return react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", {
+ className: "pocket-logged-in-cta"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("a", {
+ className: "pocket-cta-button",
+ href: pocketCta.ctaUrl ? pocketCta.ctaUrl : "https://getpocket.com/"
+ }, pocketCta.ctaButton ? pocketCta.ctaButton : react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "pocket_cta_button"
+ })), react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("a", {
+ href: pocketCta.ctaUrl ? pocketCta.ctaUrl : "https://getpocket.com/"
+ }, react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", {
+ className: "cta-text"
+ }, pocketCta.ctaText ? pocketCta.ctaText : react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], {
+ id: "pocket_cta_text"
+ }))));
+ }
+
+}
+const PocketLoggedInCta = Object(react_redux__WEBPACK_IMPORTED_MODULE_0__["connect"])(state => ({
+ Pocket: state.Pocket
+}))(_PocketLoggedInCta);
/***/ }),
/* 52 */
@@ -7098,40 +7321,35 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
-
class Topic extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
render() {
- const { url, name } = this.props;
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "li",
- null,
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "a",
- { key: name, href: url },
- name
- )
- );
+ const {
+ url,
+ name
+ } = this.props;
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("li", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("a", {
+ key: name,
+ href: url
+ }, name));
}
-}
+}
class Topics extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureComponent {
render() {
- const { topics } = this.props;
- return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "span",
- { className: "topics" },
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "span",
- null,
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], { id: "pocket_read_more" })
- ),
- react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
- "ul",
- null,
- topics && topics.map(t => react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(Topic, { key: t.name, url: t.url, name: t.name }))
- )
- );
+ const {
+ topics
+ } = this.props;
+ return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", {
+ className: "topics"
+ }, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("span", null, react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_0__["FormattedMessage"], {
+ id: "pocket_read_more"
+ })), react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement("ul", null, topics && topics.map(t => react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(Topic, {
+ key: t.name,
+ url: t.url,
+ name: t.name
+ }))));
}
+
}
/***/ }),
@@ -7145,25 +7363,24 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(41);
-
const VISIBLE = "visible";
const VISIBILITY_CHANGE_EVENT = "visibilitychange";
-
class DetectUserSessionStart {
constructor(store, options = {}) {
- this._store = store;
- // Overrides for testing
+ this._store = store; // Overrides for testing
+
this.document = options.document || global.document;
this._perfService = options.perfService || common_PerfService_jsm__WEBPACK_IMPORTED_MODULE_1__["perfService"];
this._onVisibilityChange = this._onVisibilityChange.bind(this);
}
-
/**
* sendEventOrAddListener - Notify immediately if the page is already visible,
* or else set up a listener for when visibility changes.
* This is needed for accurate session tracking for telemetry,
* because tabs are pre-loaded.
*/
+
+
sendEventOrAddListener() {
if (this.document.visibilityState === VISIBLE) {
// If the document is already visible, to the user, send a notification
@@ -7174,12 +7391,13 @@ class DetectUserSessionStart {
this.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
}
-
/**
* _sendEvent - Sends a message to the main process to indicate the current
* tab is now visible to the user, includes the
* visibility_event_rcvd_ts time in ms from the UNIX epoch.
*/
+
+
_sendEvent() {
this._perfService.mark("visibility_event_rcvd_ts");
@@ -7188,24 +7406,28 @@ class DetectUserSessionStart {
this._store.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].AlsoToMain({
type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].SAVE_SESSION_PERF_DATA,
- data: { visibility_event_rcvd_ts }
+ data: {
+ visibility_event_rcvd_ts
+ }
}));
- } catch (ex) {
- // If this failed, it's likely because the `privacy.resistFingerprinting`
+ } catch (ex) {// If this failed, it's likely because the `privacy.resistFingerprinting`
// pref is true. We should at least not blow up.
}
}
-
/**
* _onVisibilityChange - If the visibility has changed to visible, sends a notification
* and removes the event listener. This should only be called once per tab.
*/
+
+
_onVisibilityChange() {
if (this.document.visibilityState === VISIBLE) {
this._sendEvent();
+
this.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
}
}
+
}
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
@@ -7220,6 +7442,7 @@ function enableASRouterContent(store, asrouterContent) {
// Enable asrouter content
store.subscribe(() => {
const state = store.getState();
+
if (!state.ASRouter.initialized) {
return;
}
@@ -7227,9 +7450,11 @@ function enableASRouterContent(store, asrouterContent) {
if (!asrouterContent.initialized) {
asrouterContent.init(store);
}
- });
- // Return this for testing purposes
- return { asrouterContent };
+ }); // Return this for testing purposes
+
+ return {
+ asrouterContent
+ };
}
/***/ }),
@@ -7256,7 +7481,6 @@ var external_React_default = /*#__PURE__*/__webpack_require__.n(external_React_)
-
class DSLinkMenu_DSLinkMenu extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
@@ -7283,58 +7507,64 @@ class DSLinkMenu_DSLinkMenu extends external_React_default.a.PureComponent {
const dsLinkMenuHostDiv = this.contextMenuButtonRef.current.parentElement;
dsLinkMenuHostDiv.parentElement.classList.remove("active", "last-item");
}
- this.setState({ showContextMenu });
+
+ this.setState({
+ showContextMenu
+ });
}
onMenuShow() {
const dsLinkMenuHostDiv = this.contextMenuButtonRef.current.parentElement;
+
if (window.scrollMaxX > 0) {
dsLinkMenuHostDiv.parentElement.classList.add("last-item");
}
+
dsLinkMenuHostDiv.parentElement.classList.add("active");
}
render() {
- const { index, dispatch } = this.props;
+ const {
+ index,
+ dispatch
+ } = this.props;
const isContextMenuOpen = this.state.showContextMenu && this.state.activeCard === index;
const TOP_STORIES_CONTEXT_MENU_OPTIONS = ["OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"];
const title = this.props.title || this.props.source;
const type = this.props.type || "DISCOVERY_STREAM";
-
- return external_React_default.a.createElement(
- "div",
- null,
- external_React_default.a.createElement(
- "button",
- { ref: this.contextMenuButtonRef,
- className: "context-menu-button icon",
- title: this.props.intl.formatMessage({ id: "context_menu_title" }),
- onClick: this.onMenuButtonClick },
- external_React_default.a.createElement(
- "span",
- { className: "sr-only" },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: "context_menu_button_sr", values: { title } })
- )
- ),
- isContextMenuOpen && external_React_default.a.createElement(LinkMenu["LinkMenu"], {
- dispatch: dispatch,
- index: index,
- source: type.toUpperCase(),
- onUpdate: this.onMenuUpdate,
- onShow: this.onMenuShow,
- options: TOP_STORIES_CONTEXT_MENU_OPTIONS,
- shouldSendImpressionStats: true,
- site: {
- referrer: "https://getpocket.com/recommendations",
- title: this.props.title,
- type: this.props.type,
- url: this.props.url,
- guid: this.props.id
- } })
- );
+ return external_React_default.a.createElement("div", null, external_React_default.a.createElement("button", {
+ ref: this.contextMenuButtonRef,
+ className: "context-menu-button icon",
+ title: this.props.intl.formatMessage({
+ id: "context_menu_title"
+ }),
+ onClick: this.onMenuButtonClick
+ }, external_React_default.a.createElement("span", {
+ className: "sr-only"
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: "context_menu_button_sr",
+ values: {
+ title
+ }
+ }))), isContextMenuOpen && external_React_default.a.createElement(LinkMenu["LinkMenu"], {
+ dispatch: dispatch,
+ index: index,
+ source: type.toUpperCase(),
+ onUpdate: this.onMenuUpdate,
+ onShow: this.onMenuShow,
+ options: TOP_STORIES_CONTEXT_MENU_OPTIONS,
+ shouldSendImpressionStats: true,
+ site: {
+ referrer: "https://getpocket.com/recommendations",
+ title: this.props.title,
+ type: this.props.type,
+ url: this.props.url,
+ guid: this.props.id
+ }
+ }));
}
-}
+}
const DSLinkMenu = Object(external_ReactIntl_["injectIntl"])(DSLinkMenu_DSLinkMenu);
// EXTERNAL MODULE: ./content-src/components/DiscoveryStreamImpressionStats/ImpressionStats.jsx
var ImpressionStats = __webpack_require__(33);
@@ -7342,7 +7572,6 @@ var ImpressionStats = __webpack_require__(33);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/SafeAnchor/SafeAnchor.jsx
-
class SafeAnchor_SafeAnchor extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
@@ -7353,19 +7582,31 @@ class SafeAnchor_SafeAnchor extends external_React_default.a.PureComponent {
// Use dispatch instead of normal link click behavior to include referrer
if (this.props.dispatch) {
event.preventDefault();
- const { altKey, button, ctrlKey, metaKey, shiftKey } = event;
+ const {
+ altKey,
+ button,
+ ctrlKey,
+ metaKey,
+ shiftKey
+ } = event;
this.props.dispatch(Actions["actionCreators"].OnlyToMain({
type: Actions["actionTypes"].OPEN_LINK,
data: {
- event: { altKey, button, ctrlKey, metaKey, shiftKey },
+ event: {
+ altKey,
+ button,
+ ctrlKey,
+ metaKey,
+ shiftKey
+ },
referrer: "https://getpocket.com/recommendations",
// Use the anchor's url, which could have been cleaned up
url: event.currentTarget.href
}
}));
- }
+ } // Propagate event if there's a handler
+
- // Propagate event if there's a handler
if (this.props.onLinkClick) {
this.props.onLinkClick(event);
}
@@ -7373,6 +7614,7 @@ class SafeAnchor_SafeAnchor extends external_React_default.a.PureComponent {
safeURI(url) {
let protocol = null;
+
try {
protocol = new URL(url).protocol;
} catch (e) {
@@ -7380,21 +7622,28 @@ class SafeAnchor_SafeAnchor extends external_React_default.a.PureComponent {
}
const isAllowed = ["http:", "https:"].includes(protocol);
+
if (!isAllowed) {
console.warn(`${url} is not allowed for anchor targets.`); // eslint-disable-line no-console
+
return "";
}
+
return url;
}
render() {
- const { url, className } = this.props;
- return external_React_default.a.createElement(
- "a",
- { href: this.safeURI(url), className: className, onClick: this.onClick },
- this.props.children
- );
+ const {
+ url,
+ className
+ } = this.props;
+ return external_React_default.a.createElement("a", {
+ href: this.safeURI(url),
+ className: className,
+ onClick: this.onClick
+ }, this.props.children);
}
+
}
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSCard/DSCard.jsx
@@ -7402,11 +7651,9 @@ class SafeAnchor_SafeAnchor extends external_React_default.a.PureComponent {
-
class DSCard_DSCard extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
-
this.onLinkClick = this.onLinkClick.bind(this);
}
@@ -7417,95 +7664,74 @@ class DSCard_DSCard extends external_React_default.a.PureComponent {
source: this.props.type.toUpperCase(),
action_position: this.props.pos
}));
-
this.props.dispatch(Actions["actionCreators"].ImpressionStats({
source: this.props.type.toUpperCase(),
click: 0,
- tiles: [{ id: this.props.id, pos: this.props.pos }]
+ tiles: [{
+ id: this.props.id,
+ pos: this.props.pos
+ }]
}));
}
}
render() {
- return external_React_default.a.createElement(
- "div",
- { className: "ds-card" },
- external_React_default.a.createElement(
- SafeAnchor_SafeAnchor,
- {
- className: "ds-card-link",
- dispatch: this.props.dispatch,
- onLinkClick: this.onLinkClick,
- url: this.props.url },
- external_React_default.a.createElement(
- "div",
- { className: "img-wrapper" },
- external_React_default.a.createElement("div", { className: "img", style: { backgroundImage: `url(${this.props.image_src}` } })
- ),
- external_React_default.a.createElement(
- "div",
- { className: "meta" },
- external_React_default.a.createElement(
- "div",
- { className: "info-wrap" },
- external_React_default.a.createElement(
- "header",
- { className: "title" },
- this.props.title
- ),
- this.props.excerpt && external_React_default.a.createElement(
- "p",
- { className: "excerpt" },
- this.props.excerpt
- )
- ),
- external_React_default.a.createElement(
- "p",
- null,
- this.props.context && external_React_default.a.createElement(
- "span",
- null,
- external_React_default.a.createElement(
- "span",
- { className: "context" },
- this.props.context
- ),
- external_React_default.a.createElement("br", null)
- ),
- external_React_default.a.createElement(
- "span",
- { className: "source" },
- this.props.source
- )
- )
- ),
- external_React_default.a.createElement(ImpressionStats["ImpressionStats"], {
- campaignId: this.props.campaignId,
- rows: [{ id: this.props.id, pos: this.props.pos }],
- dispatch: this.props.dispatch,
- source: this.props.type })
- ),
- external_React_default.a.createElement(DSLinkMenu, {
+ return external_React_default.a.createElement("div", {
+ className: "ds-card"
+ }, external_React_default.a.createElement(SafeAnchor_SafeAnchor, {
+ className: "ds-card-link",
+ dispatch: this.props.dispatch,
+ onLinkClick: this.onLinkClick,
+ url: this.props.url
+ }, external_React_default.a.createElement("div", {
+ className: "img-wrapper"
+ }, external_React_default.a.createElement("div", {
+ className: "img",
+ style: {
+ backgroundImage: `url(${this.props.image_src}`
+ }
+ })), external_React_default.a.createElement("div", {
+ className: "meta"
+ }, external_React_default.a.createElement("div", {
+ className: "info-wrap"
+ }, external_React_default.a.createElement("header", {
+ className: "title"
+ }, this.props.title), this.props.excerpt && external_React_default.a.createElement("p", {
+ className: "excerpt"
+ }, this.props.excerpt)), external_React_default.a.createElement("p", null, this.props.context && external_React_default.a.createElement("span", null, external_React_default.a.createElement("span", {
+ className: "context"
+ }, this.props.context), external_React_default.a.createElement("br", null)), external_React_default.a.createElement("span", {
+ className: "source"
+ }, this.props.source))), external_React_default.a.createElement(ImpressionStats["ImpressionStats"], {
+ campaignId: this.props.campaignId,
+ rows: [{
id: this.props.id,
- index: this.props.pos,
- dispatch: this.props.dispatch,
- intl: this.props.intl,
- url: this.props.url,
- title: this.props.title,
- source: this.props.source,
- type: this.props.type })
- );
+ pos: this.props.pos
+ }],
+ dispatch: this.props.dispatch,
+ source: this.props.type
+ })), external_React_default.a.createElement(DSLinkMenu, {
+ id: this.props.id,
+ index: this.props.pos,
+ dispatch: this.props.dispatch,
+ intl: this.props.intl,
+ url: this.props.url,
+ title: this.props.title,
+ source: this.props.source,
+ type: this.props.type
+ }));
}
+
}
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/CardGrid/CardGrid.jsx
-
class CardGrid_CardGrid extends external_React_default.a.PureComponent {
render() {
- const { data } = this.props;
+ const {
+ data
+ } = this.props; // Handle a render before feed has been fetched by displaying nothing
- // Handle a render before feed has been fetched by displaying nothing
if (!data) {
return external_React_default.a.createElement("div", null);
}
@@ -7522,8 +7748,8 @@ class CardGrid_CardGrid extends external_React_default.a.PureComponent {
type: this.props.type,
context: rec.context,
dispatch: this.props.dispatch,
- source: rec.domain }));
-
+ source: rec.domain
+ }));
let divisibility = ``;
if (this.props.items % 4 === 0) {
@@ -7532,26 +7758,18 @@ class CardGrid_CardGrid extends external_React_default.a.PureComponent {
divisibility = `divisible-by-3`;
}
- return external_React_default.a.createElement(
- "div",
- null,
- external_React_default.a.createElement(
- "div",
- { className: "ds-header" },
- this.props.title
- ),
- external_React_default.a.createElement(
- "div",
- { className: `ds-card-grid ds-card-grid-${this.props.border} ds-card-grid-${divisibility}` },
- cards
- )
- );
+ return external_React_default.a.createElement("div", null, external_React_default.a.createElement("div", {
+ className: "ds-header"
+ }, this.props.title), external_React_default.a.createElement("div", {
+ className: `ds-card-grid ds-card-grid-${this.props.border} ds-card-grid-${divisibility}`
+ }, cards));
}
-}
+}
CardGrid_CardGrid.defaultProps = {
border: `border`,
items: 4 // Number of stories to display
+
};
// EXTERNAL MODULE: external "ReactRedux"
var external_ReactRedux_ = __webpack_require__(24);
@@ -7559,29 +7777,25 @@ var external_ReactRedux_ = __webpack_require__(24);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/DSMessage/DSMessage.jsx
-
class DSMessage_DSMessage extends external_React_default.a.PureComponent {
render() {
- return external_React_default.a.createElement(
- "div",
- { className: "ds-message" },
- external_React_default.a.createElement(
- "header",
- { className: "title" },
- this.props.icon && external_React_default.a.createElement("div", { className: "glyph", style: { backgroundImage: `url(${this.props.icon})` } }),
- this.props.title && external_React_default.a.createElement(
- "span",
- { className: "title-text" },
- this.props.title
- ),
- this.props.link_text && this.props.link_url && external_React_default.a.createElement(
- SafeAnchor_SafeAnchor,
- { className: "link", url: this.props.link_url },
- this.props.link_text
- )
- )
- );
+ return external_React_default.a.createElement("div", {
+ className: "ds-message"
+ }, external_React_default.a.createElement("header", {
+ className: "title"
+ }, this.props.icon && external_React_default.a.createElement("div", {
+ className: "glyph",
+ style: {
+ backgroundImage: `url(${this.props.icon})`
+ }
+ }), this.props.title && external_React_default.a.createElement("span", {
+ className: "title-text"
+ }, this.props.title), this.props.link_text && this.props.link_url && external_React_default.a.createElement(SafeAnchor_SafeAnchor, {
+ className: "link",
+ url: this.props.link_url
+ }, this.props.link_text)));
}
+
}
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/List/List.jsx
@@ -7590,10 +7804,10 @@ class DSMessage_DSMessage extends external_React_default.a.PureComponent {
-
/**
* @note exported for testing only
*/
+
class List_ListItem extends external_React_default.a.PureComponent {
// TODO performance: get feeds to send appropriately sized images rather
// than waiting longer and scaling down on client?
@@ -7609,93 +7823,75 @@ class List_ListItem extends external_React_default.a.PureComponent {
source: this.props.type.toUpperCase(),
action_position: this.props.pos
}));
-
this.props.dispatch(Actions["actionCreators"].ImpressionStats({
source: this.props.type.toUpperCase(),
click: 0,
- tiles: [{ id: this.props.id, pos: this.props.pos }]
+ tiles: [{
+ id: this.props.id,
+ pos: this.props.pos
+ }]
}));
}
}
render() {
- return external_React_default.a.createElement(
- "li",
- { className: "ds-list-item" },
- external_React_default.a.createElement(
- SafeAnchor_SafeAnchor,
- {
- className: "ds-list-item-link",
- dispatch: this.props.dispatch,
- onLinkClick: this.onLinkClick,
- url: this.props.url },
- external_React_default.a.createElement(
- "div",
- { className: "ds-list-item-text" },
- external_React_default.a.createElement(
- "div",
- null,
- external_React_default.a.createElement(
- "div",
- { className: "ds-list-item-title" },
- this.props.title
- ),
- this.props.excerpt && external_React_default.a.createElement(
- "div",
- { className: "ds-list-item-excerpt" },
- this.props.excerpt
- )
- ),
- external_React_default.a.createElement(
- "p",
- null,
- this.props.context && external_React_default.a.createElement(
- "span",
- null,
- external_React_default.a.createElement(
- "span",
- { className: "ds-list-item-context" },
- this.props.context
- ),
- external_React_default.a.createElement("br", null)
- ),
- external_React_default.a.createElement(
- "span",
- { className: "ds-list-item-info" },
- this.props.domain
- )
- )
- ),
- external_React_default.a.createElement("div", { className: "ds-list-image", style: { backgroundImage: `url(${this.props.image_src})` } }),
- external_React_default.a.createElement(ImpressionStats["ImpressionStats"], {
- campaignId: this.props.campaignId,
- rows: [{ id: this.props.id, pos: this.props.pos }],
- dispatch: this.props.dispatch,
- source: this.props.type })
- ),
- external_React_default.a.createElement(DSLinkMenu, {
+ return external_React_default.a.createElement("li", {
+ className: "ds-list-item"
+ }, external_React_default.a.createElement(SafeAnchor_SafeAnchor, {
+ className: "ds-list-item-link",
+ dispatch: this.props.dispatch,
+ onLinkClick: this.onLinkClick,
+ url: this.props.url
+ }, external_React_default.a.createElement("div", {
+ className: "ds-list-item-text"
+ }, external_React_default.a.createElement("div", null, external_React_default.a.createElement("div", {
+ className: "ds-list-item-title"
+ }, this.props.title), this.props.excerpt && external_React_default.a.createElement("div", {
+ className: "ds-list-item-excerpt"
+ }, this.props.excerpt)), external_React_default.a.createElement("p", null, this.props.context && external_React_default.a.createElement("span", null, external_React_default.a.createElement("span", {
+ className: "ds-list-item-context"
+ }, this.props.context), external_React_default.a.createElement("br", null)), external_React_default.a.createElement("span", {
+ className: "ds-list-item-info"
+ }, this.props.domain))), external_React_default.a.createElement("div", {
+ className: "ds-list-image",
+ style: {
+ backgroundImage: `url(${this.props.image_src})`
+ }
+ }), external_React_default.a.createElement(ImpressionStats["ImpressionStats"], {
+ campaignId: this.props.campaignId,
+ rows: [{
id: this.props.id,
- index: this.props.pos,
- dispatch: this.props.dispatch,
- intl: this.props.intl,
- url: this.props.url,
- title: this.props.title,
- source: this.props.source,
- type: this.props.type })
- );
+ pos: this.props.pos
+ }],
+ dispatch: this.props.dispatch,
+ source: this.props.type
+ })), external_React_default.a.createElement(DSLinkMenu, {
+ id: this.props.id,
+ index: this.props.pos,
+ dispatch: this.props.dispatch,
+ intl: this.props.intl,
+ url: this.props.url,
+ title: this.props.title,
+ source: this.props.source,
+ type: this.props.type
+ }));
}
-}
+}
/**
* @note exported for testing only
*/
+
function _List(props) {
const feed = props.data;
+
if (!feed || !feed.recommendations) {
return null;
}
+
const recs = feed.recommendations;
- let recMarkup = recs.slice(props.recStartingPoint, props.recStartingPoint + props.items).map((rec, index) => external_React_default.a.createElement(List_ListItem, { key: `ds-list-item-${index}`,
+ let recMarkup = recs.slice(props.recStartingPoint, props.recStartingPoint + props.items).map((rec, index) => external_React_default.a.createElement(List_ListItem, {
+ key: `ds-list-item-${index}`,
dispatch: props.dispatch,
campaignId: rec.campaign_id,
domain: rec.domain,
@@ -7706,34 +7902,32 @@ function _List(props) {
title: rec.title,
context: rec.context,
type: props.type,
- url: rec.url }));
+ url: rec.url
+ }));
const listStyles = ["ds-list", props.fullWidth ? "ds-list-full-width" : "", props.hasBorders ? "ds-list-borders" : "", props.hasImages ? "ds-list-images" : "", props.hasNumbers ? "ds-list-numbers" : ""];
- return external_React_default.a.createElement(
- "div",
- null,
- props.header && props.header.title ? external_React_default.a.createElement(
- "div",
- { className: "ds-header" },
- props.header.title
- ) : null,
- external_React_default.a.createElement(
- "ul",
- { className: listStyles.join(" ") },
- recMarkup
- )
- );
+ return external_React_default.a.createElement("div", null, props.header && props.header.title ? external_React_default.a.createElement("div", {
+ className: "ds-header"
+ }, props.header.title) : null, external_React_default.a.createElement("ul", {
+ className: listStyles.join(" ")
+ }, recMarkup));
}
-
_List.defaultProps = {
- recStartingPoint: 0, // Index of recommendations to start displaying from
- fullWidth: false, // Display items taking up the whole column
- hasBorders: false, // Display lines separating each item
- hasImages: false, // Display images for each item
- hasNumbers: false, // Display numbers for each item
+ recStartingPoint: 0,
+ // Index of recommendations to start displaying from
+ fullWidth: false,
+ // Display items taking up the whole column
+ hasBorders: false,
+ // Display lines separating each item
+ hasImages: false,
+ // Display images for each item
+ hasNumbers: false,
+ // Display numbers for each item
items: 6 // Number of stories to display. TODO: get from endpoint
-};
-const List = Object(external_ReactRedux_["connect"])(state => ({ DiscoveryStream: state.DiscoveryStream }))(_List);
+};
+const List = Object(external_ReactRedux_["connect"])(state => ({
+ DiscoveryStream: state.DiscoveryStream
+}))(_List);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx
@@ -7742,7 +7936,6 @@ const List = Object(external_ReactRedux_["connect"])(state => ({ DiscoveryStream
-
class Hero_Hero extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
@@ -7756,26 +7949,28 @@ class Hero_Hero extends external_React_default.a.PureComponent {
source: this.props.type.toUpperCase(),
action_position: this.heroRec.pos
}));
-
this.props.dispatch(Actions["actionCreators"].ImpressionStats({
source: this.props.type.toUpperCase(),
click: 0,
- tiles: [{ id: this.heroRec.id, pos: this.heroRec.pos }]
+ tiles: [{
+ id: this.heroRec.id,
+ pos: this.heroRec.pos
+ }]
}));
}
}
render() {
- const { data } = this.props;
+ const {
+ data
+ } = this.props; // Handle a render before feed has been fetched by displaying nothing
- // Handle a render before feed has been fetched by displaying nothing
if (!data || !data.recommendations || !data.recommendations.length) {
return external_React_default.a.createElement("div", null);
}
let [heroRec, ...otherRecs] = data.recommendations.slice(0, this.props.items);
this.heroRec = heroRec;
-
let cards = otherRecs.map((rec, index) => external_React_default.a.createElement(DSCard_DSCard, {
campaignId: rec.campaign_id,
key: `dscard-${index}`,
@@ -7787,173 +7982,139 @@ class Hero_Hero extends external_React_default.a.PureComponent {
type: this.props.type,
dispatch: this.props.dispatch,
context: rec.context,
- source: rec.domain }));
-
+ source: rec.domain
+ }));
let list = external_React_default.a.createElement(List, {
recStartingPoint: 1,
data: data,
hasImages: true,
hasBorders: this.props.border === `border`,
items: this.props.items - 1,
- type: `Hero` });
-
- return external_React_default.a.createElement(
- "div",
- null,
- external_React_default.a.createElement(
- "div",
- { className: "ds-header" },
- this.props.title
- ),
- external_React_default.a.createElement(
- "div",
- { className: `ds-hero ds-hero-${this.props.border}` },
- external_React_default.a.createElement(
- "div",
- { className: "ds-hero-item" },
- external_React_default.a.createElement(
- SafeAnchor_SafeAnchor,
- {
- className: "wrapper",
- dispatch: this.props.dispatch,
- onLinkClick: this.onLinkClick,
- url: heroRec.url },
- external_React_default.a.createElement(
- "div",
- { className: "img-wrapper" },
- external_React_default.a.createElement("div", { className: "img", style: { backgroundImage: `url(${heroRec.image_src})` } })
- ),
- external_React_default.a.createElement(
- "div",
- { className: "meta" },
- external_React_default.a.createElement(
- "div",
- { className: "header-and-excerpt" },
- external_React_default.a.createElement(
- "header",
- null,
- heroRec.title
- ),
- external_React_default.a.createElement(
- "p",
- { className: "excerpt" },
- heroRec.excerpt
- )
- ),
- heroRec.context ? external_React_default.a.createElement(
- "p",
- { className: "context" },
- heroRec.context
- ) : external_React_default.a.createElement(
- "p",
- { className: "source" },
- heroRec.domain
- )
- ),
- external_React_default.a.createElement(ImpressionStats["ImpressionStats"], {
- campaignId: heroRec.campaignId,
- rows: [{ id: heroRec.id, pos: heroRec.pos }],
- dispatch: this.props.dispatch,
- source: this.props.type })
- ),
- external_React_default.a.createElement(DSLinkMenu, {
- id: heroRec.id,
- index: heroRec.pos,
- dispatch: this.props.dispatch,
- intl: this.props.intl,
- url: heroRec.url,
- title: heroRec.title,
- source: heroRec.domain,
- type: this.props.type })
- ),
- external_React_default.a.createElement(
- "div",
- { className: `${this.props.subComponentType}` },
- this.props.subComponentType === `cards` ? cards : list
- )
- )
- );
+ type: `Hero`
+ });
+ return external_React_default.a.createElement("div", null, external_React_default.a.createElement("div", {
+ className: "ds-header"
+ }, this.props.title), external_React_default.a.createElement("div", {
+ className: `ds-hero ds-hero-${this.props.border}`
+ }, external_React_default.a.createElement("div", {
+ className: "ds-hero-item"
+ }, external_React_default.a.createElement(SafeAnchor_SafeAnchor, {
+ className: "wrapper",
+ dispatch: this.props.dispatch,
+ onLinkClick: this.onLinkClick,
+ url: heroRec.url
+ }, external_React_default.a.createElement("div", {
+ className: "img-wrapper"
+ }, external_React_default.a.createElement("div", {
+ className: "img",
+ style: {
+ backgroundImage: `url(${heroRec.image_src})`
+ }
+ })), external_React_default.a.createElement("div", {
+ className: "meta"
+ }, external_React_default.a.createElement("div", {
+ className: "header-and-excerpt"
+ }, external_React_default.a.createElement("header", null, heroRec.title), external_React_default.a.createElement("p", {
+ className: "excerpt"
+ }, heroRec.excerpt)), heroRec.context ? external_React_default.a.createElement("p", {
+ className: "context"
+ }, heroRec.context) : external_React_default.a.createElement("p", {
+ className: "source"
+ }, heroRec.domain)), external_React_default.a.createElement(ImpressionStats["ImpressionStats"], {
+ campaignId: heroRec.campaignId,
+ rows: [{
+ id: heroRec.id,
+ pos: heroRec.pos
+ }],
+ dispatch: this.props.dispatch,
+ source: this.props.type
+ })), external_React_default.a.createElement(DSLinkMenu, {
+ id: heroRec.id,
+ index: heroRec.pos,
+ dispatch: this.props.dispatch,
+ intl: this.props.intl,
+ url: heroRec.url,
+ title: heroRec.title,
+ source: heroRec.domain,
+ type: this.props.type
+ })), external_React_default.a.createElement("div", {
+ className: `${this.props.subComponentType}`
+ }, this.props.subComponentType === `cards` ? cards : list)));
}
-}
+}
Hero_Hero.defaultProps = {
data: {},
border: `border`,
items: 1 // Number of stories to display
+
};
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule.jsx
-
class HorizontalRule_HorizontalRule extends external_React_default.a.PureComponent {
render() {
- return external_React_default.a.createElement("hr", { className: "ds-hr" });
+ return external_React_default.a.createElement("hr", {
+ className: "ds-hr"
+ });
}
+
}
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/Navigation/Navigation.jsx
-
class Navigation_Topic extends external_React_default.a.PureComponent {
render() {
- const { url, name } = this.props;
- return external_React_default.a.createElement(
- "li",
- null,
- external_React_default.a.createElement(
- SafeAnchor_SafeAnchor,
- { key: name, url: url },
- name
- )
- );
+ const {
+ url,
+ name
+ } = this.props;
+ return external_React_default.a.createElement("li", null, external_React_default.a.createElement(SafeAnchor_SafeAnchor, {
+ key: name,
+ url: url
+ }, name));
}
-}
+}
class Navigation_Navigation extends external_React_default.a.PureComponent {
render() {
- const { links } = this.props || [];
- const { alignment } = this.props || "centered";
+ const {
+ links
+ } = this.props || [];
+ const {
+ alignment
+ } = this.props || "centered";
const header = this.props.header || {};
- return external_React_default.a.createElement(
- "div",
- { className: `ds-navigation ds-navigation-${alignment}` },
- header.title ? external_React_default.a.createElement(
- "div",
- { className: "ds-header" },
- header.title
- ) : null,
- external_React_default.a.createElement(
- "div",
- null,
- external_React_default.a.createElement(
- "ul",
- null,
- links && links.map(t => external_React_default.a.createElement(Navigation_Topic, { key: t.name, url: t.url, name: t.name }))
- )
- )
- );
+ return external_React_default.a.createElement("div", {
+ className: `ds-navigation ds-navigation-${alignment}`
+ }, header.title ? external_React_default.a.createElement("div", {
+ className: "ds-header"
+ }, header.title) : null, external_React_default.a.createElement("div", null, external_React_default.a.createElement("ul", null, links && links.map(t => external_React_default.a.createElement(Navigation_Topic, {
+ key: t.name,
+ url: t.url,
+ name: t.name
+ })))));
}
+
}
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/SectionTitle/SectionTitle.jsx
-
class SectionTitle_SectionTitle extends external_React_default.a.PureComponent {
render() {
- const { header: { title, subtitle } } = this.props;
- return external_React_default.a.createElement(
- "div",
- { className: "ds-section-title" },
- external_React_default.a.createElement(
- "div",
- { className: "title" },
- title
- ),
- subtitle ? external_React_default.a.createElement(
- "div",
- { className: "subtitle" },
+ const {
+ header: {
+ title,
subtitle
- ) : null
- );
+ }
+ } = this.props;
+ return external_React_default.a.createElement("div", {
+ className: "ds-section-title"
+ }, external_React_default.a.createElement("div", {
+ className: "title"
+ }, title), subtitle ? external_React_default.a.createElement("div", {
+ className: "subtitle"
+ }, subtitle) : null);
}
+
}
// CONCATENATED MODULE: ./node_modules/reselect/es/index.js
function defaultEqualityCheck(a, b) {
@@ -8078,13 +8239,9 @@ function createStructuredSelector(selectors) {
}
// CONCATENATED MODULE: ./content-src/lib/selectLayoutRender.js
-
-const selectLayoutRender = createSelector(
-// Selects layout, feeds, spocs so that we only recompute if
+const selectLayoutRender = createSelector( // Selects layout, feeds, spocs so that we only recompute if
// any of these values change.
-[state => state.DiscoveryStream.layout, state => state.DiscoveryStream.feeds, state => state.DiscoveryStream.spocs],
-
-// Adds data to each component from feeds. This function only re-runs if one of the inputs change.
+[state => state.DiscoveryStream.layout, state => state.DiscoveryStream.feeds, state => state.DiscoveryStream.spocs], // Adds data to each component from feeds. This function only re-runs if one of the inputs change.
// TODO: calculate spocs
function layoutRender(layout, feeds, spocs) {
let spocIndex = 0;
@@ -8092,25 +8249,25 @@ function layoutRender(layout, feeds, spocs) {
function maybeInjectSpocs(data, spocsConfig) {
if (data && spocsConfig && spocsConfig.positions && spocsConfig.positions.length && spocs.data.spocs && spocs.data.spocs.length) {
const recommendations = [...data.recommendations];
+
for (let position of spocsConfig.positions) {
let rickRoll = Math.random();
+
if (spocs.data.spocs[spocIndex] && rickRoll <= spocsConfig.probability) {
recommendations.splice(position.index, 0, spocs.data.spocs[spocIndex++]);
}
}
- return Object.assign({}, data, {
+ return { ...data,
recommendations
- });
+ };
}
return data;
}
const positions = {};
-
- return layout.map(row => Object.assign({}, row, {
-
+ return layout.map(row => ({ ...row,
// Loops through all the components and adds a .data property
// containing data from feeds
components: row.components.map(component => {
@@ -8119,30 +8276,33 @@ function layoutRender(layout, feeds, spocs) {
}
positions[component.type] = positions[component.type] || 0;
-
- let { data } = feeds.data[component.feed.url];
+ let {
+ data
+ } = feeds.data[component.feed.url];
if (component && component.properties && component.properties.offset) {
- data = Object.assign({}, data, {
+ data = { ...data,
recommendations: data.recommendations.slice(component.properties.offset)
- });
+ };
}
data = maybeInjectSpocs(data, component.spocs);
-
let items = 0;
+
if (component.properties && component.properties.items) {
items = Math.min(component.properties.items, data.recommendations.length);
- }
-
- // loop through a component items
+ } // loop through a component items
// Store the items position sequentially for multiple components of the same type.
// Example: A second card grid starts pos offset from the last card grid.
+
+
for (let i = 0; i < items; i++) {
data.recommendations[i].pos = positions[component.type]++;
}
- return Object.assign({}, component, { data });
+ return { ...component,
+ data
+ };
})
}));
});
@@ -8153,29 +8313,24 @@ var TopSites = __webpack_require__(34);
-
class TopSites_TopSites extends external_React_default.a.PureComponent {
render() {
const header = this.props.header || {};
- return external_React_default.a.createElement(
- "div",
- { className: "ds-top-sites" },
- header.title ? external_React_default.a.createElement(
- "div",
- { className: "ds-header" },
- external_React_default.a.createElement("span", { className: "icon icon-small-spacer icon-topsites" }),
- external_React_default.a.createElement(
- "span",
- { className: "ds-header-title" },
- header.title
- )
- ) : null,
- external_React_default.a.createElement(TopSites["TopSites"], null)
- );
- }
-}
-
-const TopSites_TopSites_TopSites = Object(external_ReactRedux_["connect"])(state => ({ TopSites: state.TopSites }))(TopSites_TopSites);
+ return external_React_default.a.createElement("div", {
+ className: "ds-top-sites"
+ }, header.title ? external_React_default.a.createElement("div", {
+ className: "ds-header"
+ }, external_React_default.a.createElement("span", {
+ className: "icon icon-small-spacer icon-topsites"
+ }), external_React_default.a.createElement("span", {
+ className: "ds-header-title"
+ }, header.title)) : null, external_React_default.a.createElement(TopSites["TopSites"], null));
+ }
+
+}
+const TopSites_TopSites_TopSites = Object(external_ReactRedux_["connect"])(state => ({
+ TopSites: state.TopSites
+}))(TopSites_TopSites);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamBase/DiscoveryStreamBase.jsx
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isAllowedCSS", function() { return isAllowedCSS; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_DiscoveryStreamBase", function() { return DiscoveryStreamBase_DiscoveryStreamBase; });
@@ -8191,26 +8346,24 @@ const TopSites_TopSites_TopSites = Object(external_ReactRedux_["connect"])(state
-
const ALLOWED_CSS_URL_PREFIXES = ["chrome://", "resource://", "https://img-getpocket.cdn.mozilla.net/"];
const DUMMY_CSS_SELECTOR = "DUMMY#CSS.SELECTOR";
-
/**
* Validate a CSS declaration. The values are assumed to be normalized by CSSOM.
*/
+
function isAllowedCSS(property, value) {
// Bug 1454823: INTERNAL properties, e.g., -moz-context-properties, are
// exposed but their values aren't resulting in getting nothing. Fortunately,
// we don't care about validating the values of the current set of properties.
if (value === undefined) {
return true;
- }
+ } // Make sure all urls are of the allowed protocols/prefixes
+
- // Make sure all urls are of the allowed protocols/prefixes
const urls = value.match(/url\("[^"]+"\)/g);
return !urls || urls.every(url => ALLOWED_CSS_URL_PREFIXES.some(prefix => url.slice(5).startsWith(prefix)));
}
-
class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
@@ -8223,7 +8376,9 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
return;
}
- const { sheet } = style;
+ const {
+ sheet
+ } = style;
const styles = JSON.parse(style.dataset.styles);
styles.forEach((row, rowIndex) => {
row.forEach((component, componentIndex) => {
@@ -8235,28 +8390,26 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
Object.entries(component).forEach(([selectors, declarations]) => {
// Start with a dummy rule to validate declarations and selectors
sheet.insertRule(`${DUMMY_CSS_SELECTOR} {}`);
- const [rule] = sheet.cssRules;
-
- // Validate declarations and remove any offenders. CSSOM silently
+ const [rule] = sheet.cssRules; // Validate declarations and remove any offenders. CSSOM silently
// discards invalid entries, so here we apply extra restrictions.
+
rule.style = declarations;
[...rule.style].forEach(property => {
const value = rule.style[property];
+
if (!isAllowedCSS(property, value)) {
console.error(`Bad CSS declaration ${property}: ${value}`); // eslint-disable-line no-console
+
rule.style.removeProperty(property);
}
- });
+ }); // Set the actual desired selectors scoped to the component
- // Set the actual desired selectors scoped to the component
- const prefix = `.ds-layout > .ds-column:nth-child(${rowIndex + 1}) .ds-column-grid > :nth-child(${componentIndex + 1})`;
- // NB: Splitting on "," doesn't work with strings with commas, but
+ const prefix = `.ds-layout > .ds-column:nth-child(${rowIndex + 1}) .ds-column-grid > :nth-child(${componentIndex + 1})`; // NB: Splitting on "," doesn't work with strings with commas, but
// we're okay with not supporting those selectors
- rule.selectorText = selectors.split(",").map(selector => prefix + (
- // Assume :pseudo-classes are for component instead of descendant
- selector[0] === ":" ? "" : " ") + selector).join(",");
- // CSSOM silently ignores bad selectors, so we'll be noisy instead
+ rule.selectorText = selectors.split(",").map(selector => prefix + ( // Assume :pseudo-classes are for component instead of descendant
+ selector[0] === ":" ? "" : " ") + selector).join(","); // CSSOM silently ignores bad selectors, so we'll be noisy instead
+
if (rule.selectorText === DUMMY_CSS_SELECTOR) {
console.error(`Bad CSS selector ${selectors}`); // eslint-disable-line no-console
}
@@ -8268,22 +8421,31 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
renderComponent(component, embedWidth) {
switch (component.type) {
case "TopSites":
- return external_React_default.a.createElement(TopSites_TopSites_TopSites, { header: component.header });
+ return external_React_default.a.createElement(TopSites_TopSites_TopSites, {
+ header: component.header
+ });
+
case "Message":
return external_React_default.a.createElement(DSMessage_DSMessage, {
title: component.header && component.header.title,
subtitle: component.header && component.header.subtitle,
link_text: component.header && component.header.link_text,
link_url: component.header && component.header.link_url,
- icon: component.header && component.header.icon });
+ icon: component.header && component.header.icon
+ });
+
case "SectionTitle":
return external_React_default.a.createElement(SectionTitle_SectionTitle, {
- header: component.header });
+ header: component.header
+ });
+
case "Navigation":
return external_React_default.a.createElement(Navigation_Navigation, {
links: component.properties.links,
alignment: component.properties.alignment,
- header: component.header });
+ header: component.header
+ });
+
case "CardGrid":
return external_React_default.a.createElement(CardGrid_CardGrid, {
title: component.header && component.header.title,
@@ -8292,7 +8454,9 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
border: component.properties.border,
type: component.type,
dispatch: this.props.dispatch,
- items: component.properties.items });
+ items: component.properties.items
+ });
+
case "Hero":
return external_React_default.a.createElement(Hero_Hero, {
subComponentType: embedWidth >= 9 ? `cards` : `list`,
@@ -8302,9 +8466,12 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
border: component.properties.border,
type: component.type,
dispatch: this.props.dispatch,
- items: component.properties.items });
+ items: component.properties.items
+ });
+
case "HorizontalRule":
return external_React_default.a.createElement(HorizontalRule_HorizontalRule, null);
+
case "List":
return external_React_default.a.createElement(List, {
data: component.data,
@@ -8314,13 +8481,11 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
hasNumbers: component.properties.has_numbers,
items: component.properties.items,
type: component.type,
- header: component.header });
+ header: component.header
+ });
+
default:
- return external_React_default.a.createElement(
- "div",
- null,
- component.type
- );
+ return external_React_default.a.createElement("div", null, component.type);
}
}
@@ -8328,47 +8493,49 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
// Use json string as both the key and styles to render so React knows when
// to unmount and mount a new instance for new styles.
const json = JSON.stringify(styles);
- return external_React_default.a.createElement("style", { key: json, "data-styles": json, ref: this.onStyleMount });
+ return external_React_default.a.createElement("style", {
+ key: json,
+ "data-styles": json,
+ ref: this.onStyleMount
+ });
}
render() {
- const { layoutRender } = this.props.DiscoveryStream;
+ const {
+ layoutRender
+ } = this.props.DiscoveryStream;
const styles = [];
- const { spocs, feeds } = this.props.DiscoveryStream;
+ const {
+ spocs,
+ feeds
+ } = this.props.DiscoveryStream;
if (!spocs.loaded || !feeds.loaded) {
return null;
}
- return external_React_default.a.createElement(
- "div",
- { className: "discovery-stream ds-layout" },
- layoutRender.map((row, rowIndex) => external_React_default.a.createElement(
- "div",
- { key: `row-${rowIndex}`, className: `ds-column ds-column-${row.width}` },
- external_React_default.a.createElement(
- "div",
- { className: "ds-column-grid" },
- row.components.map((component, componentIndex) => {
- styles[rowIndex] = [...(styles[rowIndex] || []), component.styles];
- return external_React_default.a.createElement(
- "div",
- { key: `component-${componentIndex}` },
- this.renderComponent(component, row.width)
- );
- })
- )
- )),
- this.renderStyles(styles)
- );
+ return external_React_default.a.createElement("div", {
+ className: "discovery-stream ds-layout"
+ }, layoutRender.map((row, rowIndex) => external_React_default.a.createElement("div", {
+ key: `row-${rowIndex}`,
+ className: `ds-column ds-column-${row.width}`
+ }, external_React_default.a.createElement("div", {
+ className: "ds-column-grid"
+ }, row.components.map((component, componentIndex) => {
+ styles[rowIndex] = [...(styles[rowIndex] || []), component.styles];
+ return external_React_default.a.createElement("div", {
+ key: `component-${componentIndex}`
+ }, this.renderComponent(component, row.width));
+ })))), this.renderStyles(styles));
}
+
}
function transform(state) {
return {
- DiscoveryStream: Object.assign({}, state.DiscoveryStream, {
+ DiscoveryStream: { ...state.DiscoveryStream,
layoutRender: selectLayoutRender(state)
- })
+ }
};
}
@@ -8390,34 +8557,34 @@ var EOYSnippet_schema = __webpack_require__(18);
// CONCATENATED MODULE: ./content-src/asrouter/components/Button/Button.jsx
-
const ALLOWED_STYLE_TAGS = ["color", "backgroundColor"];
-
const Button = props => {
- const style = {};
+ const style = {}; // Add allowed style tags from props, e.g. props.color becomes style={color: props.color}
- // Add allowed style tags from props, e.g. props.color becomes style={color: props.color}
for (const tag of ALLOWED_STYLE_TAGS) {
if (typeof props[tag] !== "undefined") {
style[tag] = props[tag];
}
- }
- // remove border if bg is set to something custom
+ } // remove border if bg is set to something custom
+
+
if (style.backgroundColor) {
style.border = "0";
}
- return external_React_default.a.createElement(
- "button",
- { onClick: props.onClick,
- className: props.className || "ASRouterButton secondary",
- style: style },
- props.children
- );
+ return external_React_default.a.createElement("button", {
+ onClick: props.onClick,
+ className: props.className || "ASRouterButton secondary",
+ style: style
+ }, props.children);
};
// CONCATENATED MODULE: ./content-src/asrouter/components/ConditionalWrapper/ConditionalWrapper.jsx
// lifted from https://gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f
-const ConditionalWrapper = ({ condition, wrap, children }) => condition ? wrap(children) : children;
+const ConditionalWrapper = ({
+ condition,
+ wrap,
+ children
+}) => condition ? wrap(children) : children;
// EXTERNAL MODULE: ./content-src/asrouter/components/RichText/RichText.jsx
var RichText = __webpack_require__(16);
@@ -8430,7 +8597,6 @@ var SimpleSnippet_schema = __webpack_require__(19);
// CONCATENATED MODULE: ./content-src/asrouter/components/SnippetBase/SnippetBase.jsx
-
class SnippetBase_SnippetBase extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
@@ -8440,7 +8606,10 @@ class SnippetBase_SnippetBase extends external_React_default.a.PureComponent {
onBlockClicked() {
if (this.props.provider !== "preview") {
- this.props.sendUserActionTelemetry({ event: "BLOCK", id: this.props.UISurface });
+ this.props.sendUserActionTelemetry({
+ event: "BLOCK",
+ id: this.props.UISurface
+ });
}
this.props.onBlock();
@@ -8448,7 +8617,10 @@ class SnippetBase_SnippetBase extends external_React_default.a.PureComponent {
onDismissClicked() {
if (this.props.provider !== "preview") {
- this.props.sendUserActionTelemetry({ event: "DISMISS", id: this.props.UISurface });
+ this.props.sendUserActionTelemetry({
+ event: "DISMISS",
+ id: this.props.UISurface
+ });
}
this.props.onDismiss();
@@ -8456,47 +8628,40 @@ class SnippetBase_SnippetBase extends external_React_default.a.PureComponent {
renderDismissButton() {
if (this.props.footerDismiss) {
- return external_React_default.a.createElement(
- "div",
- { className: "footer" },
- external_React_default.a.createElement(
- "div",
- { className: "footer-content" },
- external_React_default.a.createElement(
- "button",
- {
- className: "ASRouterButton secondary",
- onClick: this.onDismissClicked },
- this.props.content.scene2_dismiss_button_text
- )
- )
- );
+ return external_React_default.a.createElement("div", {
+ className: "footer"
+ }, external_React_default.a.createElement("div", {
+ className: "footer-content"
+ }, external_React_default.a.createElement("button", {
+ className: "ASRouterButton secondary",
+ onClick: this.onDismissClicked
+ }, this.props.content.scene2_dismiss_button_text)));
}
const defaultTitle = SimpleSnippet_schema.properties.block_button_text.default;
- return external_React_default.a.createElement("button", { className: "blockButton", title: this.props.content.block_button_text || defaultTitle, onClick: this.onBlockClicked });
+ return external_React_default.a.createElement("button", {
+ className: "blockButton",
+ title: this.props.content.block_button_text || defaultTitle,
+ onClick: this.onBlockClicked
+ });
}
render() {
- const { props } = this;
-
+ const {
+ props
+ } = this;
const containerClassName = `SnippetBaseContainer${props.className ? ` ${props.className}` : ""}`;
-
- return external_React_default.a.createElement(
- "div",
- { className: containerClassName, style: this.props.textStyle },
- external_React_default.a.createElement(
- "div",
- { className: "innerWrapper" },
- props.children
- ),
- this.renderDismissButton()
- );
+ return external_React_default.a.createElement("div", {
+ className: containerClassName,
+ style: this.props.textStyle
+ }, external_React_default.a.createElement("div", {
+ className: "innerWrapper"
+ }, props.children), this.renderDismissButton());
}
+
}
// CONCATENATED MODULE: ./content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
@@ -8505,7 +8670,6 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
const DEFAULT_ICON_PATH = "chrome://branding/content/icon64.png";
-
class SimpleSnippet_SimpleSnippet extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
@@ -8514,15 +8678,24 @@ class SimpleSnippet_SimpleSnippet extends external_React_default.a.PureComponent
onButtonClick() {
if (this.props.provider !== "preview") {
- this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", id: this.props.UISurface });
+ this.props.sendUserActionTelemetry({
+ event: "CLICK_BUTTON",
+ id: this.props.UISurface
+ });
}
- const { button_url } = this.props.content;
- // If button_url is defined handle it as OPEN_URL action
+
+ const {
+ button_url
+ } = this.props.content; // If button_url is defined handle it as OPEN_URL action
+
const type = this.props.content.button_action || button_url && "OPEN_URL";
this.props.onAction({
type,
- data: { args: this.props.content.button_action_args || button_url }
+ data: {
+ args: this.props.content.button_action_args || button_url
+ }
});
+
if (!this.props.content.do_not_autoblock) {
this.props.onBlock();
}
@@ -8533,141 +8706,131 @@ class SimpleSnippet_SimpleSnippet extends external_React_default.a.PureComponent
}
renderTitle() {
- const { title } = this.props.content;
- return title ? external_React_default.a.createElement(
- "h3",
- { className: `title ${this._shouldRenderButton() ? "title-inline" : ""}` },
- this.renderTitleIcon(),
- " ",
+ const {
title
- ) : null;
+ } = this.props.content;
+ return title ? external_React_default.a.createElement("h3", {
+ className: `title ${this._shouldRenderButton() ? "title-inline" : ""}`
+ }, this.renderTitleIcon(), " ", title) : null;
}
renderTitleIcon() {
const titleIcon = Object(template_utils["safeURI"])(this.props.content.title_icon);
- return titleIcon ? external_React_default.a.createElement("span", { className: "titleIcon", style: { backgroundImage: `url("${titleIcon}")` } }) : null;
+ return titleIcon ? external_React_default.a.createElement("span", {
+ className: "titleIcon",
+ style: {
+ backgroundImage: `url("${titleIcon}")`
+ }
+ }) : null;
}
renderButton() {
- const { props } = this;
+ const {
+ props
+ } = this;
+
if (!this._shouldRenderButton()) {
return null;
}
- return external_React_default.a.createElement(
- Button,
- {
- onClick: props.onButtonClick || this.onButtonClick,
- color: props.content.button_color,
- backgroundColor: props.content.button_background_color },
- props.content.button_label
- );
+ return external_React_default.a.createElement(Button, {
+ onClick: props.onButtonClick || this.onButtonClick,
+ color: props.content.button_color,
+ backgroundColor: props.content.button_background_color
+ }, props.content.button_label);
}
renderText() {
- const { props } = this;
- return external_React_default.a.createElement(RichText["RichText"], { text: props.content.text,
+ const {
+ props
+ } = this;
+ return external_React_default.a.createElement(RichText["RichText"], {
+ text: props.content.text,
customElements: this.props.customElements,
localization_id: "text",
links: props.content.links,
- sendClick: props.sendClick });
+ sendClick: props.sendClick
+ });
}
wrapSectionHeader(url) {
return function (children) {
- return external_React_default.a.createElement(
- "a",
- { href: url },
- children
- );
+ return external_React_default.a.createElement("a", {
+ href: url
+ }, children);
};
}
wrapSnippetContent(children) {
- return external_React_default.a.createElement(
- "div",
- { className: "innerContentWrapper" },
- children
- );
+ return external_React_default.a.createElement("div", {
+ className: "innerContentWrapper"
+ }, children);
}
renderSectionHeader() {
- const { props } = this;
+ const {
+ props
+ } = this; // an icon and text must be specified to render the section header
- // an icon and text must be specified to render the section header
if (props.content.section_title_icon && props.content.section_title_text) {
const sectionTitleIcon = Object(template_utils["safeURI"])(props.content.section_title_icon);
const sectionTitleURL = props.content.section_title_url;
-
- return external_React_default.a.createElement(
- "div",
- { className: "section-header" },
- external_React_default.a.createElement(
- "h3",
- { className: "section-title" },
- external_React_default.a.createElement(
- ConditionalWrapper,
- { condition: sectionTitleURL, wrap: this.wrapSectionHeader(sectionTitleURL) },
- external_React_default.a.createElement("span", { className: "icon icon-small-spacer", style: { backgroundImage: `url("${sectionTitleIcon}")` } }),
- external_React_default.a.createElement(
- "span",
- { className: "section-title-text" },
- props.content.section_title_text
- )
- )
- )
- );
+ return external_React_default.a.createElement("div", {
+ className: "section-header"
+ }, external_React_default.a.createElement("h3", {
+ className: "section-title"
+ }, external_React_default.a.createElement(ConditionalWrapper, {
+ condition: sectionTitleURL,
+ wrap: this.wrapSectionHeader(sectionTitleURL)
+ }, external_React_default.a.createElement("span", {
+ className: "icon icon-small-spacer",
+ style: {
+ backgroundImage: `url("${sectionTitleIcon}")`
+ }
+ }), external_React_default.a.createElement("span", {
+ className: "section-title-text"
+ }, props.content.section_title_text))));
}
return null;
}
render() {
- const { props } = this;
+ const {
+ props
+ } = this;
const sectionHeader = this.renderSectionHeader();
let className = "SimpleSnippet";
if (props.className) {
className += ` ${props.className}`;
}
+
if (props.content.tall) {
className += " tall";
}
+
if (sectionHeader) {
className += " has-section-header";
}
- return external_React_default.a.createElement(
- SnippetBase_SnippetBase,
- _extends({}, props, { className: className, textStyle: this.props.textStyle }),
- sectionHeader,
- external_React_default.a.createElement(
- ConditionalWrapper,
- { condition: sectionHeader, wrap: this.wrapSnippetContent },
- external_React_default.a.createElement("img", { src: Object(template_utils["safeURI"])(props.content.icon) || DEFAULT_ICON_PATH, className: "icon" }),
- external_React_default.a.createElement(
- "div",
- null,
- this.renderTitle(),
- " ",
- external_React_default.a.createElement(
- "p",
- { className: "body" },
- this.renderText()
- ),
- this.props.extraContent
- ),
- external_React_default.a.createElement(
- "div",
- null,
- this.renderButton()
- )
- )
- );
+ return external_React_default.a.createElement(SnippetBase_SnippetBase, _extends({}, props, {
+ className: className,
+ textStyle: this.props.textStyle
+ }), sectionHeader, external_React_default.a.createElement(ConditionalWrapper, {
+ condition: sectionHeader,
+ wrap: this.wrapSnippetContent
+ }, external_React_default.a.createElement("img", {
+ src: Object(template_utils["safeURI"])(props.content.icon) || DEFAULT_ICON_PATH,
+ className: "icon"
+ }), external_React_default.a.createElement("div", null, this.renderTitle(), " ", external_React_default.a.createElement("p", {
+ className: "body"
+ }, this.renderText()), this.props.extraContent), external_React_default.a.createElement("div", null, this.renderButton())));
}
+
}
// CONCATENATED MODULE: ./content-src/asrouter/templates/EOYSnippet/EOYSnippet.jsx
-var EOYSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+function EOYSnippet_extends() { EOYSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return EOYSnippet_extends.apply(this, arguments); }
@@ -8678,13 +8841,15 @@ class EOYSnippet_EOYSnippetBase extends external_React_default.a.PureComponent {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
-
/**
* setFrequencyValue - `frequency` form parameter value should be `monthly`
* if `monthly-checkbox` is selected or `single` otherwise
*/
+
+
setFrequencyValue() {
const frequencyCheckbox = this.refs.form.querySelector("#monthly-checkbox");
+
if (frequencyCheckbox.checked) {
this.refs.form.querySelector("[name='frequency']").value = "monthly";
}
@@ -8694,6 +8859,7 @@ class EOYSnippet_EOYSnippetBase extends external_React_default.a.PureComponent {
event.preventDefault();
this.setFrequencyValue();
this.refs.form.submit();
+
if (!this.props.content.do_not_autoblock) {
this.props.onBlock();
}
@@ -8705,56 +8871,72 @@ class EOYSnippet_EOYSnippetBase extends external_React_default.a.PureComponent {
style: "currency",
currency: this.props.content.currency_code,
minimumFractionDigits: 0
- });
- // Default to `second` button
- const { selected_button } = this.props.content;
+ }); // Default to `second` button
+
+ const {
+ selected_button
+ } = this.props.content;
const btnStyle = {
color: this.props.content.button_color,
backgroundColor: this.props.content.button_background_color
};
const donationURLParams = [];
const paramsStartIndex = this.props.content.donation_form_url.indexOf("?");
+
for (const entry of new URLSearchParams(this.props.content.donation_form_url.slice(paramsStartIndex)).entries()) {
donationURLParams.push(entry);
}
- return external_React_default.a.createElement(
- "form",
- { className: "EOYSnippetForm", action: this.props.content.donation_form_url, method: this.props.form_method, onSubmit: this.handleSubmit, ref: "form" },
- donationURLParams.map(([key, value], idx) => external_React_default.a.createElement("input", { type: "hidden", name: key, value: value, key: idx })),
- fieldNames.map((field, idx) => {
- const button_name = `donation_amount_${field}`;
- const amount = this.props.content[button_name];
- return external_React_default.a.createElement(
- external_React_default.a.Fragment,
- { key: idx },
- external_React_default.a.createElement("input", { type: "radio", name: "amount", value: amount, id: field, defaultChecked: button_name === selected_button }),
- external_React_default.a.createElement(
- "label",
- { htmlFor: field, className: "donation-amount" },
- numberFormat.format(amount)
- )
- );
- }),
- external_React_default.a.createElement(
- "div",
- { className: "monthly-checkbox-container" },
- external_React_default.a.createElement("input", { id: "monthly-checkbox", type: "checkbox" }),
- external_React_default.a.createElement(
- "label",
- { htmlFor: "monthly-checkbox" },
- this.props.content.monthly_checkbox_label_text
- )
- ),
- external_React_default.a.createElement("input", { type: "hidden", name: "frequency", value: "single" }),
- external_React_default.a.createElement("input", { type: "hidden", name: "currency", value: this.props.content.currency_code }),
- external_React_default.a.createElement("input", { type: "hidden", name: "presets", value: fieldNames.map(field => this.props.content[`donation_amount_${field}`]) }),
- external_React_default.a.createElement(
- "button",
- { style: btnStyle, type: "submit", className: "ASRouterButton primary donation-form-url" },
- this.props.content.button_label
- )
- );
+ return external_React_default.a.createElement("form", {
+ className: "EOYSnippetForm",
+ action: this.props.content.donation_form_url,
+ method: this.props.form_method,
+ onSubmit: this.handleSubmit,
+ ref: "form"
+ }, donationURLParams.map(([key, value], idx) => external_React_default.a.createElement("input", {
+ type: "hidden",
+ name: key,
+ value: value,
+ key: idx
+ })), fieldNames.map((field, idx) => {
+ const button_name = `donation_amount_${field}`;
+ const amount = this.props.content[button_name];
+ return external_React_default.a.createElement(external_React_default.a.Fragment, {
+ key: idx
+ }, external_React_default.a.createElement("input", {
+ type: "radio",
+ name: "amount",
+ value: amount,
+ id: field,
+ defaultChecked: button_name === selected_button
+ }), external_React_default.a.createElement("label", {
+ htmlFor: field,
+ className: "donation-amount"
+ }, numberFormat.format(amount)));
+ }), external_React_default.a.createElement("div", {
+ className: "monthly-checkbox-container"
+ }, external_React_default.a.createElement("input", {
+ id: "monthly-checkbox",
+ type: "checkbox"
+ }), external_React_default.a.createElement("label", {
+ htmlFor: "monthly-checkbox"
+ }, this.props.content.monthly_checkbox_label_text)), external_React_default.a.createElement("input", {
+ type: "hidden",
+ name: "frequency",
+ value: "single"
+ }), external_React_default.a.createElement("input", {
+ type: "hidden",
+ name: "currency",
+ value: this.props.content.currency_code
+ }), external_React_default.a.createElement("input", {
+ type: "hidden",
+ name: "presets",
+ value: fieldNames.map(field => this.props.content[`donation_amount_${field}`])
+ }), external_React_default.a.createElement("button", {
+ style: btnStyle,
+ type: "submit",
+ className: "ASRouterButton primary donation-form-url"
+ }, this.props.content.button_label));
}
render() {
@@ -8762,35 +8944,45 @@ class EOYSnippet_EOYSnippetBase extends external_React_default.a.PureComponent {
color: this.props.content.text_color,
backgroundColor: this.props.content.background_color
};
- const customElement = external_React_default.a.createElement("em", { style: { backgroundColor: this.props.content.highlight_color } });
+ const customElement = external_React_default.a.createElement("em", {
+ style: {
+ backgroundColor: this.props.content.highlight_color
+ }
+ });
return external_React_default.a.createElement(SimpleSnippet_SimpleSnippet, EOYSnippet_extends({}, this.props, {
className: this.props.content.test,
- customElements: { em: customElement },
+ customElements: {
+ em: customElement
+ },
textStyle: textStyle,
- extraContent: this.renderDonations() }));
+ extraContent: this.renderDonations()
+ }));
}
+
}
const EOYSnippet = props => {
- const extendedContent = Object.assign({
+ const extendedContent = {
monthly_checkbox_label_text: EOYSnippet_schema.properties.monthly_checkbox_label_text.default,
locale: EOYSnippet_schema.properties.locale.default,
currency_code: EOYSnippet_schema.properties.currency_code.default,
- selected_button: EOYSnippet_schema.properties.selected_button.default
- }, props.content);
-
+ selected_button: EOYSnippet_schema.properties.selected_button.default,
+ ...props.content
+ };
return external_React_default.a.createElement(EOYSnippet_EOYSnippetBase, EOYSnippet_extends({}, props, {
content: extendedContent,
- form_method: "GET" }));
+ form_method: "GET"
+ }));
};
// EXTERNAL MODULE: ./content-src/asrouter/templates/FXASignupSnippet/FXASignupSnippet.schema.json
var FXASignupSnippet_schema = __webpack_require__(20);
// CONCATENATED MODULE: ./content-src/asrouter/templates/SubmitFormSnippet/SubmitFormSnippet.jsx
-var SubmitFormSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+function SubmitFormSnippet_extends() { SubmitFormSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return SubmitFormSnippet_extends.apply(this, arguments); }
-function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
+function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
@@ -8815,7 +9007,9 @@ class SubmitFormSnippet_SubmitFormSnippet extends external_React_default.a.PureC
handleSubmitAttempt() {
if (!this.state.submitAttempted) {
- this.setState({ submitAttempted: true });
+ this.setState({
+ submitAttempted: true
+ });
}
}
@@ -8830,19 +9024,41 @@ class SubmitFormSnippet_SubmitFormSnippet extends external_React_default.a.PureC
}
event.preventDefault();
- _this.setState({ disableForm: true });
- _this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", value: "conversion-subscribe-activation", id: "NEWTAB_FOOTER_BAR_CONTENT" });
+
+ _this.setState({
+ disableForm: true
+ });
+
+ _this.props.sendUserActionTelemetry({
+ event: "CLICK_BUTTON",
+ value: "conversion-subscribe-activation",
+ id: "NEWTAB_FOOTER_BAR_CONTENT"
+ });
if (_this.props.form_method.toUpperCase() === "GET") {
- _this.props.onBlock({ preventDismiss: true });
+ _this.props.onBlock({
+ preventDismiss: true
+ });
+
_this.refs.form.submit();
+
return;
}
- const { url, formData } = _this.props.processFormData ? _this.props.processFormData(_this.refs.mainInput, _this.props) : { url: _this.refs.form.action, formData: new FormData(_this.refs.form) };
+ const {
+ url,
+ formData
+ } = _this.props.processFormData ? _this.props.processFormData(_this.refs.mainInput, _this.props) : {
+ url: _this.refs.form.action,
+ formData: new FormData(_this.refs.form)
+ };
try {
- const fetchRequest = new Request(url, { body: formData, method: "POST", credentials: "omit" });
+ const fetchRequest = new Request(url, {
+ body: formData,
+ method: "POST",
+ credentials: "omit"
+ });
const response = yield fetch(fetchRequest);
json = yield response.json();
} catch (err) {
@@ -8850,24 +9066,49 @@ class SubmitFormSnippet_SubmitFormSnippet extends external_React_default.a.PureC
}
if (json && json.status === "ok") {
- _this.setState({ signupSuccess: true, signupSubmitted: true });
+ _this.setState({
+ signupSuccess: true,
+ signupSubmitted: true
+ });
+
if (!_this.props.content.do_not_autoblock) {
- _this.props.onBlock({ preventDismiss: true });
+ _this.props.onBlock({
+ preventDismiss: true
+ });
}
- _this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", value: "subscribe-success", id: "NEWTAB_FOOTER_BAR_CONTENT" });
+
+ _this.props.sendUserActionTelemetry({
+ event: "CLICK_BUTTON",
+ value: "subscribe-success",
+ id: "NEWTAB_FOOTER_BAR_CONTENT"
+ });
} else {
console.error("There was a problem submitting the form", json || "[No JSON response]"); // eslint-disable-line no-console
- _this.setState({ signupSuccess: false, signupSubmitted: true });
- _this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", value: "subscribe-error", id: "NEWTAB_FOOTER_BAR_CONTENT" });
+
+ _this.setState({
+ signupSuccess: false,
+ signupSubmitted: true
+ });
+
+ _this.props.sendUserActionTelemetry({
+ event: "CLICK_BUTTON",
+ value: "subscribe-error",
+ id: "NEWTAB_FOOTER_BAR_CONTENT"
+ });
}
- _this.setState({ disableForm: false });
+ _this.setState({
+ disableForm: false
+ });
})();
}
expandSnippet() {
- this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", value: "scene1-button-learn-more", id: this.props.UISurface });
-
+ this.props.sendUserActionTelemetry({
+ event: "CLICK_BUTTON",
+ value: "scene1-button-learn-more",
+ id: this.props.UISurface
+ });
this.setState({
expanded: true,
signupSuccess: false,
@@ -8876,89 +9117,99 @@ class SubmitFormSnippet_SubmitFormSnippet extends external_React_default.a.PureC
}
renderHiddenFormInputs() {
- const { hidden_inputs } = this.props.content;
+ const {
+ hidden_inputs
+ } = this.props.content;
if (!hidden_inputs) {
return null;
}
- return Object.keys(hidden_inputs).map((key, idx) => external_React_default.a.createElement("input", { key: idx, type: "hidden", name: key, value: hidden_inputs[key] }));
+ return Object.keys(hidden_inputs).map((key, idx) => external_React_default.a.createElement("input", {
+ key: idx,
+ type: "hidden",
+ name: key,
+ value: hidden_inputs[key]
+ }));
}
renderDisclaimer() {
- const { content } = this.props;
+ const {
+ content
+ } = this.props;
+
if (!content.scene2_disclaimer_html) {
return null;
}
- return external_React_default.a.createElement(
- "p",
- { className: "disclaimerText" },
- external_React_default.a.createElement(RichText["RichText"], { text: content.scene2_disclaimer_html,
- localization_id: "disclaimer_html",
- links: content.links,
- doNotAutoBlock: true,
- openNewWindow: true,
- sendClick: this.props.sendClick })
- );
+
+ return external_React_default.a.createElement("p", {
+ className: "disclaimerText"
+ }, external_React_default.a.createElement(RichText["RichText"], {
+ text: content.scene2_disclaimer_html,
+ localization_id: "disclaimer_html",
+ links: content.links,
+ doNotAutoBlock: true,
+ openNewWindow: true,
+ sendClick: this.props.sendClick
+ }));
}
renderFormPrivacyNotice() {
- const { content } = this.props;
+ const {
+ content
+ } = this.props;
+
if (!content.scene2_privacy_html) {
return null;
}
- return external_React_default.a.createElement(
- "p",
- { className: "privacyNotice" },
- external_React_default.a.createElement("input", { type: "checkbox", id: "id_privacy", name: "privacy", required: "required" }),
- external_React_default.a.createElement(
- "label",
- { htmlFor: "id_privacy" },
- external_React_default.a.createElement(RichText["RichText"], { text: content.scene2_privacy_html,
- localization_id: "privacy_html",
- links: content.links,
- doNotAutoBlock: true,
- openNewWindow: true,
- sendClick: this.props.sendClick })
- )
- );
+
+ return external_React_default.a.createElement("p", {
+ className: "privacyNotice"
+ }, external_React_default.a.createElement("input", {
+ type: "checkbox",
+ id: "id_privacy",
+ name: "privacy",
+ required: "required"
+ }), external_React_default.a.createElement("label", {
+ htmlFor: "id_privacy"
+ }, external_React_default.a.createElement(RichText["RichText"], {
+ text: content.scene2_privacy_html,
+ localization_id: "privacy_html",
+ links: content.links,
+ doNotAutoBlock: true,
+ openNewWindow: true,
+ sendClick: this.props.sendClick
+ })));
}
renderSignupSubmitted() {
- const { content } = this.props;
+ const {
+ content
+ } = this.props;
const isSuccess = this.state.signupSuccess;
const successTitle = isSuccess && content.success_title;
- const bodyText = isSuccess ? { success_text: content.success_text } : { error_text: content.error_text };
+ const bodyText = isSuccess ? {
+ success_text: content.success_text
+ } : {
+ error_text: content.error_text
+ };
const retryButtonText = content.scene1_button_label;
- return external_React_default.a.createElement(
- SnippetBase_SnippetBase,
- this.props,
- external_React_default.a.createElement(
- "div",
- { className: "submissionStatus" },
- successTitle ? external_React_default.a.createElement(
- "h2",
- { className: "submitStatusTitle" },
- successTitle
- ) : null,
- external_React_default.a.createElement(
- "p",
- null,
- external_React_default.a.createElement(RichText["RichText"], SubmitFormSnippet_extends({}, bodyText, { localization_id: isSuccess ? "success_text" : "error_text" })),
- isSuccess ? null : external_React_default.a.createElement(
- Button,
- { onClick: this.expandSnippet },
- retryButtonText
- )
- )
- )
- );
+ return external_React_default.a.createElement(SnippetBase_SnippetBase, this.props, external_React_default.a.createElement("div", {
+ className: "submissionStatus"
+ }, successTitle ? external_React_default.a.createElement("h2", {
+ className: "submitStatusTitle"
+ }, successTitle) : null, external_React_default.a.createElement("p", null, external_React_default.a.createElement(RichText["RichText"], SubmitFormSnippet_extends({}, bodyText, {
+ localization_id: isSuccess ? "success_text" : "error_text"
+ })), isSuccess ? null : external_React_default.a.createElement(Button, {
+ onClick: this.expandSnippet
+ }, retryButtonText))));
}
onInputChange(event) {
if (!this.props.validateInput) {
return;
}
+
const hasError = this.props.validateInput(event.target.value, this.props.content);
event.target.setCustomValidity(hasError);
}
@@ -8973,52 +9224,40 @@ class SubmitFormSnippet_SubmitFormSnippet extends external_React_default.a.PureC
required: true,
placeholder: placholder,
onChange: this.props.validateInput ? this.onInputChange : null,
- autoFocus: true });
+ autoFocus: true
+ });
}
renderSignupView() {
- const { content } = this.props;
+ const {
+ content
+ } = this.props;
const containerClass = `SubmitFormSnippet ${this.props.className}`;
- return external_React_default.a.createElement(
- SnippetBase_SnippetBase,
- SubmitFormSnippet_extends({}, this.props, { className: containerClass, footerDismiss: true }),
- content.scene2_icon ? external_React_default.a.createElement(
- "div",
- { className: "scene2Icon" },
- external_React_default.a.createElement("img", { src: content.scene2_icon })
- ) : null,
- external_React_default.a.createElement(
- "div",
- { className: "message" },
- external_React_default.a.createElement(
- "p",
- null,
- content.scene2_title && external_React_default.a.createElement(
- "h3",
- { className: "scene2Title" },
- content.scene2_title
- ),
- " ",
- content.scene2_text && external_React_default.a.createElement(RichText["RichText"], { scene2_text: content.scene2_text, localization_id: "scene2_text" })
- )
- ),
- external_React_default.a.createElement(
- "form",
- { action: this.props.form_action, method: this.props.form_method, onSubmit: this.handleSubmit, ref: "form" },
- this.renderHiddenFormInputs(),
- external_React_default.a.createElement(
- "div",
- null,
- this.renderInput(),
- external_React_default.a.createElement(
- "button",
- { type: "submit", className: "ASRouterButton primary", onClick: this.handleSubmitAttempt, ref: "formSubmitBtn" },
- content.scene2_button_label
- )
- ),
- this.renderFormPrivacyNotice() || this.renderDisclaimer()
- )
- );
+ return external_React_default.a.createElement(SnippetBase_SnippetBase, SubmitFormSnippet_extends({}, this.props, {
+ className: containerClass,
+ footerDismiss: true
+ }), content.scene2_icon ? external_React_default.a.createElement("div", {
+ className: "scene2Icon"
+ }, external_React_default.a.createElement("img", {
+ src: content.scene2_icon
+ })) : null, external_React_default.a.createElement("div", {
+ className: "message"
+ }, external_React_default.a.createElement("p", null, content.scene2_title && external_React_default.a.createElement("h3", {
+ className: "scene2Title"
+ }, content.scene2_title), " ", content.scene2_text && external_React_default.a.createElement(RichText["RichText"], {
+ scene2_text: content.scene2_text,
+ localization_id: "scene2_text"
+ }))), external_React_default.a.createElement("form", {
+ action: this.props.form_action,
+ method: this.props.form_method,
+ onSubmit: this.handleSubmit,
+ ref: "form"
+ }, this.renderHiddenFormInputs(), external_React_default.a.createElement("div", null, this.renderInput(), external_React_default.a.createElement("button", {
+ type: "submit",
+ className: "ASRouterButton primary",
+ onClick: this.handleSubmitAttempt,
+ ref: "formSubmitBtn"
+ }, content.scene2_button_label)), this.renderFormPrivacyNotice() || this.renderDisclaimer()));
}
getFirstSceneContent() {
@@ -9029,20 +9268,27 @@ class SubmitFormSnippet_SubmitFormSnippet extends external_React_default.a.PureC
}
render() {
- const content = Object.assign({}, this.props.content, this.getFirstSceneContent());
+ const content = { ...this.props.content,
+ ...this.getFirstSceneContent()
+ };
if (this.state.signupSubmitted) {
return this.renderSignupSubmitted();
}
+
if (this.state.expanded) {
return this.renderSignupView();
}
- return external_React_default.a.createElement(SimpleSnippet_SimpleSnippet, SubmitFormSnippet_extends({}, this.props, { content: content, onButtonClick: this.expandSnippet }));
+
+ return external_React_default.a.createElement(SimpleSnippet_SimpleSnippet, SubmitFormSnippet_extends({}, this.props, {
+ content: content,
+ onButtonClick: this.expandSnippet
+ }));
}
+
}
// CONCATENATED MODULE: ./content-src/asrouter/templates/FXASignupSnippet/FXASignupSnippet.jsx
-var FXASignupSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function FXASignupSnippet_extends() { FXASignupSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return FXASignupSnippet_extends.apply(this, arguments); }
@@ -9050,13 +9296,13 @@ var FXASignupSnippet_extends = Object.assign || function (target) { for (var i =
const FXASignupSnippet = props => {
const userAgent = window.navigator.userAgent.match(/Firefox\/([0-9]+)\./);
const firefox_version = userAgent ? parseInt(userAgent[1], 10) : 0;
- const extendedContent = Object.assign({
+ const extendedContent = {
scene1_button_label: FXASignupSnippet_schema.properties.scene1_button_label.default,
scene2_email_placeholder_text: FXASignupSnippet_schema.properties.scene2_email_placeholder_text.default,
scene2_button_label: FXASignupSnippet_schema.properties.scene2_button_label.default,
- scene2_dismiss_button_text: FXASignupSnippet_schema.properties.scene2_dismiss_button_text.default
- }, props.content, {
- hidden_inputs: Object.assign({
+ scene2_dismiss_button_text: FXASignupSnippet_schema.properties.scene2_dismiss_button_text.default,
+ ...props.content,
+ hidden_inputs: {
action: "email",
context: "fx_desktop_v3",
entrypoint: "snippets",
@@ -9064,45 +9310,46 @@ const FXASignupSnippet = props => {
utm_source: "snippet",
utm_content: firefox_version,
utm_campaign: props.content.utm_campaign,
- utm_term: props.content.utm_term
- }, props.content.hidden_inputs)
- });
-
+ utm_term: props.content.utm_term,
+ ...props.content.hidden_inputs
+ }
+ };
return external_React_default.a.createElement(SubmitFormSnippet_SubmitFormSnippet, FXASignupSnippet_extends({}, props, {
content: extendedContent,
form_action: "https://accounts.firefox.com/",
- form_method: "GET" }));
+ form_method: "GET"
+ }));
};
// EXTERNAL MODULE: ./content-src/asrouter/templates/NewsletterSnippet/NewsletterSnippet.schema.json
var NewsletterSnippet_schema = __webpack_require__(21);
// CONCATENATED MODULE: ./content-src/asrouter/templates/NewsletterSnippet/NewsletterSnippet.jsx
-var NewsletterSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+function NewsletterSnippet_extends() { NewsletterSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return NewsletterSnippet_extends.apply(this, arguments); }
const NewsletterSnippet = props => {
- const extendedContent = Object.assign({
+ const extendedContent = {
scene1_button_label: NewsletterSnippet_schema.properties.scene1_button_label.default,
scene2_email_placeholder_text: NewsletterSnippet_schema.properties.scene2_email_placeholder_text.default,
scene2_button_label: NewsletterSnippet_schema.properties.scene2_button_label.default,
scene2_dismiss_button_text: NewsletterSnippet_schema.properties.scene2_dismiss_button_text.default,
- scene2_newsletter: NewsletterSnippet_schema.properties.scene2_newsletter.default
- }, props.content, {
- hidden_inputs: Object.assign({
+ scene2_newsletter: NewsletterSnippet_schema.properties.scene2_newsletter.default,
+ ...props.content,
+ hidden_inputs: {
newsletters: props.content.scene2_newsletter || NewsletterSnippet_schema.properties.scene2_newsletter.default,
fmt: NewsletterSnippet_schema.properties.hidden_inputs.properties.fmt.default,
lang: props.content.locale || NewsletterSnippet_schema.properties.locale.default,
- source_url: `https://snippets.mozilla.com/show/${props.id}`
- }, props.content.hidden_inputs)
- });
-
+ source_url: `https://snippets.mozilla.com/show/${props.id}`,
+ ...props.content.hidden_inputs
+ }
+ };
return external_React_default.a.createElement(SubmitFormSnippet_SubmitFormSnippet, NewsletterSnippet_extends({}, props, {
content: extendedContent,
form_action: "https://basket.mozilla.org/subscribe.json",
- form_method: "POST" }));
+ form_method: "POST"
+ }));
};
// CONCATENATED MODULE: ./content-src/asrouter/templates/SendToDeviceSnippet/isEmailOrPhoneNumber.js
/**
@@ -9112,38 +9359,45 @@ const NewsletterSnippet = props => {
* @returns {"email"|"phone"|""} The type of the input
*/
function isEmailOrPhoneNumber(val, content) {
- const { locale } = content;
- // http://emailregex.com/
+ const {
+ locale
+ } = content; // http://emailregex.com/
+
const email_re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const check_email = email_re.test(val);
let check_phone; // depends on locale
+
switch (locale) {
case "en-US":
case "en-CA":
// allow 10-11 digits in case user wants to enter country code
check_phone = val.length >= 10 && val.length <= 11 && !isNaN(val);
break;
+
case "de":
// allow between 2 and 12 digits for german phone numbers
check_phone = val.length >= 2 && val.length <= 12 && !isNaN(val);
break;
// this case should never be hit, but good to have a fallback just in case
+
default:
check_phone = !isNaN(val);
break;
}
+
if (check_email) {
return "email";
} else if (check_phone) {
return "phone";
}
+
return "";
}
// EXTERNAL MODULE: ./content-src/asrouter/templates/SendToDeviceSnippet/SendToDeviceSnippet.schema.json
var SendToDeviceSnippet_schema = __webpack_require__(22);
// CONCATENATED MODULE: ./content-src/asrouter/templates/SendToDeviceSnippet/SendToDeviceSnippet.jsx
-var SendToDeviceSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
+function SendToDeviceSnippet_extends() { SendToDeviceSnippet_extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return SendToDeviceSnippet_extends.apply(this, arguments); }
@@ -9156,10 +9410,13 @@ function validateInput(value, content) {
}
function processFormData(input, message) {
- const { content } = message;
+ const {
+ content
+ } = message;
const type = content.include_sms ? isEmailOrPhoneNumber(input.value, content) : "email";
const formData = new FormData();
let url;
+
if (type === "phone") {
url = "https://basket.mozilla.org/news/subscribe_sms/";
formData.append("mobile_number", input.value);
@@ -9171,13 +9428,17 @@ function processFormData(input, message) {
formData.append("newsletters", content.message_id_email);
formData.append("source_url", encodeURIComponent(`https://snippets.mozilla.com/show/${message.id}`));
}
+
formData.append("lang", content.locale);
- return { formData, url };
+ return {
+ formData,
+ url
+ };
}
function addDefaultValues(props) {
- return Object.assign({}, props, {
- content: Object.assign({
+ return { ...props,
+ content: {
scene1_button_label: SendToDeviceSnippet_schema.properties.scene1_button_label.default,
scene2_dismiss_button_text: SendToDeviceSnippet_schema.properties.scene2_dismiss_button_text.default,
scene2_button_label: SendToDeviceSnippet_schema.properties.scene2_button_label.default,
@@ -9185,20 +9446,21 @@ function addDefaultValues(props) {
locale: SendToDeviceSnippet_schema.properties.locale.default,
country: SendToDeviceSnippet_schema.properties.country.default,
message_id_email: "",
- include_sms: SendToDeviceSnippet_schema.properties.include_sms.default
- }, props.content)
- });
+ include_sms: SendToDeviceSnippet_schema.properties.include_sms.default,
+ ...props.content
+ }
+ };
}
const SendToDeviceSnippet = props => {
const propsWithDefaults = addDefaultValues(props);
-
return external_React_default.a.createElement(SubmitFormSnippet_SubmitFormSnippet, SendToDeviceSnippet_extends({}, propsWithDefaults, {
form_method: "POST",
className: "send_to_device_snippet",
inputType: propsWithDefaults.content.include_sms ? "text" : "email",
validateInput: propsWithDefaults.content.include_sms ? validateInput : null,
- processFormData: processFormData }));
+ processFormData: processFormData
+ }));
};
// CONCATENATED MODULE: ./content-src/asrouter/templates/template-manifest.jsx
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SnippetsTemplates", function() { return SnippetsTemplates; });
@@ -9206,9 +9468,8 @@ const SendToDeviceSnippet = props => {
+ // Key names matching schema name of templates
-
-// Key names matching schema name of templates
const SnippetsTemplates = {
simple_snippet: SimpleSnippet_SimpleSnippet,
newsletter_snippet: NewsletterSnippet,
@@ -9226,13 +9487,10 @@ __webpack_require__.r(__webpack_exports__);
// CONCATENATED MODULE: ./node_modules/fluent/src/parser.js
/* eslint no-magic-numbers: [0] */
-
const MAX_PLACEABLES = 100;
-
const entryIdentifierRe = /-?[a-zA-Z][a-zA-Z0-9_-]*/y;
const identifierRe = /[a-zA-Z][a-zA-Z0-9_-]*/y;
const functionIdentifierRe = /^[A-Z][A-Z_?-]*$/;
-
/**
* The `Parser` class is responsible for parsing FTL resources.
*
@@ -9246,6 +9504,7 @@ const functionIdentifierRe = /^[A-Z][A-Z_?-]*$/;
* There is an equivalent of this parser in syntax/parser which is
* generating full AST which is useful for FTL tools.
*/
+
class RuntimeParser {
/**
* Parse FTL code into entries formattable by the MessageContext.
@@ -9261,34 +9520,34 @@ class RuntimeParser {
this._index = 0;
this._length = string.length;
this.entries = {};
-
const errors = [];
-
this.skipWS();
+
while (this._index < this._length) {
try {
this.getEntry();
} catch (e) {
if (e instanceof SyntaxError) {
errors.push(e);
-
this.skipToNextEntryStart();
} else {
throw e;
}
}
+
this.skipWS();
}
return [this.entries, errors];
}
-
/**
* Parse the source string from the current index as an FTL entry
* and add it to object's entries property.
*
* @private
*/
+
+
getEntry() {
// The index here should either be at the beginning of the file
// or right after new line.
@@ -9297,9 +9556,8 @@ class RuntimeParser {
at the beginning of the file or on a new line.`);
}
- const ch = this._source[this._index];
+ const ch = this._source[this._index]; // We don't care about comments or sections at runtime
- // We don't care about comments or sections at runtime
if (ch === "/" || ch === "#" && [" ", "#", "\n"].includes(this._source[this._index + 1])) {
this.skipComment();
return;
@@ -9312,20 +9570,21 @@ class RuntimeParser {
this.getMessage();
}
-
/**
* Skip the section entry from the current index.
*
* @private
*/
+
+
skipSection() {
this._index += 1;
+
if (this._source[this._index] !== "[") {
throw this.error('Expected "[[" to open a section');
}
this._index += 1;
-
this.skipInlineWS();
this.getVariantName();
this.skipInlineWS();
@@ -9336,16 +9595,16 @@ class RuntimeParser {
this._index += 2;
}
-
/**
* Parse the source string from the current index as an FTL message
* and add it to the entries property on the Parser.
*
* @private
*/
+
+
getMessage() {
const id = this.getEntryIdentifier();
-
this.skipInlineWS();
if (this._source[this._index] === "=") {
@@ -9353,7 +9612,6 @@ class RuntimeParser {
}
this.skipInlineWS();
-
const val = this.getPattern();
if (id.startsWith("-") && val === null) {
@@ -9390,40 +9648,44 @@ class RuntimeParser {
}
}
}
-
/**
* Skip whitespace.
*
* @private
*/
+
+
skipWS() {
let ch = this._source[this._index];
+
while (ch === " " || ch === "\n" || ch === "\t" || ch === "\r") {
ch = this._source[++this._index];
}
}
-
/**
* Skip inline whitespace (space and \t).
*
* @private
*/
+
+
skipInlineWS() {
let ch = this._source[this._index];
+
while (ch === " " || ch === "\t") {
ch = this._source[++this._index];
}
}
-
/**
* Skip blank lines.
*
* @private
*/
+
+
skipBlankLines() {
while (true) {
const ptr = this._index;
-
this.skipInlineWS();
if (this._source[this._index] === "\n") {
@@ -9434,7 +9696,6 @@ class RuntimeParser {
}
}
}
-
/**
* Get identifier using the provided regex.
*
@@ -9444,6 +9705,8 @@ class RuntimeParser {
* @returns {String}
* @private
*/
+
+
getIdentifier(re = identifierRe) {
re.lastIndex = this._index;
const result = re.exec(this._source);
@@ -9456,27 +9719,29 @@ class RuntimeParser {
this._index = re.lastIndex;
return result[0];
}
-
/**
* Get identifier of a Message or a Term (staring with a dash).
*
* @returns {String}
* @private
*/
+
+
getEntryIdentifier() {
return this.getIdentifier(entryIdentifierRe);
}
-
/**
* Get Variant name.
*
* @returns {Object}
* @private
*/
+
+
getVariantName() {
let name = "";
-
const start = this._index;
+
let cc = this._source.charCodeAt(this._index);
if (cc >= 97 && cc <= 122 || // a-z
@@ -9494,27 +9759,30 @@ class RuntimeParser {
cc === 95 || cc === 45 || cc === 32) {
// _- <space>
cc = this._source.charCodeAt(++this._index);
- }
-
- // If we encountered the end of name, we want to test if the last
+ } // If we encountered the end of name, we want to test if the last
// collected character is a space.
// If it is, we will backtrack to the last non-space character because
// the keyword cannot end with a space character.
+
+
while (this._source.charCodeAt(this._index - 1) === 32) {
this._index--;
}
name += this._source.slice(start, this._index);
-
- return { type: "varname", name };
+ return {
+ type: "varname",
+ name
+ };
}
-
/**
* Get simple string argument enclosed in `"`.
*
* @returns {String}
* @private
*/
+
+
getString() {
const start = this._index + 1;
@@ -9532,7 +9800,6 @@ class RuntimeParser {
return this._source.substring(start, this._index++);
}
-
/**
* Parses a Message pattern.
* Message Pattern may be a simple string or an array of strings
@@ -9541,6 +9808,8 @@ class RuntimeParser {
* @returns {String|Array}
* @private
*/
+
+
getPattern() {
// We're going to first try to see if the pattern is simple.
// If it is we can just look for the end of the line and read the string.
@@ -9548,6 +9817,7 @@ class RuntimeParser {
// Then, if either the line contains a placeable opening `{` or the
// next line starts an indentation, we switch to complex pattern.
const start = this._index;
+
let eol = this._source.indexOf("\n", this._index);
if (eol === -1) {
@@ -9561,7 +9831,6 @@ class RuntimeParser {
}
this._index = eol + 1;
-
this.skipBlankLines();
if (this._source[this._index] !== " ") {
@@ -9572,7 +9841,6 @@ class RuntimeParser {
}
const lineStart = this._index;
-
this.skipInlineWS();
if (this._source[this._index] === ".") {
@@ -9590,7 +9858,6 @@ class RuntimeParser {
return this.getComplexPattern();
}
-
/**
* Parses a complex Message pattern.
* This function is called by getPattern when the message is multiline,
@@ -9600,24 +9867,25 @@ class RuntimeParser {
* @returns {Array}
* @private
*/
+
/* eslint-disable complexity */
+
+
getComplexPattern() {
let buffer = "";
const content = [];
let placeables = 0;
-
let ch = this._source[this._index];
while (this._index < this._length) {
// This block handles multi-line strings combining strings separated
// by new line.
if (ch === "\n") {
- this._index++;
-
- // We want to capture the start and end pointers
+ this._index++; // We want to capture the start and end pointers
// around blank lines and add them to the buffer
// but only if the blank lines are in the middle
// of the string.
+
const blankLinesStart = this._index;
this.skipBlankLines();
const blankLinesEnd = this._index;
@@ -9625,6 +9893,7 @@ class RuntimeParser {
if (this._source[this._index] !== " ") {
break;
}
+
this.skipInlineWS();
if (this._source[this._index] === "}" || this._source[this._index] === "[" || this._source[this._index] === "*" || this._source[this._index] === ".") {
@@ -9637,10 +9906,12 @@ class RuntimeParser {
if (buffer.length || content.length) {
buffer += "\n";
}
+
ch = this._source[this._index];
continue;
} else if (ch === "\\") {
const ch2 = this._source[this._index + 1];
+
if (ch2 === '"' || ch2 === "{" || ch2 === "\\") {
ch = ch2;
this._index++;
@@ -9650,14 +9921,14 @@ class RuntimeParser {
if (buffer.length) {
content.push(buffer);
}
+
if (placeables > MAX_PLACEABLES - 1) {
throw this.error(`Too many placeables, maximum allowed is ${MAX_PLACEABLES}`);
}
+
buffer = "";
content.push(this.getPlaceable());
-
this._index++;
-
ch = this._source[this._index];
placeables++;
continue;
@@ -9666,6 +9937,7 @@ class RuntimeParser {
if (ch) {
buffer += ch;
}
+
this._index++;
ch = this._source[this._index];
}
@@ -9689,30 +9961,27 @@ class RuntimeParser {
* @returns {Object}
* @private
*/
+
+
getPlaceable() {
const start = ++this._index;
-
this.skipWS();
if (this._source[this._index] === "*" || this._source[this._index] === "[" && this._source[this._index + 1] !== "]") {
const variants = this.getVariants();
-
return {
type: "sel",
exp: null,
vars: variants[0],
def: variants[1]
};
- }
+ } // Rewind the index and only support in-line white-space now.
+
- // Rewind the index and only support in-line white-space now.
this._index = start;
this.skipInlineWS();
-
const selector = this.getSelectorExpression();
-
this.skipWS();
-
const ch = this._source[this._index];
if (ch === "}") {
@@ -9748,7 +10017,6 @@ class RuntimeParser {
}
this.skipWS();
-
const variants = this.getVariants();
if (variants[0].length === 0) {
@@ -9762,13 +10030,14 @@ class RuntimeParser {
def: variants[1]
};
}
-
/**
* Parses a selector expression.
*
* @returns {Object}
* @private
*/
+
+
getSelectorExpression() {
const literal = this.getLiteral();
@@ -9778,7 +10047,6 @@ class RuntimeParser {
if (this._source[this._index] === ".") {
this._index++;
-
const name = this.getIdentifier();
this._index++;
return {
@@ -9790,7 +10058,6 @@ class RuntimeParser {
if (this._source[this._index] === "[") {
this._index++;
-
const key = this.getVariantKey();
this._index++;
return {
@@ -9809,9 +10076,7 @@ class RuntimeParser {
}
this._index++;
-
literal.type = "fun";
-
return {
type: "call",
fun: literal,
@@ -9821,13 +10086,14 @@ class RuntimeParser {
return literal;
}
-
/**
* Parses call arguments for a CallExpression.
*
* @returns {Array}
* @private
*/
+
+
getCallArgs() {
const args = [];
@@ -9838,10 +10104,9 @@ class RuntimeParser {
return args;
}
- const exp = this.getSelectorExpression();
-
- // MessageReference in this place may be an entity reference, like:
+ const exp = this.getSelectorExpression(); // MessageReference in this place may be an entity reference, like:
// `call(foo)`, or, if it's followed by `:` it will be a key-value pair.
+
if (exp.type !== "ref") {
args.push(exp);
} else {
@@ -9850,14 +10115,12 @@ class RuntimeParser {
if (this._source[this._index] === ":") {
this._index++;
this.skipInlineWS();
-
- const val = this.getSelectorExpression();
-
- // If the expression returned as a value of the argument
+ const val = this.getSelectorExpression(); // If the expression returned as a value of the argument
// is not a quote delimited string or number, throw.
//
// We don't have to check here if the pattern is quote delimited
// because that's the only type of string allowed in expressions.
+
if (typeof val === "string" || Array.isArray(val) || val.type === "num") {
args.push({
type: "narg",
@@ -9886,45 +10149,46 @@ class RuntimeParser {
return args;
}
-
/**
* Parses an FTL Number.
*
* @returns {Object}
* @private
*/
+
+
getNumber() {
let num = "";
- let cc = this._source.charCodeAt(this._index);
- // The number literal may start with negative sign `-`.
+ let cc = this._source.charCodeAt(this._index); // The number literal may start with negative sign `-`.
+
+
if (cc === 45) {
num += "-";
cc = this._source.charCodeAt(++this._index);
- }
+ } // next, we expect at least one digit
+
- // next, we expect at least one digit
if (cc < 48 || cc > 57) {
throw this.error(`Unknown literal "${num}"`);
- }
+ } // followed by potentially more digits
+
- // followed by potentially more digits
while (cc >= 48 && cc <= 57) {
num += this._source[this._index++];
cc = this._source.charCodeAt(this._index);
- }
+ } // followed by an optional decimal separator `.`
+
- // followed by an optional decimal separator `.`
if (cc === 46) {
num += this._source[this._index++];
- cc = this._source.charCodeAt(this._index);
+ cc = this._source.charCodeAt(this._index); // followed by at least one digit
- // followed by at least one digit
if (cc < 48 || cc > 57) {
throw this.error(`Unknown literal "${num}"`);
- }
+ } // and optionally more digits
+
- // and optionally more digits
while (cc >= 48 && cc <= 57) {
num += this._source[this._index++];
cc = this._source.charCodeAt(this._index);
@@ -9936,13 +10200,14 @@ class RuntimeParser {
val: num
};
}
-
/**
* Parses a list of Message attributes.
*
* @returns {Object}
* @private
*/
+
+
getAttributes() {
const attrs = {};
@@ -9950,24 +10215,23 @@ class RuntimeParser {
if (this._source[this._index] !== " ") {
break;
}
+
this.skipInlineWS();
if (this._source[this._index] !== ".") {
break;
}
- this._index++;
+ this._index++;
const key = this.getIdentifier();
-
this.skipInlineWS();
if (this._source[this._index] !== "=") {
throw this.error('Expected "="');
}
- this._index++;
+ this._index++;
this.skipInlineWS();
-
const val = this.getPattern();
if (val === null) {
@@ -9987,13 +10251,14 @@ class RuntimeParser {
return attrs;
}
-
/**
* Parses a list of Selector variants.
*
* @returns {Array}
* @private
*/
+
+
getVariants() {
const variants = [];
let index = 0;
@@ -10005,6 +10270,7 @@ class RuntimeParser {
if ((ch !== "[" || this._source[this._index + 1] === "[") && ch !== "*") {
break;
}
+
if (ch === "*") {
this._index++;
defaultIndex = index;
@@ -10015,35 +10281,35 @@ class RuntimeParser {
}
this._index++;
-
const key = this.getVariantKey();
-
this.skipInlineWS();
-
const val = this.getPattern();
if (val === null) {
throw this.error("Expected variant to have a value");
}
- variants[index++] = { key, val };
-
+ variants[index++] = {
+ key,
+ val
+ };
this.skipWS();
}
return [variants, defaultIndex];
}
-
/**
* Parses a Variant key.
*
* @returns {String}
* @private
*/
+
+
getVariantKey() {
// VariantKey may be a Keyword or Number
-
const cc = this._source.charCodeAt(this._index);
+
let literal;
if (cc >= 48 && cc <= 57 || cc === 45) {
@@ -10059,13 +10325,14 @@ class RuntimeParser {
this._index++;
return literal;
}
-
/**
* Parses an FTL literal.
*
* @returns {Object}
* @private
*/
+
+
getLiteral() {
const cc0 = this._source.charCodeAt(this._index);
@@ -10080,8 +10347,7 @@ class RuntimeParser {
const cc1 = cc0 === 45 // -
// Peek at the next character after the dash.
- ? this._source.charCodeAt(this._index + 1)
- // Or keep using the character at the current index.
+ ? this._source.charCodeAt(this._index + 1) // Or keep using the character at the current index.
: cc0;
if (cc1 >= 97 && cc1 <= 122 || // a-z
@@ -10105,12 +10371,13 @@ class RuntimeParser {
throw this.error("Expected literal");
}
-
/**
* Skips an FTL comment.
*
* @private
*/
+
+
skipComment() {
// At runtime, we don't care about comments so we just have
// to parse them properly and skip their content.
@@ -10118,7 +10385,6 @@ class RuntimeParser {
while (eol !== -1 && (this._source[eol + 1] === "/" && this._source[eol + 2] === "/" || this._source[eol + 1] === "#" && [" ", "#"].includes(this._source[eol + 2]))) {
this._index = eol + 3;
-
eol = this._source.indexOf("\n", this._index);
if (eol === -1) {
@@ -10132,7 +10398,6 @@ class RuntimeParser {
this._index = eol + 1;
}
}
-
/**
* Creates a new SyntaxError object with a given message.
*
@@ -10140,10 +10405,11 @@ class RuntimeParser {
* @returns {Object}
* @private
*/
+
+
error(message) {
return new SyntaxError(message);
}
-
/**
* Skips to the beginning of a next entry after the current position.
* This is used to mark the boundary of junk entry in case of error,
@@ -10151,6 +10417,8 @@ class RuntimeParser {
*
* @private
*/
+
+
skipToNextEntryStart() {
let start = this._index;
@@ -10173,11 +10441,12 @@ class RuntimeParser {
this._index = this._length;
return;
}
+
start++;
}
}
-}
+}
/**
* Parses an FTL string using RuntimeParser and returns the generated
* object with entries and a list of errors.
@@ -10185,6 +10454,8 @@ class RuntimeParser {
* @param {String} string
* @returns {Array<Object, Array>}
*/
+
+
function parse(string) {
const parser = new RuntimeParser();
return parser.getResource(string);
@@ -10200,7 +10471,6 @@ function parse(string) {
* `Intl` formatter.
*/
class FluentType {
-
/**
* Create an `FluentType` instance.
*
@@ -10212,16 +10482,16 @@ class FluentType {
this.value = value;
this.opts = opts;
}
-
/**
* Unwrap the raw value stored by this `FluentType`.
*
* @returns {Any}
*/
+
+
valueOf() {
return this.value;
}
-
/**
* Format this instance of `FluentType` to a string.
*
@@ -10232,17 +10502,19 @@ class FluentType {
* @param {MessageContext} [ctx]
* @returns {string}
*/
+
+
toString() {
throw new Error("Subclasses of FluentType must implement toString.");
}
-}
+}
class FluentNone extends FluentType {
toString() {
return this.value || "???";
}
-}
+}
class FluentNumber extends FluentType {
constructor(value, opts) {
super(parseFloat(value), opts);
@@ -10251,13 +10523,13 @@ class FluentNumber extends FluentType {
toString(ctx) {
try {
const nf = ctx._memoizeIntlObject(Intl.NumberFormat, this.opts);
+
return nf.format(this.value);
} catch (e) {
// XXX Report the error.
return this.value;
}
}
-
/**
* Compare the object with another instance of a FluentType.
*
@@ -10265,14 +10537,17 @@ class FluentNumber extends FluentType {
* @param {FluentType} other
* @returns {bool}
*/
+
+
match(ctx, other) {
if (other instanceof FluentNumber) {
return this.value === other.value;
}
+
return false;
}
-}
+}
class FluentDateTime extends FluentType {
constructor(value, opts) {
super(new Date(value), opts);
@@ -10281,19 +10556,19 @@ class FluentDateTime extends FluentType {
toString(ctx) {
try {
const dtf = ctx._memoizeIntlObject(Intl.DateTimeFormat, this.opts);
+
return dtf.format(this.value);
} catch (e) {
// XXX Report the error.
return this.value;
}
}
-}
+}
class FluentSymbol extends FluentType {
toString() {
return this.value;
}
-
/**
* Compare the object with another instance of a FluentType.
*
@@ -10301,6 +10576,8 @@ class FluentSymbol extends FluentType {
* @param {FluentType} other
* @returns {bool}
*/
+
+
match(ctx, other) {
if (other instanceof FluentSymbol) {
return this.value === other.value;
@@ -10308,10 +10585,13 @@ class FluentSymbol extends FluentType {
return this.value === other;
} else if (other instanceof FluentNumber) {
const pr = ctx._memoizeIntlObject(Intl.PluralRules, other.opts);
+
return this.value === pr.select(other.value);
}
+
return false;
}
+
}
// CONCATENATED MODULE: ./node_modules/fluent/src/builtins.js
/**
@@ -10327,8 +10607,6 @@ class FluentSymbol extends FluentType {
* `FluentType`. Functions must return `FluentType` objects as well.
*/
-
-
/* harmony default export */ var builtins = ({
"NUMBER": ([arg], opts) => new FluentNumber(arg.valueOf(), merge(arg.opts, opts)),
"DATETIME": ([arg], opts) => new FluentDateTime(arg.valueOf(), merge(arg.opts, opts))
@@ -10340,9 +10618,11 @@ function merge(argopts, opts) {
function values(opts) {
const unwrapped = {};
+
for (const [name, opt] of Object.entries(opts)) {
unwrapped[name] = opt.valueOf();
}
+
return unwrapped;
}
// CONCATENATED MODULE: ./node_modules/fluent/src/resolver.js
@@ -10394,16 +10674,12 @@ function values(opts) {
* This is used to prevent cyclic resolutions.
*/
+ // Prevent expansion of too long placeables.
+const MAX_PLACEABLE_LENGTH = 2500; // Unicode bidi isolation characters.
-
-// Prevent expansion of too long placeables.
-const MAX_PLACEABLE_LENGTH = 2500;
-
-// Unicode bidi isolation characters.
const FSI = "\u2068";
const PDI = "\u2069";
-
/**
* Helper for choosing the default value from a set of members.
*
@@ -10418,16 +10694,18 @@ const PDI = "\u2069";
* @returns {FluentType}
* @private
*/
+
function DefaultMember(env, members, def) {
if (members[def]) {
return members[def];
}
- const { errors } = env;
+ const {
+ errors
+ } = env;
errors.push(new RangeError("No default"));
return new FluentNone();
}
-
/**
* Resolve a reference to another message.
*
@@ -10440,8 +10718,15 @@ function DefaultMember(env, members, def) {
* @returns {FluentType}
* @private
*/
-function MessageReference(env, { name }) {
- const { ctx, errors } = env;
+
+
+function MessageReference(env, {
+ name
+}) {
+ const {
+ ctx,
+ errors
+ } = env;
const message = name.startsWith("-") ? ctx._terms.get(name) : ctx._messages.get(name);
if (!message) {
@@ -10452,7 +10737,6 @@ function MessageReference(env, { name }) {
return message;
}
-
/**
* Resolve a variant expression to the variant object.
*
@@ -10469,13 +10753,22 @@ function MessageReference(env, { name }) {
* @returns {FluentType}
* @private
*/
-function VariantExpression(env, { id, key }) {
+
+
+function VariantExpression(env, {
+ id,
+ key
+}) {
const message = MessageReference(env, id);
+
if (message instanceof FluentNone) {
return message;
}
- const { ctx, errors } = env;
+ const {
+ ctx,
+ errors
+ } = env;
const keyword = Type(env, key);
function isVariantList(node) {
@@ -10486,6 +10779,7 @@ function VariantExpression(env, { id, key }) {
// Match the specified key against keys of each variant, in order.
for (const variant of message.val[0].vars) {
const variantKey = Type(env, variant.key);
+
if (keyword.match(ctx, variantKey)) {
return variant;
}
@@ -10495,7 +10789,6 @@ function VariantExpression(env, { id, key }) {
errors.push(new ReferenceError(`Unknown variant: ${keyword.toString(ctx)}`));
return Type(env, message);
}
-
/**
* Resolve an attribute expression to the attribute object.
*
@@ -10510,8 +10803,14 @@ function VariantExpression(env, { id, key }) {
* @returns {FluentType}
* @private
*/
-function AttributeExpression(env, { id, name }) {
+
+
+function AttributeExpression(env, {
+ id,
+ name
+}) {
const message = MessageReference(env, id);
+
if (message instanceof FluentNone) {
return message;
}
@@ -10525,11 +10824,12 @@ function AttributeExpression(env, { id, name }) {
}
}
- const { errors } = env;
+ const {
+ errors
+ } = env;
errors.push(new ReferenceError(`Unknown attribute: ${name}`));
return Type(env, message);
}
-
/**
* Resolve a select expression to the member object.
*
@@ -10546,17 +10846,24 @@ function AttributeExpression(env, { id, name }) {
* @returns {FluentType}
* @private
*/
-function SelectExpression(env, { exp, vars, def }) {
+
+
+function SelectExpression(env, {
+ exp,
+ vars,
+ def
+}) {
if (exp === null) {
return DefaultMember(env, vars, def);
}
const selector = Type(env, exp);
+
if (selector instanceof FluentNone) {
return DefaultMember(env, vars, def);
- }
+ } // Match the selector against keys of each variant, in order.
+
- // Match the selector against keys of each variant, in order.
for (const variant of vars) {
const key = Type(env, variant.key);
const keyCanMatch = key instanceof FluentNumber || key instanceof FluentSymbol;
@@ -10565,7 +10872,9 @@ function SelectExpression(env, { exp, vars, def }) {
continue;
}
- const { ctx } = env;
+ const {
+ ctx
+ } = env;
if (key.match(ctx, selector)) {
return variant;
@@ -10574,7 +10883,6 @@ function SelectExpression(env, { exp, vars, def }) {
return DefaultMember(env, vars, def);
}
-
/**
* Resolve expression to a Fluent type.
*
@@ -10589,15 +10897,17 @@ function SelectExpression(env, { exp, vars, def }) {
* @returns {FluentType}
* @private
*/
+
+
function Type(env, expr) {
// A fast-path for strings which are the most common case, and for
// `FluentNone` which doesn't require any additional logic.
if (typeof expr === "string" || expr instanceof FluentNone) {
return expr;
- }
-
- // The Runtime AST (Entries) encodes patterns (complex strings with
+ } // The Runtime AST (Entries) encodes patterns (complex strings with
// placeables) as Arrays.
+
+
if (Array.isArray(expr)) {
return Pattern(env, expr);
}
@@ -10605,34 +10915,43 @@ function Type(env, expr) {
switch (expr.type) {
case "varname":
return new FluentSymbol(expr.name);
+
case "num":
return new FluentNumber(expr.val);
+
case "ext":
return ExternalArgument(env, expr);
+
case "fun":
return FunctionReference(env, expr);
+
case "call":
return CallExpression(env, expr);
+
case "ref":
{
const message = MessageReference(env, expr);
return Type(env, message);
}
+
case "attr":
{
const attr = AttributeExpression(env, expr);
return Type(env, attr);
}
+
case "var":
{
const variant = VariantExpression(env, expr);
return Type(env, variant);
}
+
case "sel":
{
const member = SelectExpression(env, expr);
return Type(env, member);
}
+
case undefined:
{
// If it's a node with a value, resolve the value.
@@ -10640,15 +10959,17 @@ function Type(env, expr) {
return Type(env, expr.val);
}
- const { errors } = env;
+ const {
+ errors
+ } = env;
errors.push(new RangeError("No value"));
return new FluentNone();
}
+
default:
return new FluentNone();
}
}
-
/**
* Resolve a reference to an external argument.
*
@@ -10661,37 +10982,45 @@ function Type(env, expr) {
* @returns {FluentType}
* @private
*/
-function ExternalArgument(env, { name }) {
- const { args, errors } = env;
+
+
+function ExternalArgument(env, {
+ name
+}) {
+ const {
+ args,
+ errors
+ } = env;
if (!args || !args.hasOwnProperty(name)) {
errors.push(new ReferenceError(`Unknown external: ${name}`));
return new FluentNone(name);
}
- const arg = args[name];
+ const arg = args[name]; // Return early if the argument already is an instance of FluentType.
- // Return early if the argument already is an instance of FluentType.
if (arg instanceof FluentType) {
return arg;
- }
+ } // Convert the argument to a Fluent type.
+
- // Convert the argument to a Fluent type.
switch (typeof arg) {
case "string":
return arg;
+
case "number":
return new FluentNumber(arg);
+
case "object":
if (arg instanceof Date) {
return new FluentDateTime(arg);
}
+
default:
errors.push(new TypeError(`Unsupported external type: ${name}, ${typeof arg}`));
return new FluentNone(name);
}
}
-
/**
* Resolve a reference to a function.
*
@@ -10704,10 +11033,19 @@ function ExternalArgument(env, { name }) {
* @returns {Function}
* @private
*/
-function FunctionReference(env, { name }) {
+
+
+function FunctionReference(env, {
+ name
+}) {
// Some functions are built-in. Others may be provided by the runtime via
// the `MessageContext` constructor.
- const { ctx: { _functions }, errors } = env;
+ const {
+ ctx: {
+ _functions
+ },
+ errors
+ } = env;
const func = _functions[name] || builtins[name];
if (!func) {
@@ -10722,7 +11060,6 @@ function FunctionReference(env, { name }) {
return func;
}
-
/**
* Resolve a call to a Function with positional and key-value arguments.
*
@@ -10737,7 +11074,12 @@ function FunctionReference(env, { name }) {
* @returns {FluentType}
* @private
*/
-function CallExpression(env, { fun, args }) {
+
+
+function CallExpression(env, {
+ fun,
+ args
+}) {
const callee = FunctionReference(env, fun);
if (callee instanceof FluentNone) {
@@ -10762,7 +11104,6 @@ function CallExpression(env, { fun, args }) {
return new FluentNone();
}
}
-
/**
* Resolve a pattern (a complex string with placeables).
*
@@ -10773,20 +11114,25 @@ function CallExpression(env, { fun, args }) {
* @returns {Array}
* @private
*/
+
+
function Pattern(env, ptn) {
- const { ctx, dirty, errors } = env;
+ const {
+ ctx,
+ dirty,
+ errors
+ } = env;
if (dirty.has(ptn)) {
errors.push(new RangeError("Cyclic reference"));
return new FluentNone();
- }
+ } // Tag the pattern as dirty for the purpose of the current resolution.
- // Tag the pattern as dirty for the purpose of the current resolution.
- dirty.add(ptn);
- const result = [];
- // Wrap interpolations with Directional Isolate Formatting characters
+ dirty.add(ptn);
+ const result = []; // Wrap interpolations with Directional Isolate Formatting characters
// only when the pattern has more than one element.
+
const useIsolating = ctx._useIsolating && ptn.length > 1;
for (const elem of ptn) {
@@ -10816,7 +11162,6 @@ function Pattern(env, ptn) {
dirty.delete(ptn);
return result.join("");
}
-
/**
* Format a translation into a string.
*
@@ -10832,16 +11177,20 @@ function Pattern(env, ptn) {
* An error array that any encountered errors will be appended to.
* @returns {FluentType}
*/
+
+
function resolve(ctx, args, message, errors = []) {
const env = {
- ctx, args, errors, dirty: new WeakSet()
+ ctx,
+ args,
+ errors,
+ dirty: new WeakSet()
};
return Type(env, message).toString(ctx);
}
// CONCATENATED MODULE: ./node_modules/fluent/src/context.js
-
/**
* Message contexts are single-language stores of translations. They are
* responsible for parsing translation resources in the Fluent syntax and can
@@ -10855,8 +11204,8 @@ function resolve(ctx, args, message, errors = []) {
* into the context's language. See the documentation of the Fluent syntax for
* more information.
*/
-class context_MessageContext {
+class context_MessageContext {
/**
* Create an instance of `MessageContext`.
*
@@ -10888,35 +11237,38 @@ class context_MessageContext {
* @param {Object} [options]
* @returns {MessageContext}
*/
- constructor(locales, { functions = {}, useIsolating = true } = {}) {
+ constructor(locales, {
+ functions = {},
+ useIsolating = true
+ } = {}) {
this.locales = Array.isArray(locales) ? locales : [locales];
-
this._terms = new Map();
this._messages = new Map();
this._functions = functions;
this._useIsolating = useIsolating;
this._intls = new WeakMap();
}
-
/*
* Return an iterator over public `[id, message]` pairs.
*
* @returns {Iterator}
*/
+
+
get messages() {
return this._messages[Symbol.iterator]();
}
-
/*
* Check if a message is present in the context.
*
* @param {string} id - The identifier of the message to check.
* @returns {bool}
*/
+
+
hasMessage(id) {
return this._messages.has(id);
}
-
/*
* Return the internal representation of a message.
*
@@ -10926,10 +11278,11 @@ class context_MessageContext {
* @param {string} id - The identifier of the message to check.
* @returns {Any}
*/
+
+
getMessage(id) {
return this._messages.get(id);
}
-
/**
* Add a translation resource to the context.
*
@@ -10948,8 +11301,11 @@ class context_MessageContext {
* @param {string} source - Text resource with translations.
* @returns {Array<Error>}
*/
+
+
addMessages(source) {
const [entries, errors] = parse(source);
+
for (const id in entries) {
if (id.startsWith("-")) {
// Identifiers starting with a dash (-) define terms. Terms are private
@@ -10958,19 +11314,20 @@ class context_MessageContext {
errors.push(`Attempt to override an existing term: "${id}"`);
continue;
}
+
this._terms.set(id, entries[id]);
} else {
if (this._messages.has(id)) {
errors.push(`Attempt to override an existing message: "${id}"`);
continue;
}
+
this._messages.set(id, entries[id]);
}
}
return errors;
}
-
/**
* Format a message to a string or null.
*
@@ -11001,18 +11358,20 @@ class context_MessageContext {
* @param {Array} errors
* @returns {?string}
*/
+
+
format(message, args, errors) {
// optimize entities which are simple strings with no attributes
if (typeof message === "string") {
return message;
- }
+ } // optimize simple-string entities with attributes
+
- // optimize simple-string entities with attributes
if (typeof message.val === "string") {
return message.val;
- }
+ } // optimize entities with null values
+
- // optimize entities with null values
if (message.val === undefined) {
return null;
}
@@ -11026,14 +11385,18 @@ class context_MessageContext {
if (!cache[id]) {
cache[id] = new ctor(this.locales, opts);
+
this._intls.set(ctor, cache);
}
return cache[id];
}
+
}
// CONCATENATED MODULE: ./node_modules/fluent/src/cached_iterable.js
-function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
+
+function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
/*
* CachedIterable caches the elements yielded by an iterable.
@@ -11061,50 +11424,66 @@ class CachedIterable {
}
[Symbol.iterator]() {
- const { seen, iterator } = this;
+ const {
+ seen,
+ iterator
+ } = this;
let cur = 0;
-
return {
next() {
if (seen.length <= cur) {
seen.push(iterator.next());
}
+
return seen[cur++];
}
+
};
}
[Symbol.asyncIterator]() {
- const { seen, iterator } = this;
+ const {
+ seen,
+ iterator
+ } = this;
let cur = 0;
-
return {
next() {
return _asyncToGenerator(function* () {
if (seen.length <= cur) {
seen.push((yield iterator.next()));
}
+
return seen[cur++];
})();
}
+
};
}
-
/**
* This method allows user to consume the next element from the iterator
* into the cache.
*/
+
+
touchNext() {
- const { seen, iterator } = this;
+ const {
+ seen,
+ iterator
+ } = this;
+
if (seen.length === 0 || seen[seen.length - 1].done === false) {
seen.push(iterator.next());
}
}
+
}
// CONCATENATED MODULE: ./node_modules/fluent/src/fallback.js
-function _asyncIterator(iterable) { if (typeof Symbol === "function") { if (Symbol.asyncIterator) { var method = iterable[Symbol.asyncIterator]; if (method != null) return method.call(iterable); } if (Symbol.iterator) { return iterable[Symbol.iterator](); } } throw new TypeError("Object is not async iterable"); }
+function fallback_asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
+
+function fallback_asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { fallback_asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { fallback_asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
-function fallback_asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+function _asyncIterator(iterable) { var method; if (typeof Symbol === "function") { if (Symbol.asyncIterator) { method = iterable[Symbol.asyncIterator]; if (method != null) return method.call(iterable); } if (Symbol.iterator) { method = iterable[Symbol.iterator]; if (method != null) return method.call(iterable); } } throw new TypeError("Object is not async iterable"); }
/*
* @overview
@@ -11163,10 +11542,10 @@ function mapContextSync(iterable, ids) {
return ids.map(id => getContextForId(iterable, id));
}
-
/*
* Find the best `MessageContext` with the translation for `id`.
*/
+
function getContextForId(iterable, id) {
for (const context of iterable) {
if (context.hasMessage(id)) {
@@ -11176,7 +11555,6 @@ function getContextForId(iterable, id) {
return null;
}
-
/*
* Asynchronously map an identifier or an array of identifiers to the best
* `MessageContext` instance(s).
@@ -11185,12 +11563,19 @@ function getContextForId(iterable, id) {
* @param {string|Array<string>} ids
* @returns {Promise<MessageContext|Array<MessageContext>>}
*/
-let mapContextAsync = (() => {
- var _ref = fallback_asyncToGenerator(function* (iterable, ids) {
+
+
+function mapContextAsync(_x, _x2) {
+ return _mapContextAsync.apply(this, arguments);
+}
+
+function _mapContextAsync() {
+ _mapContextAsync = fallback_asyncToGenerator(function* (iterable, ids) {
if (!Array.isArray(ids)) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
- var _iteratorError = undefined;
+
+ var _iteratorError;
try {
for (var _iterator = _asyncIterator(iterable), _step, _value; _step = yield _iterator.next(), _iteratorNormalCompletion = _step.done, _value = yield _step.value, !_iteratorNormalCompletion; _iteratorNormalCompletion = true) {
@@ -11205,7 +11590,7 @@ let mapContextAsync = (() => {
_iteratorError = err;
} finally {
try {
- if (!_iteratorNormalCompletion && _iterator.return) {
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
yield _iterator.return();
}
} finally {
@@ -11218,10 +11603,10 @@ let mapContextAsync = (() => {
let remainingCount = ids.length;
const foundContexts = new Array(remainingCount).fill(null);
-
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
- var _iteratorError2 = undefined;
+
+ var _iteratorError2;
try {
for (var _iterator2 = _asyncIterator(iterable), _step2, _value2; _step2 = yield _iterator2.next(), _iteratorNormalCompletion2 = _step2.done, _value2 = yield _step2.value, !_iteratorNormalCompletion2; _iteratorNormalCompletion2 = true) {
@@ -11231,12 +11616,13 @@ let mapContextAsync = (() => {
// See https://github.com/babel/babel/issues/5880.
for (let index = 0; index < ids.length; index++) {
const id = ids[index];
+
if (!foundContexts[index] && context.hasMessage(id)) {
foundContexts[index] = context;
remainingCount--;
- }
+ } // Return early when all ids have been mapped to contexts.
+
- // Return early when all ids have been mapped to contexts.
if (remainingCount === 0) {
return foundContexts;
}
@@ -11247,7 +11633,7 @@ let mapContextAsync = (() => {
_iteratorError2 = err;
} finally {
try {
- if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
yield _iterator2.return();
}
} finally {
@@ -11259,11 +11645,8 @@ let mapContextAsync = (() => {
return foundContexts;
});
-
- return function mapContextAsync(_x, _x2) {
- return _ref.apply(this, arguments);
- };
-})();
+ return _mapContextAsync.apply(this, arguments);
+}
// CONCATENATED MODULE: ./node_modules/fluent/src/util.js
function nonBlank(line) {
return !/^\s*$/.test(line);
@@ -11273,7 +11656,6 @@ function countIndent(line) {
const [indent] = line.match(/^\s*/);
return indent.length;
}
-
/**
* Template literal tag for dedenting FTL code.
*
@@ -11281,13 +11663,14 @@ function countIndent(line) {
*
* @param {Array<string>} strings
*/
+
+
function ftl(strings) {
const [code] = strings;
const lines = code.split("\n").filter(nonBlank);
const indents = lines.map(countIndent);
const common = Math.min(...indents);
const indent = new RegExp(`^\\s{${common}}`);
-
return lines.map(line => line.replace(indent, "")).join("\n");
}
// CONCATENATED MODULE: ./node_modules/fluent/src/index.js
@@ -11315,10 +11698,6 @@ function ftl(strings) {
-
-
-
-
/***/ }),
/* 58 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
@@ -11338,7 +11717,6 @@ var src = __webpack_require__(57);
// CONCATENATED MODULE: ./node_modules/fluent-react/src/localization.js
-
/*
* `ReactLocalization` handles translation formatting and fallback.
*
@@ -11354,33 +11732,36 @@ var src = __webpack_require__(57);
* The `ReactLocalization` class instances are exposed to `Localized` elements
* via the `LocalizationProvider` component.
*/
+
class localization_ReactLocalization {
constructor(messages) {
this.contexts = new src["CachedIterable"](messages);
this.subs = new Set();
}
-
/*
* Subscribe a `Localized` component to changes of `messages`.
*/
+
+
subscribe(comp) {
this.subs.add(comp);
}
-
/*
* Unsubscribe a `Localized` component from `messages` changes.
*/
+
+
unsubscribe(comp) {
this.subs.delete(comp);
}
-
/*
* Set a new `messages` iterable and trigger the retranslation.
*/
+
+
setMessages(messages) {
- this.contexts = new src["CachedIterable"](messages);
+ this.contexts = new src["CachedIterable"](messages); // Update all subscribed Localized components.
- // Update all subscribed Localized components.
this.subs.forEach(comp => comp.relocalize());
}
@@ -11393,17 +11774,22 @@ class localization_ReactLocalization {
if (msg.attrs) {
var attrs = {};
+
for (const name of Object.keys(msg.attrs)) {
attrs[name] = mcx.format(msg.attrs[name], args);
}
}
- return { value, attrs };
+ return {
+ value,
+ attrs
+ };
}
-
/*
* Find a translation by `id` and format it to a string using `args`.
*/
+
+
getString(id, args, fallback) {
const mcx = this.getMessageContext(id);
@@ -11414,8 +11800,8 @@ class localization_ReactLocalization {
const msg = mcx.getMessage(id);
return mcx.format(msg, args);
}
-}
+}
function isReactLocalization(props, propName) {
const prop = props[propName];
@@ -11429,8 +11815,6 @@ function isReactLocalization(props, propName) {
-
-
/*
* The Provider component for the `ReactLocalization` class.
*
@@ -11449,10 +11833,13 @@ function isReactLocalization(props, propName) {
* `ReactLocalization` to format translations. If a translation is missing in
* one instance, `ReactLocalization` will fall back to the next one.
*/
+
class provider_LocalizationProvider extends external_React_["Component"] {
constructor(props) {
super(props);
- const { messages } = props;
+ const {
+ messages
+ } = props;
if (messages === undefined) {
throw new Error("LocalizationProvider must receive the messages prop.");
@@ -11472,7 +11859,9 @@ class provider_LocalizationProvider extends external_React_["Component"] {
}
componentWillReceiveProps(next) {
- const { messages } = next;
+ const {
+ messages
+ } = next;
if (messages !== this.props.messages) {
this.l10n.setMessages(messages);
@@ -11482,12 +11871,11 @@ class provider_LocalizationProvider extends external_React_["Component"] {
render() {
return external_React_["Children"].only(this.props.children);
}
-}
+}
provider_LocalizationProvider.childContextTypes = {
l10n: isReactLocalization
};
-
provider_LocalizationProvider.propTypes = {
children: external_PropTypes_default.a.element.isRequired,
messages: isIterable
@@ -11505,12 +11893,12 @@ function isIterable(props, propName, componentName) {
// CONCATENATED MODULE: ./node_modules/fluent-react/src/with_localization.js
-
-
function withLocalization(Inner) {
class WithLocalization extends external_React_["Component"] {
componentDidMount() {
- const { l10n } = this.context;
+ const {
+ l10n
+ } = this.context;
if (l10n) {
l10n.subscribe(this);
@@ -11518,27 +11906,33 @@ function withLocalization(Inner) {
}
componentWillUnmount() {
- const { l10n } = this.context;
+ const {
+ l10n
+ } = this.context;
if (l10n) {
l10n.unsubscribe(this);
}
}
-
/*
* Rerender this component in a new language.
*/
+
+
relocalize() {
// When the `ReactLocalization`'s fallback chain changes, update the
// component.
this.forceUpdate();
}
-
/*
* Find a translation by `id` and format it to a string using `args`.
*/
+
+
getString(id, args, fallback) {
- const { l10n } = this.context;
+ const {
+ l10n
+ } = this.context;
if (!l10n) {
return fallback || id;
@@ -11548,18 +11942,18 @@ function withLocalization(Inner) {
}
render() {
- return Object(external_React_["createElement"])(Inner, Object.assign(
- // getString needs to be re-bound on updates to trigger a re-render
- { getString: (...args) => this.getString(...args) }, this.props));
+ return Object(external_React_["createElement"])(Inner, Object.assign( // getString needs to be re-bound on updates to trigger a re-render
+ {
+ getString: (...args) => this.getString(...args)
+ }, this.props));
}
+
}
WithLocalization.displayName = `WithLocalization(${displayName(Inner)})`;
-
WithLocalization.contextTypes = {
l10n: isReactLocalization
};
-
return WithLocalization;
}
@@ -11568,9 +11962,7 @@ function displayName(component) {
}
// CONCATENATED MODULE: ./node_modules/fluent-react/src/markup.js
/* eslint-env browser */
-
const TEMPLATE = document.createElement("template");
-
function parseMarkup(str) {
TEMPLATE.innerHTML = str;
return TEMPLATE.content;
@@ -11582,10 +11974,8 @@ function parseMarkup(str) {
* This source code is licensed under the MIT license found in the
* LICENSE file in this directory.
*/
-
// For HTML, certain tags should omit their close tag. We keep a whitelist for
// those special-case tags.
-
var omittedCloseTags = {
area: true,
base: true,
@@ -11601,10 +11991,9 @@ var omittedCloseTags = {
param: true,
source: true,
track: true,
- wbr: true
- // NOTE: menuitem's close tag should be omitted, but that causes problems.
-};
+ wbr: true // NOTE: menuitem's close tag should be omitted, but that causes problems.
+};
/* harmony default export */ var vendor_omittedCloseTags = (omittedCloseTags);
// CONCATENATED MODULE: ./node_modules/fluent-react/vendor/voidElementTags.js
/**
@@ -11613,32 +12002,27 @@ var omittedCloseTags = {
* This source code is licensed under the MIT license found in the
* LICENSE file in this directory.
*/
-
-
-
-// For HTML, certain tags cannot have children. This has the same purpose as
+ // For HTML, certain tags cannot have children. This has the same purpose as
// `omittedCloseTags` except that `menuitem` should still have its closing tag.
-var voidElementTags = Object.assign({
- menuitem: true
-}, vendor_omittedCloseTags);
-
+var voidElementTags = {
+ menuitem: true,
+ ...vendor_omittedCloseTags
+};
/* harmony default export */ var vendor_voidElementTags = (voidElementTags);
// CONCATENATED MODULE: ./node_modules/fluent-react/src/localized.js
-
-
-
-// Match the opening angle bracket (<) in HTML tags, and HTML entities like
+ // Match the opening angle bracket (<) in HTML tags, and HTML entities like
// &amp;, &#0038;, &#x0026;.
-const reMarkup = /<|&#?\w+;/;
+const reMarkup = /<|&#?\w+;/;
/*
* Prepare props passed to `Localized` for formatting.
*/
+
function toArguments(props) {
const args = {};
const elems = {};
@@ -11657,7 +12041,6 @@ function toArguments(props) {
return [args, elems];
}
-
/*
* The `Localized` class renders its child with translated props and children.
*
@@ -11680,9 +12063,13 @@ function toArguments(props) {
* translation is available. It also makes it easy to grep for strings in the
* source code.
*/
+
+
class localized_Localized extends external_React_["Component"] {
componentDidMount() {
- const { l10n } = this.context;
+ const {
+ l10n
+ } = this.context;
if (l10n) {
l10n.subscribe(this);
@@ -11690,16 +12077,19 @@ class localized_Localized extends external_React_["Component"] {
}
componentWillUnmount() {
- const { l10n } = this.context;
+ const {
+ l10n
+ } = this.context;
if (l10n) {
l10n.unsubscribe(this);
}
}
-
/*
* Rerender this component in a new language.
*/
+
+
relocalize() {
// When the `ReactLocalization`'s fallback chain changes, update the
// component.
@@ -11707,8 +12097,14 @@ class localized_Localized extends external_React_["Component"] {
}
render() {
- const { l10n } = this.context;
- const { id, attrs, children } = this.props;
+ const {
+ l10n
+ } = this.context;
+ const {
+ id,
+ attrs,
+ children
+ } = this.props;
const elem = external_React_["Children"].only(children);
if (!l10n) {
@@ -11728,11 +12124,10 @@ class localized_Localized extends external_React_["Component"] {
const {
value: messageValue,
attrs: messageAttrs
- } = l10n.formatCompound(mcx, msg, args);
-
- // The default is to forbid all message attributes. If the attrs prop exists
+ } = l10n.formatCompound(mcx, msg, args); // The default is to forbid all message attributes. If the attrs prop exists
// on the Localized instance, only set message attributes which have been
// explicitly allowed by the developer.
+
if (attrs && messageAttrs) {
var localizedProps = {};
@@ -11741,67 +12136,64 @@ class localized_Localized extends external_React_["Component"] {
localizedProps[name] = value;
}
}
- }
-
- // If the wrapped component is a known void element, explicitly dismiss the
+ } // If the wrapped component is a known void element, explicitly dismiss the
// message value and do not pass it to cloneElement in order to avoid the
// "void element tags must neither have `children` nor use
// `dangerouslySetInnerHTML`" error.
+
+
if (elem.type in vendor_voidElementTags) {
return Object(external_React_["cloneElement"])(elem, localizedProps);
- }
-
- // If the message has a null value, we're only interested in its attributes.
+ } // If the message has a null value, we're only interested in its attributes.
// Do not pass the null value to cloneElement as it would nuke all children
// of the wrapped component.
+
+
if (messageValue === null) {
return Object(external_React_["cloneElement"])(elem, localizedProps);
- }
-
- // If the message value doesn't contain any markup nor any HTML entities,
+ } // If the message value doesn't contain any markup nor any HTML entities,
// insert it as the only child of the wrapped component.
+
+
if (!reMarkup.test(messageValue)) {
return Object(external_React_["cloneElement"])(elem, localizedProps, messageValue);
- }
-
- // If the message contains markup, parse it and try to match the children
+ } // If the message contains markup, parse it and try to match the children
// found in the translation with the props passed to this Localized.
+
+
const translationNodes = Array.from(parseMarkup(messageValue).childNodes);
const translatedChildren = translationNodes.map(childNode => {
if (childNode.nodeType === childNode.TEXT_NODE) {
return childNode.textContent;
- }
+ } // If the child is not expected just take its textContent.
+
- // If the child is not expected just take its textContent.
if (!elems.hasOwnProperty(childNode.localName)) {
return childNode.textContent;
}
- const sourceChild = elems[childNode.localName];
-
- // If the element passed as a prop to <Localized> is a known void element,
+ const sourceChild = elems[childNode.localName]; // If the element passed as a prop to <Localized> is a known void element,
// explicitly dismiss any textContent which might have accidentally been
// defined in the translation to prevent the "void element tags must not
// have children" error.
+
if (sourceChild.type in vendor_voidElementTags) {
return sourceChild;
- }
-
- // TODO Protect contents of elements wrapped in <Localized>
+ } // TODO Protect contents of elements wrapped in <Localized>
// https://github.com/projectfluent/fluent.js/issues/184
// TODO Control localizable attributes on elements passed as props
// https://github.com/projectfluent/fluent.js/issues/185
+
+
return Object(external_React_["cloneElement"])(sourceChild, null, childNode.textContent);
});
-
return Object(external_React_["cloneElement"])(elem, localizedProps, ...translatedChildren);
}
-}
+}
localized_Localized.contextTypes = {
l10n: isReactLocalization
};
-
localized_Localized.propTypes = {
children: external_PropTypes_default.a.element.isRequired
};
@@ -11834,7 +12226,6 @@ localized_Localized.propTypes = {
-
/***/ }),
/* 59 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
@@ -11854,29 +12245,36 @@ class Dedupe {
defaultCreateKey(item) {
return item;
}
-
/**
* Dedupe any number of grouped elements favoring those from earlier groups.
*
* @param {Array} groups Contains an arbitrary number of arrays of elements.
* @returns {Array} A matching array of each provided group deduped.
*/
+
+
group(...groups) {
const globalKeys = new Set();
const result = [];
+
for (const values of groups) {
const valueMap = new Map();
+
for (const value of values) {
const key = this.createKey(value);
+
if (!globalKeys.has(key) && !valueMap.has(key)) {
valueMap.set(key, value);
}
}
+
result.push(valueMap);
valueMap.forEach((value, key) => globalKeys.add(key));
}
+
return result.map(m => Array.from(m.values()));
}
+
}
// CONCATENATED MODULE: ./common/Reducers.jsm
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TOP_SITES_DEFAULT_ROWS", function() { return TOP_SITES_DEFAULT_ROWS; });
@@ -11893,10 +12291,7 @@ class Dedupe {
const TOP_SITES_DEFAULT_ROWS = 1;
const TOP_SITES_MAX_SITES_PER_ROW = 8;
-
-
const dedupe = new Dedupe(site => site && site.url);
-
const INITIAL_STATE = {
App: {
// Have we received real data from the app yet?
@@ -11906,7 +12301,9 @@ const INITIAL_STATE = {
initialized: false,
allowLegacySnippets: null
},
- Snippets: { initialized: false },
+ Snippets: {
+ initialized: false
+ },
TopSites: {
// Have we received real data from history yet?
initialized: false,
@@ -11936,19 +12333,22 @@ const INITIAL_STATE = {
// This is the new pocket configurable layout state.
DiscoveryStream: {
// This is a JSON-parsed copy of the discoverystream.config pref value.
- config: { enabled: false, layout_endpoint: "" },
+ config: {
+ enabled: false,
+ layout_endpoint: ""
+ },
layout: [],
lastUpdated: null,
feeds: {
- data: {
- // "https://foo.com/feed1": {lastUpdated: 123, data: []}
+ data: {// "https://foo.com/feed1": {lastUpdated: 123, data: []}
},
loaded: false
},
spocs: {
spocs_endpoint: "",
lastUpdated: null,
- data: {}, // {spocs: []}
+ data: {},
+ // {spocs: []}
loaded: false
}
},
@@ -11963,11 +12363,13 @@ const INITIAL_STATE = {
}
};
-
function App(prevState = INITIAL_STATE.App, action) {
switch (action.type) {
case Actions["actionTypes"].INIT:
- return Object.assign({}, prevState, action.data || {}, { initialized: true });
+ return Object.assign({}, prevState, action.data || {}, {
+ initialized: true
+ });
+
default:
return prevState;
}
@@ -11976,14 +12378,19 @@ function App(prevState = INITIAL_STATE.App, action) {
function ASRouter(prevState = INITIAL_STATE.ASRouter, action) {
switch (action.type) {
case Actions["actionTypes"].AS_ROUTER_INITIALIZED:
- return Object.assign({}, action.data, { initialized: true });
+ return { ...action.data,
+ initialized: true
+ };
+
case Actions["actionTypes"].AS_ROUTER_PREF_CHANGED:
- return Object.assign({}, prevState, action.data);
+ return { ...prevState,
+ ...action.data
+ };
+
default:
return prevState;
}
}
-
/**
* insertPinned - Inserts pinned links in their specified slots
*
@@ -11991,6 +12398,8 @@ function ASRouter(prevState = INITIAL_STATE.ASRouter, action) {
* @param {array} a list of pinned links
* @return {array} resulting list of links with pinned links inserted
*/
+
+
function insertPinned(links, pinned) {
// Remove any pinned links
const pinnedUrls = pinned.map(link => link && link.url);
@@ -12000,37 +12409,51 @@ function insertPinned(links, pinned) {
delete link.isPinned;
delete link.pinIndex;
}
+
return link;
- });
+ }); // Then insert them in their specified location
- // Then insert them in their specified location
pinned.forEach((val, index) => {
if (!val) {
return;
}
- let link = Object.assign({}, val, { isPinned: true, pinIndex: index });
+
+ let link = Object.assign({}, val, {
+ isPinned: true,
+ pinIndex: index
+ });
+
if (index > newLinks.length) {
newLinks[index] = link;
} else {
newLinks.splice(index, 0, link);
}
});
-
return newLinks;
}
-
function TopSites(prevState = INITIAL_STATE.TopSites, action) {
let hasMatch;
let newRows;
+
switch (action.type) {
case Actions["actionTypes"].TOP_SITES_UPDATED:
if (!action.data || !action.data.links) {
return prevState;
}
- return Object.assign({}, prevState, { initialized: true, rows: action.data.links }, action.data.pref ? { pref: action.data.pref } : {});
+
+ return Object.assign({}, prevState, {
+ initialized: true,
+ rows: action.data.links
+ }, action.data.pref ? {
+ pref: action.data.pref
+ } : {});
+
case Actions["actionTypes"].TOP_SITES_PREFS_UPDATED:
- return Object.assign({}, prevState, { pref: action.data.pref });
+ return Object.assign({}, prevState, {
+ pref: action.data.pref
+ });
+
case Actions["actionTypes"].TOP_SITES_EDIT:
return Object.assign({}, prevState, {
editForm: {
@@ -12038,16 +12461,27 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
previewResponse: null
}
});
+
case Actions["actionTypes"].TOP_SITES_CANCEL_EDIT:
- return Object.assign({}, prevState, { editForm: null });
+ return Object.assign({}, prevState, {
+ editForm: null
+ });
+
case Actions["actionTypes"].TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL:
- return Object.assign({}, prevState, { showSearchShortcutsForm: true });
+ return Object.assign({}, prevState, {
+ showSearchShortcutsForm: true
+ });
+
case Actions["actionTypes"].TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL:
- return Object.assign({}, prevState, { showSearchShortcutsForm: false });
+ return Object.assign({}, prevState, {
+ showSearchShortcutsForm: false
+ });
+
case Actions["actionTypes"].PREVIEW_RESPONSE:
if (!prevState.editForm || action.data.url !== prevState.editForm.previewUrl) {
return prevState;
}
+
return Object.assign({}, prevState, {
editForm: {
index: prevState.editForm.index,
@@ -12055,10 +12489,12 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
previewUrl: action.data.url
}
});
+
case Actions["actionTypes"].PREVIEW_REQUEST:
if (!prevState.editForm) {
return prevState;
}
+
return Object.assign({}, prevState, {
editForm: {
index: prevState.editForm.index,
@@ -12066,41 +12502,64 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
previewUrl: action.data.url
}
});
+
case Actions["actionTypes"].PREVIEW_REQUEST_CANCEL:
if (!prevState.editForm) {
return prevState;
}
+
return Object.assign({}, prevState, {
editForm: {
index: prevState.editForm.index,
previewResponse: null
}
});
+
case Actions["actionTypes"].SCREENSHOT_UPDATED:
newRows = prevState.rows.map(row => {
if (row && row.url === action.data.url) {
hasMatch = true;
- return Object.assign({}, row, { screenshot: action.data.screenshot });
+ return Object.assign({}, row, {
+ screenshot: action.data.screenshot
+ });
}
+
return row;
});
- return hasMatch ? Object.assign({}, prevState, { rows: newRows }) : prevState;
+ return hasMatch ? Object.assign({}, prevState, {
+ rows: newRows
+ }) : prevState;
+
case Actions["actionTypes"].PLACES_BOOKMARK_ADDED:
if (!action.data) {
return prevState;
}
+
newRows = prevState.rows.map(site => {
if (site && site.url === action.data.url) {
- const { bookmarkGuid, bookmarkTitle, dateAdded } = action.data;
- return Object.assign({}, site, { bookmarkGuid, bookmarkTitle, bookmarkDateCreated: dateAdded });
+ const {
+ bookmarkGuid,
+ bookmarkTitle,
+ dateAdded
+ } = action.data;
+ return Object.assign({}, site, {
+ bookmarkGuid,
+ bookmarkTitle,
+ bookmarkDateCreated: dateAdded
+ });
}
+
return site;
});
- return Object.assign({}, prevState, { rows: newRows });
+ return Object.assign({}, prevState, {
+ rows: newRows
+ });
+
case Actions["actionTypes"].PLACES_BOOKMARK_REMOVED:
if (!action.data) {
return prevState;
}
+
newRows = prevState.rows.map(site => {
if (site && site.url === action.data.url) {
const newSite = Object.assign({}, site);
@@ -12109,19 +12568,33 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
delete newSite.bookmarkDateCreated;
return newSite;
}
+
return site;
});
- return Object.assign({}, prevState, { rows: newRows });
+ return Object.assign({}, prevState, {
+ rows: newRows
+ });
+
case Actions["actionTypes"].PLACES_LINK_DELETED:
if (!action.data) {
return prevState;
}
+
newRows = prevState.rows.filter(site => action.data.url !== site.url);
- return Object.assign({}, prevState, { rows: newRows });
+ return Object.assign({}, prevState, {
+ rows: newRows
+ });
+
case Actions["actionTypes"].UPDATE_SEARCH_SHORTCUTS:
- return Object.assign({}, prevState, { searchShortcuts: action.data.searchShortcuts });
+ return { ...prevState,
+ searchShortcuts: action.data.searchShortcuts
+ };
+
case Actions["actionTypes"].SNIPPETS_PREVIEW_MODE:
- return Object.assign({}, prevState, { rows: [] });
+ return { ...prevState,
+ rows: []
+ };
+
default:
return prevState;
}
@@ -12130,11 +12603,19 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
function Dialog(prevState = INITIAL_STATE.Dialog, action) {
switch (action.type) {
case Actions["actionTypes"].DIALOG_OPEN:
- return Object.assign({}, prevState, { visible: true, data: action.data });
+ return Object.assign({}, prevState, {
+ visible: true,
+ data: action.data
+ });
+
case Actions["actionTypes"].DIALOG_CANCEL:
- return Object.assign({}, prevState, { visible: false });
+ return Object.assign({}, prevState, {
+ visible: false
+ });
+
case Actions["actionTypes"].DELETE_HISTORY_URL:
return Object.assign({}, INITIAL_STATE.Dialog);
+
default:
return prevState;
}
@@ -12142,13 +12623,21 @@ function Dialog(prevState = INITIAL_STATE.Dialog, action) {
function Prefs(prevState = INITIAL_STATE.Prefs, action) {
let newValues;
+
switch (action.type) {
case Actions["actionTypes"].PREFS_INITIAL_VALUES:
- return Object.assign({}, prevState, { initialized: true, values: action.data });
+ return Object.assign({}, prevState, {
+ initialized: true,
+ values: action.data
+ });
+
case Actions["actionTypes"].PREF_CHANGED:
newValues = Object.assign({}, prevState.values);
newValues[action.data.name] = action.data.value;
- return Object.assign({}, prevState, { values: newValues });
+ return Object.assign({}, prevState, {
+ values: newValues
+ });
+
default:
return prevState;
}
@@ -12157,9 +12646,11 @@ function Prefs(prevState = INITIAL_STATE.Prefs, action) {
function Sections(prevState = INITIAL_STATE.Sections, action) {
let hasMatch;
let newState;
+
switch (action.type) {
case Actions["actionTypes"].SECTION_DEREGISTER:
return prevState.filter(section => section.id !== action.data);
+
case Actions["actionTypes"].SECTION_REGISTER:
// If section exists in prevState, update it
newState = prevState.map(section => {
@@ -12167,24 +12658,34 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
hasMatch = true;
return Object.assign({}, section, action.data);
}
+
return section;
- });
- // Otherwise, append it
+ }); // Otherwise, append it
+
if (!hasMatch) {
const initialized = !!(action.data.rows && action.data.rows.length > 0);
- const section = Object.assign({ title: "", rows: [], enabled: false }, action.data, { initialized });
+ const section = Object.assign({
+ title: "",
+ rows: [],
+ enabled: false
+ }, action.data, {
+ initialized
+ });
newState.push(section);
}
+
return newState;
+
case Actions["actionTypes"].SECTION_UPDATE:
newState = prevState.map(section => {
if (section && section.id === action.data.id) {
// If the action is updating rows, we should consider initialized to be true.
// This can be overridden if initialized is defined in the action.data
- const initialized = action.data.rows ? { initialized: true } : {};
-
- // Make sure pinned cards stay at their current position when rows are updated.
+ const initialized = action.data.rows ? {
+ initialized: true
+ } : {}; // Make sure pinned cards stay at their current position when rows are updated.
// Disabling a section (SECTION_UPDATE with empty rows) does not retain pinned cards.
+
if (action.data.rows && action.data.rows.length > 0 && section.rows.find(card => card.pinned)) {
const rows = Array.from(action.data.rows);
section.rows.forEach((card, index) => {
@@ -12195,11 +12696,14 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
}
}
});
- return Object.assign({}, section, initialized, Object.assign({}, action.data, { rows }));
+ return Object.assign({}, section, initialized, Object.assign({}, action.data, {
+ rows
+ }));
}
return Object.assign({}, section, initialized, action.data);
}
+
return section;
});
@@ -12215,15 +12719,16 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
const [, newRows] = dedupe.group(dedupeSection.rows, rows);
return newRows;
}, section.rows);
-
- return Object.assign({}, section, { rows: dedupedRows });
+ return Object.assign({}, section, {
+ rows: dedupedRows
+ });
}
return section;
});
});
-
return newState;
+
case Actions["actionTypes"].SECTION_UPDATE_CARD:
return prevState.map(section => {
if (section && section.id === action.data.id && section.rows) {
@@ -12231,21 +12736,31 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
if (card.url === action.data.url) {
return Object.assign({}, card, action.data.options);
}
+
return card;
});
- return Object.assign({}, section, { rows: newRows });
+ return Object.assign({}, section, {
+ rows: newRows
+ });
}
+
return section;
});
+
case Actions["actionTypes"].PLACES_BOOKMARK_ADDED:
if (!action.data) {
return prevState;
}
+
return prevState.map(section => Object.assign({}, section, {
rows: section.rows.map(item => {
// find the item within the rows that is attempted to be bookmarked
if (item.url === action.data.url) {
- const { bookmarkGuid, bookmarkTitle, dateAdded } = action.data;
+ const {
+ bookmarkGuid,
+ bookmarkTitle,
+ dateAdded
+ } = action.data;
return Object.assign({}, item, {
bookmarkGuid,
bookmarkTitle,
@@ -12253,13 +12768,16 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
type: "bookmark"
});
}
+
return item;
})
}));
+
case Actions["actionTypes"].PLACES_SAVED_TO_POCKET:
if (!action.data) {
return prevState;
}
+
return prevState.map(section => Object.assign({}, section, {
rows: section.rows.map(item => {
if (item.url === action.data.url) {
@@ -12270,13 +12788,16 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
type: "pocket"
});
}
+
return item;
})
}));
+
case Actions["actionTypes"].PLACES_BOOKMARK_REMOVED:
if (!action.data) {
return prevState;
}
+
return prevState.map(section => Object.assign({}, section, {
rows: section.rows.map(item => {
// find the bookmark within the rows that is attempted to be removed
@@ -12285,25 +12806,39 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
delete newSite.bookmarkGuid;
delete newSite.bookmarkTitle;
delete newSite.bookmarkDateCreated;
+
if (!newSite.type || newSite.type === "bookmark") {
newSite.type = "history";
}
+
return newSite;
}
+
return item;
})
}));
+
case Actions["actionTypes"].PLACES_LINK_DELETED:
case Actions["actionTypes"].PLACES_LINK_BLOCKED:
if (!action.data) {
return prevState;
}
- return prevState.map(section => Object.assign({}, section, { rows: section.rows.filter(site => site.url !== action.data.url) }));
+
+ return prevState.map(section => Object.assign({}, section, {
+ rows: section.rows.filter(site => site.url !== action.data.url)
+ }));
+
case Actions["actionTypes"].DELETE_FROM_POCKET:
case Actions["actionTypes"].ARCHIVE_FROM_POCKET:
- return prevState.map(section => Object.assign({}, section, { rows: section.rows.filter(site => site.pocket_id !== action.data.pocket_id) }));
+ return prevState.map(section => Object.assign({}, section, {
+ rows: section.rows.filter(site => site.pocket_id !== action.data.pocket_id)
+ }));
+
case Actions["actionTypes"].SNIPPETS_PREVIEW_MODE:
- return prevState.map(section => Object.assign({}, section, { rows: [] }));
+ return prevState.map(section => ({ ...section,
+ rows: []
+ }));
+
default:
return prevState;
}
@@ -12312,13 +12847,23 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
function Snippets(prevState = INITIAL_STATE.Snippets, action) {
switch (action.type) {
case Actions["actionTypes"].SNIPPETS_DATA:
- return Object.assign({}, prevState, { initialized: true }, action.data);
+ return Object.assign({}, prevState, {
+ initialized: true
+ }, action.data);
+
case Actions["actionTypes"].SNIPPET_BLOCKED:
- return Object.assign({}, prevState, { blockList: prevState.blockList.concat(action.data) });
+ return Object.assign({}, prevState, {
+ blockList: prevState.blockList.concat(action.data)
+ });
+
case Actions["actionTypes"].SNIPPETS_BLOCKLIST_CLEARED:
- return Object.assign({}, prevState, { blockList: [] });
+ return Object.assign({}, prevState, {
+ blockList: []
+ });
+
case Actions["actionTypes"].SNIPPETS_RESET:
return INITIAL_STATE.Snippets;
+
default:
return prevState;
}
@@ -12327,18 +12872,25 @@ function Snippets(prevState = INITIAL_STATE.Snippets, action) {
function Pocket(prevState = INITIAL_STATE.Pocket, action) {
switch (action.type) {
case Actions["actionTypes"].POCKET_WAITING_FOR_SPOC:
- return Object.assign({}, prevState, { waitingForSpoc: action.data });
+ return { ...prevState,
+ waitingForSpoc: action.data
+ };
+
case Actions["actionTypes"].POCKET_LOGGED_IN:
- return Object.assign({}, prevState, { isUserLoggedIn: !!action.data });
+ return { ...prevState,
+ isUserLoggedIn: !!action.data
+ };
+
case Actions["actionTypes"].POCKET_CTA:
- return Object.assign({}, prevState, {
+ return { ...prevState,
pocketCta: {
ctaButton: action.data.cta_button,
ctaText: action.data.cta_text,
ctaUrl: action.data.cta_url,
useCta: action.data.use_cta
}
- });
+ };
+
default:
return prevState;
}
@@ -12346,62 +12898,79 @@ function Pocket(prevState = INITIAL_STATE.Pocket, action) {
function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
switch (action.type) {
- case Actions["actionTypes"].DISCOVERY_STREAM_CONFIG_CHANGE:
- // The reason this is a separate action is so it doesn't trigger a listener update on init
+ case Actions["actionTypes"].DISCOVERY_STREAM_CONFIG_CHANGE: // The reason this is a separate action is so it doesn't trigger a listener update on init
+
case Actions["actionTypes"].DISCOVERY_STREAM_CONFIG_SETUP:
- return Object.assign({}, prevState, { config: action.data || {} });
+ return { ...prevState,
+ config: action.data || {}
+ };
+
case Actions["actionTypes"].DISCOVERY_STREAM_LAYOUT_UPDATE:
- return Object.assign({}, prevState, { lastUpdated: action.data.lastUpdated || null, layout: action.data.layout || [] });
+ return { ...prevState,
+ lastUpdated: action.data.lastUpdated || null,
+ layout: action.data.layout || []
+ };
+
case Actions["actionTypes"].DISCOVERY_STREAM_LAYOUT_RESET:
- return Object.assign({}, prevState, { lastUpdated: INITIAL_STATE.DiscoveryStream.lastUpdated, layout: INITIAL_STATE.DiscoveryStream.layout });
+ return { ...prevState,
+ lastUpdated: INITIAL_STATE.DiscoveryStream.lastUpdated,
+ layout: INITIAL_STATE.DiscoveryStream.layout
+ };
+
case Actions["actionTypes"].DISCOVERY_STREAM_FEEDS_UPDATE:
- return Object.assign({}, prevState, {
- feeds: Object.assign({}, prevState.feeds, {
+ return { ...prevState,
+ feeds: { ...prevState.feeds,
data: action.data || prevState.feeds.data,
loaded: true
- })
- });
+ }
+ };
+
case Actions["actionTypes"].DISCOVERY_STREAM_SPOCS_ENDPOINT:
- return Object.assign({}, prevState, {
- spocs: Object.assign({}, INITIAL_STATE.DiscoveryStream.spocs, {
+ return { ...prevState,
+ spocs: { ...INITIAL_STATE.DiscoveryStream.spocs,
spocs_endpoint: action.data || INITIAL_STATE.DiscoveryStream.spocs.spocs_endpoint
- })
- });
+ }
+ };
+
case Actions["actionTypes"].PLACES_LINK_BLOCKED:
// Return if action data is empty, or spocs or feeds data is not loaded
if (!action.data || !prevState.spocs.loaded || !prevState.feeds.loaded) {
return prevState;
- }
- // Filter spocs and recommendations data inside feeds by removing action.data.url
+ } // Filter spocs and recommendations data inside feeds by removing action.data.url
// received on PLACES_LINK_BLOCKED triggered by dismiss link menu option
- return Object.assign({}, prevState, {
- spocs: Object.assign({}, prevState.spocs, {
+
+
+ return { ...prevState,
+ spocs: { ...prevState.spocs,
data: prevState.spocs.data.spocs ? {
spocs: prevState.spocs.data.spocs.filter(s => s.url !== action.data.url)
} : {}
- }),
- feeds: Object.assign({}, prevState.feeds, {
+ },
+ feeds: { ...prevState.feeds,
data: Object.keys(prevState.feeds.data).reduce((accumulator, feed_url) => {
accumulator[feed_url] = {
- data: Object.assign({}, prevState.feeds.data[feed_url].data, {
+ data: { ...prevState.feeds.data[feed_url].data,
recommendations: prevState.feeds.data[feed_url].data.recommendations.filter(r => r.url !== action.data.url)
- })
+ }
};
return accumulator;
}, {})
- })
- });
+ }
+ };
+
case Actions["actionTypes"].DISCOVERY_STREAM_SPOCS_UPDATE:
if (action.data) {
- return Object.assign({}, prevState, {
- spocs: Object.assign({}, prevState.spocs, {
+ return { ...prevState,
+ spocs: { ...prevState.spocs,
lastUpdated: action.data.lastUpdated,
data: action.data.spocs,
loaded: true
- })
- });
+ }
+ };
}
+
return prevState;
+
default:
return prevState;
}
@@ -12410,11 +12979,21 @@ function DiscoveryStream(prevState = INITIAL_STATE.DiscoveryStream, action) {
function Search(prevState = INITIAL_STATE.Search, action) {
switch (action.type) {
case Actions["actionTypes"].HIDE_SEARCH:
- return Object.assign(Object.assign({}, prevState, { hide: true }));
+ return Object.assign({ ...prevState,
+ hide: true
+ });
+
case Actions["actionTypes"].FAKE_FOCUS_SEARCH:
- return Object.assign(Object.assign({}, prevState, { fakeFocus: true }));
+ return Object.assign({ ...prevState,
+ fakeFocus: true
+ });
+
case Actions["actionTypes"].SHOW_SEARCH:
- return Object.assign(Object.assign({}, prevState, { hide: false, fakeFocus: false }));
+ return Object.assign({ ...prevState,
+ hide: false,
+ fakeFocus: false
+ });
+
default:
return prevState;
}
@@ -12493,8 +13072,9 @@ var screenshot_utils = __webpack_require__(44);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Card", function() { return Card_Card; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Card", function() { return Card; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlaceholderCard", function() { return PlaceholderCard; });
-function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
+function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
@@ -12503,10 +13083,9 @@ function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, a
+ // Keep track of pending image loads to only request once
-// Keep track of pending image loads to only request once
const gImageLoading = new Map();
-
/**
* Card component.
* Cards are found within a Section component and contain information about a link such
@@ -12516,6 +13095,7 @@ const gImageLoading = new Map();
* this class. Each card will then get a context menu which reflects the actions that
* can be done on this Card.
*/
+
class Card_Card extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
@@ -12529,51 +13109,51 @@ class Card_Card extends external_React_default.a.PureComponent {
this.onMenuUpdate = this.onMenuUpdate.bind(this);
this.onLinkClick = this.onLinkClick.bind(this);
}
-
/**
* Helper to conditionally load an image and update state when it loads.
*/
+
+
maybeLoadImage() {
var _this = this;
return _asyncToGenerator(function* () {
// No need to load if it's already loaded or no image
- const { cardImage } = _this.state;
+ const {
+ cardImage
+ } = _this.state;
+
if (!cardImage) {
return;
}
const imageUrl = cardImage.url;
+
if (!_this.state.imageLoaded) {
// Initialize a promise to share a load across multiple card updates
if (!gImageLoading.has(imageUrl)) {
- const loaderPromise = new Promise(function (resolve, reject) {
+ const loaderPromise = new Promise((resolve, reject) => {
const loader = new Image();
loader.addEventListener("load", resolve);
loader.addEventListener("error", reject);
loader.src = imageUrl;
- });
+ }); // Save and remove the promise only while it's pending
- // Save and remove the promise only while it's pending
gImageLoading.set(imageUrl, loaderPromise);
- loaderPromise.catch(function (ex) {
- return ex;
- }).then(function () {
- return gImageLoading.delete(imageUrl);
- }).catch();
- }
+ loaderPromise.catch(ex => ex).then(() => gImageLoading.delete(imageUrl)).catch();
+ } // Wait for the image whether just started loading or reused promise
+
- // Wait for the image whether just started loading or reused promise
- yield gImageLoading.get(imageUrl);
+ yield gImageLoading.get(imageUrl); // Only update state if we're still waiting to load the original image
- // Only update state if we're still waiting to load the original image
if (screenshot_utils["ScreenshotUtils"].isRemoteImageLocal(_this.state.cardImage, _this.props.link.image) && !_this.state.imageLoaded) {
- _this.setState({ imageLoaded: true });
+ _this.setState({
+ imageLoaded: true
+ });
}
}
})();
}
-
/**
* Helper to obtain the next state based on nextProps and prevState.
*
@@ -12585,26 +13165,29 @@ class Card_Card extends external_React_default.a.PureComponent {
*
* See https://github.com/airbnb/enzyme/blob/master/packages/enzyme-adapter-react-16/package.json#L43.
*/
+
+
static getNextStateFromProps(nextProps, prevState) {
- const { image } = nextProps.link;
+ const {
+ image
+ } = nextProps.link;
const imageInState = screenshot_utils["ScreenshotUtils"].isRemoteImageLocal(prevState.cardImage, image);
- let nextState = null;
+ let nextState = null; // Image is updating.
- // Image is updating.
if (!imageInState && nextProps.link) {
- nextState = { imageLoaded: false };
+ nextState = {
+ imageLoaded: false
+ };
}
if (imageInState) {
return nextState;
- }
+ } // Since image was updated, attempt to revoke old image blob URL, if it exists.
- // Since image was updated, attempt to revoke old image blob URL, if it exists.
- screenshot_utils["ScreenshotUtils"].maybeRevokeBlobObjectURL(prevState.cardImage);
+ screenshot_utils["ScreenshotUtils"].maybeRevokeBlobObjectURL(prevState.cardImage);
nextState = nextState || {};
nextState.cardImage = screenshot_utils["ScreenshotUtils"].createLocalImageObject(image);
-
return nextState;
}
@@ -12615,14 +13198,19 @@ class Card_Card extends external_React_default.a.PureComponent {
showContextMenu: true
});
}
-
/**
* Report to telemetry additional information about the item.
*/
+
+
_getTelemetryInfo() {
// Filter out "history" type for being the default
if (this.props.link.type !== "history") {
- return { value: { card_type: this.props.link.type } };
+ return {
+ value: {
+ card_type: this.props.link.type
+ }
+ };
}
return null;
@@ -12630,18 +13218,34 @@ class Card_Card extends external_React_default.a.PureComponent {
onLinkClick(event) {
event.preventDefault();
+
if (this.props.link.type === "download") {
this.props.dispatch(Actions["actionCreators"].OnlyToMain({
type: Actions["actionTypes"].SHOW_DOWNLOAD_FILE,
data: this.props.link
}));
} else {
- const { altKey, button, ctrlKey, metaKey, shiftKey } = event;
+ const {
+ altKey,
+ button,
+ ctrlKey,
+ metaKey,
+ shiftKey
+ } = event;
this.props.dispatch(Actions["actionCreators"].OnlyToMain({
type: Actions["actionTypes"].OPEN_LINK,
- data: Object.assign(this.props.link, { event: { altKey, button, ctrlKey, metaKey, shiftKey } })
+ data: Object.assign(this.props.link, {
+ event: {
+ altKey,
+ button,
+ ctrlKey,
+ metaKey,
+ shiftKey
+ }
+ })
}));
}
+
if (this.props.isWebExtension) {
this.props.dispatch(Actions["actionCreators"].WebExtEvent(Actions["actionTypes"].WEBEXT_CLICK, {
source: this.props.eventSource,
@@ -12659,14 +13263,19 @@ class Card_Card extends external_React_default.a.PureComponent {
this.props.dispatch(Actions["actionCreators"].ImpressionStats({
source: this.props.eventSource,
click: 0,
- tiles: [{ id: this.props.link.guid, pos: this.props.index }]
+ tiles: [{
+ id: this.props.link.guid,
+ pos: this.props.index
+ }]
}));
}
}
}
onMenuUpdate(showContextMenu) {
- this.setState({ showContextMenu });
+ this.setState({
+ showContextMenu
+ });
}
componentDidMount() {
@@ -12675,23 +13284,25 @@ class Card_Card extends external_React_default.a.PureComponent {
componentDidUpdate() {
this.maybeLoadImage();
- }
-
- // NOTE: Remove this function when we update React to >= 16.3 since React will
+ } // NOTE: Remove this function when we update React to >= 16.3 since React will
// call getDerivedStateFromProps automatically. We will also need to
// rename getNextStateFromProps to getDerivedStateFromProps.
+
+
componentWillMount() {
const nextState = Card_Card.getNextStateFromProps(this.props, this.state);
+
if (nextState) {
this.setState(nextState);
}
- }
-
- // NOTE: Remove this function when we update React to >= 16.3 since React will
+ } // NOTE: Remove this function when we update React to >= 16.3 since React will
// call getDerivedStateFromProps automatically. We will also need to
// rename getNextStateFromProps to getDerivedStateFromProps.
+
+
componentWillReceiveProps(nextProps) {
const nextState = Card_Card.getNextStateFromProps(nextProps, this.state);
+
if (nextState) {
this.setState(nextState);
}
@@ -12702,101 +13313,104 @@ class Card_Card extends external_React_default.a.PureComponent {
}
render() {
- const { index, className, link, dispatch, contextMenuOptions, eventSource, shouldSendImpressionStats } = this.props;
- const { props } = this;
- const isContextMenuOpen = this.state.showContextMenu && this.state.activeCard === index;
- // Display "now" as "trending" until we have new strings #3402
- const { icon, intlID } = cardContextTypes[link.type === "now" ? "trending" : link.type] || {};
+ const {
+ index,
+ className,
+ link,
+ dispatch,
+ contextMenuOptions,
+ eventSource,
+ shouldSendImpressionStats
+ } = this.props;
+ const {
+ props
+ } = this;
+ const isContextMenuOpen = this.state.showContextMenu && this.state.activeCard === index; // Display "now" as "trending" until we have new strings #3402
+
+ const {
+ icon,
+ intlID
+ } = cardContextTypes[link.type === "now" ? "trending" : link.type] || {};
const hasImage = this.state.cardImage || link.hasImage;
- const imageStyle = { backgroundImage: this.state.cardImage ? `url(${this.state.cardImage.url})` : "none" };
+ const imageStyle = {
+ backgroundImage: this.state.cardImage ? `url(${this.state.cardImage.url})` : "none"
+ };
const outerClassName = ["card-outer", className, isContextMenuOpen && "active", props.placeholder && "placeholder"].filter(v => v).join(" ");
+ return external_React_default.a.createElement("li", {
+ className: outerClassName
+ }, external_React_default.a.createElement("a", {
+ href: link.type === "pocket" ? link.open_url : link.url,
+ onClick: !props.placeholder ? this.onLinkClick : undefined
+ }, external_React_default.a.createElement("div", {
+ className: "card"
+ }, external_React_default.a.createElement("div", {
+ className: "card-preview-image-outer"
+ }, hasImage && external_React_default.a.createElement("div", {
+ className: `card-preview-image${this.state.imageLoaded ? " loaded" : ""}`,
+ style: imageStyle
+ })), external_React_default.a.createElement("div", {
+ className: "card-details"
+ }, link.type === "download" && external_React_default.a.createElement("div", {
+ className: "card-host-name alternate"
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: Object(link_menu_options["GetPlatformString"])(this.props.platform)
+ })), link.hostname && external_React_default.a.createElement("div", {
+ className: "card-host-name"
+ }, link.hostname.slice(0, 100), link.type === "download" && ` \u2014 ${link.description}`), external_React_default.a.createElement("div", {
+ className: ["card-text", icon ? "" : "no-context", link.description ? "" : "no-description", link.hostname ? "" : "no-host-name"].join(" ")
+ }, external_React_default.a.createElement("h4", {
+ className: "card-title",
+ dir: "auto"
+ }, link.title), external_React_default.a.createElement("p", {
+ className: "card-description",
+ dir: "auto"
+ }, link.description)), external_React_default.a.createElement("div", {
+ className: "card-context"
+ }, icon && !link.context && external_React_default.a.createElement("span", {
+ className: `card-context-icon icon icon-${icon}`
+ }), link.icon && link.context && external_React_default.a.createElement("span", {
+ className: "card-context-icon icon",
+ style: {
+ backgroundImage: `url('${link.icon}')`
+ }
+ }), intlID && !link.context && external_React_default.a.createElement("div", {
+ className: "card-context-label"
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: intlID,
+ defaultMessage: "Visited"
+ })), link.context && external_React_default.a.createElement("div", {
+ className: "card-context-label"
+ }, link.context))))), !props.placeholder && external_React_default.a.createElement("button", {
+ className: "context-menu-button icon",
+ title: this.props.intl.formatMessage({
+ id: "context_menu_title"
+ }),
+ onClick: this.onMenuButtonClick
+ }, external_React_default.a.createElement("span", {
+ className: "sr-only"
+ }, `Open context menu for ${link.title}`)), isContextMenuOpen && external_React_default.a.createElement(LinkMenu["LinkMenu"], {
+ dispatch: dispatch,
+ index: index,
+ source: eventSource,
+ onUpdate: this.onMenuUpdate,
+ options: link.contextMenuOptions || contextMenuOptions,
+ site: link,
+ siteInfo: this._getTelemetryInfo(),
+ shouldSendImpressionStats: shouldSendImpressionStats
+ }));
+ }
- return external_React_default.a.createElement(
- "li",
- { className: outerClassName },
- external_React_default.a.createElement(
- "a",
- { href: link.type === "pocket" ? link.open_url : link.url, onClick: !props.placeholder ? this.onLinkClick : undefined },
- external_React_default.a.createElement(
- "div",
- { className: "card" },
- external_React_default.a.createElement(
- "div",
- { className: "card-preview-image-outer" },
- hasImage && external_React_default.a.createElement("div", { className: `card-preview-image${this.state.imageLoaded ? " loaded" : ""}`, style: imageStyle })
- ),
- external_React_default.a.createElement(
- "div",
- { className: "card-details" },
- link.type === "download" && external_React_default.a.createElement(
- "div",
- { className: "card-host-name alternate" },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: Object(link_menu_options["GetPlatformString"])(this.props.platform) })
- ),
- link.hostname && external_React_default.a.createElement(
- "div",
- { className: "card-host-name" },
- link.hostname.slice(0, 100),
- link.type === "download" && ` \u2014 ${link.description}`
- ),
- external_React_default.a.createElement(
- "div",
- { className: ["card-text", icon ? "" : "no-context", link.description ? "" : "no-description", link.hostname ? "" : "no-host-name"].join(" ") },
- external_React_default.a.createElement(
- "h4",
- { className: "card-title", dir: "auto" },
- link.title
- ),
- external_React_default.a.createElement(
- "p",
- { className: "card-description", dir: "auto" },
- link.description
- )
- ),
- external_React_default.a.createElement(
- "div",
- { className: "card-context" },
- icon && !link.context && external_React_default.a.createElement("span", { className: `card-context-icon icon icon-${icon}` }),
- link.icon && link.context && external_React_default.a.createElement("span", { className: "card-context-icon icon", style: { backgroundImage: `url('${link.icon}')` } }),
- intlID && !link.context && external_React_default.a.createElement(
- "div",
- { className: "card-context-label" },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: intlID, defaultMessage: "Visited" })
- ),
- link.context && external_React_default.a.createElement(
- "div",
- { className: "card-context-label" },
- link.context
- )
- )
- )
- )
- ),
- !props.placeholder && external_React_default.a.createElement(
- "button",
- { className: "context-menu-button icon", title: this.props.intl.formatMessage({ id: "context_menu_title" }),
- onClick: this.onMenuButtonClick },
- external_React_default.a.createElement(
- "span",
- { className: "sr-only" },
- `Open context menu for ${link.title}`
- )
- ),
- isContextMenuOpen && external_React_default.a.createElement(LinkMenu["LinkMenu"], {
- dispatch: dispatch,
- index: index,
- source: eventSource,
- onUpdate: this.onMenuUpdate,
- options: link.contextMenuOptions || contextMenuOptions,
- site: link,
- siteInfo: this._getTelemetryInfo(),
- shouldSendImpressionStats: shouldSendImpressionStats })
- );
- }
-}
-Card_Card.defaultProps = { link: {} };
-const Card = Object(external_ReactRedux_["connect"])(state => ({ platform: state.Prefs.values.platform }))(Object(external_ReactIntl_["injectIntl"])(Card_Card));
-const PlaceholderCard = props => external_React_default.a.createElement(Card, { placeholder: true, className: props.className });
+}
+Card_Card.defaultProps = {
+ link: {}
+};
+const Card = Object(external_ReactRedux_["connect"])(state => ({
+ platform: state.Prefs.values.platform
+}))(Object(external_ReactIntl_["injectIntl"])(Card_Card));
+const PlaceholderCard = props => external_React_default.a.createElement(Card, {
+ placeholder: true,
+ className: props.className
+});
/***/ }),
/* 61 */
@@ -12821,11 +13435,12 @@ var TopSitesConstants = __webpack_require__(35);
// CONCATENATED MODULE: ./content-src/components/TopSites/TopSiteFormInput.jsx
-
class TopSiteFormInput_TopSiteFormInput extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
- this.state = { validationError: this.props.validationError };
+ this.state = {
+ validationError: this.props.validationError
+ };
this.onChange = this.onChange.bind(this);
this.onMount = this.onMount.bind(this);
}
@@ -12834,19 +13449,28 @@ class TopSiteFormInput_TopSiteFormInput extends external_React_default.a.PureCom
if (nextProps.shouldFocus && !this.props.shouldFocus) {
this.input.focus();
}
+
if (nextProps.validationError && !this.props.validationError) {
- this.setState({ validationError: true });
- }
- // If the component is in an error state but the value was cleared by the parent
+ this.setState({
+ validationError: true
+ });
+ } // If the component is in an error state but the value was cleared by the parent
+
+
if (this.state.validationError && !nextProps.value) {
- this.setState({ validationError: false });
+ this.setState({
+ validationError: false
+ });
}
}
onChange(ev) {
if (this.state.validationError) {
- this.setState({ validationError: false });
+ this.setState({
+ validationError: false
+ });
}
+
this.props.onChange(ev);
}
@@ -12856,38 +13480,41 @@ class TopSiteFormInput_TopSiteFormInput extends external_React_default.a.PureCom
render() {
const showClearButton = this.props.value && this.props.onClear;
- const { typeUrl } = this.props;
- const { validationError } = this.state;
-
- return external_React_default.a.createElement(
- "label",
- null,
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: this.props.titleId }),
- external_React_default.a.createElement(
- "div",
- { className: `field ${typeUrl ? "url" : ""}${validationError ? " invalid" : ""}` },
- this.props.loading ? external_React_default.a.createElement(
- "div",
- { className: "loading-container" },
- external_React_default.a.createElement("div", { className: "loading-animation" })
- ) : showClearButton && external_React_default.a.createElement("div", { className: "icon icon-clear-input", onClick: this.props.onClear }),
- external_React_default.a.createElement("input", { type: "text",
- value: this.props.value,
- ref: this.onMount,
- onChange: this.onChange,
- placeholder: this.props.intl.formatMessage({ id: this.props.placeholderId }),
- autoFocus: this.props.shouldFocus,
- disabled: this.props.loading }),
- validationError && external_React_default.a.createElement(
- "aside",
- { className: "error-tooltip" },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: this.props.errorMessageId })
- )
- )
- );
+ const {
+ typeUrl
+ } = this.props;
+ const {
+ validationError
+ } = this.state;
+ return external_React_default.a.createElement("label", null, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: this.props.titleId
+ }), external_React_default.a.createElement("div", {
+ className: `field ${typeUrl ? "url" : ""}${validationError ? " invalid" : ""}`
+ }, this.props.loading ? external_React_default.a.createElement("div", {
+ className: "loading-container"
+ }, external_React_default.a.createElement("div", {
+ className: "loading-animation"
+ })) : showClearButton && external_React_default.a.createElement("div", {
+ className: "icon icon-clear-input",
+ onClick: this.props.onClear
+ }), external_React_default.a.createElement("input", {
+ type: "text",
+ value: this.props.value,
+ ref: this.onMount,
+ onChange: this.onChange,
+ placeholder: this.props.intl.formatMessage({
+ id: this.props.placeholderId
+ }),
+ autoFocus: this.props.shouldFocus,
+ disabled: this.props.loading
+ }), validationError && external_React_default.a.createElement("aside", {
+ className: "error-tooltip"
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: this.props.errorMessageId
+ }))));
}
-}
+}
TopSiteFormInput_TopSiteFormInput.defaultProps = {
showClearButton: false,
value: "",
@@ -12904,11 +13531,12 @@ var TopSite = __webpack_require__(43);
-
class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
- const { site } = props;
+ const {
+ site
+ } = props;
this.state = {
label: site ? site.label || site.hostname : "",
url: site ? site.url : "",
@@ -12929,7 +13557,9 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
}
onLabelChange(event) {
- this.setState({ "label": event.target.value });
+ this.setState({
+ "label": event.target.value
+ });
}
onUrlChange(event) {
@@ -12947,7 +13577,9 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
}
onEnableScreenshotUrlForm() {
- this.setState({ showCustomScreenshotForm: true });
+ this.setState({
+ showCustomScreenshotForm: true
+ });
}
_updateCustomScreenshotInput(customScreenshotUrl) {
@@ -12955,7 +13587,9 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
customScreenshotUrl,
validationError: false
});
- this.props.dispatch({ type: Actions["actionTypes"].PREVIEW_REQUEST_CANCEL });
+ this.props.dispatch({
+ type: Actions["actionTypes"].PREVIEW_REQUEST_CANCEL
+ });
}
onCustomScreenshotUrlChange(event) {
@@ -12975,8 +13609,13 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
ev.preventDefault();
if (this.validateForm()) {
- const site = { url: this.cleanUrl(this.state.url) };
- const { index } = this.props;
+ const site = {
+ url: this.cleanUrl(this.state.url)
+ };
+ const {
+ index
+ } = this.props;
+
if (this.state.label !== "") {
site.label = this.state.label;
}
@@ -12987,26 +13626,32 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
// Used to flag that previously cached screenshot should be removed
site.customScreenshotURL = null;
}
+
this.props.dispatch(Actions["actionCreators"].AlsoToMain({
type: Actions["actionTypes"].TOP_SITES_PIN,
- data: { site, index }
+ data: {
+ site,
+ index
+ }
}));
this.props.dispatch(Actions["actionCreators"].UserEvent({
source: TopSitesConstants["TOP_SITES_SOURCE"],
event: "TOP_SITES_EDIT",
action_position: index
}));
-
this.props.onClose();
}
}
onPreviewButtonClick(event) {
event.preventDefault();
+
if (this.validateForm()) {
this.props.dispatch(Actions["actionCreators"].AlsoToMain({
type: Actions["actionTypes"].PREVIEW_REQUEST,
- data: { url: this.cleanUrl(this.state.customScreenshotUrl) }
+ data: {
+ url: this.cleanUrl(this.state.customScreenshotUrl)
+ }
}));
this.props.dispatch(Actions["actionCreators"].UserEvent({
source: TopSitesConstants["TOP_SITES_SOURCE"],
@@ -13020,6 +13665,7 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
if (!url.startsWith("http:") && !url.startsWith("https:")) {
return `http://${url}`;
}
+
return url;
}
@@ -13033,13 +13679,16 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
validateUrl(url) {
const validProtocols = ["http:", "https:"];
+
const urlObj = this._tryParseUrl(url) || this._tryParseUrl(this.cleanUrl(url));
return urlObj && validProtocols.includes(urlObj.protocol);
}
validateCustomScreenshotUrl() {
- const { customScreenshotUrl } = this.state;
+ const {
+ customScreenshotUrl
+ } = this.state;
return !customScreenshotUrl || this.validateUrl(customScreenshotUrl);
}
@@ -13047,121 +13696,126 @@ class TopSiteForm_TopSiteForm extends external_React_default.a.PureComponent {
const validate = this.validateUrl(this.state.url) && this.validateCustomScreenshotUrl();
if (!validate) {
- this.setState({ validationError: true });
+ this.setState({
+ validationError: true
+ });
}
return validate;
}
_renderCustomScreenshotInput() {
- const { customScreenshotUrl } = this.state;
+ const {
+ customScreenshotUrl
+ } = this.state;
const requestFailed = this.props.previewResponse === "";
- const validationError = this.state.validationError && !this.validateCustomScreenshotUrl() || requestFailed;
- // Set focus on error if the url field is valid or when the input is first rendered and is empty
+ const validationError = this.state.validationError && !this.validateCustomScreenshotUrl() || requestFailed; // Set focus on error if the url field is valid or when the input is first rendered and is empty
+
const shouldFocus = validationError && this.validateUrl(this.state.url) || !customScreenshotUrl;
const isLoading = this.props.previewResponse === null && customScreenshotUrl && this.props.previewUrl === this.cleanUrl(customScreenshotUrl);
if (!this.state.showCustomScreenshotForm) {
- return external_React_default.a.createElement(
- "a",
- { className: "enable-custom-image-input", onClick: this.onEnableScreenshotUrlForm },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: "topsites_form_use_image_link" })
- );
- }
- return external_React_default.a.createElement(
- "div",
- { className: "custom-image-input-container" },
- external_React_default.a.createElement(TopSiteFormInput_TopSiteFormInput, {
- errorMessageId: requestFailed ? "topsites_form_image_validation" : "topsites_form_url_validation",
- loading: isLoading,
- onChange: this.onCustomScreenshotUrlChange,
- onClear: this.onClearScreenshotInput,
- shouldFocus: shouldFocus,
- typeUrl: true,
- value: customScreenshotUrl,
- validationError: validationError,
- titleId: "topsites_form_image_url_label",
- placeholderId: "topsites_form_url_placeholder",
- intl: this.props.intl })
- );
+ return external_React_default.a.createElement("a", {
+ className: "enable-custom-image-input",
+ onClick: this.onEnableScreenshotUrlForm
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: "topsites_form_use_image_link"
+ }));
+ }
+
+ return external_React_default.a.createElement("div", {
+ className: "custom-image-input-container"
+ }, external_React_default.a.createElement(TopSiteFormInput_TopSiteFormInput, {
+ errorMessageId: requestFailed ? "topsites_form_image_validation" : "topsites_form_url_validation",
+ loading: isLoading,
+ onChange: this.onCustomScreenshotUrlChange,
+ onClear: this.onClearScreenshotInput,
+ shouldFocus: shouldFocus,
+ typeUrl: true,
+ value: customScreenshotUrl,
+ validationError: validationError,
+ titleId: "topsites_form_image_url_label",
+ placeholderId: "topsites_form_url_placeholder",
+ intl: this.props.intl
+ }));
}
render() {
- const { customScreenshotUrl } = this.state;
- const requestFailed = this.props.previewResponse === "";
- // For UI purposes, editing without an existing link is "add"
+ const {
+ customScreenshotUrl
+ } = this.state;
+ const requestFailed = this.props.previewResponse === ""; // For UI purposes, editing without an existing link is "add"
+
const showAsAdd = !this.props.site;
const previous = this.props.site && this.props.site.customScreenshotURL || "";
- const changed = customScreenshotUrl && this.cleanUrl(customScreenshotUrl) !== previous;
- // Preview mode if changes were made to the custom screenshot URL and no preview was received yet
+ const changed = customScreenshotUrl && this.cleanUrl(customScreenshotUrl) !== previous; // Preview mode if changes were made to the custom screenshot URL and no preview was received yet
// or the request failed
+
const previewMode = changed && !this.props.previewResponse;
const previewLink = Object.assign({}, this.props.site);
+
if (this.props.previewResponse) {
previewLink.screenshot = this.props.previewResponse;
previewLink.customScreenshotURL = this.props.previewUrl;
}
- return external_React_default.a.createElement(
- "form",
- { className: "topsite-form" },
- external_React_default.a.createElement(
- "div",
- { className: "form-input-container" },
- external_React_default.a.createElement(
- "h3",
- { className: "section-title" },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: showAsAdd ? "topsites_form_add_header" : "topsites_form_edit_header" })
- ),
- external_React_default.a.createElement(
- "div",
- { className: "fields-and-preview" },
- external_React_default.a.createElement(
- "div",
- { className: "form-wrapper" },
- external_React_default.a.createElement(TopSiteFormInput_TopSiteFormInput, { onChange: this.onLabelChange,
- value: this.state.label,
- titleId: "topsites_form_title_label",
- placeholderId: "topsites_form_title_placeholder",
- intl: this.props.intl }),
- external_React_default.a.createElement(TopSiteFormInput_TopSiteFormInput, { onChange: this.onUrlChange,
- shouldFocus: this.state.validationError && !this.validateUrl(this.state.url),
- value: this.state.url,
- onClear: this.onClearUrlClick,
- validationError: this.state.validationError && !this.validateUrl(this.state.url),
- titleId: "topsites_form_url_label",
- typeUrl: true,
- placeholderId: "topsites_form_url_placeholder",
- errorMessageId: "topsites_form_url_validation",
- intl: this.props.intl }),
- this._renderCustomScreenshotInput()
- ),
- external_React_default.a.createElement(TopSite["TopSiteLink"], { link: previewLink,
- defaultStyle: requestFailed,
- title: this.state.label })
- )
- ),
- external_React_default.a.createElement(
- "section",
- { className: "actions" },
- external_React_default.a.createElement(
- "button",
- { className: "cancel", type: "button", onClick: this.onCancelButtonClick },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: "topsites_form_cancel_button" })
- ),
- previewMode ? external_React_default.a.createElement(
- "button",
- { className: "done preview", type: "submit", onClick: this.onPreviewButtonClick },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: "topsites_form_preview_button" })
- ) : external_React_default.a.createElement(
- "button",
- { className: "done", type: "submit", onClick: this.onDoneButtonClick },
- external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], { id: showAsAdd ? "topsites_form_add_button" : "topsites_form_save_button" })
- )
- )
- );
+
+ return external_React_default.a.createElement("form", {
+ className: "topsite-form"
+ }, external_React_default.a.createElement("div", {
+ className: "form-input-container"
+ }, external_React_default.a.createElement("h3", {
+ className: "section-title"
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: showAsAdd ? "topsites_form_add_header" : "topsites_form_edit_header"
+ })), external_React_default.a.createElement("div", {
+ className: "fields-and-preview"
+ }, external_React_default.a.createElement("div", {
+ className: "form-wrapper"
+ }, external_React_default.a.createElement(TopSiteFormInput_TopSiteFormInput, {
+ onChange: this.onLabelChange,
+ value: this.state.label,
+ titleId: "topsites_form_title_label",
+ placeholderId: "topsites_form_title_placeholder",
+ intl: this.props.intl
+ }), external_React_default.a.createElement(TopSiteFormInput_TopSiteFormInput, {
+ onChange: this.onUrlChange,
+ shouldFocus: this.state.validationError && !this.validateUrl(this.state.url),
+ value: this.state.url,
+ onClear: this.onClearUrlClick,
+ validationError: this.state.validationError && !this.validateUrl(this.state.url),
+ titleId: "topsites_form_url_label",
+ typeUrl: true,
+ placeholderId: "topsites_form_url_placeholder",
+ errorMessageId: "topsites_form_url_validation",
+ intl: this.props.intl
+ }), this._renderCustomScreenshotInput()), external_React_default.a.createElement(TopSite["TopSiteLink"], {
+ link: previewLink,
+ defaultStyle: requestFailed,
+ title: this.state.label
+ }))), external_React_default.a.createElement("section", {
+ className: "actions"
+ }, external_React_default.a.createElement("button", {
+ className: "cancel",
+ type: "button",
+ onClick: this.onCancelButtonClick
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: "topsites_form_cancel_button"
+ })), previewMode ? external_React_default.a.createElement("button", {
+ className: "done preview",
+ type: "submit",
+ onClick: this.onPreviewButtonClick
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: "topsites_form_preview_button"
+ })) : external_React_default.a.createElement("button", {
+ className: "done",
+ type: "submit",
+ onClick: this.onDoneButtonClick
+ }, external_React_default.a.createElement(external_ReactIntl_["FormattedMessage"], {
+ id: showAsAdd ? "topsites_form_add_button" : "topsites_form_save_button"
+ }))));
}
-}
+}
TopSiteForm_TopSiteForm.defaultProps = {
site: null,
index: -1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment