Backed out changeset 8dde92f89a24 (bug 1489962) for browser_asrouter_cfr.js failures. a=backout

This commit is contained in:
Bogdan Tara 2018-09-20 02:42:00 +03:00
Родитель e7c653959c
Коммит b240c5a949
464 изменённых файлов: 2115 добавлений и 7087 удалений

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

@ -78,6 +78,7 @@ module.exports = {
"camelcase": 0,
"capitalized-comments": 0,
"class-methods-use-this": 0,
"comma-dangle": [2, "never"],
"consistent-this": [2, "use-bind"],
"curly": [2, "all"],
"default-case": 0,

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

@ -2,7 +2,7 @@ language: node_js
node_js:
# when changing this, be sure to edit .nvrmc and package.json too
- 8
- 7
python:
- "2.7"

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

@ -100,7 +100,7 @@ AboutNewTabService.prototype = {
classID: Components.ID("{dfcd2adc-7867-4d3a-ba70-17501f208142}"),
QueryInterface: ChromeUtils.generateQI([
Ci.nsIAboutNewTabService,
Ci.nsIObserver,
Ci.nsIObserver
]),
observe(subject, topic, data) {
@ -153,7 +153,7 @@ AboutNewTabService.prototype = {
`${BASE_URL}vendor/redux.js`,
`${BASE_URL}vendor/react-redux.js`,
`${BASE_URL}prerendered/${this.activityStreamLocale}/activity-stream-strings.js`,
`${BASE_URL}data/content/activity-stream.bundle.js`,
`${BASE_URL}data/content/activity-stream.bundle.js`
];
if (this._activityStreamPrerender) {
@ -251,7 +251,7 @@ AboutNewTabService.prototype = {
this._activityStreamPrerender ? "-prerendered" : "",
this._activityStreamDebug ? "-debug" : "",
this._privilegedContentProcess ? "-noscripts" : "",
".html",
".html"
].join("");
},
@ -339,7 +339,7 @@ AboutNewTabService.prototype = {
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
}
this.initialized = false;
},
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutNewTabService]);

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

@ -107,5 +107,5 @@ exports.CENTRAL_LOCALES = [
"wo",
"xh",
"zh-CN",
"zh-TW",
"zh-TW"
];

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

@ -12,7 +12,7 @@ const {CENTRAL_LOCALES, DEFAULT_LOCALE} = require("./locales");
// in mozilla-central.
const DEFAULT_OPTIONS = {
addonPath: "..",
baseUrl: "resource://activity-stream/",
baseUrl: "resource://activity-stream/"
};
// Locales that should be displayed RTL
@ -76,7 +76,7 @@ function templateHTML(options, html) {
`${options.baseUrl}vendor/redux.js`,
`${options.baseUrl}vendor/react-redux.js`,
`${options.baseUrl}prerendered/${options.locale}/activity-stream-strings.js`,
`${options.baseUrl}data/content/activity-stream.bundle.js`,
`${options.baseUrl}data/content/activity-stream.bundle.js`
];
if (isPrerendered) {
scripts.unshift(`${options.baseUrl}prerendered/static/activity-stream-initial-state.js`);
@ -155,7 +155,7 @@ const STATIC_FILES = new Map([
["activity-stream-debug-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))],
["activity-stream-initial-state.js", ({state}) => templateJs("gActivityStreamPrerenderedState", "static", state)],
["activity-stream-prerendered-debug.html", ({html, options}) => templateHTML(options, html)],
["activity-stream-prerendered-debug-noscripts.html", ({html, options}) => templateHTML(Object.assign({}, options, {noscripts: true}), html)],
["activity-stream-prerendered-debug-noscripts.html", ({html, options}) => templateHTML(Object.assign({}, options, {noscripts: true}), html)]
]);
const LOCALIZED_FILES = new Map([
@ -163,7 +163,7 @@ const LOCALIZED_FILES = new Map([
["activity-stream-prerendered-noscripts.html", ({html, options}) => templateHTML(Object.assign({}, options, {noscripts: true}), html)],
["activity-stream-strings.js", ({options: {locale, strings}}) => templateJs("gActivityStreamStrings", locale, strings)],
["activity-stream.html", ({options}) => templateHTML(options)],
["activity-stream-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))],
["activity-stream-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))]
]);
/**
@ -177,8 +177,8 @@ function main() { // eslint-disable-line max-statements
const args = require("minimist")(process.argv.slice(2), {
alias: {
addonPath: "a",
baseUrl: "b",
},
baseUrl: "b"
}
});
const baseOptions = Object.assign({debug: false}, DEFAULT_OPTIONS, args || {});
@ -211,7 +211,7 @@ function main() { // eslint-disable-line max-statements
const options = Object.assign({}, baseOptions, {
direction: getTextDirection(locale),
locale,
strings,
strings
});
// Put locale-specific files in their own directory

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

@ -79,7 +79,7 @@ function findNewlyMergedPRs() {
"base:master",
// if it's already been pushed to pine, don't do it again
`-label:${ALREADY_PUSHED_LABEL}`,
`-label:${ALREADY_PUSHED_LABEL}`
];
console.log(`Searching ${AS_REPO} for newly merged PRs`);
@ -97,7 +97,7 @@ function getPRMergeCommitId(prNumber) {
return github.issues.getEvents({
owner: AS_REPO_OWNER,
repo: AS_REPO_NAME,
issue_number: prNumber,
issue_number: prNumber
}).then(({data}) => {
if (data.incomplete_results) {
// XXX should handle this case theoretically, but since we'll be running
@ -190,7 +190,7 @@ function commitToHg([commitId, commitMsg]) {
"--addremove",
"-m",
`${commitMsg}\n\nExport of ${commitId} from ${AS_REPO_OWNER}/${AS_REPO_NAME}`,
".",
"."
],
{cwd: TESTING_LOCAL_MC, env: process.env, timeout: 5 * 60 * 1000},
(code, stdout, stderr) => {
@ -257,7 +257,7 @@ function annotateGithubPR(prNumber, annotation) {
owner: AS_REPO_OWNER,
repo: AS_REPO_NAME,
number: prNumber,
body: annotation,
body: annotation
}).catch(reason => console.log(reason));
}
@ -271,7 +271,7 @@ function labelGithubPR(prNumber) {
owner: AS_REPO_OWNER,
repo: AS_REPO_NAME,
number: prNumber,
labels: [ALREADY_PUSHED_LABEL],
labels: [ALREADY_PUSHED_LABEL]
}).catch(reason => console.log(reason));
}

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

@ -28,8 +28,6 @@ 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",
@ -95,7 +93,6 @@ for (const type of [
"SNIPPETS_BLOCKLIST_CLEARED",
"SNIPPETS_BLOCKLIST_UPDATED",
"SNIPPETS_DATA",
"SNIPPETS_PREVIEW_MODE",
"SNIPPETS_RESET",
"SNIPPET_BLOCKED",
"SUBMIT_EMAIL",
@ -120,7 +117,7 @@ for (const type of [
"UPDATE_SEARCH_SHORTCUTS",
"UPDATE_SECTION_PREFS",
"WEBEXT_CLICK",
"WEBEXT_DISMISS",
"WEBEXT_DISMISS"
]) {
actionTypes[type] = type;
}
@ -133,7 +130,7 @@ for (const type of [
"OPEN_APPLICATIONS_MENU",
"OPEN_PRIVATE_BROWSER_WINDOW",
"OPEN_URL",
"OPEN_ABOUT_PAGE",
"OPEN_ABOUT_PAGE"
]) {
ASRouterActions[type] = type;
}
@ -171,7 +168,7 @@ function AlsoToMain(action, fromTarget, skipLocal) {
from: CONTENT_MESSAGE_TYPE,
to: MAIN_MESSAGE_TYPE,
fromTarget,
skipLocal,
skipLocal
});
}
@ -196,7 +193,7 @@ function OnlyToMain(action, fromTarget) {
function BroadcastToContent(action) {
return _RouteMessage(action, {
from: MAIN_MESSAGE_TYPE,
to: CONTENT_MESSAGE_TYPE,
to: CONTENT_MESSAGE_TYPE
});
}
@ -217,7 +214,7 @@ function AlsoToOneContent(action, target, skipMain) {
from: MAIN_MESSAGE_TYPE,
to: CONTENT_MESSAGE_TYPE,
toTarget: target,
skipMain,
skipMain
});
}
@ -242,7 +239,7 @@ function OnlyToOneContent(action, target) {
function AlsoToPreloaded(action) {
return _RouteMessage(action, {
from: MAIN_MESSAGE_TYPE,
to: PRELOAD_MESSAGE_TYPE,
to: PRELOAD_MESSAGE_TYPE
});
}
@ -256,7 +253,7 @@ function AlsoToPreloaded(action) {
function UserEvent(data) {
return AlsoToMain({
type: actionTypes.TELEMETRY_USER_EVENT,
data,
data
});
}
@ -270,7 +267,7 @@ function UserEvent(data) {
function ASRouterUserEvent(data) {
return AlsoToMain({
type: actionTypes.AS_ROUTER_TELEMETRY_USER_EVENT,
data,
data
});
}
@ -284,7 +281,7 @@ function ASRouterUserEvent(data) {
function UndesiredEvent(data, importContext = globalImportContext) {
const action = {
type: actionTypes.TELEMETRY_UNDESIRED_EVENT,
data,
data
};
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
@ -299,7 +296,7 @@ function UndesiredEvent(data, importContext = globalImportContext) {
function PerfEvent(data, importContext = globalImportContext) {
const action = {
type: actionTypes.TELEMETRY_PERFORMANCE_EVENT,
data,
data
};
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
@ -314,7 +311,7 @@ function PerfEvent(data, importContext = globalImportContext) {
function ImpressionStats(data, importContext = globalImportContext) {
const action = {
type: actionTypes.TELEMETRY_IMPRESSION_STATS,
data,
data
};
return importContext === UI_CODE ? AlsoToMain(action) : action;
}
@ -348,7 +345,7 @@ this.actionCreators = {
OnlyToMain,
AlsoToPreloaded,
SetPref,
WebExtEvent,
WebExtEvent
};
// These are helpers to test for certain kinds of actions
@ -394,7 +391,7 @@ this.actionUtils = {
getPortIdOfSender(action) {
return (action.meta && action.meta.fromTarget) || null;
},
_RouteMessage,
_RouteMessage
};
const EXPORTED_SYMBOLS = [
@ -407,5 +404,5 @@ const EXPORTED_SYMBOLS = [
"BACKGROUND_PROCESS",
"MAIN_MESSAGE_TYPE",
"CONTENT_MESSAGE_TYPE",
"PRELOAD_MESSAGE_TYPE",
"PRELOAD_MESSAGE_TYPE"
];

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

@ -22,7 +22,7 @@ if (typeof Services !== "undefined") {
// task.
usablePerfObj = {
now() {},
mark() {},
mark() {}
};
}
@ -118,7 +118,7 @@ _PerfService.prototype = {
let mostRecentEntry = entries[entries.length - 1];
return this._perf.timeOrigin + mostRecentEntry.startTime;
},
}
};
this.perfService = new _PerfService();

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

@ -63,7 +63,7 @@ this.PrerenderData = new _PrerenderData({
"feeds.section.topstories": true,
"feeds.section.highlights": true,
"sectionOrder": "topsites,topstories,highlights",
"collapsed": false,
"collapsed": 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
@ -81,7 +81,7 @@ this.PrerenderData = new _PrerenderData({
{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"]},
{indexedDB: ["collapsed"]}
],
initialSections: [
{
@ -89,16 +89,16 @@ this.PrerenderData = new _PrerenderData({
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"}
}
]
});
this._PrerenderData = _PrerenderData;

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

@ -14,12 +14,7 @@ const dedupe = new Dedupe(site => site && site.url);
const INITIAL_STATE = {
App: {
// Have we received real data from the app yet?
initialized: false,
},
ASRouter: {
initialized: false,
allowLegacyOnboarding: null,
allowLegacySnippets: null,
initialized: false
},
Snippets: {initialized: false},
TopSites: {
@ -32,22 +27,22 @@ const INITIAL_STATE = {
// Used in content only to open the SearchShortcutsForm modal.
showSearchShortcutsForm: false,
// The list of available search shortcuts.
searchShortcuts: [],
searchShortcuts: []
},
Prefs: {
initialized: false,
values: {},
values: {}
},
Dialog: {
visible: false,
data: {},
data: {}
},
Sections: [],
Pocket: {
isUserLoggedIn: null,
isUserLoggedIn: false,
pocketCta: {},
waitingForSpoc: true,
},
waitingForSpoc: true
}
};
function App(prevState = INITIAL_STATE.App, action) {
@ -59,17 +54,6 @@ function App(prevState = INITIAL_STATE.App, action) {
}
}
function ASRouter(prevState = INITIAL_STATE.ASRouter, action) {
switch (action.type) {
case at.AS_ROUTER_INITIALIZED:
return {...action.data, initialized: true};
case at.AS_ROUTER_PREF_CHANGED:
return {...prevState, ...action.data};
default:
return prevState;
}
}
/**
* insertPinned - Inserts pinned links in their specified slots
*
@ -118,8 +102,8 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
return Object.assign({}, prevState, {
editForm: {
index: action.data.index,
previewResponse: null,
},
previewResponse: null
}
});
case at.TOP_SITES_CANCEL_EDIT:
return Object.assign({}, prevState, {editForm: null});
@ -135,8 +119,8 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
editForm: {
index: prevState.editForm.index,
previewResponse: action.data.preview,
previewUrl: action.data.url,
},
previewUrl: action.data.url
}
});
case at.PREVIEW_REQUEST:
if (!prevState.editForm) {
@ -146,8 +130,8 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
editForm: {
index: prevState.editForm.index,
previewResponse: null,
previewUrl: action.data.url,
},
previewUrl: action.data.url
}
});
case at.PREVIEW_REQUEST_CANCEL:
if (!prevState.editForm) {
@ -156,8 +140,8 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
return Object.assign({}, prevState, {
editForm: {
index: prevState.editForm.index,
previewResponse: null,
},
previewResponse: null
}
});
case at.SCREENSHOT_UPDATED:
newRows = prevState.rows.map(row => {
@ -203,8 +187,6 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
return Object.assign({}, prevState, {rows: newRows});
case at.UPDATE_SEARCH_SHORTCUTS:
return {...prevState, searchShortcuts: action.data.searchShortcuts};
case at.SNIPPETS_PREVIEW_MODE:
return {...prevState, rows: []};
default:
return prevState;
}
@ -330,11 +312,11 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
bookmarkGuid,
bookmarkTitle,
bookmarkDateCreated: dateAdded,
type: "bookmark",
type: "bookmark"
});
}
return item;
}),
})
}));
case at.PLACES_SAVED_TO_POCKET:
if (!action.data) {
@ -347,11 +329,11 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
open_url: action.data.open_url,
pocket_id: action.data.pocket_id,
title: action.data.title,
type: "pocket",
type: "pocket"
});
}
return item;
}),
})
}));
case at.PLACES_BOOKMARK_REMOVED:
if (!action.data) {
@ -371,7 +353,7 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
return newSite;
}
return item;
}),
})
}));
case at.PLACES_LINK_DELETED:
case at.PLACES_LINK_BLOCKED:
@ -384,8 +366,6 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
case at.ARCHIVE_FROM_POCKET:
return prevState.map(section =>
Object.assign({}, section, {rows: section.rows.filter(site => site.pocket_id !== action.data.pocket_id)}));
case at.SNIPPETS_PREVIEW_MODE:
return prevState.map(section => ({...section, rows: []}));
default:
return prevState;
}
@ -419,8 +399,8 @@ function Pocket(prevState = INITIAL_STATE.Pocket, action) {
ctaButton: action.data.cta_button,
ctaText: action.data.cta_text,
ctaUrl: action.data.cta_url,
useCta: action.data.use_cta,
},
useCta: action.data.use_cta
}
};
default:
return prevState;
@ -431,6 +411,6 @@ this.INITIAL_STATE = INITIAL_STATE;
this.TOP_SITES_DEFAULT_ROWS = TOP_SITES_DEFAULT_ROWS;
this.TOP_SITES_MAX_SITES_PER_ROW = TOP_SITES_MAX_SITES_PER_ROW;
this.reducers = {TopSites, App, ASRouter, Snippets, Prefs, Dialog, Sections, Pocket};
this.reducers = {TopSites, App, Snippets, Prefs, Dialog, Sections, Pocket};
const EXPORTED_SYMBOLS = ["reducers", "INITIAL_STATE", "insertPinned", "TOP_SITES_DEFAULT_ROWS", "TOP_SITES_MAX_SITES_PER_ROW"];

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

@ -40,6 +40,6 @@ export function prerender(locale, strings,
return {
html,
state: store.getState(),
store,
store
};
}

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

@ -31,7 +31,7 @@ export const ASRouterUtils = {
executeAction(button_action) {
ASRouterUtils.sendMessage({
type: "USER_ACTION",
data: button_action,
data: button_action
});
},
unblockById(id) {
@ -57,13 +57,13 @@ export const ASRouterUtils = {
const endpoint = new URL(params.get("endpoint"));
return {
url: endpoint.href,
snippetId: params.get("snippetId"),
snippetId: params.get("snippetId")
};
} catch (e) {}
}
return null;
},
}
};
// Note: nextProps/prevProps refer to props passed to <ImpressionsWrapper />, not <ASRouterUISurface />
@ -84,7 +84,7 @@ const ALLOWED_TAGS = {
u: <u />,
strong: <strong />,
em: <em />,
br: <br />,
br: <br />
};
/**
@ -133,7 +133,7 @@ export class ASRouterUISurface extends React.PureComponent {
message_id: message.id || extraProps.message_id,
source: extraProps.id,
action: eventType,
...extraProps,
...extraProps
});
}
@ -150,12 +150,9 @@ export class ASRouterUISurface extends React.PureComponent {
value: event.target.dataset.metric,
// Used for the `source` of the event. Needed to differentiate
// from other snippet or onboarding events that may occur.
id: "NEWTAB_FOOTER_BAR_CONTENT",
id: "NEWTAB_FOOTER_BAR_CONTENT"
};
this.sendUserActionTelemetry({event: "CLICK_BUTTON", ...metric});
if (!this.state.message.content.do_not_autoblock) {
ASRouterUtils.blockById(this.state.message.id);
}
}
onBlockById(id) {
@ -245,28 +242,11 @@ export class ASRouterUISurface extends React.PureComponent {
sendUserActionTelemetry={this.sendUserActionTelemetry} />);
}
renderPreviewBanner() {
if (this.state.message.provider !== "preview") {
return null;
}
return (
<div className="snippets-preview-banner">
<span className="icon icon-small-spacer icon-info" />
<span>Preview Purposes Only</span>
</div>
);
}
render() {
const {message, bundle} = this.state;
if (!message.id && !bundle.template) { return null; }
return (
<div>
{this.renderPreviewBanner()}
{bundle.template === "onboarding" ? this.renderOnboarding() : this.renderSnippets()}
</div>
);
if (bundle.template === "onboarding") { return this.renderOnboarding(); }
return this.renderSnippets();
}
}

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

@ -56,5 +56,5 @@ export class ImpressionsWrapper extends React.PureComponent {
ImpressionsWrapper.defaultProps = {
document: global.document,
sendOnMount: true,
sendOnMount: true
};

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

@ -56,18 +56,3 @@
display: block;
}
}
.snippets-preview-banner {
font-size: 15px;
line-height: 42px;
color: $grey-60-70;
background: $grey-30-60;
text-align: center;
position: absolute;
top: 0;
width: 100%;
span {
vertical-align: middle;
}
}

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

@ -23,7 +23,7 @@ Field name | Type | Required | Description | Example / Note
title: "Find it faster",
body: "Access all of your favorite search engines with a click. Search the whole Web or just one website from the search box."
},
targeting: "usesFirefoxSync && !addonsInfo.addons['activity-stream@mozilla.org']",
targeting: "hasFxAccount && !addonsInfo.addons['activity-stream@mozilla.org']",
frequency: {
lifetime: 20,
custom: [{period: "daily", cap: 5}, {period: 3600000, cap: 1}]
@ -90,7 +90,7 @@ Name | Type | Example value | Description
--- | --- | --- | ---
`addonsInfo` | `Object` | [example below](#addonsinfo-example) | Information about the addons the user has installed
`devToolsOpenedCount` | `Integer` | Number of usages of the web console or scratchpad
`usesFirefoxSync` | `Boolean` | `true` | Does the user have a firefox account
`hasFxAccount` | `Boolean` | `true` | Does the user have a firefox account
`isDefaultBrowser` | `Boolean` or `null` | Is Firefox the user's default browser? If we could not determine the default browser, this value is `null`
`profileAgeCreated` | Number | `1522843725924` | Profile creation timestamp
`profileAgeReset` | `Number` or `undefined` | `1522843725924` | When (if) the profile was reset
@ -98,10 +98,6 @@ Name | Type | Example value | Description
`searchEngines` | `Object` | [example below](#searchengines-example) | Information about the current and available search engines
`browserSettings.attribution` | `Object` or `undefined` | [example below](#attribution-example) | Attribution for the source of of where the browser was downloaded.
`providerCohorts` | `Object` | `{onboarding: "hello"}` | Cohorts defined for all providers
`previousSessionEnd` | `Number` | `1536325802800` | Timestamp in milliseconds of previously closed session
`totalBookmarksCount` | `Number` | `8` | Total number of bookmarks
`firefoxVersion` | `Number` | `64` | The major Firefox version of the browser
`region` | `String` | `US` | Country code retrieved from `location.services.mozilla.com` can be `""` if request did not finish, encountered an error
#### addonsInfo Example
```javascript
@ -157,14 +153,14 @@ Examples:
"id": "7864",
"content": {...},
// simple equality check
"targeting": "usesFirefoxSync == true"
"targeting": "hasFxAccount == true"
}
{
"id": "7865",
"content": {...},
// using JEXL transforms and combining two attributes
"targeting": "usesFirefoxSync == true && profileAgeCreated > '2018-01-07'|date"
"targeting": "hasFxAccount == true && profileAgeCreated > '2018-01-07'|date"
}
{

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

@ -2,7 +2,7 @@
"title": "ProviderResponse",
"description": "A response object for remote providers of AS Router",
"type": "object",
"version": "6.1.0",
"version": "0.1.0",
"properties": {
"messages": {
"type": "array",

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

@ -8,7 +8,7 @@ export function safeURI(url) {
"https:",
"data:",
"resource:",
"chrome:",
"chrome:"
].includes(protocol);
if (!isAllowed) {
console.warn(`The protocol ${protocol} is not allowed for template URLs.`); // eslint-disable-line no-console

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

@ -44,20 +44,8 @@
"label": {
"oneOf": [
{
"type": "object",
"properties": {
"attributes": {
"type": "object",
"properties": {
"tooltiptext": {
"type": "string",
"description": "Text for button tooltip used to provide information about the doorhanger."
}
},
"required": ["tooltiptext"]
}
},
"required": ["attributes"]
"type": "string",
"description": "Text for button tooltip used to provide information about the doorhanger."
},
{
"type": "object",

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

@ -13,7 +13,7 @@ class OnboardingCard extends React.PureComponent {
event: "CLICK_BUTTON",
message_id: props.id,
id: props.UISurface,
includeClientID: true,
includeClientID: true
};
props.sendUserActionTelemetry(ping);
props.onAction(props.content.button_action);

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

@ -14,9 +14,6 @@ export class SimpleSnippet extends React.PureComponent {
onButtonClick() {
this.props.sendUserActionTelemetry({event: "CLICK_BUTTON", id: this.props.UISurface});
this.props.onAction(this.props.content.button_action);
if (!this.props.content.do_not_autoblock) {
this.props.onBlock();
}
}
renderTitle() {

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

@ -75,10 +75,6 @@
"type": "boolean",
"description": "To be used by fundraising only, increases height to roughly 120px. Defaults to false."
},
"do_not_autoblock": {
"type": "boolean",
"description": "Used to prevent blocking the snippet after the CTA (link or button) has been clicked"
},
"links": {
"additionalProperties": {
"url": {

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

@ -82,18 +82,8 @@ export class ASRouterAdmin extends React.PureComponent {
</tbody></table>);
}
renderTableHead() {
return (<thead>
<tr className="message-item">
<td>id</td>
<td>source</td>
<td>last updated</td>
</tr>
</thead>);
}
renderProviders() {
return (<table>{this.renderTableHead()}<tbody>
return (<table><tbody>
{this.state.providers.map((provider, i) => {
let label = "(local)";
if (provider.type === "remote") {
@ -104,7 +94,6 @@ export class ASRouterAdmin extends React.PureComponent {
return (<tr className="message-item" key={i}>
<td>{provider.id}</td>
<td>{label}</td>
<td>{provider.lastUpdated ? new Date(provider.lastUpdated).toString() : ""}</td>
</tr>);
})}
</tbody></table>);

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

@ -40,7 +40,8 @@ function debounce(func, wait) {
export class _Base extends React.PureComponent {
componentWillMount() {
const {locale} = this.props;
const {App, locale} = this.props;
this.sendNewTabRehydrated(App);
addLocaleDataForReactIntl(locale);
if (this.props.isFirstrun) {
global.document.body.classList.add("welcome", "hide-main");
@ -61,8 +62,29 @@ export class _Base extends React.PureComponent {
this.updateTheme();
}
componentWillUpdate() {
hasTopStoriesSectionChanged(nextProps) {
const nPropsSections = nextProps.Sections.find(section => section.id === "topstories");
const tPropsSections = this.props.Sections.find(section => section.id === "topstories");
if (nPropsSections && nPropsSections.options) {
if (!tPropsSections || !tPropsSections.options) {
return true;
}
if (nPropsSections.options.show_spocs !== tPropsSections.options.show_spocs) {
return true;
}
if (nPropsSections.options.stories_endpoint !== tPropsSections.options.stories_endpoint) {
return true;
}
}
return false;
}
componentWillUpdate(nextProps) {
this.updateTheme();
if (this.hasTopStoriesSectionChanged(nextProps)) {
this.renderNotified = false;
}
this.sendNewTabRehydrated(nextProps.App);
}
updateTheme() {
@ -71,18 +93,28 @@ export class _Base extends React.PureComponent {
// 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" : "",
document.body.classList.contains("hide-main") ? "hide-main" : ""
].filter(v => v).join(" ");
global.document.body.className = bodyClassName;
}
// 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(App) {
if (App && App.initialized && !this.renderNotified) {
this.props.dispatch(ac.AlsoToMain({type: at.NEW_TAB_REHYDRATED, data: {}}));
this.renderNotified = true;
}
}
render() {
const {props} = this;
const {App, locale, strings} = props;
const {initialized} = App;
const prefs = props.Prefs.values;
if (prefs["asrouter.devtoolsEnabled"] && window.location.hash === "#asrouter") {
if (prefs.asrouterExperimentEnabled && window.location.hash === "#asrouter") {
return (<ASRouterAdmin />);
}
@ -90,6 +122,17 @@ export class _Base extends React.PureComponent {
return null;
}
// Until we can delete the existing onboarding tour, just hide the onboarding button when users are in
// the new simplified onboarding experiment. CSS hacks ftw
let isOnboardingEnabled = false;
try {
isOnboardingEnabled = JSON.parse(prefs["asrouter.messageProviders"]).find(i => i.id === "onboarding").enabled;
} catch (e) {}
if (isOnboardingEnabled) {
global.document.body.classList.add("hide-onboarding");
}
return (<IntlProvider locale={locale} messages={strings}>
<ErrorBoundary className="base-content-fallback">
<BaseContent {...this.props} />
@ -139,7 +182,7 @@ export class BaseContent extends React.PureComponent {
const outerClassName = [
"outer-wrapper",
shouldBeFixedToTop && "fixed-to-top",
prefs.showSearch && this.state.fixedSearch && "fixed-search",
prefs.showSearch && this.state.fixedSearch && "fixed-search"
].filter(v => v).join(" ");
return (

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

@ -59,7 +59,7 @@ main {
$selectors-to-hide: '
.section-title,
.sections-list .section:last-of-type,
.topics
.topic
';
#{$selectors-to-hide} {

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

@ -26,7 +26,7 @@ export class _Card extends React.PureComponent {
activeCard: null,
imageLoaded: false,
showContextMenu: false,
cardImage: null,
cardImage: null
};
this.onMenuButtonClick = this.onMenuButtonClick.bind(this);
this.onMenuUpdate = this.onMenuUpdate.bind(this);
@ -108,7 +108,7 @@ export class _Card extends React.PureComponent {
event.preventDefault();
this.setState({
activeCard: this.props.index,
showContextMenu: true,
showContextMenu: true
});
}
@ -129,33 +129,33 @@ export class _Card extends React.PureComponent {
if (this.props.link.type === "download") {
this.props.dispatch(ac.OnlyToMain({
type: at.SHOW_DOWNLOAD_FILE,
data: this.props.link,
data: this.props.link
}));
} else {
const {altKey, button, ctrlKey, metaKey, shiftKey} = event;
this.props.dispatch(ac.OnlyToMain({
type: at.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(ac.WebExtEvent(at.WEBEXT_CLICK, {
source: this.props.eventSource,
url: this.props.link.url,
action_position: this.props.index,
action_position: this.props.index
}));
} else {
this.props.dispatch(ac.UserEvent(Object.assign({
event: "CLICK",
source: this.props.eventSource,
action_position: this.props.index,
action_position: this.props.index
}, this._getTelemetryInfo())));
if (this.props.shouldSendImpressionStats) {
this.props.dispatch(ac.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}]
}));
}
}
@ -209,7 +209,7 @@ export class _Card extends React.PureComponent {
"card-outer",
className,
isContextMenuOpen && "active",
props.placeholder && "placeholder",
props.placeholder && "placeholder"
].filter(v => v).join(" ");
return (<li className={outerClassName}>
@ -231,7 +231,7 @@ export class _Card extends React.PureComponent {
"card-text",
icon ? "" : "no-context",
link.description ? "" : "no-description",
link.hostname ? "" : "no-host-name",
link.hostname ? "" : "no-host-name"
].join(" ")}>
<h4 className="card-title" dir="auto">{link.title}</h4>
<p className="card-description" dir="auto">{link.description}</p>

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

@ -1,26 +1,26 @@
export const cardContextTypes = {
history: {
intlID: "type_label_visited",
icon: "history-item",
icon: "history-item"
},
bookmark: {
intlID: "type_label_bookmarked",
icon: "bookmark-added",
icon: "bookmark-added"
},
trending: {
intlID: "type_label_recommended",
icon: "trending",
icon: "trending"
},
now: {
intlID: "type_label_now",
icon: "now",
icon: "now"
},
pocket: {
intlID: "type_label_pocket",
icon: "pocket",
icon: "pocket"
},
download: {
intlID: "type_label_downloaded",
icon: "download",
},
icon: "download"
}
};

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

@ -69,13 +69,13 @@ export class _CollapsibleSection extends React.PureComponent {
// Get the current height of the body so max-height transitions can work
this.setState({
isAnimating: true,
maxHeight: `${this.sectionBody.scrollHeight}px`,
maxHeight: `${this.sectionBody.scrollHeight}px`
});
const {action, userEvent} = SectionMenuOptions.CheckCollapsed(this.props);
this.props.dispatch(action);
this.props.dispatch(ac.UserEvent({
event: userEvent,
source: this.props.source,
source: this.props.source
}));
}
@ -186,9 +186,9 @@ _CollapsibleSection.defaultProps = {
document: global.document || {
addEventListener: () => {},
removeEventListener: () => {},
visibilityState: "hidden",
visibilityState: "hidden"
},
Prefs: {values: {}},
Prefs: {values: {}}
};
export const CollapsibleSection = injectIntl(_CollapsibleSection);

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

@ -120,7 +120,7 @@ export class ComponentPerfTimer extends React.Component {
this.props.dispatch(ac.OnlyToMain({
type: at.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`
@ -144,7 +144,7 @@ export class ComponentPerfTimer extends React.Component {
this.props.dispatch(ac.OnlyToMain({
type: at.SAVE_SESSION_PERF_DATA,
data,
data
}));
} catch (ex) {
// If this failed, it's likely because the `privacy.resistFingerprinting`

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

@ -25,7 +25,7 @@ export class _LinkMenu extends React.PureComponent {
const userEventData = Object.assign({
event: userEvent,
source,
action_position: index,
action_position: index
}, siteInfo);
props.dispatch(ac.UserEvent(userEventData));
}

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

@ -30,7 +30,7 @@ export class _SectionMenu extends React.PureComponent {
if (userEvent) {
props.dispatch(ac.UserEvent({
event: userEvent,
source: props.source,
source: props.source
}));
}
};

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

@ -1,6 +1,6 @@
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
import {Card, PlaceholderCard} from "content-src/components/Card/Card";
import {FormattedMessage, injectIntl} from "react-intl";
import {actionCreators as ac} from "common/Actions.jsm";
import {CollapsibleSection} from "content-src/components/CollapsibleSection/CollapsibleSection";
import {ComponentPerfTimer} from "content-src/components/ComponentPerfTimer/ComponentPerfTimer";
import {connect} from "react-redux";
@ -40,7 +40,7 @@ export class Section extends React.PureComponent {
if (this.needsImpressionStats(cards)) {
props.dispatch(ac.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);
}
@ -78,10 +78,6 @@ export class Section extends React.PureComponent {
}
}
componentWillMount() {
this.sendNewTabRehydrated(this.props.initialized);
}
componentDidMount() {
if (this.props.rows.length && !this.props.pref.collapsed) {
this.sendImpressionStatsOrAddListener();
@ -107,10 +103,6 @@ export class Section extends React.PureComponent {
}
}
componentWillUpdate(nextProps) {
this.sendNewTabRehydrated(nextProps.initialized);
}
componentWillUnmount() {
if (this._onVisibilityChange) {
this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
@ -131,22 +123,12 @@ export class Section extends React.PureComponent {
return false;
}
// 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(ac.AlsoToMain({type: at.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,
pref, privacyNoticeURL, isFirst, isLast
} = this.props;
const waitingForSpoc = id === "topstories" && this.props.Pocket.waitingForSpoc;
@ -155,21 +137,14 @@ export class Section extends React.PureComponent {
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,
// to avoid a flash of logged out state while we render.
const isPocketLoggedInDefined = (isUserLoggedIn === true || isUserLoggedIn === false);
const shouldShowPocketCta = (id === "topstories" &&
useCta && isUserLoggedIn === false);
Pocket.pocketCta.useCta && !Pocket.isUserLoggedIn);
// 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.
// Show topics only for top stories and if it's not initialized yet (so
// content doesn't shift when it is loaded) or has loaded with topics
const shouldShowTopics = (id === "topstories" &&
(topics && topics.length > 0) &&
((useCta && isUserLoggedIn === true) || (!useCta && isPocketLoggedInDefined)));
(!topics || topics.length > 0) &&
!shouldShowPocketCta);
const realRows = rows.slice(0, maxCards);
@ -208,7 +183,7 @@ export class Section extends React.PureComponent {
const sectionClassName = [
"section",
compactCards ? "compact-cards" : "normal-cards",
compactCards ? "compact-cards" : "normal-cards"
].join(" ");
// <Section> <-- React component
@ -259,7 +234,7 @@ Section.defaultProps = {
rows: [],
emptyState: {},
pref: {},
title: "",
title: ""
};
export const SectionIntl = connect(state => ({Prefs: state.Prefs, Pocket: state.Pocket}))(injectIntl(Section));
@ -276,7 +251,7 @@ export class _Sections extends React.PureComponent {
const commonProps = {
key: sectionId,
isFirst: sections.length === 0,
isLast: sections.length === expectedCount - 1,
isLast: sections.length === expectedCount - 1
};
if (sectionId === "topsites" && showTopSites) {
sections.push(<TopSites {...commonProps} />);

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

@ -83,7 +83,6 @@
@media (min-width: $break-point-large) {
line-height: 16px;
height: 16px;
}
// This is a clearfix to for the more-recommendations link which is floating and causes

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

@ -17,7 +17,7 @@ export class _StartupOverlay extends React.PureComponent {
emailInput: "",
overlayRemoved: false,
flowId: "",
flowBeginTime: 0,
flowBeginTime: 0
};
this.didFetch = false;
}
@ -33,7 +33,7 @@ export class _StartupOverlay extends React.PureComponent {
this.setState({flowId, flowBeginTime});
}
} catch (error) {
this.props.dispatch(ac.OnlyToMain({type: at.TELEMETRY_UNDESIRED_EVENT, data: {event: "FXA_METRICS_ERROR"}}));
this.props.dispatch(ac.OnlyToMain({type: at.TELEMETRY_UNDESIRED_EVENT, data: {value: "FXA_METRICS_ERROR"}}));
}
}
}
@ -124,7 +124,7 @@ export class _StartupOverlay extends React.PureComponent {
id="firstrun_extra_legal_links"
values={{
terms: termsLink,
privacy: privacyLink,
privacy: privacyLink
}} />
</div>
<button className="continue-button" type="submit"><FormattedMessage id="firstrun_continue_to_login" /></button>

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

@ -41,7 +41,7 @@ export class SearchShortcutsForm extends React.PureComponent {
searchShortcuts.forEach(shortcut => {
shortcuts.push({
...shortcut,
isSelected: !!rows.find(row => row && row.isPinned && row.searchTopSite && row.label === shortcut.keyword),
isSelected: !!rows.find(row => row && row.isPinned && row.searchTopSite && row.label === shortcut.keyword)
});
});
this.state = {shortcuts};
@ -84,8 +84,8 @@ export class SearchShortcutsForm extends React.PureComponent {
type: at.UPDATE_PINNED_SEARCH_SHORTCUTS,
data: {
addedShortcuts: pinQueue,
deletedShortcuts: unpinQueue,
},
deletedShortcuts: unpinQueue
}
}));
// Send the Telemetry pings.
@ -93,14 +93,14 @@ export class SearchShortcutsForm extends React.PureComponent {
this.props.dispatch(ac.UserEvent({
source: TOP_SITES_SOURCE,
event: "SEARCH_EDIT_ADD",
value: {search_vendor: shortcut.searchVendor},
value: {search_vendor: shortcut.searchVendor}
}));
});
unpinQueue.forEach(shortcut => {
this.props.dispatch(ac.UserEvent({
source: TOP_SITES_SOURCE,
event: "SEARCH_EDIT_DELETE",
value: {search_vendor: shortcut.searchVendor},
value: {search_vendor: shortcut.searchVendor}
}));
});
@ -112,7 +112,7 @@ export class SearchShortcutsForm extends React.PureComponent {
url: shortcut.url,
searchTopSite: true,
label: shortcut.keyword,
searchVendor: shortcut.shortURL,
searchVendor: shortcut.shortURL
};
}

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

@ -5,7 +5,7 @@ import {
MIN_RICH_FAVICON_SIZE,
TOP_SITES_CONTEXT_MENU_OPTIONS,
TOP_SITES_SEARCH_SHORTCUTS_CONTEXT_MENU_OPTIONS,
TOP_SITES_SOURCE,
TOP_SITES_SOURCE
} from "./TopSitesConstants";
import {LinkMenu} from "content-src/components/LinkMenu/LinkMenu";
import React from "react";
@ -139,7 +139,7 @@ export class TopSiteLink extends React.PureComponent {
imageClassName = "top-site-icon rich-icon";
imageStyle = {
backgroundColor: link.backgroundColor,
backgroundImage: `url(${tippyTopIcon})`,
backgroundImage: `url(${tippyTopIcon})`
};
smallFaviconStyle = {backgroundImage: `url(${tippyTopIcon})`};
} else if (link.customScreenshotURL) {
@ -147,14 +147,14 @@ export class TopSiteLink extends React.PureComponent {
imageClassName = "top-site-icon rich-icon";
imageStyle = {
backgroundColor: link.backgroundColor,
backgroundImage: hasScreenshotImage ? `url(${this.state.screenshotImage.url})` : "none",
backgroundImage: hasScreenshotImage ? `url(${this.state.screenshotImage.url})` : "none"
};
} else if (tippyTopIcon || faviconSize >= MIN_RICH_FAVICON_SIZE) {
// styles and class names for top sites with rich icons
imageClassName = "top-site-icon rich-icon";
imageStyle = {
backgroundColor: link.backgroundColor,
backgroundImage: `url(${tippyTopIcon || link.favicon})`,
backgroundImage: `url(${tippyTopIcon || link.favicon})`
};
} else {
// styles and class names for top sites with screenshot + small icon in top left corner
@ -178,7 +178,7 @@ export class TopSiteLink extends React.PureComponent {
onClick: this.onDragEvent,
onDragEnd: this.onDragEvent,
onDragStart: this.onDragEvent,
onMouseDown: this.onDragEvent,
onMouseDown: this.onDragEvent
};
}
return (<li className={topSiteOuterClassName} onDrop={this.onDragEvent} onDragOver={this.onDragEvent} onDragEnter={this.onDragEvent} onDragLeave={this.onDragEvent} {...draggableProps}>
@ -205,7 +205,7 @@ export class TopSiteLink extends React.PureComponent {
TopSiteLink.defaultProps = {
title: "",
link: {},
isDraggable: true,
isDraggable: true
};
export class TopSite extends React.PureComponent {
@ -238,7 +238,7 @@ export class TopSite extends React.PureComponent {
this.props.dispatch(ac.UserEvent(Object.assign({
event,
source: TOP_SITES_SOURCE,
action_position: this.props.index,
action_position: this.props.index
}, this._getTelemetryInfo())));
}
@ -252,12 +252,12 @@ export class TopSite extends React.PureComponent {
if (!this.props.link.searchTopSite) {
this.props.dispatch(ac.OnlyToMain({
type: at.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(ac.OnlyToMain({
type: at.FILL_SEARCH_TERM,
data: {label: this.props.link.label},
data: {label: this.props.link.label}
}));
}
}
@ -300,7 +300,7 @@ export class TopSite extends React.PureComponent {
}
TopSite.defaultProps = {
link: {},
onActivate() {},
onActivate() {}
};
export class TopSitePlaceholder extends React.PureComponent {
@ -330,7 +330,7 @@ export class _TopSiteList extends React.PureComponent {
draggedIndex: null,
draggedSite: null,
draggedTitle: null,
topSitesPreview: null,
topSitesPreview: null
};
}
@ -358,7 +358,7 @@ export class _TopSiteList extends React.PureComponent {
this.props.dispatch(ac.UserEvent({
event,
source: TOP_SITES_SOURCE,
action_position: index,
action_position: index
}));
}
@ -370,7 +370,7 @@ export class _TopSiteList extends React.PureComponent {
draggedIndex: index,
draggedSite: link,
draggedTitle: title,
activeIndex: null,
activeIndex: null
});
this.userEvent("DRAG", index);
break;
@ -398,11 +398,11 @@ export class _TopSiteList extends React.PureComponent {
label: this.state.draggedTitle,
customScreenshotURL: this.state.draggedSite.customScreenshotURL,
// Only if the search topsites experiment is enabled
...(this.state.draggedSite.searchTopSite && {searchTopSite: true}),
...(this.state.draggedSite.searchTopSite && {searchTopSite: true})
},
index,
draggedFromIndex: this.state.draggedIndex,
},
draggedFromIndex: this.state.draggedIndex
}
}));
this.userEvent("DROP", index);
}
@ -470,7 +470,7 @@ export class _TopSiteList extends React.PureComponent {
const commonProps = {
onDragEvent: this.onDragEvent,
dispatch: props.dispatch,
intl: props.intl,
intl: props.intl
};
// 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
@ -486,7 +486,7 @@ export class _TopSiteList extends React.PureComponent {
const link = topSites[i] && Object.assign({}, topSites[i], {iconType: this.props.topSiteIconType(topSites[i])});
const slotProps = {
key: link ? link.url : holeIndex++,
index: i,
index: i
};
if (i >= maxNarrowVisibleIndex) {
slotProps.className = "hide-for-narrow";

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

@ -14,7 +14,7 @@ export class TopSiteForm extends React.PureComponent {
url: site ? site.url : "",
validationError: false,
customScreenshotUrl: site ? site.customScreenshotURL : "",
showCustomScreenshotForm: site ? site.customScreenshotURL : false,
showCustomScreenshotForm: site ? site.customScreenshotURL : false
};
this.onClearScreenshotInput = this.onClearScreenshotInput.bind(this);
this.onLabelChange = this.onLabelChange.bind(this);
@ -35,14 +35,14 @@ export class TopSiteForm extends React.PureComponent {
onUrlChange(event) {
this.setState({
url: event.target.value,
validationError: false,
validationError: false
});
}
onClearUrlClick() {
this.setState({
url: "",
validationError: false,
validationError: false
});
}
@ -53,7 +53,7 @@ export class TopSiteForm extends React.PureComponent {
_updateCustomScreenshotInput(customScreenshotUrl) {
this.setState({
customScreenshotUrl,
validationError: false,
validationError: false
});
this.props.dispatch({type: at.PREVIEW_REQUEST_CANCEL});
}
@ -89,12 +89,12 @@ export class TopSiteForm extends React.PureComponent {
}
this.props.dispatch(ac.AlsoToMain({
type: at.TOP_SITES_PIN,
data: {site, index},
data: {site, index}
}));
this.props.dispatch(ac.UserEvent({
source: TOP_SITES_SOURCE,
event: "TOP_SITES_EDIT",
action_position: index,
action_position: index
}));
this.props.onClose();
@ -106,11 +106,11 @@ export class TopSiteForm extends React.PureComponent {
if (this.validateForm()) {
this.props.dispatch(ac.AlsoToMain({
type: at.PREVIEW_REQUEST,
data: {url: this.cleanUrl(this.state.customScreenshotUrl)},
data: {url: this.cleanUrl(this.state.customScreenshotUrl)}
}));
this.props.dispatch(ac.UserEvent({
source: TOP_SITES_SOURCE,
event: "PREVIEW_REQUEST",
event: "PREVIEW_REQUEST"
}));
}
}
@ -247,5 +247,5 @@ export class TopSiteForm extends React.PureComponent {
TopSiteForm.defaultProps = {
site: null,
index: -1,
index: -1
};

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

@ -62,5 +62,5 @@ export class TopSiteFormInput extends React.PureComponent {
TopSiteFormInput.defaultProps = {
showClearButton: false,
value: "",
validationError: false,
validationError: false
};

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

@ -46,7 +46,7 @@ function countTopSitesIconsTypes(topSites) {
"screenshot": 0,
"tippytop": 0,
"rich_icon": 0,
"no_image": 0,
"no_image": 0
});
}
@ -71,8 +71,8 @@ export class _TopSites extends React.PureComponent {
data: {
topsites_icon_stats: topSitesIconsStats,
topsites_pinned: topSitesPinned,
topsites_search_shortcuts: searchShortcuts,
},
topsites_search_shortcuts: searchShortcuts
}
}));
}
@ -100,7 +100,7 @@ export class _TopSites extends React.PureComponent {
onEditFormClose() {
this.props.dispatch(ac.UserEvent({
source: TOP_SITES_SOURCE,
event: "TOP_SITES_EDIT_CLOSE",
event: "TOP_SITES_EDIT_CLOSE"
}));
this.props.dispatch({type: at.TOP_SITES_CANCEL_EDIT});
}
@ -108,7 +108,7 @@ export class _TopSites extends React.PureComponent {
onSearchShortcutsFormClose() {
this.props.dispatch(ac.UserEvent({
source: TOP_SITES_SOURCE,
event: "SEARCH_EDIT_CLOSE",
event: "SEARCH_EDIT_CLOSE"
}));
this.props.dispatch({type: at.TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL});
}
@ -169,5 +169,5 @@ export class _TopSites extends React.PureComponent {
export const TopSites = connect(state => ({
TopSites: state.TopSites,
Prefs: state.Prefs,
TopSitesRows: state.Prefs.values.topSitesRows,
TopSitesRows: state.Prefs.values.topSitesRows
}))(injectIntl(_TopSites));

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

@ -1,25 +1,11 @@
export function enableASRouterContent(store, asrouterContent) {
let didHideOnboarding = false;
// Enable asrouter content
store.subscribe(() => {
const state = store.getState();
if (!state.ASRouter.initialized) {
return;
}
if (!asrouterContent.initialized) {
if (state.Prefs.values.asrouterExperimentEnabled && !asrouterContent.initialized) {
asrouterContent.init();
}
// Until we can delete the existing onboarding tour, just hide the onboarding button when users are in
// the new simplified onboarding experiment. CSS hacks ftw
if (state.ASRouter.allowLegacyOnboarding === false && !didHideOnboarding) {
global.document.body.classList.add("hide-onboarding");
didHideOnboarding = true;
} else if (state.ASRouter.allowLegacyOnboarding === true && didHideOnboarding) {
global.document.body.classList.remove("hide-onboarding");
didHideOnboarding = false;
} else if (!state.Prefs.values.asrouterExperimentEnabled && asrouterContent.initialized) {
asrouterContent.uninit();
}
});
// Return this for testing purposes

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

@ -44,7 +44,7 @@ export class DetectUserSessionStart {
this._store.dispatch(ac.AlsoToMain({
type: at.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`

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

@ -5,9 +5,9 @@ const _OpenInPrivateWindow = site => ({
icon: "new-window-private",
action: ac.OnlyToMain({
type: at.OPEN_PRIVATE_WINDOW,
data: {url: site.url, referrer: site.referrer},
data: {url: site.url, referrer: site.referrer}
}),
userEvent: "OPEN_PRIVATE_WINDOW",
userEvent: "OPEN_PRIVATE_WINDOW"
});
export const GetPlatformString = platform => {
@ -36,18 +36,18 @@ export const LinkMenuOptions = {
icon: "bookmark-added",
action: ac.AlsoToMain({
type: at.DELETE_BOOKMARK_BY_ID,
data: site.bookmarkGuid,
data: site.bookmarkGuid
}),
userEvent: "BOOKMARK_DELETE",
userEvent: "BOOKMARK_DELETE"
}),
AddBookmark: site => ({
id: "menu_action_bookmark",
icon: "bookmark-hollow",
action: ac.AlsoToMain({
type: at.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",
userEvent: "BOOKMARK_ADD"
}),
OpenInNewWindow: site => ({
id: "menu_action_open_new_window",
@ -57,24 +57,24 @@ export const LinkMenuOptions = {
data: {
referrer: site.referrer,
typedBonus: site.typedBonus,
url: site.url,
},
url: site.url
}
}),
userEvent: "OPEN_NEW_WINDOW",
userEvent: "OPEN_NEW_WINDOW"
}),
BlockUrl: (site, index, eventSource) => ({
id: "menu_action_dismiss",
icon: "dismiss",
action: ac.AlsoToMain({
type: at.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: ac.ImpressionStats({
source: eventSource,
block: 0,
tiles: [{id: site.guid, pos: index}],
tiles: [{id: site.guid, pos: index}]
}),
userEvent: "BLOCK",
userEvent: "BLOCK"
}),
// This is an option for web extentions which will result in remove items from
@ -86,8 +86,8 @@ export const LinkMenuOptions = {
action: ac.WebExtEvent(at.WEBEXT_DISMISS, {
source: eventSource,
url: site.url,
action_position: index,
}),
action_position: index
})
}),
DeleteUrl: (site, index, eventSource, isEnabled, siteInfo) => ({
id: "menu_action_delete",
@ -97,57 +97,57 @@ export const LinkMenuOptions = {
data: {
onConfirm: [
ac.AlsoToMain({type: at.DELETE_HISTORY_URL, data: {url: site.url, pocket_id: site.pocket_id, forceBlock: site.bookmarkGuid}}),
ac.UserEvent(Object.assign({event: "DELETE", source: eventSource, action_position: index}, siteInfo)),
ac.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",
cancel_button_string_id: "topsites_form_cancel_button",
icon: "modal-delete",
},
icon: "modal-delete"
}
},
userEvent: "DIALOG_OPEN",
userEvent: "DIALOG_OPEN"
}),
ShowFile: (site, index, eventSource, isEnabled, siteInfo, platform) => ({
id: GetPlatformString(platform),
icon: "search",
action: ac.OnlyToMain({
type: at.SHOW_DOWNLOAD_FILE,
data: {url: site.url},
}),
data: {url: site.url}
})
}),
OpenFile: site => ({
id: "menu_action_open_file",
icon: "open-file",
action: ac.OnlyToMain({
type: at.OPEN_DOWNLOAD_FILE,
data: {url: site.url},
}),
data: {url: site.url}
})
}),
CopyDownloadLink: site => ({
id: "menu_action_copy_download_link",
icon: "copy",
action: ac.OnlyToMain({
type: at.COPY_DOWNLOAD_LINK,
data: {url: site.url},
}),
data: {url: site.url}
})
}),
GoToDownloadPage: site => ({
id: "menu_action_go_to_download_page",
icon: "download",
action: ac.OnlyToMain({
type: at.OPEN_LINK,
data: {url: site.referrer},
data: {url: site.referrer}
}),
disabled: !site.referrer,
disabled: !site.referrer
}),
RemoveDownload: site => ({
id: "menu_action_remove_download",
icon: "delete",
action: ac.OnlyToMain({
type: at.REMOVE_DOWNLOAD_FILE,
data: {url: site.url},
}),
data: {url: site.url}
})
}),
PinTopSite: ({url, searchTopSite, label}, index) => ({
id: "menu_action_pin",
@ -157,65 +157,65 @@ export const LinkMenuOptions = {
data: {
site: {
url,
...(searchTopSite && {searchTopSite, label}),
...(searchTopSite && {searchTopSite, label})
},
index,
},
index
}
}),
userEvent: "PIN",
userEvent: "PIN"
}),
UnpinTopSite: site => ({
id: "menu_action_unpin",
icon: "unpin",
action: ac.AlsoToMain({
type: at.TOP_SITES_UNPIN,
data: {site: {url: site.url}},
data: {site: {url: site.url}}
}),
userEvent: "UNPIN",
userEvent: "UNPIN"
}),
SaveToPocket: (site, index, eventSource) => ({
id: "menu_action_save_to_pocket",
icon: "pocket-save",
action: ac.AlsoToMain({
type: at.SAVE_TO_POCKET,
data: {site: {url: site.url, title: site.title}},
data: {site: {url: site.url, title: site.title}}
}),
impression: ac.ImpressionStats({
source: eventSource,
pocket: 0,
tiles: [{id: site.guid, pos: index}],
tiles: [{id: site.guid, pos: index}]
}),
userEvent: "SAVE_TO_POCKET",
userEvent: "SAVE_TO_POCKET"
}),
DeleteFromPocket: site => ({
id: "menu_action_delete_pocket",
icon: "delete",
action: ac.AlsoToMain({
type: at.DELETE_FROM_POCKET,
data: {pocket_id: site.pocket_id},
data: {pocket_id: site.pocket_id}
}),
userEvent: "DELETE_FROM_POCKET",
userEvent: "DELETE_FROM_POCKET"
}),
ArchiveFromPocket: site => ({
id: "menu_action_archive_pocket",
icon: "check",
action: ac.AlsoToMain({
type: at.ARCHIVE_FROM_POCKET,
data: {pocket_id: site.pocket_id},
data: {pocket_id: site.pocket_id}
}),
userEvent: "ARCHIVE_FROM_POCKET",
userEvent: "ARCHIVE_FROM_POCKET"
}),
EditTopSite: (site, index) => ({
id: "edit_topsites_button_text",
icon: "edit",
action: {
type: at.TOP_SITES_EDIT,
data: {index},
},
data: {index}
}
}),
CheckBookmark: site => (site.bookmarkGuid ? LinkMenuOptions.RemoveBookmark(site) : LinkMenuOptions.AddBookmark(site)),
CheckPinTopSite: (site, index) => (site.isPinned ? LinkMenuOptions.UnpinTopSite(site) : LinkMenuOptions.PinTopSite(site, index)),
CheckSavedToPocket: (site, index) => (site.pocket_id ? LinkMenuOptions.DeleteFromPocket(site) : LinkMenuOptions.SaveToPocket(site, index)),
CheckBookmarkOrArchive: site => (site.pocket_id ? LinkMenuOptions.ArchiveFromPocket(site) : LinkMenuOptions.CheckBookmark(site)),
OpenInPrivateWindow: (site, index, eventSource, isEnabled) => (isEnabled ? _OpenInPrivateWindow(site) : LinkMenuOptions.EmptyItem()),
OpenInPrivateWindow: (site, index, eventSource, isEnabled) => (isEnabled ? _OpenInPrivateWindow(site) : LinkMenuOptions.EmptyItem())
};

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

@ -46,5 +46,5 @@ export const ScreenshotUtils = {
// This will only handle the remaining three possible outcomes.
// (i.e. everything except when both image and localImage are present)
return !remoteImage && !localImage;
},
}
};

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

@ -11,70 +11,70 @@ export const SectionMenuOptions = {
icon: "arrowhead-up",
action: ac.OnlyToMain({
type: at.SECTION_MOVE,
data: {id: section.id, direction: -1},
data: {id: section.id, direction: -1}
}),
userEvent: "MENU_MOVE_UP",
disabled: !!section.isFirst,
disabled: !!section.isFirst
}),
MoveDown: section => ({
id: "section_menu_action_move_down",
icon: "arrowhead-down",
action: ac.OnlyToMain({
type: at.SECTION_MOVE,
data: {id: section.id, direction: +1},
data: {id: section.id, direction: +1}
}),
userEvent: "MENU_MOVE_DOWN",
disabled: !!section.isLast,
disabled: !!section.isLast
}),
RemoveSection: section => ({
id: "section_menu_action_remove_section",
icon: "dismiss",
action: ac.SetPref(section.showPrefName, false),
userEvent: "MENU_REMOVE",
userEvent: "MENU_REMOVE"
}),
CollapseSection: section => ({
id: "section_menu_action_collapse_section",
icon: "minimize",
action: ac.OnlyToMain({type: at.UPDATE_SECTION_PREFS, data: {id: section.id, value: {collapsed: true}}}),
userEvent: "MENU_COLLAPSE",
userEvent: "MENU_COLLAPSE"
}),
ExpandSection: section => ({
id: "section_menu_action_expand_section",
icon: "maximize",
action: ac.OnlyToMain({type: at.UPDATE_SECTION_PREFS, data: {id: section.id, value: {collapsed: false}}}),
userEvent: "MENU_EXPAND",
userEvent: "MENU_EXPAND"
}),
ManageSection: section => ({
id: "section_menu_action_manage_section",
icon: "settings",
action: ac.OnlyToMain({type: at.SETTINGS_OPEN}),
userEvent: "MENU_MANAGE",
userEvent: "MENU_MANAGE"
}),
ManageWebExtension: section => ({
id: "section_menu_action_manage_webext",
icon: "settings",
action: ac.OnlyToMain({type: at.OPEN_WEBEXT_SETTINGS, data: section.id}),
action: ac.OnlyToMain({type: at.OPEN_WEBEXT_SETTINGS, data: section.id})
}),
AddTopSite: section => ({
id: "section_menu_action_add_topsite",
icon: "add",
action: {type: at.TOP_SITES_EDIT, data: {index: -1}},
userEvent: "MENU_ADD_TOPSITE",
userEvent: "MENU_ADD_TOPSITE"
}),
AddSearchShortcut: section => ({
id: "section_menu_action_add_search_engine",
icon: "search",
action: {type: at.TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL},
userEvent: "MENU_ADD_SEARCH",
userEvent: "MENU_ADD_SEARCH"
}),
PrivacyNotice: section => ({
id: "section_menu_action_privacy_notice",
icon: "info",
action: ac.OnlyToMain({
type: at.OPEN_LINK,
data: {url: section.privacyNoticeURL},
data: {url: section.privacyNoticeURL}
}),
userEvent: "MENU_PRIVACY_NOTICE",
userEvent: "MENU_PRIVACY_NOTICE"
}),
CheckCollapsed: section => (section.collapsed ? SectionMenuOptions.ExpandSection(section) : SectionMenuOptions.CollapseSection(section)),
CheckCollapsed: section => (section.collapsed ? SectionMenuOptions.ExpandSection(section) : SectionMenuOptions.CollapseSection(section))
};

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

@ -313,7 +313,7 @@ export class SnippetsProvider {
Object.assign(this, {
appData: {},
elementId: "snippets",
connect: true,
connect: true
}, options);
// Add listener so we know when snippets are blocked on other pages
@ -381,25 +381,17 @@ export function addSnippetsSubscriber(store) {
store.subscribe(async () => {
const state = store.getState();
/**
* Sorry this code is so complicated. It will be removed soon.
* This is what the different values actually mean:
*
* ASRouter.initialized Is ASRouter.jsm initialised?
* ASRouter.allowLegacySnippets Are ASRouter snippets turned OFF (i.e. legacy snippets are allowed)
* state.Prefs.values["feeds.snippets"] User preference for snippets
* state.Snippets.initialized Is SnippetsFeed.jsm initialised?
* snippets.initialized Is in-content snippets currently initialised?
* state.Prefs.values.disableSnippets This pref is used to disable legacy snippets in an emergency
* in a way that is not user-editable (true = disabled)
*/
/** If we should initialize snippets... */
if (
state.Prefs.values["feeds.snippets"] &&
state.ASRouter.initialized &&
state.ASRouter.allowLegacySnippets &&
let snippetsEnabled = false;
try {
snippetsEnabled = JSON.parse(state.Prefs.values["asrouter.messageProviders"]).find(i => i.id === "snippets").enabled;
} catch (e) {}
const isASRouterEnabled = state.Prefs.values.asrouterExperimentEnabled && snippetsEnabled;
// state.Prefs.values["feeds.snippets"]: Should snippets be shown?
// state.Snippets.initialized Is the snippets data initialized?
// snippets.initialized: Is SnippetsProvider currently initialised?
if (state.Prefs.values["feeds.snippets"] &&
// If the message center experiment is enabled, don't show snippets
!isASRouterEnabled &&
!state.Prefs.values.disableSnippets &&
state.Snippets.initialized &&
!snippets.initialized &&
@ -409,27 +401,13 @@ export function addSnippetsSubscriber(store) {
) {
initializing = true;
await snippets.init({appData: state.Snippets});
// istanbul ignore if
if (state.Prefs.values["asrouter.devtoolsEnabled"]) {
console.log("Legacy snippets initialized"); // eslint-disable-line no-console
}
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)
) &&
(state.Prefs.values["feeds.snippets"] === false ||
state.Prefs.values.disableSnippets === true) &&
snippets.initialized
) {
// Remove snippets
snippets.uninit();
// istanbul ignore if
if (state.Prefs.values["asrouter.devtoolsEnabled"]) {
console.log("Legacy snippets removed"); // eslint-disable-line no-console
}
}
});

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

@ -27,7 +27,6 @@ $grey-10-95: rgba($grey-10, 0.95);
$grey-20-60: rgba($grey-20, 0.6);
$grey-20-80: rgba($grey-20, 0.8);
$grey-30-60: rgba($grey-30, 0.6);
$grey-60-70: rgba($grey-60, 0.7);
$grey-80-95: rgba($grey-80, 0.95);
$grey-90-10: rgba($grey-90, 0.1);
$grey-90-20: rgba($grey-90, 0.2);

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

@ -362,13 +362,13 @@ main {
.body-wrapper .section-title,
.body-wrapper .sections-list .section:last-of-type,
.body-wrapper .topics {
.body-wrapper .topic {
opacity: 0; }
.body-wrapper.on .section-title,
.body-wrapper.on .sections-list .section:last-of-type,
.body-wrapper.on .topics {
.body-wrapper.on .topic {
opacity: 1; }
.non-collapsible-section {
@ -922,8 +922,7 @@ main {
font-size: 13px; }
@media (min-width: 866px) {
.top-stories-bottom-container {
line-height: 16px;
height: 16px; } }
line-height: 16px; } }
.top-stories-bottom-container::after {
clear: both;
content: '';
@ -1920,18 +1919,6 @@ a.firstrun-link {
.SnippetBaseContainer:hover .blockButton {
display: block; }
.snippets-preview-banner {
font-size: 15px;
line-height: 42px;
color: rgba(74, 74, 79, 0.7);
background: rgba(215, 215, 219, 0.6);
text-align: center;
position: absolute;
top: 0;
width: 100%; }
.snippets-preview-banner span {
vertical-align: middle; }
.activity-stream.modal-open {
overflow: hidden; }

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

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

@ -365,13 +365,13 @@ main {
.body-wrapper .section-title,
.body-wrapper .sections-list .section:last-of-type,
.body-wrapper .topics {
.body-wrapper .topic {
opacity: 0; }
.body-wrapper.on .section-title,
.body-wrapper.on .sections-list .section:last-of-type,
.body-wrapper.on .topics {
.body-wrapper.on .topic {
opacity: 1; }
.non-collapsible-section {
@ -925,8 +925,7 @@ main {
font-size: 13px; }
@media (min-width: 866px) {
.top-stories-bottom-container {
line-height: 16px;
height: 16px; } }
line-height: 16px; } }
.top-stories-bottom-container::after {
clear: both;
content: '';
@ -1923,18 +1922,6 @@ a.firstrun-link {
.SnippetBaseContainer:hover .blockButton {
display: block; }
.snippets-preview-banner {
font-size: 15px;
line-height: 42px;
color: rgba(74, 74, 79, 0.7);
background: rgba(215, 215, 219, 0.6);
text-align: center;
position: absolute;
top: 0;
width: 100%; }
.snippets-preview-banner span {
vertical-align: middle; }
.activity-stream.modal-open {
overflow: hidden; }

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

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

@ -362,13 +362,13 @@ main {
.body-wrapper .section-title,
.body-wrapper .sections-list .section:last-of-type,
.body-wrapper .topics {
.body-wrapper .topic {
opacity: 0; }
.body-wrapper.on .section-title,
.body-wrapper.on .sections-list .section:last-of-type,
.body-wrapper.on .topics {
.body-wrapper.on .topic {
opacity: 1; }
.non-collapsible-section {
@ -922,8 +922,7 @@ main {
font-size: 13px; }
@media (min-width: 866px) {
.top-stories-bottom-container {
line-height: 16px;
height: 16px; } }
line-height: 16px; } }
.top-stories-bottom-container::after {
clear: both;
content: '';
@ -1920,18 +1919,6 @@ a.firstrun-link {
.SnippetBaseContainer:hover .blockButton {
display: block; }
.snippets-preview-banner {
font-size: 15px;
line-height: 42px;
color: rgba(74, 74, 79, 0.7);
background: rgba(215, 215, 219, 0.6);
text-align: center;
position: absolute;
top: 0;
width: 100%; }
.snippets-preview-banner span {
vertical-align: middle; }
.activity-stream.modal-open {
overflow: hidden; }

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

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

@ -211,7 +211,7 @@ const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS :
// }
const actionTypes = {};
for (const type of ["ADDONS_INFO_REQUEST", "ADDONS_INFO_RESPONSE", "ARCHIVE_FROM_POCKET", "AS_ROUTER_INITIALIZED", "AS_ROUTER_PREF_CHANGED", "AS_ROUTER_TELEMETRY_USER_EVENT", "BLOCK_URL", "BOOKMARK_URL", "COPY_DOWNLOAD_LINK", "DELETE_BOOKMARK_BY_ID", "DELETE_FROM_POCKET", "DELETE_HISTORY_URL", "DIALOG_CANCEL", "DIALOG_OPEN", "DISABLE_ONBOARDING", "DOWNLOAD_CHANGED", "FILL_SEARCH_TERM", "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", "SKIPPED_SIGNIN", "SNIPPETS_BLOCKLIST_CLEARED", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "SNIPPETS_PREVIEW_MODE", "SNIPPETS_RESET", "SNIPPET_BLOCKED", "SUBMIT_EMAIL", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_CANCEL_EDIT", "TOP_SITES_CLOSE_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_EDIT", "TOP_SITES_INSERT", "TOP_SITES_OPEN_SEARCH_SHORTCUTS_MODAL", "TOP_SITES_PIN", "TOP_SITES_PREFS_UPDATED", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "TOTAL_BOOKMARKS_REQUEST", "TOTAL_BOOKMARKS_RESPONSE", "UNINIT", "UPDATE_PINNED_SEARCH_SHORTCUTS", "UPDATE_SEARCH_SHORTCUTS", "UPDATE_SECTION_PREFS", "WEBEXT_CLICK", "WEBEXT_DISMISS"]) {
for (const type of ["ADDONS_INFO_REQUEST", "ADDONS_INFO_RESPONSE", "ARCHIVE_FROM_POCKET", "AS_ROUTER_TELEMETRY_USER_EVENT", "BLOCK_URL", "BOOKMARK_URL", "COPY_DOWNLOAD_LINK", "DELETE_BOOKMARK_BY_ID", "DELETE_FROM_POCKET", "DELETE_HISTORY_URL", "DIALOG_CANCEL", "DIALOG_OPEN", "DISABLE_ONBOARDING", "DOWNLOAD_CHANGED", "FILL_SEARCH_TERM", "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", "SKIPPED_SIGNIN", "SNIPPETS_BLOCKLIST_CLEARED", "SNIPPETS_BLOCKLIST_UPDATED", "SNIPPETS_DATA", "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;
}
@ -885,40 +885,26 @@ function addSnippetsSubscriber(store) {
store.subscribe(_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:
*
* ASRouter.initialized Is ASRouter.jsm initialised?
* ASRouter.allowLegacySnippets Are ASRouter snippets turned OFF (i.e. legacy snippets are allowed)
* state.Prefs.values["feeds.snippets"] User preference for snippets
* state.Snippets.initialized Is SnippetsFeed.jsm initialised?
* snippets.initialized Is in-content snippets currently initialised?
* state.Prefs.values.disableSnippets This pref is used to disable legacy snippets in an emergency
* in a way that is not user-editable (true = disabled)
*/
/** 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 &&
let snippetsEnabled = false;
try {
snippetsEnabled = JSON.parse(state.Prefs.values["asrouter.messageProviders"]).find(function (i) {
return i.id === "snippets";
}).enabled;
} catch (e) {}
const isASRouterEnabled = state.Prefs.values.asrouterExperimentEnabled && snippetsEnabled;
// state.Prefs.values["feeds.snippets"]: Should snippets be shown?
// state.Snippets.initialized Is the snippets data initialized?
// snippets.initialized: Is SnippetsProvider currently initialised?
if (state.Prefs.values["feeds.snippets"] &&
// If the message center experiment is enabled, don't show snippets
!isASRouterEnabled && !state.Prefs.values.disableSnippets && state.Snippets.initialized && !snippets.initialized &&
// Don't call init multiple times
!initializing && location.href !== "about:welcome") {
initializing = true;
yield snippets.init({ appData: state.Snippets });
// istanbul ignore if
if (state.Prefs.values["asrouter.devtoolsEnabled"]) {
console.log("Legacy snippets initialized"); // eslint-disable-line no-console
}
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
} else if ((state.Prefs.values["feeds.snippets"] === false || state.Prefs.values.disableSnippets === true) && snippets.initialized) {
snippets.uninit();
// istanbul ignore if
if (state.Prefs.values["asrouter.devtoolsEnabled"]) {
console.log("Legacy snippets removed"); // eslint-disable-line no-console
}
}
}));
@ -1109,9 +1095,6 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_6___default.a.Pur
id: "NEWTAB_FOOTER_BAR_CONTENT"
};
this.sendUserActionTelemetry(Object.assign({ event: "CLICK_BUTTON" }, metric));
if (!this.state.message.content.do_not_autoblock) {
ASRouterUtils.blockById(this.state.message.id);
}
}
onBlockById(id) {
@ -1201,34 +1184,15 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_6___default.a.Pur
sendUserActionTelemetry: this.sendUserActionTelemetry }));
}
renderPreviewBanner() {
if (this.state.message.provider !== "preview") {
return null;
}
return react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
"div",
{ className: "snippets-preview-banner" },
react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement("span", { className: "icon icon-small-spacer icon-info" }),
react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
"span",
null,
"Preview Purposes Only"
)
);
}
render() {
const { message, bundle } = this.state;
if (!message.id && !bundle.template) {
return null;
}
return react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
"div",
null,
this.renderPreviewBanner(),
bundle.template === "onboarding" ? this.renderOnboarding() : this.renderSnippets()
);
if (bundle.template === "onboarding") {
return this.renderOnboarding();
}
return this.renderSnippets();
}
}
@ -1602,7 +1566,8 @@ function debounce(func, wait) {
class _Base extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
componentWillMount() {
const { locale } = this.props;
const { App, locale } = this.props;
this.sendNewTabRehydrated(App);
addLocaleDataForReactIntl(locale);
if (this.props.isFirstrun) {
global.document.body.classList.add("welcome", "hide-main");
@ -1623,8 +1588,29 @@ class _Base extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
this.updateTheme();
}
componentWillUpdate() {
hasTopStoriesSectionChanged(nextProps) {
const nPropsSections = nextProps.Sections.find(section => section.id === "topstories");
const tPropsSections = this.props.Sections.find(section => section.id === "topstories");
if (nPropsSections && nPropsSections.options) {
if (!tPropsSections || !tPropsSections.options) {
return true;
}
if (nPropsSections.options.show_spocs !== tPropsSections.options.show_spocs) {
return true;
}
if (nPropsSections.options.stories_endpoint !== tPropsSections.options.stories_endpoint) {
return true;
}
}
return false;
}
componentWillUpdate(nextProps) {
this.updateTheme();
if (this.hasTopStoriesSectionChanged(nextProps)) {
this.renderNotified = false;
}
this.sendNewTabRehydrated(nextProps.App);
}
updateTheme() {
@ -1635,13 +1621,23 @@ class _Base extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
global.document.body.className = bodyClassName;
}
// 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(App) {
if (App && App.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.renderNotified = true;
}
}
render() {
const { props } = this;
const { App, locale, strings } = props;
const { initialized } = App;
const prefs = props.Prefs.values;
if (prefs["asrouter.devtoolsEnabled"] && window.location.hash === "#asrouter") {
if (prefs.asrouterExperimentEnabled && window.location.hash === "#asrouter") {
return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(content_src_components_ASRouterAdmin_ASRouterAdmin__WEBPACK_IMPORTED_MODULE_2__["ASRouterAdmin"], null);
}
@ -1649,6 +1645,17 @@ class _Base extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
return null;
}
// Until we can delete the existing onboarding tour, just hide the onboarding button when users are in
// the new simplified onboarding experiment. CSS hacks ftw
let isOnboardingEnabled = false;
try {
isOnboardingEnabled = JSON.parse(prefs["asrouter.messageProviders"]).find(i => i.id === "onboarding").enabled;
} catch (e) {}
if (isOnboardingEnabled) {
global.document.body.classList.add("hide-onboarding");
}
return react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(
react_intl__WEBPACK_IMPORTED_MODULE_1__["IntlProvider"],
{ locale: locale, messages: strings },
@ -1882,37 +1889,10 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
);
}
renderTableHead() {
return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"thead",
null,
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"tr",
{ className: "message-item" },
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"td",
null,
"id"
),
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"td",
null,
"source"
),
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"td",
null,
"last updated"
)
)
);
}
renderProviders() {
return react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"table",
null,
this.renderTableHead(),
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"tbody",
null,
@ -1939,11 +1919,6 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
"td",
null,
label
),
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
"td",
null,
provider.lastUpdated ? new Date(provider.lastUpdated).toString() : ""
)
);
})
@ -2505,10 +2480,10 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SectionIntl", function() { return SectionIntl; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "_Sections", function() { return _Sections; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Sections", function() { return Sections; });
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(47);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(13);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var content_src_components_Card_Card__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(47);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(13);
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var common_Actions_jsm__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
/* harmony import */ var content_src_components_CollapsibleSection_CollapsibleSection__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(27);
/* harmony import */ var content_src_components_ComponentPerfTimer_ComponentPerfTimer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(30);
/* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(16);
@ -2543,7 +2518,7 @@ function getFormattedMessage(message) {
"span",
null,
message
) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_2__["FormattedMessage"], message);
) : react__WEBPACK_IMPORTED_MODULE_8___default.a.createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__["FormattedMessage"], message);
}
class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
@ -2565,7 +2540,7 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
const cards = props.rows.slice(0, maxCards);
if (this.needsImpressionStats(cards)) {
props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].ImpressionStats({
props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_2__["actionCreators"].ImpressionStats({
source: props.eventSource,
tiles: cards.map(link => ({ id: link.guid }))
}));
@ -2605,10 +2580,6 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
}
}
componentWillMount() {
this.sendNewTabRehydrated(this.props.initialized);
}
componentDidMount() {
if (this.props.rows.length && !this.props.pref.collapsed) {
this.sendImpressionStatsOrAddListener();
@ -2631,10 +2602,6 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
}
}
componentWillUpdate(nextProps) {
this.sendNewTabRehydrated(nextProps.initialized);
}
componentWillUnmount() {
if (this._onVisibilityChange) {
this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
@ -2655,16 +2622,6 @@ 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
// 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.renderNotified = true;
}
}
render() {
const {
id, eventSource, title, icon, rows, Pocket, topics,
@ -2679,18 +2636,11 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
const maxCards = maxCardsPerRow * numRows;
const maxCardsOnNarrow = CARDS_PER_ROW_DEFAULT * numRows;
const { pocketCta, isUserLoggedIn } = Pocket || {};
const { useCta } = pocketCta || {};
const shouldShowPocketCta = id === "topstories" && Pocket.pocketCta.useCta && !Pocket.isUserLoggedIn;
// 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 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" && topics && topics.length > 0 && (useCta && isUserLoggedIn === true || !useCta && isPocketLoggedInDefined);
// Show topics only for top stories and if it's not initialized yet (so
// content doesn't shift when it is loaded) or has loaded with topics
const shouldShowTopics = id === "topstories" && (!topics || topics.length > 0) && !shouldShowPocketCta;
const realRows = rows.slice(0, maxCards);
@ -2711,7 +2661,7 @@ class Section extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent
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_0__["Card"], { key: i,
index: i,
className: className,
dispatch: dispatch,
@ -2719,7 +2669,7 @@ 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_0__["PlaceholderCard"], { key: i, className: className }));
}
}
@ -2784,7 +2734,7 @@ Section.defaultProps = {
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_1__["injectIntl"])(Section));
class _Sections extends react__WEBPACK_IMPORTED_MODULE_8___default.a.PureComponent {
renderSections() {
@ -5114,7 +5064,7 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
_this.setState({ flowId, flowBeginTime });
}
} 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: { value: "FXA_METRICS_ERROR" } }));
}
}
})();
@ -5357,35 +5307,20 @@ class DetectUserSessionStart {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* WEBPACK VAR INJECTION */(function(global) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "enableASRouterContent", function() { return enableASRouterContent; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "enableASRouterContent", function() { return enableASRouterContent; });
function enableASRouterContent(store, asrouterContent) {
let didHideOnboarding = false;
// Enable asrouter content
store.subscribe(() => {
const state = store.getState();
if (!state.ASRouter.initialized) {
return;
}
if (!asrouterContent.initialized) {
if (state.Prefs.values.asrouterExperimentEnabled && !asrouterContent.initialized) {
asrouterContent.init();
}
// Until we can delete the existing onboarding tour, just hide the onboarding button when users are in
// the new simplified onboarding experiment. CSS hacks ftw
if (state.ASRouter.allowLegacyOnboarding === false && !didHideOnboarding) {
global.document.body.classList.add("hide-onboarding");
didHideOnboarding = true;
} else if (state.ASRouter.allowLegacyOnboarding === true && didHideOnboarding) {
global.document.body.classList.remove("hide-onboarding");
didHideOnboarding = false;
} else if (!state.Prefs.values.asrouterExperimentEnabled && asrouterContent.initialized) {
asrouterContent.uninit();
}
});
// Return this for testing purposes
return { asrouterContent };
}
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(1)))
/***/ }),
/* 42 */
@ -8094,9 +8029,6 @@ class SimpleSnippet_SimpleSnippet extends external_React_default.a.PureComponent
onButtonClick() {
this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", id: this.props.UISurface });
this.props.onAction(this.props.content.button_action);
if (!this.props.content.do_not_autoblock) {
this.props.onBlock();
}
}
renderTitle() {
@ -8224,11 +8156,6 @@ const INITIAL_STATE = {
// Have we received real data from the app yet?
initialized: false
},
ASRouter: {
initialized: false,
allowLegacyOnboarding: null,
allowLegacySnippets: null
},
Snippets: { initialized: false },
TopSites: {
// Have we received real data from history yet?
@ -8252,7 +8179,7 @@ const INITIAL_STATE = {
},
Sections: [],
Pocket: {
isUserLoggedIn: null,
isUserLoggedIn: false,
pocketCta: {},
waitingForSpoc: true
}
@ -8268,17 +8195,6 @@ 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 });
case Actions["actionTypes"].AS_ROUTER_PREF_CHANGED:
return Object.assign({}, prevState, action.data);
default:
return prevState;
}
}
/**
* insertPinned - Inserts pinned links in their specified slots
*
@ -8415,8 +8331,6 @@ function TopSites(prevState = INITIAL_STATE.TopSites, action) {
return Object.assign({}, prevState, { rows: newRows });
case Actions["actionTypes"].UPDATE_SEARCH_SHORTCUTS:
return Object.assign({}, prevState, { searchShortcuts: action.data.searchShortcuts });
case Actions["actionTypes"].SNIPPETS_PREVIEW_MODE:
return Object.assign({}, prevState, { rows: [] });
default:
return prevState;
}
@ -8594,8 +8508,6 @@ function Sections(prevState = INITIAL_STATE.Sections, action) {
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) }));
case Actions["actionTypes"].SNIPPETS_PREVIEW_MODE:
return prevState.map(section => Object.assign({}, section, { rows: [] }));
default:
return prevState;
}
@ -8636,7 +8548,7 @@ function Pocket(prevState = INITIAL_STATE.Pocket, action) {
}
}
var reducers = { TopSites, App, ASRouter, Snippets, Prefs, Dialog, Sections, Pocket };
var reducers = { TopSites, App, Snippets, Prefs, Dialog, Sections, Pocket };
/***/ }),
/* 46 */

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

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

@ -13,7 +13,7 @@ const PATHS = {
// a RegEx matching all Cu.import statements of local files
resourcePathRegEx: /^resource:\/\/activity-stream\//,
coverageReportingPath: "logs/coverage/",
coverageReportingPath: "logs/coverage/"
};
// When tweaking here, be sure to review the docs about the execution ordering
@ -21,7 +21,7 @@ const PATHS = {
const preprocessors = {};
preprocessors[PATHS.testFilesPattern] = [
"webpack", // require("karma-webpack")
"sourcemap", // require("karma-sourcemap-loader")
"sourcemap" // require("karma-sourcemap-loader")
];
module.exports = function(config) {
@ -33,17 +33,17 @@ module.exports = function(config) {
customLaunchers: {
FirefoxHeadless: {
base: "Firefox",
flags: ["--headless"],
},
flags: ["--headless"]
}
},
frameworks: [
"chai", // require("chai") require("karma-chai")
"mocha", // require("mocha") require("karma-mocha")
"sinon", // require("sinon") require("karma-sinon")
"sinon" // require("sinon") require("karma-sinon")
],
reporters: [
"coverage", // require("karma-coverage")
"mocha", // require("karma-mocha-reporter")
"mocha" // require("karma-mocha-reporter")
],
coverageReporter: {
dir: PATHS.coverageReportingPath,
@ -53,14 +53,14 @@ module.exports = function(config) {
statements: 100,
lines: 100,
functions: 100,
branches: 90,
},
branches: 90
}
},
reporters: [
{type: "html", subdir: "report-html"},
{type: "text", subdir: ".", file: "text.txt"},
{type: "text-summary", subdir: ".", file: "text-summary.txt"},
],
{type: "text-summary", subdir: ".", file: "text-summary.txt"}
]
},
files: [PATHS.testEntryFile],
preprocessors,
@ -74,15 +74,15 @@ module.exports = function(config) {
extensions: [".js", ".jsx"],
modules: [
PATHS.moduleResolveDirectory,
"node_modules",
],
"node_modules"
]
},
externals: {
// enzyme needs these for backwards compatibility with 0.13.
// see https://github.com/airbnb/enzyme/blob/master/docs/guides/webpack.md#using-enzyme-with-webpack
"react/addons": true,
"react/lib/ReactContext": true,
"react/lib/ExecutionEnvironment": true,
"react/lib/ExecutionEnvironment": true
},
module: {
rules: [
@ -98,10 +98,10 @@ module.exports = function(config) {
["jsm-to-commonjs", {basePath: PATHS.resourcePathRegEx, replace: true}], // require("babel-plugin-jsm-to-commonjs")
["transform-async-to-module-method", {module: "co-task", method: "async"}], // require("babel-plugin-transform-async-to-module-method")
"transform-es2015-modules-commonjs", // require("babel-plugin-transform-es2015-modules-commonjs")
["transform-object-rest-spread", {"useBuiltIns": true}], // require("babel-plugin-transform-object-rest-spread")
],
},
}],
["transform-object-rest-spread", {"useBuiltIns": true}] // require("babel-plugin-transform-object-rest-spread")
]
}
}]
},
{
test: /\.js$/,
@ -114,10 +114,10 @@ module.exports = function(config) {
"transform-es2015-modules-commonjs",
["transform-object-rest-spread", {"useBuiltIns": true}],
["transform-async-to-generator"],
["transform-async-generator-functions"],
],
},
}],
["transform-async-generator-functions"]
]
}
}]
},
{
test: /\.jsx$/,
@ -125,8 +125,8 @@ module.exports = function(config) {
loader: "babel-loader",
options: {
presets: ["react"], // require("babel-preset-react")
plugins: [["transform-object-rest-spread", {"useBuiltIns": true}]],
},
plugins: [["transform-object-rest-spread", {"useBuiltIns": true}]]
}
},
{
enforce: "post",
@ -135,7 +135,7 @@ module.exports = function(config) {
include: [
path.resolve("content-src"),
path.resolve("lib"),
path.resolve("common"),
path.resolve("common")
],
exclude: [
path.resolve("test"),
@ -144,13 +144,13 @@ module.exports = function(config) {
path.resolve("lib/ASRouterTriggerListeners.jsm"),
path.resolve("lib/OnboardingMessageProvider.jsm"),
path.resolve("lib/CFRMessageProvider.jsm"),
path.resolve("lib/CFRPageActions.jsm"),
],
},
],
},
path.resolve("lib/CFRPageActions.jsm")
]
}
]
}
},
// Silences some overly-verbose logging of individual module builds
webpackMiddleware: {noInfo: true},
webpackMiddleware: {noInfo: true}
});
};

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

@ -8,16 +8,14 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
XPCOMUtils.defineLazyModuleGetters(this, {
AddonManager: "resource://gre/modules/AddonManager.jsm",
UITour: "resource:///modules/UITour.jsm",
UITour: "resource:///modules/UITour.jsm"
});
const {ASRouterActions: ra, actionTypes: at, actionCreators: ac} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
const {ASRouterActions: ra, actionCreators: ac} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
const {CFRMessageProvider} = ChromeUtils.import("resource://activity-stream/lib/CFRMessageProvider.jsm", {});
const {OnboardingMessageProvider} = ChromeUtils.import("resource://activity-stream/lib/OnboardingMessageProvider.jsm", {});
const {RemoteSettings} = ChromeUtils.import("resource://services-settings/remote-settings.js", {});
const {CFRPageActions} = ChromeUtils.import("resource://activity-stream/lib/CFRPageActions.jsm", {});
ChromeUtils.defineModuleGetter(this, "ASRouterPreferences",
"resource://activity-stream/lib/ASRouterPreferences.jsm");
ChromeUtils.defineModuleGetter(this, "ASRouterTargeting",
"resource://activity-stream/lib/ASRouterTargeting.jsm");
ChromeUtils.defineModuleGetter(this, "ASRouterTriggerListeners",
@ -25,25 +23,22 @@ ChromeUtils.defineModuleGetter(this, "ASRouterTriggerListeners",
const INCOMING_MESSAGE_NAME = "ASRouter:child-to-parent";
const OUTGOING_MESSAGE_NAME = "ASRouter:parent-to-child";
const MESSAGE_PROVIDER_PREF = "browser.newtabpage.activity-stream.asrouter.messageProviders";
const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;
// List of hosts for endpoints that serve router messages.
// Key is allowed host, value is a name for the endpoint host.
const DEFAULT_WHITELIST_HOSTS = {
"activity-stream-icons.services.mozilla.com": "production",
"snippets-admin.mozilla.org": "preview",
"snippets-admin.mozilla.org": "preview"
};
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
const SNIPPETS_ENDPOINT_WHITELIST = "browser.newtab.activity-stream.asrouter.whitelistHosts";
// Max possible impressions cap for any message
const MAX_MESSAGE_LIFETIME_CAP = 100;
const LOCAL_MESSAGE_PROVIDERS = {OnboardingMessageProvider, CFRMessageProvider};
const STARTPAGE_VERSION = "6";
const STARTPAGE_VERSION = "0.1.0";
const MessageLoaderUtils = {
STARTPAGE_VERSION,
REMOTE_LOADER_CACHE_KEY: "RemoteLoaderCache",
/**
* _localLoader - Loads messages for a local provider (i.e. one that lives in mozilla central)
*
@ -55,74 +50,26 @@ const MessageLoaderUtils = {
return provider.messages;
},
async _remoteLoaderCache(storage) {
let allCached;
try {
allCached = await storage.get(MessageLoaderUtils.REMOTE_LOADER_CACHE_KEY) || {};
} catch (e) {
// istanbul ignore next
Cu.reportError(e);
// istanbul ignore next
allCached = {};
}
return allCached;
},
/**
* _remoteLoader - Loads messages for a remote provider
*
* @param {obj} provider An AS router provider
* @param {string} provider.url An endpoint that returns an array of messages as JSON
* @param {obj} storage A storage object with get() and set() methods for caching.
* @returns {Promise} resolves with an array of messages, or an empty array if none could be fetched
*/
async _remoteLoader(provider, storage) {
async _remoteLoader(provider) {
let remoteMessages = [];
if (provider.url) {
const allCached = await MessageLoaderUtils._remoteLoaderCache(storage);
const cached = allCached[provider.id];
let etag;
if (cached && cached.url === provider.url && cached.version === STARTPAGE_VERSION) {
const {lastFetched, messages} = cached;
if (!MessageLoaderUtils.shouldProviderUpdate({...provider, lastUpdated: lastFetched})) {
// Cached messages haven't expired, return early.
return messages;
}
etag = cached.etag;
remoteMessages = messages;
}
let headers = new Headers();
if (etag) {
headers.set("If-None-Match", etag);
}
try {
const response = await fetch(provider.url, {headers});
const response = await fetch(provider.url);
if (
// Empty response
response.status !== 204 &&
// Not modified
response.status !== 304 &&
(response.ok || response.status === 302)
) {
remoteMessages = (await response.json())
.messages
.map(msg => ({...msg, provider_url: provider.url}));
// Cache the results if this isn't a preview URL.
if (provider.updateCycleInMs > 0) {
etag = response.headers.get("ETag");
const cacheInfo = {
messages: remoteMessages,
etag,
lastFetched: Date.now(),
version: STARTPAGE_VERSION,
};
storage.set(MessageLoaderUtils.REMOTE_LOADER_CACHE_KEY, {...allCached, [provider.id]: cacheInfo});
}
}
} catch (e) {
Cu.reportError(e);
@ -190,19 +137,13 @@ const MessageLoaderUtils = {
*
* @param {obj} provider An AS Router provider
* @param {string} provider.type An AS Router provider type (defaults to "local")
* @param {obj} storage A storage object with get() and set() methods for caching.
* @returns {obj} Returns an object with .messages (an array of messages) and .lastUpdated (the time the messages were updated)
*/
async loadMessagesForProvider(provider, storage) {
const loader = this._getMessageLoader(provider);
let messages = await loader(provider, storage);
// istanbul ignore if
if (!messages) {
messages = [];
Cu.reportError(new Error(`Tried to load messages for ${provider.id} but the result was not an Array.`));
}
async loadMessagesForProvider(provider) {
const messages = (await this._getMessageLoader(provider)(provider))
.map(msg => ({...msg, provider: provider.id}));
const lastUpdated = Date.now();
return {messages: messages.map(msg => ({...msg, provider: provider.id})), lastUpdated};
return {messages, lastUpdated};
},
async installAddonFromURL(browser, url) {
@ -213,27 +154,7 @@ const MessageLoaderUtils = {
await AddonManager.installAddonFromWebpage("application/x-xpinstall", browser,
systemPrincipal, install);
} catch (e) {}
},
/**
* cleanupCache - Removes cached data of removed providers.
*
* @param {Array} providers A list of activer AS Router providers
*/
async cleanupCache(providers, storage) {
const ids = providers.filter(p => p.type === "remote").map(p => p.id);
const cache = await MessageLoaderUtils._remoteLoaderCache(storage);
let dirty = false;
for (let id in cache) {
if (!ids.includes(id)) {
delete cache[id];
dirty = true;
}
}
if (dirty) {
await storage.set(MessageLoaderUtils.REMOTE_LOADER_CACHE_KEY, cache);
}
},
}
};
this.MessageLoaderUtils = MessageLoaderUtils;
@ -247,7 +168,7 @@ this.MessageLoaderUtils = MessageLoaderUtils;
* so that it can be more easily unit tested.
*/
class _ASRouter {
constructor(localProviders = LOCAL_MESSAGE_PROVIDERS) {
constructor(messageProviderPref = MESSAGE_PROVIDER_PREF, localProviders = LOCAL_MESSAGE_PROVIDERS) {
this.initialized = false;
this.messageChannel = null;
this.dispatchToAS = null;
@ -260,53 +181,41 @@ class _ASRouter {
providerBlockList: [],
messageImpressions: {},
providerImpressions: {},
messages: [],
messages: []
};
this._triggerHandler = this._triggerHandler.bind(this);
this._messageProviderPref = messageProviderPref;
this._localProviders = localProviders;
this.onMessage = this.onMessage.bind(this);
this._handleTargetingError = this._handleTargetingError.bind(this);
this.onPrefChange = this.onPrefChange.bind(this);
}
/**
* Turns legacy onboarding off or on using the ONBOARDING_FINISHED_PREF.
* This is required since ASRouter also shows snippets and onboarding, which
* interferes with legacy onboarding.
*
* Note that when this pref is true, legacy onboarding does NOT show up;
* when it is false, iegacy onboarding may show up if the profile age etc.
* is appropriate for the user to see it.
*/
overrideOrEnableLegacyOnboarding() {
const {allowLegacyOnboarding} = ASRouterPreferences.specialConditions;
const onboardingFinished = Services.prefs.getBoolPref(ONBOARDING_FINISHED_PREF, true);
if (!allowLegacyOnboarding && onboardingFinished === false) {
Services.prefs.setBoolPref(ONBOARDING_FINISHED_PREF, true);
} else if (allowLegacyOnboarding && onboardingFinished === true) {
Services.prefs.setBoolPref(ONBOARDING_FINISHED_PREF, false);
}
}
// Update message providers and fetch new messages on pref change
async onPrefChange() {
this._updateMessageProviders();
this.overrideOrEnableLegacyOnboarding();
async observe(aSubject, aTopic, aPrefName) {
if (aPrefName === this._messageProviderPref) {
this._updateMessageProviders();
}
await this.loadMessagesFromAllProviders();
this.dispatchToAS(ac.BroadcastToContent({type: at.AS_ROUTER_PREF_CHANGED, data: ASRouterPreferences.specialConditions}));
}
// Fetch and decode the message provider pref JSON, and update the message providers
_updateMessageProviders() {
const providers = [
// If we have added a `preview` provider, hold onto it
...this.state.providers.filter(p => p.id === "preview"),
...ASRouterPreferences.providers.filter(p => p.enabled),
].map(_provider => {
// make a copy so we don't modify the source of the pref
const provider = {..._provider};
// If we have added a `preview` provider, hold onto it
const existingPreviewProvider = this.state.providers.find(p => p.id === "preview");
const providers = existingPreviewProvider ? [existingPreviewProvider] : [];
const providersJSON = Services.prefs.getStringPref(this._messageProviderPref, "");
try {
JSON.parse(providersJSON).forEach(provider => {
if (provider.enabled) {
providers.push(provider);
}
});
} catch (e) {
Cu.reportError("Problem parsing JSON message provider pref for ASRouter");
}
providers.forEach(provider => {
if (provider.type === "local" && !provider.messages) {
// Get the messages from the local message provider
const localProvider = this._localProviders[provider.localProvider];
@ -318,14 +227,13 @@ class _ASRouter {
}
// Reset provider update timestamp to force message refresh
provider.lastUpdated = undefined;
return provider;
});
const providerIDs = providers.map(p => p.id);
this.setState(prevState => ({
providers,
// Clear any messages from removed providers
messages: [...prevState.messages.filter(message => providerIDs.includes(message.provider))],
messages: [...prevState.messages.filter(message => providerIDs.includes(message.provider))]
}));
}
@ -367,7 +275,7 @@ class _ASRouter {
let newState = {messages: [], providers: []};
for (const provider of this.state.providers) {
if (needsUpdate.includes(provider)) {
const {messages, lastUpdated} = await MessageLoaderUtils.loadMessagesForProvider(provider, this._storage);
const {messages, lastUpdated} = await MessageLoaderUtils.loadMessagesForProvider(provider);
newState.providers.push({...provider, lastUpdated});
newState.messages = [...newState.messages, ...messages];
} else {
@ -410,45 +318,30 @@ class _ASRouter {
async init(channel, storage, dispatchToAS) {
this.messageChannel = channel;
this.messageChannel.addMessageListener(INCOMING_MESSAGE_NAME, this.onMessage);
Services.prefs.addObserver(this._messageProviderPref, this);
this._storage = storage;
this.WHITELIST_HOSTS = this._loadSnippetsWhitelistHosts();
this.dispatchToAS = dispatchToAS;
this.dispatch = this.dispatch.bind(this);
ASRouterPreferences.init();
ASRouterPreferences.addListener(this.onPrefChange);
const messageBlockList = await this._storage.get("messageBlockList") || [];
const providerBlockList = await this._storage.get("providerBlockList") || [];
const messageImpressions = await this._storage.get("messageImpressions") || {};
const providerImpressions = await this._storage.get("providerImpressions") || {};
const previousSessionEnd = await this._storage.get("previousSessionEnd") || 0;
await this.setState({messageBlockList, providerBlockList, messageImpressions, providerImpressions, previousSessionEnd});
await this.setState({messageBlockList, providerBlockList, messageImpressions, providerImpressions});
this._updateMessageProviders();
this.overrideOrEnableLegacyOnboarding();
await this.loadMessagesFromAllProviders();
await MessageLoaderUtils.cleanupCache(this.state.providers, storage);
// set necessary state in the rest of AS
this.dispatchToAS(ac.BroadcastToContent({type: at.AS_ROUTER_INITIALIZED, data: ASRouterPreferences.specialConditions}));
// sets .initialized to true and resolves .waitForInitialized promise
this._finishInitializing();
}
uninit() {
this._storage.set("previousSessionEnd", Date.now());
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "CLEAR_ALL"});
this.messageChannel.removeMessageListener(INCOMING_MESSAGE_NAME, this.onMessage);
this.messageChannel = null;
this.dispatchToAS = null;
this.overrideOrEnableLegacyOnboarding();
ASRouterPreferences.removeListener(this.onPrefChange);
ASRouterPreferences.uninit();
Services.prefs.removeObserver(this._messageProviderPref, this);
// Uninitialise all trigger listeners
for (const listener of ASRouterTriggerListeners.values()) {
listener.uninit();
@ -472,9 +365,7 @@ class _ASRouter {
}
_onStateChanged(state) {
if (ASRouterPreferences.devtoolsEnabled) {
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: this.state});
}
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: state});
}
_handleTargetingError(type, error, message) {
@ -484,28 +375,17 @@ class _ASRouter {
message_id: message.id,
action: "asrouter_undesired_event",
event: "TARGETING_EXPRESSION_ERROR",
value: type,
value: type
}));
}
}
// Return an object containing targeting parameters used to select messages
_getMessagesContext() {
const {previousSessionEnd} = this.state;
return {
get previousSessionEnd() {
return previousSessionEnd;
},
};
}
_findMessage(candidateMessages, trigger) {
const messages = candidateMessages.filter(m => this.isBelowFrequencyCaps(m));
const context = this._getMessagesContext();
// Find a message that matches the targeting context as well as the trigger context (if one is provided)
// If no trigger is provided, we should find a message WITHOUT a trigger property defined.
return ASRouterTargeting.findMatchingMessage({messages, trigger, context, onError: this._handleTargetingError});
return ASRouterTargeting.findMatchingMessage({messages, trigger, onError: this._handleTargetingError});
}
_orderBundle(bundle) {
@ -735,7 +615,7 @@ class _ASRouter {
// We don't want to cache preview messages, remove them after we selected the message to show
await this.setState(state => ({
lastMessageId: message.id,
messages: state.messages.filter(m => m.id !== message.id),
messages: state.messages.filter(m => m.id !== message.id)
}));
} else {
await this.setState({lastMessageId: message ? message.id : null});
@ -825,11 +705,9 @@ class _ASRouter {
return state;
}
async _addPreviewEndpoint(url, portID) {
// When you view a preview snippet we want to hide all real content
async _addPreviewEndpoint(url) {
const providers = [...this.state.providers];
if (this._validPreviewEndpoint(url) && !providers.find(p => p.url === url)) {
this.dispatchToAS(ac.OnlyToOneContent({type: at.SNIPPETS_PREVIEW_MODE}, portID));
providers.push({id: "preview", type: "remote", url, updateCycleInMs: 0});
await this.setState({providers});
}
@ -844,7 +722,7 @@ class _ASRouter {
case ra.OPEN_URL:
target.browser.ownerGlobal.openLinkIn(action.data.url, "tabshifted", {
private: false,
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})
});
break;
case ra.OPEN_ABOUT_PAGE:
@ -876,7 +754,7 @@ class _ASRouter {
// Wait for our initial message loading to be done before responding to any UI requests
await this.waitForInitialized;
if (action.data && action.data.endpoint) {
await this._addPreviewEndpoint(action.data.endpoint.url, target.portID);
await this._addPreviewEndpoint(action.data.endpoint.url);
}
// Check if any updates are needed first
await this.loadMessagesFromAllProviders();
@ -925,7 +803,7 @@ class _ASRouter {
break;
case "ADMIN_CONNECT_STATE":
if (action.data && action.data.endpoint) {
this._addPreviewEndpoint(action.data.endpoint.url, target.portID);
this._addPreviewEndpoint(action.data.endpoint.url);
await this.loadMessagesFromAllProviders();
} else {
target.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: this.state});

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

@ -1,5 +1,8 @@
const {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
const {ASRouter} = ChromeUtils.import("resource://activity-stream/lib/ASRouter.jsm", {});
ChromeUtils.import("resource://gre/modules/Services.jsm");
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
/**
* @class ASRouterFeed - Connects ASRouter singleton (see above) to Activity Stream's
@ -11,25 +14,47 @@ class ASRouterFeed {
}
async enable() {
if (!this.router.initialized) {
await this.router.init(
this.store._messageChannel.channel,
this.store.dbStorage.getDbTable("snippets"),
this.store.dispatch
);
}
await this.router.init(
this.store._messageChannel.channel,
this.store.dbStorage.getDbTable("snippets"),
this.store.dispatch
);
// Disable onboarding
Services.prefs.setBoolPref(ONBOARDING_FINISHED_PREF, true);
}
disable() {
if (this.router.initialized) {
this.router.uninit();
// Re-enable onboarding
Services.prefs.setBoolPref(ONBOARDING_FINISHED_PREF, false);
}
}
/**
* enableOrDisableBasedOnPref - Check the experiment pref
* (asrouterExperimentEnabled) and enable or disable ASRouter based on
* its value.
*/
enableOrDisableBasedOnPref() {
const prefs = this.store.getState().Prefs.values;
const isExperimentEnabled = prefs.asrouterExperimentEnabled;
if (!this.router.initialized && isExperimentEnabled) {
this.enable();
} else if (!isExperimentEnabled && this.router.initialized) {
this.disable();
}
}
onAction(action) {
switch (action.type) {
case at.INIT:
this.enable();
this.enableOrDisableBasedOnPref();
break;
case at.PREF_CHANGED:
if (action.data.name === "asrouterExperimentEnabled") {
this.enableOrDisableBasedOnPref();
}
break;
case at.UNINIT:
this.disable();

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

@ -1,104 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/Services.jsm");
const PROVIDER_PREF = "browser.newtabpage.activity-stream.asrouter.messageProviders";
const DEVTOOLS_PREF = "browser.newtabpage.activity-stream.asrouter.devtoolsEnabled";
const DEFAULT_STATE = {
_initialized: false,
_providers: null,
_providerPref: PROVIDER_PREF,
_devtoolsEnabled: null,
_devtoolsPref: DEVTOOLS_PREF,
};
class _ASRouterPreferences {
constructor() {
Object.assign(this, DEFAULT_STATE);
this._callbacks = new Set();
}
get providers() {
if (!this._initialized || this._providers === null) {
try {
const parsed = JSON.parse(Services.prefs.getStringPref(this._providerPref, ""));
this._providers = Object.freeze(parsed.map(provider => Object.freeze(provider)));
} catch (e) {
Cu.reportError("Problem parsing JSON message provider pref for ASRouter");
this._providers = [];
}
}
return this._providers;
}
get devtoolsEnabled() {
if (!this._initialized || this._devtoolsEnabled === null) {
this._devtoolsEnabled = Services.prefs.getBoolPref(this._devtoolsPref, false);
}
return this._devtoolsEnabled;
}
get specialConditions() {
let allowLegacyOnboarding = true;
let allowLegacySnippets = true;
for (const provider of this.providers) {
if (provider.id === "onboarding" && provider.enabled && provider.cohort) {
allowLegacyOnboarding = false;
}
if (provider.id === "snippets" && provider.enabled) {
allowLegacySnippets = false;
}
}
return {
allowLegacyOnboarding,
allowLegacySnippets,
};
}
observe(aSubject, aTopic, aPrefName) {
switch (aPrefName) {
case this._providerPref:
this._providers = null;
break;
case this._devtoolsPref:
this._devtoolsEnabled = null;
break;
}
this._callbacks.forEach(cb => cb(aPrefName));
}
addListener(callback) {
this._callbacks.add(callback);
}
removeListener(callback) {
this._callbacks.delete(callback);
}
init() {
if (this._initialized) {
return;
}
Services.prefs.addObserver(this._providerPref, this);
Services.prefs.addObserver(this._devtoolsPref, this);
this._initialized = true;
}
uninit() {
if (this._initialized) {
Services.prefs.removeObserver(this._providerPref, this);
Services.prefs.removeObserver(this._devtoolsPref, this);
}
Object.assign(this, DEFAULT_STATE);
this._callbacks.clear();
}
}
this._ASRouterPreferences = _ASRouterPreferences;
this.ASRouterPreferences = new _ASRouterPreferences();
const EXPORTED_SYMBOLS = ["_ASRouterPreferences", "ASRouterPreferences"];

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

@ -1,8 +1,6 @@
ChromeUtils.import("resource://gre/modules/components-utils/FilterExpressions.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "ASRouterPreferences",
"resource://activity-stream/lib/ASRouterPreferences.jsm");
ChromeUtils.defineModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
ChromeUtils.defineModuleGetter(this, "NewTabUtils",
@ -13,11 +11,9 @@ ChromeUtils.defineModuleGetter(this, "ShellService",
"resource:///modules/ShellService.jsm");
ChromeUtils.defineModuleGetter(this, "TelemetryEnvironment",
"resource://gre/modules/TelemetryEnvironment.jsm");
ChromeUtils.defineModuleGetter(this, "AppConstants",
"resource://gre/modules/AppConstants.jsm");
const FXA_USERNAME_PREF = "services.sync.username";
const SEARCH_REGION_PREF = "browser.search.region";
const MESSAGE_PROVDIER_EXPERIMENT_PREF = "browser.newtabpage.activity-stream.asrouter.messageProviders";
const MOZ_JEXL_FILEPATH = "mozjexl";
const {activityStreamProvider: asProvider} = NewTabUtils;
@ -27,48 +23,31 @@ const FRECENT_SITES_IGNORE_BLOCKED = true;
const FRECENT_SITES_NUM_ITEMS = 25;
const FRECENT_SITES_MIN_FRECENCY = 100;
function CachedTargetingGetter(property, options = null, updateInterval = FRECENT_SITES_UPDATE_INTERVAL) {
const targetingGetter = {
_lastUpdated: 0,
_value: null,
// For testing
expire() {
this._lastUpdated = 0;
this._value = null;
},
};
Object.defineProperty(targetingGetter, property, {
get: () => new Promise(async (resolve, reject) => {
const TopFrecentSitesCache = {
_lastUpdated: 0,
_topFrecentSites: null,
get topFrecentSites() {
return new Promise(async resolve => {
const now = Date.now();
if (now - targetingGetter._lastUpdated >= updateInterval) {
try {
targetingGetter._value = await asProvider[property](options);
targetingGetter._lastUpdated = now;
} catch (e) {
Cu.reportError(e);
reject(e);
}
if (now - this._lastUpdated >= FRECENT_SITES_UPDATE_INTERVAL) {
this._topFrecentSites = await asProvider.getTopFrecentSites({
ignoreBlocked: FRECENT_SITES_IGNORE_BLOCKED,
numItems: FRECENT_SITES_NUM_ITEMS,
topsiteFrecency: FRECENT_SITES_MIN_FRECENCY,
onePerDomain: true,
includeFavicon: false
});
this._lastUpdated = now;
}
resolve(targetingGetter._value);
}),
});
return targetingGetter;
}
const TopFrecentSitesCache = new CachedTargetingGetter(
"getTopFrecentSites",
{
ignoreBlocked: FRECENT_SITES_IGNORE_BLOCKED,
numItems: FRECENT_SITES_NUM_ITEMS,
topsiteFrecency: FRECENT_SITES_MIN_FRECENCY,
onePerDomain: true,
includeFavicon: false,
resolve(this._topFrecentSites);
});
},
// For testing
expire() {
this._lastUpdated = 0;
this._topFrecentSites = null;
}
);
const TotalBookmarksCountCache = new CachedTargetingGetter("getTotalBookmarksCount");
};
/**
* removeRandomItemFromArray - Removes a random item from the array and returns it.
@ -85,7 +64,7 @@ const TargetingGetters = {
const {settings} = TelemetryEnvironment.currentEnvironment;
return {
attribution: settings.attribution,
update: settings.update,
update: settings.update
};
},
get currentDate() {
@ -97,14 +76,14 @@ const TargetingGetters = {
get profileAgeReset() {
return new ProfileAge(null, null).reset;
},
get usesFirefoxSync() {
get hasFxAccount() {
return Services.prefs.prefHasUserValue(FXA_USERNAME_PREF);
},
get sync() {
return {
desktopDevices: Services.prefs.getIntPref("services.sync.clients.devices.desktop", 0),
mobileDevices: Services.prefs.getIntPref("services.sync.clients.devices.mobile", 0),
totalDevices: Services.prefs.getIntPref("services.sync.numClients", 0),
totalDevices: Services.prefs.getIntPref("services.sync.numClients", 0)
};
},
get addonsInfo() {
@ -116,13 +95,13 @@ const TargetingGetters = {
version: addon.version,
type: addon.type,
isSystem: addon.isSystem,
isWebExtension: addon.isWebExtension,
isWebExtension: addon.isWebExtension
};
if (fullData) {
Object.assign(info[addon.id], {
name: addon.name,
userDisabled: addon.userDisabled,
installDate: addon.installDate,
installDate: addon.installDate
});
}
}
@ -139,7 +118,7 @@ const TargetingGetters = {
current: Services.search.defaultEngine.identifier,
installed: engines
.map(engine => engine.identifier)
.filter(engine => engine),
.filter(engine => engine)
});
} else {
resolve({installed: [], current: ""});
@ -157,35 +136,39 @@ const TargetingGetters = {
return Services.prefs.getIntPref("devtools.selfxss.count");
},
get topFrecentSites() {
return TopFrecentSitesCache.getTopFrecentSites.then(sites => sites.map(site => (
return TopFrecentSitesCache.topFrecentSites.then(sites => sites.map(site => (
{
url: site.url,
host: (new URL(site.url)).hostname,
frecency: site.frecency,
lastVisitDate: site.lastVisitDate,
lastVisitDate: site.lastVisitDate
}
)));
},
// Temporary targeting function for the purposes of running the simplified onboarding experience
get isInExperimentCohort() {
const {cohort} = ASRouterPreferences.providers.find(i => i.id === "onboarding") || {};
return (typeof cohort === "number" ? cohort : 0);
const allProviders = Services.prefs.getStringPref(MESSAGE_PROVDIER_EXPERIMENT_PREF, "");
try {
const {cohort} = JSON.parse(allProviders).find(i => i.id === "onboarding");
return (typeof cohort === "number" ? cohort : 0);
} catch (e) {
Cu.reportError("Problem parsing JSON message provider pref for ASRouter");
}
return 0;
},
get providerCohorts() {
return ASRouterPreferences.providers.reduce((prev, current) => {
prev[current.id] = current.cohort || "";
return prev;
}, {});
},
get totalBookmarksCount() {
return TotalBookmarksCountCache.getTotalBookmarksCount;
},
get firefoxVersion() {
return parseInt(AppConstants.MOZ_APP_VERSION.match(/\d+/), 10);
},
get region() {
return Services.prefs.getStringPref(SEARCH_REGION_PREF, "");
},
const allProviders = Services.prefs.getStringPref(MESSAGE_PROVDIER_EXPERIMENT_PREF, "");
const cohorts = {};
try {
JSON.parse(allProviders).reduce((prev, current) => {
prev[current.id] = current.cohort || "";
return prev;
}, cohorts);
} catch (e) {
Cu.reportError("Problem parsing JSON message provider pref for ASRouter");
}
return cohorts;
}
};
this.ASRouterTargeting = {
@ -193,17 +176,10 @@ this.ASRouterTargeting = {
ERROR_TYPES: {
MALFORMED_EXPRESSION: "MALFORMED_EXPRESSION",
OTHER_ERROR: "OTHER_ERROR",
OTHER_ERROR: "OTHER_ERROR"
},
isMatch(filterExpression, customContext) {
let context = this.Environment;
if (customContext) {
context = {};
Object.defineProperties(context, Object.getOwnPropertyDescriptors(this.Environment));
Object.defineProperties(context, Object.getOwnPropertyDescriptors(customContext));
}
isMatch(filterExpression, context = this.Environment) {
return FilterExpressions.eval(filterExpression, context);
},
@ -272,11 +248,9 @@ this.ASRouterTargeting = {
}
}
return match;
},
}
};
// Export for testing
this.TopFrecentSitesCache = TopFrecentSitesCache;
this.TotalBookmarksCountCache = TotalBookmarksCountCache;
this.CachedTargetingGetter = CachedTargetingGetter;
this.EXPORTED_SYMBOLS = ["ASRouterTargeting", "TopFrecentSitesCache", "TotalBookmarksCountCache", "CachedTargetingGetter"];
this.EXPORTED_SYMBOLS = ["ASRouterTargeting", "TopFrecentSitesCache"];

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

@ -107,8 +107,8 @@ this.ASRouterTriggerListeners = new Map([
}
break;
}
},
}],
}
}]
]);
const EXPORTED_SYMBOLS = ["ASRouterTriggerListeners"];

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

@ -19,21 +19,21 @@ const PREFS_BEFORE_SECTIONS = [
id: "search",
pref: {
feed: "showSearch",
titleString: "prefs_search_header",
titleString: "prefs_search_header"
},
icon: "chrome://browser/skin/search-glass.svg",
icon: "chrome://browser/skin/search-glass.svg"
},
{
id: "topsites",
pref: {
feed: "feeds.topsites",
titleString: "settings_pane_topsites_header",
descString: "prefs_topsites_description",
descString: "prefs_topsites_description"
},
icon: "topsites",
maxRows: 4,
rowsPref: "topSitesRows",
},
rowsPref: "topSitesRows"
}
];
const PREFS_AFTER_SECTIONS = [
{
@ -41,10 +41,10 @@ const PREFS_AFTER_SECTIONS = [
pref: {
feed: "feeds.snippets",
titleString: "settings_pane_snippets_header",
descString: "prefs_snippets_description",
descString: "prefs_snippets_description"
},
icon: "info",
},
icon: "info"
}
];
// This CSS is added to the whole about:preferences page
@ -175,13 +175,13 @@ this.AboutPreferences = class AboutPreferences {
icon = "webextension",
maxRows,
rowsPref,
shouldHidePref,
shouldHidePref
} = sectionData;
const {
feed: name,
titleString,
descString,
nestedPrefs = [],
nestedPrefs = []
} = prefData || {};
// Don't show any sections that we don't want to expose in preferences UI

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

@ -37,7 +37,7 @@ const DEFAULT_SITES = new Map([
["PL", "https://www.youtube.com/,https://www.facebook.com/,https://allegro.pl/,https://www.wikipedia.org/,https://www.olx.pl/,https://www.wykop.pl/"],
["RU", "https://vk.com/,https://www.youtube.com/,https://ok.ru/,https://www.avito.ru/,https://www.aliexpress.com/,https://www.wikipedia.org/"],
["GB", "https://www.youtube.com/,https://www.facebook.com/,https://www.reddit.com/,https://www.amazon.co.uk/,https://www.bbc.co.uk/,https://www.ebay.co.uk/"],
["FR", "https://www.youtube.com/,https://www.facebook.com/,https://www.wikipedia.org/,https://www.amazon.fr/,https://www.leboncoin.fr/,https://twitter.com/"],
["FR", "https://www.youtube.com/,https://www.facebook.com/,https://www.wikipedia.org/,https://www.amazon.fr/,https://www.leboncoin.fr/,https://twitter.com/"]
]);
const GEO_PREF = "browser.search.region";
const SPOCS_GEOS = ["US"];
@ -54,7 +54,7 @@ function showSpocs({geo}) {
const PREFS_CONFIG = new Map([
["default.sites", {
title: "Comma-separated list of default top sites to fill in behind visited sites",
getValue: ({geo}) => DEFAULT_SITES.get(DEFAULT_SITES.has(geo) ? geo : ""),
getValue: ({geo}) => DEFAULT_SITES.get(DEFAULT_SITES.has(geo) ? geo : "")
}],
["feeds.section.topstories.options", {
title: "Configuration options for top stories feed",
@ -70,12 +70,12 @@ const PREFS_CONFIG = new Map([
stories_referrer: "https://getpocket.com/recommendations",
topics_endpoint: `https://getpocket.cdn.mozilla.net/v3/firefox/trending-topics?version=2&consumer_key=$apiKey&locale_lang=${args.locale}`,
show_spocs: showSpocs(args),
personalized: true,
}),
personalized: true
})
}],
["showSponsored", {
title: "Show sponsored cards in spoc experiment (show_spocs in topstories.options has to be set to true as well)",
value: true,
value: true
}],
["pocketCta", {
title: "Pocket cta and button for logged out users.",
@ -83,90 +83,90 @@ const PREFS_CONFIG = new Map([
cta_button: "",
cta_text: "",
cta_url: "",
use_cta: false,
}),
use_cta: false
})
}],
["filterAdult", {
title: "Remove adult pages from sites, highlights, etc.",
value: true,
value: true
}],
["migrationExpired", {
title: "Boolean flag that decides whether to show the migration message or not.",
value: false,
value: false
}],
["migrationLastShownDate", {
title: "Timestamp when migration message was last shown. In seconds.",
value: 0,
value: 0
}],
["migrationRemainingDays", {
title: "Number of days to show the manual migration message",
value: 4,
value: 4
}],
["prerender", {
title: "Use the prerendered version of activity-stream.html. This is set automatically by PrefsFeed.jsm.",
value: true,
value: true
}],
["showSearch", {
title: "Show the Search bar",
value: true,
value: true
}],
["disableSnippets", {
title: "Disable snippets on activity stream",
value: false,
value: false
}],
["topSitesRows", {
title: "Number of rows of Top Sites to display",
value: 1,
value: 1
}],
["telemetry", {
title: "Enable system error and usage data collection",
value: true,
value_local_dev: false,
value_local_dev: false
}],
["telemetry.ut.events", {
title: "Enable Unified Telemetry event data collection",
value: AppConstants.EARLY_BETA_OR_EARLIER,
value_local_dev: false,
value_local_dev: false
}],
["telemetry.ping.endpoint", {
title: "Telemetry server endpoint",
value: "https://tiles.services.mozilla.com/v4/links/activity-stream",
value: "https://tiles.services.mozilla.com/v4/links/activity-stream"
}],
["section.highlights.includeVisited", {
title: "Boolean flag that decides whether or not to show visited pages in highlights.",
value: true,
value: true
}],
["section.highlights.includeBookmarks", {
title: "Boolean flag that decides whether or not to show bookmarks in highlights.",
value: true,
value: true
}],
["section.highlights.includePocket", {
title: "Boolean flag that decides whether or not to show saved Pocket stories in highlights.",
value: true,
value: true
}],
["section.highlights.includeDownloads", {
title: "Boolean flag that decides whether or not to show saved recent Downloads in highlights.",
value: true,
value: true
}],
["section.highlights.rows", {
title: "Number of rows of Highlights to display",
value: 2,
value: 2
}],
["section.topstories.rows", {
title: "Number of rows of Top Stories to display",
value: 1,
value: 1
}],
["sectionOrder", {
title: "The rendering order for the sections",
value: "topsites,topstories,highlights",
value: "topsites,topstories,highlights"
}],
["improvesearch.noDefaultSearchTile", {
title: "Experiment to remove tiles that are the same as the default search",
value: true,
value: true
}],
["improvesearch.topSiteSearchShortcuts", {
title: "Experiment to show special top sites that perform keyword searches",
value: AppConstants.MOZ_UPDATE_CHANNEL !== "release",
value: AppConstants.MOZ_UPDATE_CHANNEL !== "release"
}],
["improvesearch.topSiteSearchShortcuts.searchEngines", {
title: "An ordered, comma-delimited list of search shortcuts that we should try and pin",
@ -187,15 +187,15 @@ const PREFS_CONFIG = new Map([
searchShortcuts.push("amazon");
}
return searchShortcuts.join(",");
},
}
}],
["improvesearch.topSiteSearchShortcuts.havePinned", {
title: "A comma-delimited list of search shortcuts that have previously been pinned",
value: "",
value: ""
}],
["asrouter.devtoolsEnabled", {
title: "Are the asrouter devtools enabled?",
value: false,
["asrouterExperimentEnabled", {
title: "Is the message center experiment on?",
value: false
}],
["asrouter.messageProviders", {
title: "Configuration for ASRouter message providers",
@ -211,21 +211,21 @@ const PREFS_CONFIG = new Map([
type: "local",
localProvider: "OnboardingMessageProvider",
enabled: false,
cohort: 0,
cohort: 0
}, {
id: "snippets",
type: "remote",
url: "https://snippets.cdn.mozilla.net/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/",
url: "https://snippets.cdn.mozilla.net/us-west/bundles/bundle_d6d90fb9098ce8b45e60acf601bcb91b68322309.json",
updateCycleInMs: ONE_HOUR_IN_MS * 4,
enabled: false,
enabled: AppConstants.MOZ_UPDATE_CHANNEL !== "release"
}, {
id: "cfr",
type: "local",
localProvider: "CFRMessageProvider",
enabled: AppConstants.MOZ_UPDATE_CHANNEL !== "release",
cohort: 0,
}]),
}],
cohort: 0
}])
}]
]);
// Array of each feed's FEEDS_CONFIG factory and values to add to PREFS_CONFIG
@ -234,43 +234,43 @@ const FEEDS_DATA = [
name: "aboutpreferences",
factory: () => new AboutPreferences(),
title: "about:preferences rendering",
value: true,
value: true
},
{
name: "migration",
factory: () => new ManualMigration(),
title: "Manual migration wizard",
value: true,
value: true
},
{
name: "newtabinit",
factory: () => new NewTabInit(),
title: "Sends a copy of the state to each new tab that is opened",
value: true,
value: true
},
{
name: "places",
factory: () => new PlacesFeed(),
title: "Listens for and relays various Places-related events",
value: true,
value: true
},
{
name: "prefs",
factory: () => new PrefsFeed(PREFS_CONFIG),
title: "Preferences",
value: true,
value: true
},
{
name: "sections",
factory: () => new SectionsFeed(),
title: "Manages sections",
value: true,
value: true
},
{
name: "section.highlights",
factory: () => new HighlightsFeed(),
title: "Fetches content recommendations from places db",
value: true,
value: true
},
{
name: "section.topstories",
@ -281,47 +281,47 @@ const FEEDS_DATA = [
const locales = ({
"US": ["en-CA", "en-GB", "en-US", "en-ZA"],
"CA": ["en-CA", "en-GB", "en-US", "en-ZA"],
"DE": ["de", "de-DE", "de-AT", "de-CH"],
"DE": ["de", "de-DE", "de-AT", "de-CH"]
})[geo];
return !!locales && locales.includes(locale);
},
}
},
{
name: "snippets",
factory: () => new SnippetsFeed(),
title: "Gets snippets data",
value: true,
value: true
},
{
name: "systemtick",
factory: () => new SystemTickFeed(),
title: "Produces system tick events to periodically check for data expiry",
value: true,
value: true
},
{
name: "telemetry",
factory: () => new TelemetryFeed(),
title: "Relays telemetry-related actions to PingCentre",
value: true,
value: true
},
{
name: "favicon",
factory: () => new FaviconFeed(),
title: "Fetches tippy top manifests from remote service",
value: true,
value: true
},
{
name: "topsites",
factory: () => new TopSitesFeed(),
title: "Queries places and gets metadata for Top Sites section",
value: true,
value: true
},
{
name: "asrouterfeed",
factory: () => new ASRouterFeed(),
title: "Handles AS Router messages, such as snippets and onboaridng",
value: true,
},
value: true
}
];
const FEEDS_CONFIG = new Map();
@ -351,7 +351,7 @@ this.ActivityStream = class ActivityStream {
// Hook up the store and let all feeds and pages initialize
this.store.init(this.feeds, ac.BroadcastToContent({
type: at.INIT,
data: {},
data: {}
}), {type: at.UNINIT});
this.initialized = true;
@ -451,7 +451,7 @@ this.ActivityStream = class ActivityStream {
const newValue = prefConfig.getValue({
geo: this.geo,
locale: this.locale,
locale: this.locale
});
// If there's an existing value and it has changed, that means we need to

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

@ -19,7 +19,7 @@ const DEFAULT_OPTIONS = {
},
pageURL: ABOUT_NEW_TAB_URL,
outgoingMessageName: "ActivityStream:MainToContent",
incomingMessageName: "ActivityStream:ContentToMain",
incomingMessageName: "ActivityStream:ContentToMain"
};
this.ActivityStreamMessageChannel = class ActivityStreamMessageChannel {
@ -85,7 +85,7 @@ this.ActivityStreamMessageChannel = class ActivityStreamMessageChannel {
* @param {string} targetId The portID of the port that sent the message
*/
onActionFromContent(action, targetId) {
this.dispatch(ac.AlsoToMain(action, this.validatePortID(targetId)));
this.dispatch(ac.AlsoToMain(action, targetId));
}
/**
@ -112,18 +112,6 @@ this.ActivityStreamMessageChannel = class ActivityStreamMessageChannel {
}
}
/**
* A valid portID is a combination of process id and port
* https://searchfox.org/mozilla-central/rev/196560b95f191b48ff7cba7c2ba9237bba6b5b6a/toolkit/components/remotepagemanager/RemotePageManagerChild.jsm#14
*/
validatePortID(id) {
if (typeof id !== "string" || !id.includes(":")) {
Cu.reportError("Invalid portID");
}
return id;
}
/**
* getIdByTarget - Retrieve the id of a message target, if it exists in this.targets
*
@ -131,7 +119,6 @@ this.ActivityStreamMessageChannel = class ActivityStreamMessageChannel {
* @return {string|null} The unique id of the target, if it exists.
*/
getTargetById(id) {
this.validatePortID(id);
for (let port of this.channel.messagePorts) {
if (port.portID === id) {
return port;
@ -236,7 +223,7 @@ this.ActivityStreamMessageChannel = class ActivityStreamMessageChannel {
onNewTabInit(msg) {
this.onActionFromContent({
type: at.NEW_TAB_INIT,
data: msg.target,
data: msg.target
}, msg.target.portID);
}

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

@ -30,7 +30,7 @@ this.ActivityStreamStorage = class ActivityStreamStorage {
return {
get: this._get.bind(this, storeName),
getAll: this._getAll.bind(this, storeName),
set: this._set.bind(this, storeName),
set: this._set.bind(this, storeName)
};
}

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

@ -7,13 +7,13 @@ const AMAZON_ASSISTANT_PARAMS = {
existing_addons: ["abb@amazon.com", "{75c7fe97-5a90-4b54-9052-3534235eaf41}", "{ef34596e-1e43-4e84-b2ff-1e58e287e08d}", "{ea280feb-155a-492e-8016-ac96dd995f2c}", "izer@camelcamelcamel.com", "amptra@keepa.com", "pricealarm@icopron.ch", "{774f76c7-6807-481e-bf64-f9b7d5cda602}"],
open_urls: ["smile.amazon.com", "www.audible.com", "www.amazon.com", "amazon.com", "audible.com"],
sumo_path: "extensionrecommendations",
min_frecency: 10000,
min_frecency: 10000
};
const FACEBOOK_CONTAINER_PARAMS = {
existing_addons: ["@contain-facebook", "{bb1b80be-e6b3-40a1-9b6e-9d4073343f0b}", "{a50d61ca-d27b-437a-8b52-5fd801a0a88b}"],
open_urls: ["www.facebook.com", "facebook.com"],
sumo_path: "extensionrecommendations",
min_frecency: 10000,
min_frecency: 10000
};
const GOOGLE_TRANSLATE_PARAMS = {
existing_addons: ["jid1-93WyvpgvxzGATw@jetpack", "{087ef4e1-4286-4be6-9aa3-8d6c420ee1db}", "{4170faaa-ee87-4a0e-b57a-1aec49282887}", "jid1-TMndP6cdKgxLcQ@jetpack",
@ -23,26 +23,26 @@ const GOOGLE_TRANSLATE_PARAMS = {
"{e20e0de5-1667-4df4-bd69-705720e37391}", "{09e26ae9-e9c1-477c-80a6-99934212f2fe}", "mgxtranslator@magemagix.com", "gtranslatewins@mozilla.org"],
open_urls: ["translate.google.com"],
sumo_path: "extensionrecommendations",
min_frecency: 10000,
min_frecency: 10000
};
const YOUTUBE_ENHANCE_PARAMS = {
existing_addons: ["enhancerforyoutube@maximerf.addons.mozilla.org", "{dc8f61ab-5e98-4027-98ef-bb2ff6060d71}", "{7b1bf0b6-a1b9-42b0-b75d-252036438bdc}", "jid0-UVAeBCfd34Kk5usS8A1CBiobvM8@jetpack",
"iridium@particlecore.github.io", "jid1-ss6kLNCbNz6u0g@jetpack", "{1cf918d2-f4ea-4b4f-b34e-455283fef19f}"],
open_urls: ["www.youtube.com", "youtube.com"],
sumo_path: "extensionrecommendations",
min_frecency: 10000,
min_frecency: 10000
};
const WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS = {
existing_addons: ["@wikipediacontextmenusearch", "{ebf47fc8-01d8-4dba-aa04-2118402f4b20}", "{5737a280-b359-4e26-95b0-adec5915a854}", "olivier.debroqueville@gmail.com", "{3923146e-98cb-472b-9c13-f6849d34d6b8}"],
open_urls: ["www.wikipedia.org", "wikipedia.org"],
sumo_path: "extensionrecommendations",
min_frecency: 10000,
min_frecency: 10000
};
const REDDIT_ENHANCEMENT_PARAMS = {
existing_addons: ["jid1-xUfzOsOFlzSOXg@jetpack"],
open_urls: ["www.reddit.com", "reddit.com"],
sumo_path: "extensionrecommendations",
min_frecency: 10000,
min_frecency: 10000
};
const CFR_MESSAGES = [
@ -55,7 +55,7 @@ const CFR_MESSAGES = [
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
info_icon: {
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
sumo_path: AMAZON_ASSISTANT_PARAMS.sumo_path,
sumo_path: AMAZON_ASSISTANT_PARAMS.sumo_path
},
addon: {
title: "Amazon Assistant",
@ -63,7 +63,7 @@ const CFR_MESSAGES = [
rating: 3.3,
users: 443046,
author: "Amazon",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/amazon-browser-bar/",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/amazon-browser-bar/"
},
text: "Amazon Assistant helps you make better shopping decisions by showing product comparisons at thousands of retail sites.",
buttons: {
@ -71,20 +71,20 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-ok-button"},
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/950930/amazon_assistant_for_firefox-10.1805.2.1019-an+fx.xpi`},
},
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/950930/amazon_assistant_for_firefox-10.1805.2.1019-an+fx.xpi`}
}
},
secondary: {
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
action: {type: "CANCEL"},
},
},
action: {type: "CANCEL"}
}
}
},
frequency: {lifetime: 1},
targeting: `
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${AMAZON_ASSISTANT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
trigger: {id: "openURL", params: AMAZON_ASSISTANT_PARAMS.open_urls},
trigger: {id: "openURL", params: AMAZON_ASSISTANT_PARAMS.open_urls}
},
{
id: "FACEBOOK_CONTAINER_1",
@ -95,7 +95,7 @@ const CFR_MESSAGES = [
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
info_icon: {
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
sumo_path: FACEBOOK_CONTAINER_PARAMS.sumo_path,
sumo_path: FACEBOOK_CONTAINER_PARAMS.sumo_path
},
addon: {
title: "Facebook Container",
@ -103,7 +103,7 @@ const CFR_MESSAGES = [
rating: 4.6,
users: 299019,
author: "Mozilla",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/facebook-container/",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/facebook-container/"
},
text: "Stop Facebook from tracking your activity across the web. Use Facebook the way you normally do without annoying ads following you around.",
buttons: {
@ -111,20 +111,20 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-ok-button"},
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/918624/facebook_container-1.3.1-an+fx-linux.xpi`},
},
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/918624/facebook_container-1.3.1-an+fx-linux.xpi`}
}
},
secondary: {
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
action: {type: "CANCEL"},
},
},
action: {type: "CANCEL"}
}
}
},
frequency: {lifetime: 1},
targeting: `
(${JSON.stringify(FACEBOOK_CONTAINER_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
(${JSON.stringify(FACEBOOK_CONTAINER_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${FACEBOOK_CONTAINER_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
trigger: {id: "openURL", params: FACEBOOK_CONTAINER_PARAMS.open_urls},
trigger: {id: "openURL", params: FACEBOOK_CONTAINER_PARAMS.open_urls}
},
{
id: "GOOGLE_TRANSLATE_1",
@ -135,7 +135,7 @@ const CFR_MESSAGES = [
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
info_icon: {
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
sumo_path: GOOGLE_TRANSLATE_PARAMS.sumo_path,
sumo_path: GOOGLE_TRANSLATE_PARAMS.sumo_path
},
addon: {
title: "To Google Translate",
@ -143,7 +143,7 @@ const CFR_MESSAGES = [
rating: 4.1,
users: 313474,
author: "Juan Escobar",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/to-google-translate/",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/to-google-translate/"
},
text: "Instantly translate any webpage text. Simply highlight the text, right-click to open the context menu, and choose a text or aural translation.",
buttons: {
@ -151,20 +151,20 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-ok-button"},
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/1008798/al_traductor_de_google-3.3-an+fx.xpi`},
},
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/1008798/al_traductor_de_google-3.3-an+fx.xpi`}
}
},
secondary: {
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
action: {type: "CANCEL"},
},
},
action: {type: "CANCEL"}
}
}
},
frequency: {lifetime: 1},
targeting: `
(${JSON.stringify(GOOGLE_TRANSLATE_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
(${JSON.stringify(GOOGLE_TRANSLATE_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${GOOGLE_TRANSLATE_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
trigger: {id: "openURL", params: GOOGLE_TRANSLATE_PARAMS.open_urls},
trigger: {id: "openURL", params: GOOGLE_TRANSLATE_PARAMS.open_urls}
},
{
id: "YOUTUBE_ENHANCE_1",
@ -175,7 +175,7 @@ const CFR_MESSAGES = [
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
info_icon: {
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
sumo_path: YOUTUBE_ENHANCE_PARAMS.sumo_path,
sumo_path: YOUTUBE_ENHANCE_PARAMS.sumo_path
},
addon: {
title: "Enhancer for YouTube\u2122",
@ -183,7 +183,7 @@ const CFR_MESSAGES = [
rating: 4.8,
users: 357328,
author: "Maxime RF",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/enhancer-for-youtube/",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/enhancer-for-youtube/"
},
text: "Take control of your YouTube experience. Automatically block annoying ads, set playback speed and volume, remove annotations, and more.",
buttons: {
@ -191,20 +191,20 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-ok-button"},
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/1028400/enhancer_for_youtubetm-2.0.73-an+fx-linux.xpi`},
},
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/1028400/enhancer_for_youtubetm-2.0.73-an+fx-linux.xpi`}
}
},
secondary: {
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
action: {type: "CANCEL"},
},
},
action: {type: "CANCEL"}
}
}
},
frequency: {lifetime: 1},
targeting: `
(${JSON.stringify(YOUTUBE_ENHANCE_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
(${JSON.stringify(YOUTUBE_ENHANCE_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${YOUTUBE_ENHANCE_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
trigger: {id: "openURL", params: YOUTUBE_ENHANCE_PARAMS.open_urls},
trigger: {id: "openURL", params: YOUTUBE_ENHANCE_PARAMS.open_urls}
},
{
id: "WIKIPEDIA_CONTEXT_MENU_SEARCH_1",
@ -215,7 +215,7 @@ const CFR_MESSAGES = [
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
info_icon: {
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
sumo_path: WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.sumo_path,
sumo_path: WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.sumo_path
},
addon: {
title: "Wikipedia Context Menu Search",
@ -223,7 +223,7 @@ const CFR_MESSAGES = [
rating: 4.9,
users: 3095,
author: "Nick Diedrich",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/wikipedia-context-menu-search/",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/wikipedia-context-menu-search/"
},
text: "Get to a Wikipedia page fast, from anywhere on the web. Just highlight any webpage text and right-click to open the context menu to start a Wikipedia search.",
buttons: {
@ -231,20 +231,20 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-ok-button"},
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/890224/wikipedia_context_menu_search-1.8-an+fx.xpi`},
},
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/890224/wikipedia_context_menu_search-1.8-an+fx.xpi`}
}
},
secondary: {
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
action: {type: "CANCEL"},
},
},
action: {type: "CANCEL"}
}
}
},
frequency: {lifetime: 1},
targeting: `
(${JSON.stringify(WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
(${JSON.stringify(WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
trigger: {id: "openURL", params: WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.open_urls},
trigger: {id: "openURL", params: WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.open_urls}
},
{
id: "REDDIT_ENHANCEMENT_1",
@ -255,7 +255,7 @@ const CFR_MESSAGES = [
heading_text: {string_id: "cfr-doorhanger-extension-heading"},
info_icon: {
label: {string_id: "cfr-doorhanger-extension-sumo-link"},
sumo_path: REDDIT_ENHANCEMENT_PARAMS.sumo_path,
sumo_path: REDDIT_ENHANCEMENT_PARAMS.sumo_path
},
addon: {
title: "Reddit Enhancement Suite",
@ -263,7 +263,7 @@ const CFR_MESSAGES = [
rating: 4.6,
users: 258129,
author: "honestbleeps",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/reddit-enhancement-suite/",
amo_url: "https://addons.mozilla.org/en-US/firefox/addon/reddit-enhancement-suite/"
},
text: "New features include Inline Image Viewer, Never Ending Reddit (never click 'next page' again), Keyboard Navigation, Account Switcher, and User Tagger.",
buttons: {
@ -271,27 +271,27 @@ const CFR_MESSAGES = [
label: {string_id: "cfr-doorhanger-extension-ok-button"},
action: {
type: "INSTALL_ADDON_FROM_URL",
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/991623/reddit_enhancement_suite-5.12.5-an+fx.xpi`},
},
data: {url: `${BASE_ADDONS_DOWNLOAD_URL}/991623/reddit_enhancement_suite-5.12.5-an+fx.xpi`}
}
},
secondary: {
label: {string_id: "cfr-doorhanger-extension-cancel-button"},
action: {type: "CANCEL"},
},
},
action: {type: "CANCEL"}
}
}
},
frequency: {lifetime: 1},
targeting: `
(${JSON.stringify(REDDIT_ENHANCEMENT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
(${JSON.stringify(REDDIT_ENHANCEMENT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${REDDIT_ENHANCEMENT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
trigger: {id: "openURL", params: REDDIT_ENHANCEMENT_PARAMS.open_urls},
},
trigger: {id: "openURL", params: REDDIT_ENHANCEMENT_PARAMS.open_urls}
}
];
const CFRMessageProvider = {
getMessages() {
return CFR_MESSAGES;
},
}
};
this.CFRMessageProvider = CFRMessageProvider;

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

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/Localization.jsm");
const {Localization} = ChromeUtils.import("resource://gre/modules/Localization.jsm", {});
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
@ -50,11 +50,28 @@ class PageAction {
this.dispatchUserAction = this.dispatchUserAction.bind(this);
this._l10n = new Localization([
"browser/newtab/asrouter.ftl",
"browser/newtab/asrouter.ftl"
]);
// Saved timeout IDs for scheduled state changes, so they can be cancelled
this.stateTransitionTimeoutIDs = [];
this.container.onclick = this._handleClick;
}
_dispatchImpression(message) {
this._dispatchToASRouter({type: "IMPRESSION", data: message});
}
_sendTelemetry(ping) {
// Note `useClientID` is set to true to tell TelemetryFeed to use client_id
// instead of `impression_id`. TelemetryFeed is also responsible for deciding
// whether to use `message_id` or `bucket_id` based on the release channel and
// shield study setup.
this._dispatchToASRouter({
type: "DOORHANGER_TELEMETRY",
data: {useClientID: true, action: "cfr_user_event", source: "CFR", ...ping}
});
}
async show(recommendation, shouldExpand = false) {
@ -69,11 +86,6 @@ class PageAction {
const [{width}] = this.label.getClientRects();
this.urlbar.style.setProperty("--cfr-label-width", `${width}px`);
this.container.addEventListener("click", this._handleClick);
// Collapse the recommendation on url bar focus in order to free up more
// space to display and edit the url
this.urlbar.addEventListener("focus", this._collapse);
if (shouldExpand) {
this._clearScheduledStateChanges();
@ -95,39 +107,42 @@ class PageAction {
this.container.hidden = true;
this._clearScheduledStateChanges();
this.urlbar.removeAttribute("cfr-recommendation-state");
this.container.removeEventListener("click", this._handleClick);
this.urlbar.removeEventListener("focus", this._collapse);
if (this.currentNotification) {
this.window.PopupNotifications.remove(this.currentNotification);
this.currentNotification = null;
}
// This is safe even if this.currentNotification is invalid/undefined
this.window.PopupNotifications.remove(this.currentNotification);
}
_expand(delay) {
if (delay > 0) {
this.stateTransitionTimeoutIDs.push(this.window.setTimeout(() => {
this.urlbar.setAttribute("cfr-recommendation-state", "expanded");
}, delay));
} else {
dispatchUserAction(action) {
this._dispatchToASRouter(
{type: "USER_ACTION", data: action},
{browser: this.window.gBrowser.selectedBrowser}
);
}
_expand(delay = 0) {
if (!delay) {
// Non-delayed state change overrides any scheduled state changes
this._clearScheduledStateChanges();
this.urlbar.setAttribute("cfr-recommendation-state", "expanded");
} else {
this.stateTransitionTimeoutIDs.push(this.window.setTimeout(() => {
this.urlbar.setAttribute("cfr-recommendation-state", "expanded");
}, delay));
}
}
_collapse(delay) {
if (delay > 0) {
this.stateTransitionTimeoutIDs.push(this.window.setTimeout(() => {
if (this.urlbar.getAttribute("cfr-recommendation-state") === "expanded") {
this.urlbar.setAttribute("cfr-recommendation-state", "collapsed");
}
}, delay));
} else {
_collapse(delay = 0) {
if (!delay) {
// Non-delayed state change overrides any scheduled state changes
this._clearScheduledStateChanges();
if (this.urlbar.getAttribute("cfr-recommendation-state") === "expanded") {
this.urlbar.setAttribute("cfr-recommendation-state", "collapsed");
}
} else {
this.stateTransitionTimeoutIDs.push(this.window.setTimeout(() => {
if (this.urlbar.getAttribute("cfr-recommendation-state") === "expanded") {
this.urlbar.setAttribute("cfr-recommendation-state", "collapsed");
}
}, delay));
}
}
@ -143,31 +158,11 @@ class PageAction {
_popupStateChange(state) {
if (["dismissed", "removed"].includes(state)) {
this._collapse();
if (this.currentNotification) {
this.window.PopupNotifications.remove(this.currentNotification);
this.currentNotification = null;
}
// This is safe even if this.currentNotification is invalid/undefined
this.window.PopupNotifications.remove(this.currentNotification);
}
}
dispatchUserAction(action) {
this._dispatchToASRouter(
{type: "USER_ACTION", data: action},
{browser: this.window.gBrowser.selectedBrowser}
);
}
_dispatchImpression(message) {
this._dispatchToASRouter({type: "IMPRESSION", data: message});
}
_sendTelemetry(ping) {
this._dispatchToASRouter({
type: "DOORHANGER_TELEMETRY",
data: {action: "cfr_user_event", source: "CFR", ...ping},
});
}
_blockMessage(messageID) {
this._dispatchToASRouter(
{type: "BLOCK_MESSAGE_BY_ID", data: {id: messageID}}
@ -184,27 +179,12 @@ class PageAction {
*/
async getStrings(string, subAttribute = "") {
if (!string.string_id) {
if (subAttribute) {
if (string.attributes) {
return string.attributes[subAttribute];
}
Cu.reportError(`String ${string.value} does not contain any attributes`);
return subAttribute;
}
if (typeof string.value === "string") {
const stringWithAttributes = new String(string.value); // eslint-disable-line no-new-wrappers
stringWithAttributes.attributes = string.attributes;
return stringWithAttributes;
}
return string;
}
const [localeStrings] = await this._l10n.formatMessages([{
id: string.string_id,
args: string.args,
args: string.args
}]);
const mainString = new String(localeStrings.value); // eslint-disable-line no-new-wrappers
@ -263,7 +243,7 @@ class PageAction {
author.textContent = await this.getStrings({
string_id: "cfr-doorhanger-extension-author",
args: {name: content.addon.author},
args: {name: content.addon.author}
});
footerText.textContent = await this.getStrings(content.text);
@ -278,7 +258,7 @@ class PageAction {
const ratingString = await this.getStrings({
string_id: "cfr-doorhanger-extension-rating",
args: {total: rating},
args: {total: rating}
}, "tooltiptext");
footerFilledStars.setAttribute("tooltiptext", ratingString);
footerEmptyStars.setAttribute("tooltiptext", ratingString);
@ -293,7 +273,7 @@ class PageAction {
if (users) {
footerUsers.setAttribute("value", await this.getStrings({
string_id: "cfr-doorhanger-extension-total-users",
args: {total: users},
args: {total: users}
}));
footerUsers.removeAttribute("hidden");
} else {
@ -326,7 +306,7 @@ class PageAction {
this.hide();
this._sendTelemetry({message_id: id, bucket_id: content.bucket_id, event: "INSTALL"});
RecommendationMap.delete(browser);
},
}
};
const secondaryActions = [{
@ -336,13 +316,13 @@ class PageAction {
this.hide();
this._sendTelemetry({message_id: id, bucket_id: content.bucket_id, event: "DISMISS"});
RecommendationMap.delete(browser);
},
}
}];
const options = {
popupIconURL: content.addon.icon,
hideClose: true,
eventCallback: this._popupStateChange,
eventCallback: this._popupStateChange
};
this._sendTelemetry({message_id: id, bucket_id: content.bucket_id, event: "CLICK_DOORHANGER"});
@ -454,12 +434,8 @@ const CFRPageActions = {
// WeakMaps don't have a `clear` method
PageActionMap = new WeakMap();
RecommendationMap = new WeakMap();
this.PageActionMap = PageActionMap;
this.RecommendationMap = RecommendationMap;
},
}
};
this.PageAction = PageAction;
this.CFRPageActions = CFRPageActions;
const EXPORTED_SYMBOLS = ["CFRPageActions", "PageAction"];
const EXPORTED_SYMBOLS = ["CFRPageActions"];

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

@ -53,7 +53,7 @@ this.DownloadsManager = class DownloadsManager {
title: element.displayName,
description,
referrer: downloadedItem.source.referrer,
date_added: downloadedItem.endTime,
date_added: downloadedItem.endTime
};
}

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

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
const {getDomain} = ChromeUtils.import("resource://activity-stream/lib/TippyTopProvider.jsm", {});
const {RemoteSettings} = ChromeUtils.import("resource://services-settings/remote-settings.js", {});
@ -78,7 +80,7 @@ async function fetchVisitPaths(url) {
const visits = await NewTabUtils.activityStreamProvider.executePlacesQuery(query, {
columns: ["visit_id", "url"],
params: {url},
params: {url}
});
return visits;
}

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

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
@ -2967,5 +2969,5 @@ gAdultSet = new Set([
"zwQ/3MzTJ9rfBmrANIh14w==",
"zwY6tCjjya/bgrYaCncaag==",
"zxsSqovedB3HT99jVblCnQ==",
"zyA9f5J7mw5InjhcfeumAQ==",
"zyA9f5J7mw5InjhcfeumAQ=="
]);

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

@ -141,7 +141,7 @@ this.HighlightsFeed = class HighlightsFeed {
numItems: MANY_EXTRA_LENGTH,
excludeBookmarks: !this.store.getState().Prefs.values["section.highlights.includeBookmarks"],
excludeHistory: !this.store.getState().Prefs.values["section.highlights.includeVisited"],
excludePocket: !this.store.getState().Prefs.values["section.highlights.includePocket"],
excludePocket: !this.store.getState().Prefs.values["section.highlights.includePocket"]
});
if (this.store.getState().Prefs.values["section.highlights.includeDownloads"]) {
@ -191,7 +191,7 @@ this.HighlightsFeed = class HighlightsFeed {
hasImage: page.type !== "download", // Downloads do not have an image - all else types fall back to a screenshot
hostname,
type: page.type,
pocket_id: page.pocket_id,
pocket_id: page.pocket_id
});
// Add the "bookmark", "pocket", or not-skipped "history"

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

@ -8,6 +8,7 @@ const {actionCreators: ac, actionTypes: at} = ChromeUtils.import("resource://act
const MIGRATION_ENDED_EVENT = "Migration:Ended";
const MS_PER_DAY = 86400000;
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "MigrationUtils", "resource:///modules/MigrationUtils.jsm");

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

@ -1,63 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {toksToTfIdfVector} = ChromeUtils.import("resource://activity-stream/lib/Tokenize.jsm", {});
this.NaiveBayesTextTagger = class NaiveBayesTextTagger {
constructor(model) {
this.model = model;
}
/**
* Determines if the tokenized text belongs to class according to binary naive Bayes
* classifier. Returns an object containing the class label ("label"), and
* the log probability ("logProb") that the text belongs to that class. If
* the positive class is more likely, then "label" is the positive class
* label. If the negative class is matched, then "label" is set to null.
*/
tagTokens(tokens) {
let fv = toksToTfIdfVector(tokens, this.model.vocab_idfs);
let bestLogProb = null;
let bestClassId = -1;
let bestClassLabel = null;
let logSumExp = 0.0; // will be P(x). Used to create a proper probability
for (let classId = 0; classId < this.model.classes.length; classId++) {
let classModel = this.model.classes[classId];
let classLogProb = classModel.log_prior;
// dot fv with the class model
for (let pair of Object.values(fv)) {
let [termId, tfidf] = pair;
classLogProb += tfidf * classModel.feature_log_probs[termId];
}
if ((bestLogProb === null) || (classLogProb > bestLogProb)) {
bestLogProb = classLogProb;
bestClassId = classId;
}
logSumExp += Math.exp(classLogProb);
}
// now normalize the probability by dividing by P(x)
logSumExp = Math.log(logSumExp);
bestLogProb -= logSumExp;
if (bestClassId === this.model.positive_class_id) {
bestClassLabel = this.model.positive_class_label;
} else {
bestClassLabel = null;
}
let confident = ((bestClassId === this.model.positive_class_id) &&
(bestLogProb > this.model.positive_class_threshold_log_prob));
return {
"label": bestClassLabel,
"logProb": bestLogProb,
"confident": confident,
};
}
};
const EXPORTED_SYMBOLS = ["NaiveBayesTextTagger"];

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

@ -1,62 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {toksToTfIdfVector} = ChromeUtils.import("resource://activity-stream/lib/Tokenize.jsm", {});
this.NmfTextTagger = class NmfTextTagger {
constructor(model) {
this.model = model;
}
/**
* A multiclass classifier that scores tokenized text against several classes through
* inference of a nonnegative matrix factorization of TF-IDF vectors and
* class labels. Returns a map of class labels as string keys to scores.
* (Higher is more confident.) All classes get scored, so it is up to
* consumer of this data determine what classes are most valuable.
*/
tagTokens(tokens) {
let fv = toksToTfIdfVector(tokens, this.model.vocab_idfs);
let fve = Object.values(fv);
// normalize by the sum of the vector
let sum = 0.0;
for (let pair of fve) {
// eslint-disable-next-line prefer-destructuring
sum += pair[1];
}
for (let i = 0; i < fve.length; i++) {
// eslint-disable-next-line prefer-destructuring
fve[i][1] /= sum;
}
// dot the document with each topic vector so that we can transform it into
// the latent space
let toksInLatentSpace = [];
for (let topicVect of this.model.topic_word) {
let fvDotTwv = 0;
// dot fv with each topic word vector
for (let pair of fve) {
let [termId, tfidf] = pair;
fvDotTwv += tfidf * topicVect[termId];
}
toksInLatentSpace.push(fvDotTwv);
}
// now project toksInLatentSpace back into class space
let predictions = {};
Object.keys(this.model.document_topic).forEach(topic => {
let score = 0;
for (let i = 0; i < toksInLatentSpace.length; i++) {
score += toksInLatentSpace[i] * this.model.document_topic[topic][i];
}
predictions[topic] = score;
});
return predictions;
}
};
const EXPORTED_SYMBOLS = ["NmfTextTagger"];

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

@ -14,9 +14,9 @@ const ONBOARDING_MESSAGES = [
text: "Browse by yourself. Private Browsing with Tracking Protection blocks online trackers that follow you around the web.",
icon: "privatebrowsing",
button_label: "Try It Now",
button_action: {type: "OPEN_PRIVATE_BROWSER_WINDOW"},
button_action: {type: "OPEN_PRIVATE_BROWSER_WINDOW"}
},
trigger: {id: "firstRun"},
trigger: {id: "firstRun"}
},
{
id: "ONBOARDING_2",
@ -30,10 +30,10 @@ const ONBOARDING_MESSAGES = [
button_label: "Try It Now",
button_action: {
type: "OPEN_URL",
data: {url: "https://screenshots.firefox.com/#tour"},
},
data: {url: "https://screenshots.firefox.com/#tour"}
}
},
trigger: {id: "firstRun"},
trigger: {id: "firstRun"}
},
{
id: "ONBOARDING_3",
@ -45,10 +45,10 @@ const ONBOARDING_MESSAGES = [
text: "Add even more features that make Firefox work harder for you. Compare prices, check the weather or express your personality with a custom theme.",
icon: "addons",
button_label: "Try It Now",
button_action: {type: "OPEN_ABOUT_PAGE", data: {page: "addons"}},
button_action: {type: "OPEN_ABOUT_PAGE", data: {page: "addons"}}
},
targeting: "isInExperimentCohort == 1",
trigger: {id: "firstRun"},
trigger: {id: "firstRun"}
},
{
id: "ONBOARDING_4",
@ -60,17 +60,17 @@ const ONBOARDING_MESSAGES = [
text: "Browse faster, smarter, or safer with extensions like Ghostery, which lets you block annoying ads.",
icon: "gift",
button_label: "Try It Now",
button_action: {type: "OPEN_URL", data: {url: "https://addons.mozilla.org/en-US/firefox/addon/ghostery/"}},
button_action: {type: "OPEN_URL", data: {url: "https://addons.mozilla.org/en-US/firefox/addon/ghostery/"}}
},
targeting: "isInExperimentCohort == 2",
trigger: {id: "firstRun"},
},
trigger: {id: "firstRun"}
}
];
const OnboardingMessageProvider = {
getMessages() {
return ONBOARDING_MESSAGES;
},
}
};
this.OnboardingMessageProvider = OnboardingMessageProvider;

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

@ -4,6 +4,7 @@
"use strict";
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {actionCreators: ac, actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
@ -43,7 +44,7 @@ class HistoryObserver extends Observer {
this.dispatch({type: at.PLACES_LINKS_CHANGED});
this.dispatch({
type: at.PLACES_LINK_DELETED,
data: {url: uri.spec},
data: {url: uri.spec}
});
}
@ -114,8 +115,8 @@ class BookmarksObserver extends Observer {
bookmarkGuid,
bookmarkTitle,
dateAdded,
url: uri.spec,
},
url: uri.spec
}
});
}
@ -139,7 +140,7 @@ class BookmarksObserver extends Observer {
this.dispatch({type: at.PLACES_LINKS_CHANGED});
this.dispatch({
type: at.PLACES_BOOKMARK_REMOVED,
data: {url: uri.spec, bookmarkGuid: guid},
data: {url: uri.spec, bookmarkGuid: guid}
});
}
}
@ -229,7 +230,7 @@ class PlacesFeed {
if (topic === LINK_BLOCKED_EVENT) {
this.store.dispatch(ac.BroadcastToContent({
type: at.PLACES_LINK_BLOCKED,
data: {url: value},
data: {url: value}
}));
}
}
@ -240,7 +241,7 @@ class PlacesFeed {
openLink(action, where = "", isPrivate = false) {
const params = {
private: isPrivate,
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})
};
// Always include the referrer (even for http links) if we have one
@ -269,7 +270,7 @@ class PlacesFeed {
if (data) {
this.store.dispatch(ac.BroadcastToContent({
type: at.PLACES_SAVED_TO_POCKET,
data: {url, open_url: data.item.open_url, title, pocket_id: data.item.item_id},
data: {url, open_url: data.item.open_url, title, pocket_id: data.item.item_id}
}));
}
} catch (err) {

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

@ -22,8 +22,8 @@ const PREF_MIGRATION = {
collapsed: new Map([
["collapseTopSites", "topsites"],
["section.highlights.collapsed", "highlights"],
["section.topstories.collapsed", "topstories"],
]),
["section.topstories.collapsed", "topstories"]
])
};
this.PrefsFeed = class PrefsFeed {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -7,6 +7,8 @@ const EXPORTED_SYMBOLS = ["Screenshots"];
Cu.importGlobalProperties(["fetch"]);
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "BackgroundPageThumbs",
"resource://gre/modules/BackgroundPageThumbs.jsm");
ChromeUtils.defineModuleGetter(this, "PageThumbs",
@ -104,5 +106,5 @@ this.Screenshots = {
// Update the cache for future links and call back for existing content
cache.updateLink(property, screenshot);
onScreenshot(screenshot);
},
}
};

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

@ -11,7 +11,7 @@ const SEARCH_SHORTCUTS = [
{keyword: "@amazon", shortURL: "amazon", url: "https://amazon.com"},
{keyword: "@\u767E\u5EA6", shortURL: "baidu", url: "https://baidu.com"},
{keyword: "@google", shortURL: "google", url: "https://google.com"},
{keyword: "@\u044F\u043D\u0434\u0435\u043A\u0441", shortURL: "yandex", url: "https://yandex.com"},
{keyword: "@\u044F\u043D\u0434\u0435\u043A\u0441", shortURL: "yandex", url: "https://yandex.com"}
];
this.SEARCH_SHORTCUTS = SEARCH_SHORTCUTS;
@ -22,7 +22,7 @@ this.CUSTOM_SEARCH_SHORTCUTS = [
{keyword: "@duckduckgo", shortURL: "duckduckgo", url: "https://duckduckgo.com"},
{keyword: "@ebay", shortURL: "ebay", url: "https://ebay.com"},
{keyword: "@twitter", shortURL: "twitter", url: "https://twitter.com"},
{keyword: "@wikipedia", shortURL: "wikipedia", url: "https://wikipedia.org"},
{keyword: "@wikipedia", shortURL: "wikipedia", url: "https://wikipedia.org"}
];
// Note: you must add the activity stream branch to the beginning of this if using outside activity stream

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

@ -5,6 +5,7 @@
ChromeUtils.import("resource://gre/modules/EventEmitter.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {actionCreators: ac, actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
const {getDefaultOptions} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamStorage.jsm", {});
@ -24,8 +25,8 @@ const BUILT_IN_SECTIONS = {
nestedPrefs: options.show_spocs ? [{
name: "showSponsored",
titleString: "prefs_topstories_options_sponsored_label",
icon: "icon-info",
}] : [],
icon: "icon-info"
}] : []
},
shouldHidePref: options.hidden,
eventSource: "TOP_STORIES",
@ -34,8 +35,8 @@ const BUILT_IN_SECTIONS = {
learnMore: {
link: {
href: "https://getpocket.com/firefox/new_tab_learn_more",
id: "pocket_learn_more",
},
id: "pocket_learn_more"
}
},
privacyNoticeURL: "https://www.mozilla.org/privacy/firefox/#suggest-relevant-content",
compactCards: false,
@ -44,10 +45,10 @@ const BUILT_IN_SECTIONS = {
availableLinkMenuOptions: ["CheckBookmarkOrArchive", "CheckSavedToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"],
emptyState: {
message: {id: "topstories_empty_state", values: {provider: options.provider_name}},
icon: "check",
icon: "check"
},
shouldSendImpressionStats: true,
dedupeFrom: ["highlights"],
dedupeFrom: ["highlights"]
}),
"feeds.section.highlights": options => ({
id: "highlights",
@ -56,17 +57,17 @@ const BUILT_IN_SECTIONS = {
descString: {id: "prefs_highlights_description"},
nestedPrefs: [{
name: "section.highlights.includeVisited",
titleString: "prefs_highlights_options_visited_label",
titleString: "prefs_highlights_options_visited_label"
}, {
name: "section.highlights.includeBookmarks",
titleString: "settings_pane_highlights_options_bookmarks",
titleString: "settings_pane_highlights_options_bookmarks"
}, {
name: "section.highlights.includeDownloads",
titleString: "prefs_highlights_options_download_label",
titleString: "prefs_highlights_options_download_label"
}, {
name: "section.highlights.includePocket",
titleString: "prefs_highlights_options_pocket_label",
}],
titleString: "prefs_highlights_options_pocket_label"
}]
},
shouldHidePref: false,
eventSource: "HIGHLIGHTS",
@ -77,10 +78,10 @@ const BUILT_IN_SECTIONS = {
maxRows: 4,
emptyState: {
message: {id: "highlights_empty_state"},
icon: "highlights",
icon: "highlights"
},
shouldSendImpressionStats: false,
}),
shouldSendImpressionStats: false
})
};
const SectionsManager = {
@ -90,7 +91,7 @@ const SectionsManager = {
history: ["CheckBookmark", "CheckSavedToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl", "DeleteUrl"],
bookmark: ["CheckBookmark", "CheckSavedToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl", "DeleteUrl"],
pocket: ["ArchiveFromPocket", "CheckSavedToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"],
download: ["OpenFile", "ShowFile", "Separator", "GoToDownloadPage", "CopyDownloadLink", "Separator", "RemoveDownload", "BlockUrl"],
download: ["OpenFile", "ShowFile", "Separator", "GoToDownloadPage", "CopyDownloadLink", "Separator", "RemoveDownload", "BlockUrl"]
},
initialized: false,
sections: new Map(),
@ -106,7 +107,7 @@ const SectionsManager = {
if (section.dedupeFrom) {
this._dedupeConfiguration.push({
id: section.id,
dedupeFrom: section.dedupeFrom,
dedupeFrom: section.dedupeFrom
});
}
});
@ -203,13 +204,13 @@ const SectionsManager = {
url: card.url,
title: card.title,
description: card.description,
previewImageURL: card.image,
previewImageURL: card.image
});
// Highlights query skips bookmarks with no visits.
PlacesUtils.history.insert({
url,
title: card.title,
visits: [{}],
visits: [{}]
});
}
});
@ -298,7 +299,7 @@ const SectionsManager = {
Object.keys(this.CONTEXT_MENU_PREFS).forEach(k =>
Services.prefs.removeObserver(this.CONTEXT_MENU_PREFS[k], this));
SectionsManager.initialized = false;
},
}
};
for (const action of [
@ -310,7 +311,7 @@ for (const action of [
"UPDATE_SECTION",
"UPDATE_SECTION_CARD",
"INIT",
"UNINIT",
"UNINIT"
]) {
SectionsManager[action] = action;
}

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

@ -65,7 +65,7 @@ this.SnippetsFeed = class SnippetsFeed {
const resetDate = await profileAge.reset;
return {
createdWeeksAgo: Math.floor((Date.now() - createdDate) / ONE_WEEK),
resetWeeksAgo: resetDate ? Math.floor((Date.now() - resetDate) / ONE_WEEK) : null,
resetWeeksAgo: resetDate ? Math.floor((Date.now() - resetDate) / ONE_WEEK) : null
};
}
@ -80,7 +80,7 @@ this.SnippetsFeed = class SnippetsFeed {
searchEngineIdentifier: Services.search.defaultEngine.identifier,
engines: engines
.filter(engine => engine.identifier)
.map(engine => `${TARGET_SEARCHENGINE_PREFIX}${engine.identifier}`),
.map(engine => `${TARGET_SEARCHENGINE_PREFIX}${engine.identifier}`)
});
} else {
resolve({engines: [], searchEngineIdentifier: ""});
@ -97,13 +97,13 @@ this.SnippetsFeed = class SnippetsFeed {
version: addon.version,
type: addon.type,
isSystem: addon.isSystem,
isWebExtension: addon.isWebExtension,
isWebExtension: addon.isWebExtension
};
if (fullData) {
Object.assign(info[addon.id], {
name: addon.name,
userDisabled: addon.userDisabled,
installDate: addon.installDate,
installDate: addon.installDate
});
}
}
@ -154,7 +154,7 @@ this.SnippetsFeed = class SnippetsFeed {
defaultBrowser: this.isDefaultBrowser(),
isDevtoolsUser: this.isDevtoolsUser(),
blockList: await this._getBlockList() || [],
previousSessionEnd: this._previousSessionEnd,
previousSessionEnd: this._previousSessionEnd
};
this._dispatchChanges(data);
}

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

@ -147,7 +147,7 @@ this.Store = class Store {
async _initIndexedDB(telemetryKey) {
this.dbStorage = new ActivityStreamStorage({
storeNames: ["sectionPrefs", "snippets"],
telemetry: this.feeds.get(telemetryKey),
telemetry: this.feeds.get(telemetryKey)
});
// Accessing the db causes the object stores to be created / migrated.
// This needs to happen before other instances try to access the db, which

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

@ -3,6 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
const {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
ChromeUtils.defineModuleGetter(this, "setInterval", "resource://gre/modules/Timer.jsm");

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

@ -35,7 +35,7 @@ const USER_PREFS_ENCODING = {
"feeds.section.topstories": 1 << 2,
"feeds.section.highlights": 1 << 3,
"feeds.snippets": 1 << 4,
"showSponsored": 1 << 5,
"showSponsored": 1 << 5
};
const PREF_IMPRESSION_ID = "impressionId";
@ -102,7 +102,7 @@ this.TelemetryFeed = class TelemetryFeed {
try {
data_to_save = {
load_trigger_ts: perfService.getMostRecentAbsMarkStartByName("browser-open-newtab-start"),
load_trigger_type: "menu_plus_or_keyboard",
load_trigger_type: "menu_plus_or_keyboard"
};
} catch (e) {
// if no mark was returned, we have nothing to save
@ -149,8 +149,8 @@ this.TelemetryFeed = class TelemetryFeed {
{
value: new PingCentre({
topic: ACTIVITY_STREAM_ID,
overrideEndpointPref: ACTIVITY_STREAM_ENDPOINT_PREF,
}),
overrideEndpointPref: ACTIVITY_STREAM_ENDPOINT_PREF
})
});
return this.pingCentre;
}
@ -257,8 +257,8 @@ this.TelemetryFeed = class TelemetryFeed {
perf: {
load_trigger_type,
is_preloaded: false,
is_prerendered: false,
},
is_prerendered: false
}
};
if (load_trigger_ts) {
@ -329,7 +329,7 @@ this.TelemetryFeed = class TelemetryFeed {
const ping = {
addon_version: Services.appinfo.appBuildID,
locale: Services.locale.getAppLocaleAsLangTag(),
user_prefs: this.userPreferences,
user_prefs: this.userPreferences
};
// If the ping is part of a user session, add session-related info
@ -359,7 +359,7 @@ this.TelemetryFeed = class TelemetryFeed {
action: "activity_stream_impression_stats",
impression_id: this._impressionId,
client_id: "n/a",
session_id: "n/a",
session_id: "n/a"
}
);
}
@ -397,7 +397,7 @@ this.TelemetryFeed = class TelemetryFeed {
page: session.page,
session_duration: session.session_duration,
action: "activity_stream_session",
perf: session.perf,
perf: session.perf
}
);
}
@ -413,7 +413,7 @@ this.TelemetryFeed = class TelemetryFeed {
client_id: "n/a",
addon_version: Services.appinfo.appBuildID,
locale: Services.locale.getAppLocaleAsLangTag(),
impression_id: this._impressionId,
impression_id: this._impressionId
};
if (action.data.includeClientID) {
// Ping-centre client will fill in the client_id if it's not provided in the ping
@ -599,5 +599,5 @@ const EXPORTED_SYMBOLS = [
"PREF_IMPRESSION_ID",
"TELEMETRY_PREF",
"EVENTS_TELEMETRY_PREF",
"ROUTER_MESSAGE_PROVIDER_PREF",
"ROUTER_MESSAGE_PROVIDER_PREF"
];

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

@ -1,71 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Unicode specifies certain mnemonics for code pages and character classes.
// They call them "character properties" https://en.wikipedia.org/wiki/Unicode_character_property .
// These mnemonics are have been adopted by many regular expression libraries,
// however the standard Javascript regexp system doesn't support unicode
// character properties, so we have to define these ourself.
//
// Each of these sections contains the characters values / ranges for specific
// character property: Whitespace, Symbol (S), Punctuation (P), Number (N),
// Mark (M), and Letter (L).
const UNICODE_SPACE = "\x20\xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000";
const UNICODE_SYMBOL = "\\x24\\x2B\x3C-\x3E\\x5E\x60\\x7C\x7E\xA2-\xA6\xA8\xA9\xAC\xAE-\xB1\xB4\xB8\xD7\xF7\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0384\u0385\u03F6\u0482\u058D-\u058F\u0606-\u0608\u060B\u060E\u060F\u06DE\u06E9\u06FD\u06FE\u07F6\u09F2\u09F3\u09FA\u09FB\u0AF1\u0B70\u0BF3-\u0BFA\u0C7F\u0D4F\u0D79\u0E3F\u0F01-\u0F03\u0F13\u0F15-\u0F17\u0F1A-\u0F1F\u0F34\u0F36\u0F38\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE\u0FCF\u0FD5-\u0FD8\u109E\u109F\u1390-\u1399\u17DB\u1940\u19DE-\u19FF\u1B61-\u1B6A\u1B74-\u1B7C\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2044\u2052\u207A-\u207C\u208A-\u208C\u20A0-\u20BE\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u214F\u218A\u218B\u2190-\u2307\u230C-\u2328\u232B-\u23FE\u2400-\u2426\u2440-\u244A\u249C-\u24E9\u2500-\u2767\u2794-\u27C4\u27C7-\u27E5\u27F0-\u2982\u2999-\u29D7\u29DC-\u29FB\u29FE-\u2B73\u2B76-\u2B95\u2B98-\u2BB9\u2BBD-\u2BC8\u2BCA-\u2BD1\u2BEC-\u2BEF\u2CE5-\u2CEA\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3004\u3012\u3013\u3020\u3036\u3037\u303E\u303F\u309B\u309C\u3190\u3191\u3196-\u319F\u31C0-\u31E3\u3200-\u321E\u322A-\u3247\u3250\u3260-\u327F\u328A-\u32B0\u32C0-\u32FE\u3300-\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA700-\uA716\uA720\uA721\uA789\uA78A\uA828-\uA82B\uA836-\uA839\uAA77-\uAA79\uAB5B\uFB29\uFBB2-\uFBC1\uFDFC\uFDFD\uFE62\uFE64-\uFE66\uFE69\uFF04\uFF0B\uFF1C-\uFF1E\uFF3E\uFF40\uFF5C\uFF5E\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFFC\uFFFD";
const UNICODE_PUNCT = "\x21-\x23\x25-\\x2A\x2C-\x2F\x3A\x3B\\x3F\x40\\x5B-\\x5D\x5F\\x7B\x7D\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E44\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65";
const UNICODE_NUMBER = "0-9\xB2\xB3\xB9\xBC-\xBE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D58-\u0D5E\u0D66-\u0D78\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19";
const UNICODE_MARK = "\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08D4-\u08E1\u08E3-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C00-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C81-\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D01-\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u1885\u1886\u18A9\u1920-\u192B\u1930-\u193B\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1AB0-\u1ABE\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1CF8\u1CF9\u1DC0-\u1DF5\u1DFB-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69E\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C5\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uA9E5\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B-\uAA7D\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F";
const UNICODE_LETTER = "A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC";
const REGEXP_SPLITS = new RegExp(`[${UNICODE_SPACE}${UNICODE_SYMBOL}${UNICODE_PUNCT}]+`);
const REGEXP_ALPHANUMS = new RegExp(`^[${UNICODE_NUMBER}${UNICODE_MARK}${UNICODE_LETTER}]+$`);
/**
* Downcases the text, and splits it into consecutive alphanumeric characters.
* This is locale aware, and so will not strip accents. This uses "word
* breaks", and os is not appropriate for languages without them
* (e.g. Chinese).
*/
function tokenize(text) {
return text.toLocaleLowerCase().split(REGEXP_SPLITS).filter(tok => tok.match(REGEXP_ALPHANUMS));
}
/**
* Converts a sequence of tokens into an L2 normed TF-IDF. Any terms that are
* not preindexed (i.e. does have a computed inverse document frequency) will
* be dropped.
*/
function toksToTfIdfVector(tokens, vocab_idfs) {
let tfidfs = {};
// calcualte the term frequencies
for (let tok of tokens) {
if (!(tok in vocab_idfs)) {
continue;
}
if (!(tok in tfidfs)) {
tfidfs[tok] = [vocab_idfs[tok][0], 1];
} else {
tfidfs[tok][1]++;
}
}
// now multiply by the log inverse document frequencies, then take
// the L2 norm of this.
let l2Norm = 0.0;
Object.keys(tfidfs).forEach(tok => {
tfidfs[tok][1] *= vocab_idfs[tok][1];
l2Norm += tfidfs[tok][1] * tfidfs[tok][1];
});
l2Norm = Math.sqrt(l2Norm);
Object.keys(tfidfs).forEach(tok => {
tfidfs[tok][1] /= l2Norm;
});
return tfidfs;
}
const EXPORTED_SYMBOLS = ["tokenize", "toksToTfIdfVector"];

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

@ -18,7 +18,7 @@ const {
SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF,
SEARCH_SHORTCUTS_HAVE_PINNED_PREF,
checkHasSearchEngine,
getSearchProvider,
getSearchProvider
} = ChromeUtils.import("resource://activity-stream/lib/SearchShortcuts.jsm", {});
ChromeUtils.defineModuleGetter(this, "filterAdult",
@ -49,7 +49,7 @@ const SEARCH_FILTERS = [
"yahoo",
"bing",
"ask",
"duckduckgo",
"duckduckgo"
];
function getShortURLForCurrentSearch() {
@ -60,7 +60,7 @@ function getShortURLForCurrentSearch() {
this.TopSitesFeed = class TopSitesFeed {
constructor() {
this._tippyTopProvider = new TippyTopProvider();
XPCOMUtils.defineLazyGetter(this, "_currentSearchHostname", getShortURLForCurrentSearch);
this._currentSearchHostname = null;
this.dedupe = new Dedupe(this._dedupeKey);
this.frecentCache = new LinksCache(NewTabUtils.activityStreamLinks,
"getTopSites", CACHED_LINK_PROPS_TO_MIGRATE, (oldOptions, newOptions) =>
@ -77,18 +77,19 @@ this.TopSitesFeed = class TopSitesFeed {
this._storage = this.store.dbStorage.getDbTable("sectionPrefs");
this.refresh({broadcast: true});
Services.obs.addObserver(this, "browser-search-engine-modified");
XPCOMUtils.defineLazyGetter(this, "_currentSearchHostname", getShortURLForCurrentSearch);
}
uninit() {
PageThumbs.removeExpirationFilter(this);
Services.obs.removeObserver(this, "browser-search-engine-modified");
this._currentSearchHostname = null;
}
observe(subj, topic, data) {
// We should update the current top sites if the search engine has been changed since
// the search engine that gets filtered out of top sites has changed.
if (topic === "browser-search-engine-modified" && data === "engine-current" && this.store.getState().Prefs.values[NO_DEFAULT_SEARCH_TILE_EXP_PREF]) {
delete this._currentSearchHostname;
this._currentSearchHostname = getShortURLForCurrentSearch();
this.refresh({broadcast: true});
}
@ -107,7 +108,7 @@ this.TopSitesFeed = class TopSitesFeed {
for (const url of sites.split(",")) {
const site = {
isDefault: true,
url,
url
};
site.hostname = shortURL(site);
DEFAULT_TOP_SITES.push(site);
@ -222,14 +223,14 @@ this.TopSitesFeed = class TopSitesFeed {
const frecent = (await this.frecentCache.request({
// We need to overquery due to the top 5 alexa search + default search possibly being removed
numItems: numItems + SEARCH_FILTERS.length + 1,
topsiteFrecency: FRECENCY_THRESHOLD,
topsiteFrecency: FRECENCY_THRESHOLD
}))
.reduce((validLinks, link) => {
const hostname = shortURL(link);
if (!this.isExperimentOnAndLinkFilteredSearch(hostname)) {
validLinks.push({
...(searchShortcutsExperiment ? this.topSiteToSearchTopSite(link) : link),
hostname,
hostname
});
}
return validLinks;
@ -250,7 +251,7 @@ this.TopSitesFeed = class TopSitesFeed {
}
return [
...topsites,
searchShortcutsExperiment ? this.topSiteToSearchTopSite(link) : link,
searchShortcutsExperiment ? this.topSiteToSearchTopSite(link) : link
];
}, []);
@ -389,7 +390,7 @@ this.TopSitesFeed = class TopSitesFeed {
}, []);
this.store.dispatch(ac.BroadcastToContent({
type: at.UPDATE_SEARCH_SHORTCUTS,
data: {searchShortcuts},
data: {searchShortcuts}
}));
}
@ -401,7 +402,7 @@ this.TopSitesFeed = class TopSitesFeed {
return {
...site,
searchTopSite: true,
label: searchProvider.keyword,
label: searchProvider.keyword
};
}
@ -439,7 +440,7 @@ this.TopSitesFeed = class TopSitesFeed {
await Screenshots.maybeCacheScreenshot(link, url, "screenshot",
screenshot => this.store.dispatch(ac.BroadcastToContent({
data: {screenshot, url: link.url},
type: at.SCREENSHOT_UPDATED,
type: at.SCREENSHOT_UPDATED
})));
}
@ -452,14 +453,14 @@ this.TopSitesFeed = class TopSitesFeed {
const preview = await Screenshots.getScreenshotForURL(url) || "";
this.store.dispatch(ac.OnlyToOneContent({
data: {url, preview},
type: at.PREVIEW_RESPONSE,
type: at.PREVIEW_RESPONSE
}, target));
}
_requestRichIcon(url) {
this.store.dispatch({
type: at.RICH_ICON_MISSING,
data: {url},
data: {url}
});
}

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

@ -15,12 +15,6 @@ const {SectionsManager} = ChromeUtils.import("resource://activity-stream/lib/Sec
const {UserDomainAffinityProvider} = ChromeUtils.import("resource://activity-stream/lib/UserDomainAffinityProvider.jsm", {});
const {PersistentCache} = ChromeUtils.import("resource://activity-stream/lib/PersistentCache.jsm", {});
/* Not yet using personalization v2 taggers
const {NaiveBayesTextTagger} = ChromeUtils.import("resource://activity-stream/lib/NaiveBayesTextTagger.jsm", {});
const {NmfTextTagger} = ChromeUtils.import("resource://activity-stream/lib/NmfTextTagger.jsm", {});
const {RecipeExecutor} = ChromeUtils.import("resource://activity-stream/lib/RecipeExecutor.jsm", {});
*/
ChromeUtils.defineModuleGetter(this, "perfService", "resource://activity-stream/common/PerfService.jsm");
ChromeUtils.defineModuleGetter(this, "pktApi", "chrome://pocket/content/pktApi.jsm");
@ -205,7 +199,7 @@ this.TopStoriesFeed = class TopStoriesFeed {
"url": s.url,
"min_score": s.min_score || 0,
"score": this.personalized && this.affinityProvider ? this.affinityProvider.calculateItemRelevanceScore(s) : s.item_score || 1,
"spoc_meta": this.show_spocs ? {campaign_id: s.campaign_id, caps: s.caps} : {},
"spoc_meta": this.show_spocs ? {campaign_id: s.campaign_id, caps: s.caps} : {}
}))
.sort(this.personalized ? this.compareScore : (a, b) => 0);
}
@ -272,7 +266,7 @@ this.TopStoriesFeed = class TopStoriesFeed {
this.store.dispatch(ac.PerfEvent({
event: "topstories.domain.affinity.calculation.ms",
value: Math.round(perfService.absNow() - start),
value: Math.round(perfService.absNow() - start)
}));
const affinities = this.affinityProvider.getAffinities();

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

@ -13,7 +13,7 @@ const DEFAULT_TIME_SEGMENTS = [
{"id": "day", "startTime": 86400, "endTime": 3600, "weightPosition": 0.75},
{"id": "week", "startTime": 604800, "endTime": 86400, "weightPosition": 0.5},
{"id": "weekPlus", "startTime": 0, "endTime": 604800, "weightPosition": 0.25},
{"id": "alltime", "startTime": 0, "endTime": 0, "weightPosition": 0.25},
{"id": "alltime", "startTime": 0, "endTime": 0, "weightPosition": 0.25}
];
const DEFAULT_PARAMETER_SETS = {
@ -24,8 +24,8 @@ const DEFAULT_PARAMETER_SETS = {
"perfectFrequencyVisits": 10,
"perfectCombinedDomainScore": 2,
"multiDomainBoost": 0.1,
"itemScoreFactor": 0,
},
"itemScoreFactor": 0
}
};
const DEFAULT_MAX_HISTORY_QUERY_RESULTS = 1000;
@ -322,7 +322,7 @@ this.UserDomainAffinityProvider = class UserDomainAffinityProvider {
parameterSets: this.parameterSets,
maxHistoryQueryResults: this.maxHistoryQueryResults,
version: this.version,
scores: this.scores,
scores: this.scores
};
}
};

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

@ -142,8 +142,6 @@ pocket_read_more=Lok macuk gi lamal:
# end of the list of popular topic links.
pocket_read_even_more=Nen Lok mapol
pocket_learn_more=Nong ngec mapol
highlights_empty_state=Cak yeny, ka wa binyuto coc akwana mabeco, video, ki potbuk mukene ma ilimo cokcokki onyo ma kiketo alamabuk kany.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,9 +144,6 @@ pocket_read_more=المواضيع الشائعة:
# end of the list of popular topic links.
pocket_read_even_more=اعرض المزيد من الأخبار
pocket_more_reccommendations=مقترحات أخرى
pocket_learn_more=اطّلع على المزيد
highlights_empty_state=ابدأ التصفح وسنعرض أمامك بعض المقالات والفيديوهات والمواقع الأخرى التي زرتها حديثا أو أضفتها إلى العلامات هنا.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Məşhur Mövzular:
# end of the list of popular topic links.
pocket_read_even_more=Daha çox hekayə gör
pocket_more_reccommendations=Daha Çox Tövsiyyələr
pocket_learn_more=Ətraflı Öyrən
pocket_cta_button=Pocket əldə edin
pocket_cta_text=Sevdiyiniz məqalələri Pocket-də saxlayın və möhtəşəm yeni yazıları kəşf edin.
highlights_empty_state=İnternetdə gəzməyə başlayın, burada ziyarət edəcəyiniz və ya əlfəcinləyəcəyiniz məqalə, video və digər səhifələri göstərəcəyik.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Папулярныя тэмы:
# end of the list of popular topic links.
pocket_read_even_more=Іншыя навіны
pocket_more_reccommendations=Больш рэкамендацый
pocket_learn_more=Падрабязней
pocket_cta_button=Атрымаць Pocket
pocket_cta_text=Захоўвайце ўлюбёныя гісторыі ў Pocket, і сілкуйце свой розум добрай чытанкай.
highlights_empty_state=Пачніце агляданне, і мы пакажам вам тут некаторыя з найлепшых артыкулаў, відэаролікаў і іншых старонак, якія вы нядаўна наведалі або дадалі ў закладкі.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -1,7 +1,7 @@
newtab_page_title=K'ak'a' ruwi'
header_top_sites=Jeb'ël Taq Ruxaq
header_highlights=Ya'on kiq'ij
header_top_sites=Utziläj taq Ruxaq K'amaya'l
header_highlights=Taq k'ewachinïk
# LOCALIZATION NOTE(header_recommended_by): This is followed by the name
# of the corresponding content provider.
header_recommended_by=Chilab'en ruma {provider}
@ -106,8 +106,8 @@ prefs_highlights_options_download_label=K'a B'a' Keqasäx
prefs_highlights_options_pocket_label=Taq Ruxaq Eyakon pa Pocket
prefs_snippets_description=Kik'exoj Mozilla chuqa' Firefox
settings_pane_button_label=Tawichinaj ri ruxaq richin K'ak'a' Ruwi'
settings_pane_topsites_header=Jeb'ël Taq Ruxaq
settings_pane_highlights_header=Ya'on kiq'ij
settings_pane_topsites_header=Utziläj taq ruxaq K'amaya'l
settings_pane_highlights_header=Taq k'ewachinïk
settings_pane_highlights_options_bookmarks=Yaketal
# LOCALIZATION NOTE(settings_pane_snippets_header): For the "Snippets" feature
# traditionally on about:home. Alternative translation options: "Small Note" or
@ -144,7 +144,6 @@ pocket_read_more=Nima'q taq Na'oj:
# end of the list of popular topic links.
pocket_read_even_more=Ketz'et ch'aqa' chik taq B'anob'äl
highlights_empty_state=Katok pa k'amaya'l richin niqak'üt chawäch jeb'ël taq cholna'oj, taq silowachib'äl, chuqa' ch'aqa' chik taq ruxaq k'a b'a' ke'atz'ët o aya'on kan ketal wawe'.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Populární témata:
# end of the list of popular topic links.
pocket_read_even_more=Zobrazit více článků
pocket_more_reccommendations=Další doporučení
pocket_learn_more=Zjistit více
pocket_cta_button=Získejte Pocket
pocket_cta_text=Ukládejte si články do služby Pocket a užívejte si skvělé čtení.
highlights_empty_state=Začněte prohlížet a my vám zde ukážeme některé skvělé články, videa a další stránky, které jste nedávno viděli nebo uložili do záložek.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Pynciau Poblogaidd:
# end of the list of popular topic links.
pocket_read_even_more=Gweld Rhagor o Straeon
pocket_more_reccommendations=Rhagor o Argymhellion
pocket_learn_more=Dysgu Rhagor
pocket_cta_button=Defnyddio Pocket
pocket_cta_text=Cadw'r straeon rydych yn eu hoffi i Pocket a bwydo'ch meddwl á deunydd diddorol.
highlights_empty_state=Cychwynnwch bori ac fe ddangoswn rhai erthyglau, fideos a thudalennau eraill difyr rydych wedi ymweld â nhw'n ddiweddar neu wedi gosod nod tudalen arnyn nhw yma.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Woblubowane temy:
# end of the list of popular topic links.
pocket_read_even_more=Dalšne powěźeńki se woglědaś
pocket_more_reccommendations=Dalšne pórucenja
pocket_learn_more=Dalšne informacije
pocket_cta_button=Pocket wobstaraś
pocket_cta_text=Składujśo tšojeńka, kótarež se wam spódobuju, w Pocket a žywśo swój duch z fasciněrujucymi cytańkami.
highlights_empty_state=Zachopśo pśeglědowaś, a pokažomy někotare wjelicne nastawki, wideo a druge boki, kótarež sćo se njedawno woglědał abo how ako cytańske znamjenja składował.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,10 +144,6 @@ pocket_read_more=Δημοφιλή θέματα:
# end of the list of popular topic links.
pocket_read_even_more=Προβολή περισσότερων ιστοριών
pocket_more_reccommendations=Περισσότερες προτάσεις
pocket_learn_more=Μάθετε περισσότερα
pocket_cta_button=Αποκτήστε το Pocket
highlights_empty_state=Ξεκινήστε την περιήγηση και θα σάς δείξουμε μερικά υπέροχα άρθρα, βίντεο και άλλες σελίδες που έχετε επισκεφθεί πρόσφατα ή έχετε προσθέσει στους σελιδοδείκτες σας.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Popular Topics:
# end of the list of popular topic links.
pocket_read_even_more=View More Stories
pocket_more_reccommendations=More Recommendations
pocket_learn_more=Learn More
pocket_cta_button=Get Pocket
pocket_cta_text=Save the stories you love in Pocket, and fuel your mind with fascinating reads.
highlights_empty_state=Start browsing, and well show some of the great articles, videos, and other pages youve recently visited or bookmarked here.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Tópicos populares:
# end of the list of popular topic links.
pocket_read_even_more=Ver más historias
pocket_more_reccommendations=Más recomendaciones
pocket_learn_more=Conocer más
pocket_cta_button=Obtener Pocket
pocket_cta_text=Guarde las historias que quiera en Pocket y potencie su mente con lecturas fascinantes.
highlights_empty_state=Comenzá a navegar y te mostraremos algunos de los mejores artículos, videos y otras páginas que hayás visitado o marcado acá.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,10 +144,6 @@ pocket_read_more=Temas populares:
# end of the list of popular topic links.
pocket_read_even_more=Ver más historias
pocket_more_reccommendations=Más recomendaciones
pocket_learn_more=Aprender más
pocket_cta_button=Obtener Pocket
highlights_empty_state=Empieza a navegar, y nosotros te mostraremos aquí algunos de los mejores artículos, videos y otras páginas que hayas visitado recientemente o marcado.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

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

@ -144,11 +144,6 @@ pocket_read_more=Temas populares:
# end of the list of popular topic links.
pocket_read_even_more=Ver más historias
pocket_more_reccommendations=Más recomendaciones
pocket_learn_more=Saber más
pocket_cta_button=Obtener Pocket
pocket_cta_text=Guarda las historias que quieras en Pocket y llena tu mente con fascinantes lecturas.
highlights_empty_state=Empieza a navegar, y nosotros te mostraremos aquí algunos de los mejores artículos, videos y otras páginas que hayas visitado recientemente o marcado.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше