mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 19:55:39 +00:00
Bug 1494427 - [Export] Add locale targeting, ASR onboarding/user pref fixes, test fixes to Activity Stream r=ursula
Differential Revision: https://phabricator.services.mozilla.com/D7196 --HG-- rename : browser/components/newtab/locales/ur/strings.properties => browser/components/newtab/locales/is/strings.properties extra : moz-landing-system : lando
This commit is contained in:
parent
d8e0094e97
commit
ddf8f0cb90
@ -20,7 +20,7 @@ const TOPIC_CONTENT_DOCUMENT_INTERACTIVE = "content-document-interactive";
|
|||||||
|
|
||||||
// Automated tests ensure packaged locales are in this list. Copied output of:
|
// Automated tests ensure packaged locales are in this list. Copied output of:
|
||||||
// https://github.com/mozilla/activity-stream/blob/master/bin/render-activity-stream-html.js
|
// https://github.com/mozilla/activity-stream/blob/master/bin/render-activity-stream-html.js
|
||||||
const ACTIVITY_STREAM_BCP47 = "en-US ach an ar ast az be bg bn-BD bn-IN br bs ca cak crh cs cy da de dsb el en-CA en-GB eo es-AR es-CL es-ES es-MX et eu fa ff fi fr fy-NL ga-IE gd gl gn gu-IN he hi-IN hr hsb hu hy-AM ia id it ja ja-JP-macos ka kab kk km kn ko lij lo lt ltg lv mai mk ml mr ms my nb-NO ne-NP nl nn-NO oc pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta te th tl tr uk ur uz vi zh-CN zh-TW".split(" ");
|
const ACTIVITY_STREAM_BCP47 = "en-US ach an ar ast az be bg bn-BD bn-IN br bs ca cak crh cs cy da de dsb el en-CA en-GB eo es-AR es-CL es-ES es-MX et eu fa ff fi fr fy-NL ga-IE gd gl gn gu-IN he hi-IN hr hsb hu hy-AM ia id is it ja ja-JP-macos ka kab kk km kn ko lij lo lt ltg lv mai mk ml mr ms my nb-NO ne-NP nl nn-NO oc pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta te th tl tr uk ur uz vi zh-CN zh-TW".split(" ");
|
||||||
|
|
||||||
const ABOUT_URL = "about:newtab";
|
const ABOUT_URL = "about:newtab";
|
||||||
const BASE_URL = "resource://activity-stream/";
|
const BASE_URL = "resource://activity-stream/";
|
||||||
|
@ -11,6 +11,7 @@ import {SimpleSnippet} from "./templates/SimpleSnippet/SimpleSnippet";
|
|||||||
|
|
||||||
const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
|
const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
|
||||||
const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
|
const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
|
||||||
|
const ASR_CONTAINER_ID = "asr-newtab-container";
|
||||||
|
|
||||||
export const ASRouterUtils = {
|
export const ASRouterUtils = {
|
||||||
addListener(listener) {
|
addListener(listener) {
|
||||||
@ -40,9 +41,6 @@ export const ASRouterUtils = {
|
|||||||
unblockBundle(bundle) {
|
unblockBundle(bundle) {
|
||||||
ASRouterUtils.sendMessage({type: "UNBLOCK_BUNDLE", data: {bundle}});
|
ASRouterUtils.sendMessage({type: "UNBLOCK_BUNDLE", data: {bundle}});
|
||||||
},
|
},
|
||||||
getNextMessage() {
|
|
||||||
ASRouterUtils.sendMessage({type: "GET_NEXT_MESSAGE"});
|
|
||||||
},
|
|
||||||
overrideMessage(id) {
|
overrideMessage(id) {
|
||||||
ASRouterUtils.sendMessage({type: "OVERRIDE_MESSAGE", data: {id}});
|
ASRouterUtils.sendMessage({type: "OVERRIDE_MESSAGE", data: {id}});
|
||||||
},
|
},
|
||||||
@ -50,7 +48,7 @@ export const ASRouterUtils = {
|
|||||||
const payload = ac.ASRouterUserEvent(ping);
|
const payload = ac.ASRouterUserEvent(ping);
|
||||||
global.RPMSendAsyncMessage(AS_GENERAL_OUTGOING_MESSAGE_NAME, payload);
|
global.RPMSendAsyncMessage(AS_GENERAL_OUTGOING_MESSAGE_NAME, payload);
|
||||||
},
|
},
|
||||||
getEndpoint() {
|
getPreviewEndpoint() {
|
||||||
if (window.location.href.includes("endpoint")) {
|
if (window.location.href.includes("endpoint")) {
|
||||||
const params = new URLSearchParams(window.location.href.slice(window.location.href.indexOf("endpoint")));
|
const params = new URLSearchParams(window.location.href.slice(window.location.href.indexOf("endpoint")));
|
||||||
try {
|
try {
|
||||||
@ -203,14 +201,14 @@ export class ASRouterUISurface extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const endpoint = ASRouterUtils.getEndpoint();
|
const endpoint = ASRouterUtils.getPreviewEndpoint();
|
||||||
ASRouterUtils.addListener(this.onMessageFromParent);
|
ASRouterUtils.addListener(this.onMessageFromParent);
|
||||||
|
|
||||||
// If we are loading about:welcome we want to trigger the onboarding messages
|
// If we are loading about:welcome we want to trigger the onboarding messages
|
||||||
if (this.props.document.location.href === "about:welcome") {
|
if (this.props.document.location.href === "about:welcome") {
|
||||||
ASRouterUtils.sendMessage({type: "TRIGGER", data: {trigger: {id: "firstRun"}}});
|
ASRouterUtils.sendMessage({type: "TRIGGER", data: {trigger: {id: "firstRun"}}});
|
||||||
} else {
|
} else {
|
||||||
ASRouterUtils.sendMessage({type: "CONNECT_UI_REQUEST", data: {endpoint}});
|
ASRouterUtils.sendMessage({type: "SNIPPETS_REQUEST", data: {endpoint}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +232,6 @@ export class ASRouterUISurface extends React.PureComponent {
|
|||||||
links={this.state.message.content.links}
|
links={this.state.message.content.links}
|
||||||
sendClick={this.sendClick} />}
|
sendClick={this.sendClick} />}
|
||||||
UISurface="NEWTAB_FOOTER_BAR"
|
UISurface="NEWTAB_FOOTER_BAR"
|
||||||
getNextMessage={ASRouterUtils.getNextMessage}
|
|
||||||
onBlock={this.onBlockById(this.state.message.id)}
|
onBlock={this.onBlockById(this.state.message.id)}
|
||||||
onAction={ASRouterUtils.executeAction}
|
onAction={ASRouterUtils.executeAction}
|
||||||
sendUserActionTelemetry={this.sendUserActionTelemetry} />
|
sendUserActionTelemetry={this.sendUserActionTelemetry} />
|
||||||
@ -249,7 +246,6 @@ export class ASRouterUISurface extends React.PureComponent {
|
|||||||
UISurface="NEWTAB_OVERLAY"
|
UISurface="NEWTAB_OVERLAY"
|
||||||
onAction={ASRouterUtils.executeAction}
|
onAction={ASRouterUtils.executeAction}
|
||||||
onDoneButton={this.clearBundle(this.state.bundle.bundle)}
|
onDoneButton={this.clearBundle(this.state.bundle.bundle)}
|
||||||
getNextMessage={ASRouterUtils.getNextMessage}
|
|
||||||
sendUserActionTelemetry={this.sendUserActionTelemetry} />);
|
sendUserActionTelemetry={this.sendUserActionTelemetry} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,10 +266,10 @@ export class ASRouterUISurface extends React.PureComponent {
|
|||||||
const {message, bundle} = this.state;
|
const {message, bundle} = this.state;
|
||||||
if (!message.id && !bundle.template) { return null; }
|
if (!message.id && !bundle.template) { return null; }
|
||||||
return (
|
return (
|
||||||
<div>
|
<React.Fragment>
|
||||||
{this.renderPreviewBanner()}
|
{this.renderPreviewBanner()}
|
||||||
{bundle.template === "onboarding" ? this.renderOnboarding() : this.renderSnippets()}
|
{bundle.template === "onboarding" ? this.renderOnboarding() : this.renderSnippets()}
|
||||||
</div>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +283,14 @@ export class ASRouterContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_mount() {
|
_mount() {
|
||||||
this.containerElement = global.document.getElementById("snippets-container");
|
this.containerElement = global.document.getElementById(ASR_CONTAINER_ID);
|
||||||
|
if (!this.containerElement) {
|
||||||
|
this.containerElement = global.document.createElement("div");
|
||||||
|
this.containerElement.id = ASR_CONTAINER_ID;
|
||||||
|
this.containerElement.style.zIndex = 1;
|
||||||
|
global.document.body.appendChild(this.containerElement);
|
||||||
|
}
|
||||||
|
|
||||||
ReactDOM.render(<ASRouterUISurface />, this.containerElement);
|
ReactDOM.render(<ASRouterUISurface />, this.containerElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +100,10 @@ Name | Type | Example value | Description
|
|||||||
`providerCohorts` | `Object` | `{onboarding: "hello"}` | Cohorts defined for all providers
|
`providerCohorts` | `Object` | `{onboarding: "hello"}` | Cohorts defined for all providers
|
||||||
`previousSessionEnd` | `Number` | `1536325802800` | Timestamp in milliseconds of previously closed session
|
`previousSessionEnd` | `Number` | `1536325802800` | Timestamp in milliseconds of previously closed session
|
||||||
`totalBookmarksCount` | `Number` | `8` | Total number of bookmarks
|
`totalBookmarksCount` | `Number` | `8` | Total number of bookmarks
|
||||||
`firefoxVersion` | `Number` | `64` | The major Firefox version of the browser
|
`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
|
`region` | `String` | `US` | Country code retrieved from `location.services.mozilla.com` can be `""` if request did not finish, encountered an error
|
||||||
|
`locale` | `String` | `en-US` | Locale of the browser
|
||||||
|
`localeLanguageCode` | `String` | `en` | Locale language code (without country code) of the browser
|
||||||
#### addonsInfo Example
|
#### addonsInfo Example
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
@ -16,7 +16,7 @@ export class ASRouterAdmin extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const endpoint = ASRouterUtils.getEndpoint();
|
const endpoint = ASRouterUtils.getPreviewEndpoint();
|
||||||
ASRouterUtils.sendMessage({type: "ADMIN_CONNECT_STATE", data: {endpoint}});
|
ASRouterUtils.sendMessage({type: "ADMIN_CONNECT_STATE", data: {endpoint}});
|
||||||
ASRouterUtils.addListener(this.onMessage);
|
ASRouterUtils.addListener(this.onMessage);
|
||||||
}
|
}
|
||||||
@ -51,6 +51,10 @@ export class ASRouterAdmin extends React.PureComponent {
|
|||||||
return () => ASRouterUtils.overrideMessage(id);
|
return () => ASRouterUtils.overrideMessage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expireCache() {
|
||||||
|
ASRouterUtils.sendMessage({type: "EXPIRE_QUERY_CACHE"});
|
||||||
|
}
|
||||||
|
|
||||||
renderMessageItem(msg) {
|
renderMessageItem(msg) {
|
||||||
const isCurrent = msg.id === this.state.lastMessageId;
|
const isCurrent = msg.id === this.state.lastMessageId;
|
||||||
const isBlocked = this.state.messageBlockList.includes(msg.id);
|
const isBlocked = this.state.messageBlockList.includes(msg.id);
|
||||||
@ -113,7 +117,8 @@ export class ASRouterAdmin extends React.PureComponent {
|
|||||||
render() {
|
render() {
|
||||||
return (<div className="asrouter-admin outer-wrapper">
|
return (<div className="asrouter-admin outer-wrapper">
|
||||||
<h1>AS Router Admin</h1>
|
<h1>AS Router Admin</h1>
|
||||||
<button className="button primary" onClick={ASRouterUtils.getNextMessage}>Refresh Current Message</button>
|
<h2>Targeting Utilities</h2>
|
||||||
|
<button className="button" onClick={this.expireCache}>Expire Cache</button> (This expires the cache in ASR Targeting for bookmarks and top sites)
|
||||||
<h2>Message Providers</h2>
|
<h2>Message Providers</h2>
|
||||||
{this.state.providers ? this.renderProviders() : null}
|
{this.state.providers ? this.renderProviders() : null}
|
||||||
<h2>Messages</h2>
|
<h2>Messages</h2>
|
||||||
|
@ -31,6 +31,8 @@ export class _StartupOverlay extends React.PureComponent {
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const {flowId, flowBeginTime} = await response.json();
|
const {flowId, flowBeginTime} = await response.json();
|
||||||
this.setState({flowId, flowBeginTime});
|
this.setState({flowId, flowBeginTime});
|
||||||
|
} else {
|
||||||
|
this.props.dispatch(ac.OnlyToMain({type: at.TELEMETRY_UNDESIRED_EVENT, data: {event: "FXA_METRICS_FETCH_ERROR", value: response.status}}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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: {event: "FXA_METRICS_ERROR"}}));
|
||||||
@ -69,15 +71,24 @@ export class _StartupOverlay extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
this.props.dispatch(ac.UserEvent({event: "SUBMIT_EMAIL"}));
|
this.props.dispatch(ac.UserEvent({event: "SUBMIT_EMAIL", ...this._getFormInfo()}));
|
||||||
|
|
||||||
window.addEventListener("visibilitychange", this.removeOverlay);
|
window.addEventListener("visibilitychange", this.removeOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
clickSkip() {
|
clickSkip() {
|
||||||
this.props.dispatch(ac.UserEvent({event: "SKIPPED_SIGNIN"}));
|
this.props.dispatch(ac.UserEvent({event: "SKIPPED_SIGNIN", ...this._getFormInfo()}));
|
||||||
this.removeOverlay();
|
this.removeOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report to telemetry additional information about the form submission.
|
||||||
|
*/
|
||||||
|
_getFormInfo() {
|
||||||
|
const value = {has_flow_params: this.state.flowId.length > 0};
|
||||||
|
return {value};
|
||||||
|
}
|
||||||
|
|
||||||
onInputInvalid(e) {
|
onInputInvalid(e) {
|
||||||
let error = e.target.previousSibling;
|
let error = e.target.previousSibling;
|
||||||
error.classList.add("active");
|
error.classList.add("active");
|
||||||
|
@ -964,6 +964,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
|
|||||||
|
|
||||||
const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
|
const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
|
||||||
const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
|
const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
|
||||||
|
const ASR_CONTAINER_ID = "asr-newtab-container";
|
||||||
|
|
||||||
const ASRouterUtils = {
|
const ASRouterUtils = {
|
||||||
addListener(listener) {
|
addListener(listener) {
|
||||||
@ -993,9 +994,6 @@ const ASRouterUtils = {
|
|||||||
unblockBundle(bundle) {
|
unblockBundle(bundle) {
|
||||||
ASRouterUtils.sendMessage({ type: "UNBLOCK_BUNDLE", data: { bundle } });
|
ASRouterUtils.sendMessage({ type: "UNBLOCK_BUNDLE", data: { bundle } });
|
||||||
},
|
},
|
||||||
getNextMessage() {
|
|
||||||
ASRouterUtils.sendMessage({ type: "GET_NEXT_MESSAGE" });
|
|
||||||
},
|
|
||||||
overrideMessage(id) {
|
overrideMessage(id) {
|
||||||
ASRouterUtils.sendMessage({ type: "OVERRIDE_MESSAGE", data: { id } });
|
ASRouterUtils.sendMessage({ type: "OVERRIDE_MESSAGE", data: { id } });
|
||||||
},
|
},
|
||||||
@ -1003,7 +1001,7 @@ const ASRouterUtils = {
|
|||||||
const payload = common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__["actionCreators"].ASRouterUserEvent(ping);
|
const payload = common_Actions_jsm__WEBPACK_IMPORTED_MODULE_1__["actionCreators"].ASRouterUserEvent(ping);
|
||||||
global.RPMSendAsyncMessage(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_2__["OUTGOING_MESSAGE_NAME"], payload);
|
global.RPMSendAsyncMessage(content_src_lib_init_store__WEBPACK_IMPORTED_MODULE_2__["OUTGOING_MESSAGE_NAME"], payload);
|
||||||
},
|
},
|
||||||
getEndpoint() {
|
getPreviewEndpoint() {
|
||||||
if (window.location.href.includes("endpoint")) {
|
if (window.location.href.includes("endpoint")) {
|
||||||
const params = new URLSearchParams(window.location.href.slice(window.location.href.indexOf("endpoint")));
|
const params = new URLSearchParams(window.location.href.slice(window.location.href.indexOf("endpoint")));
|
||||||
try {
|
try {
|
||||||
@ -1159,14 +1157,14 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_6___default.a.Pur
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const endpoint = ASRouterUtils.getEndpoint();
|
const endpoint = ASRouterUtils.getPreviewEndpoint();
|
||||||
ASRouterUtils.addListener(this.onMessageFromParent);
|
ASRouterUtils.addListener(this.onMessageFromParent);
|
||||||
|
|
||||||
// If we are loading about:welcome we want to trigger the onboarding messages
|
// If we are loading about:welcome we want to trigger the onboarding messages
|
||||||
if (this.props.document.location.href === "about:welcome") {
|
if (this.props.document.location.href === "about:welcome") {
|
||||||
ASRouterUtils.sendMessage({ type: "TRIGGER", data: { trigger: { id: "firstRun" } } });
|
ASRouterUtils.sendMessage({ type: "TRIGGER", data: { trigger: { id: "firstRun" } } });
|
||||||
} else {
|
} else {
|
||||||
ASRouterUtils.sendMessage({ type: "CONNECT_UI_REQUEST", data: { endpoint } });
|
ASRouterUtils.sendMessage({ type: "SNIPPETS_REQUEST", data: { endpoint } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1192,7 +1190,6 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_6___default.a.Pur
|
|||||||
links: this.state.message.content.links,
|
links: this.state.message.content.links,
|
||||||
sendClick: this.sendClick }),
|
sendClick: this.sendClick }),
|
||||||
UISurface: "NEWTAB_FOOTER_BAR",
|
UISurface: "NEWTAB_FOOTER_BAR",
|
||||||
getNextMessage: ASRouterUtils.getNextMessage,
|
|
||||||
onBlock: this.onBlockById(this.state.message.id),
|
onBlock: this.onBlockById(this.state.message.id),
|
||||||
onAction: ASRouterUtils.executeAction,
|
onAction: ASRouterUtils.executeAction,
|
||||||
sendUserActionTelemetry: this.sendUserActionTelemetry }))
|
sendUserActionTelemetry: this.sendUserActionTelemetry }))
|
||||||
@ -1205,7 +1202,6 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_6___default.a.Pur
|
|||||||
UISurface: "NEWTAB_OVERLAY",
|
UISurface: "NEWTAB_OVERLAY",
|
||||||
onAction: ASRouterUtils.executeAction,
|
onAction: ASRouterUtils.executeAction,
|
||||||
onDoneButton: this.clearBundle(this.state.bundle.bundle),
|
onDoneButton: this.clearBundle(this.state.bundle.bundle),
|
||||||
getNextMessage: ASRouterUtils.getNextMessage,
|
|
||||||
sendUserActionTelemetry: this.sendUserActionTelemetry }));
|
sendUserActionTelemetry: this.sendUserActionTelemetry }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1232,7 +1228,7 @@ class ASRouterUISurface extends react__WEBPACK_IMPORTED_MODULE_6___default.a.Pur
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
|
return react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(
|
||||||
"div",
|
react__WEBPACK_IMPORTED_MODULE_6___default.a.Fragment,
|
||||||
null,
|
null,
|
||||||
this.renderPreviewBanner(),
|
this.renderPreviewBanner(),
|
||||||
bundle.template === "onboarding" ? this.renderOnboarding() : this.renderSnippets()
|
bundle.template === "onboarding" ? this.renderOnboarding() : this.renderSnippets()
|
||||||
@ -1249,7 +1245,14 @@ class ASRouterContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_mount() {
|
_mount() {
|
||||||
this.containerElement = global.document.getElementById("snippets-container");
|
this.containerElement = global.document.getElementById(ASR_CONTAINER_ID);
|
||||||
|
if (!this.containerElement) {
|
||||||
|
this.containerElement = global.document.createElement("div");
|
||||||
|
this.containerElement.id = ASR_CONTAINER_ID;
|
||||||
|
this.containerElement.style.zIndex = 1;
|
||||||
|
global.document.body.appendChild(this.containerElement);
|
||||||
|
}
|
||||||
|
|
||||||
react_dom__WEBPACK_IMPORTED_MODULE_7___default.a.render(react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(ASRouterUISurface, null), this.containerElement);
|
react_dom__WEBPACK_IMPORTED_MODULE_7___default.a.render(react__WEBPACK_IMPORTED_MODULE_6___default.a.createElement(ASRouterUISurface, null), this.containerElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1784,7 +1787,7 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
const endpoint = _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].getEndpoint();
|
const endpoint = _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].getPreviewEndpoint();
|
||||||
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].sendMessage({ type: "ADMIN_CONNECT_STATE", data: { endpoint } });
|
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].sendMessage({ type: "ADMIN_CONNECT_STATE", data: { endpoint } });
|
||||||
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].addListener(this.onMessage);
|
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].addListener(this.onMessage);
|
||||||
}
|
}
|
||||||
@ -1819,6 +1822,10 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
|
|||||||
return () => _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].overrideMessage(id);
|
return () => _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].overrideMessage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expireCache() {
|
||||||
|
_asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].sendMessage({ type: "EXPIRE_QUERY_CACHE" });
|
||||||
|
}
|
||||||
|
|
||||||
renderMessageItem(msg) {
|
renderMessageItem(msg) {
|
||||||
const isCurrent = msg.id === this.state.lastMessageId;
|
const isCurrent = msg.id === this.state.lastMessageId;
|
||||||
const isBlocked = this.state.messageBlockList.includes(msg.id);
|
const isBlocked = this.state.messageBlockList.includes(msg.id);
|
||||||
@ -1970,10 +1977,16 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_1___default.a.PureCom
|
|||||||
"AS Router Admin"
|
"AS Router Admin"
|
||||||
),
|
),
|
||||||
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
|
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
|
||||||
"button",
|
"h2",
|
||||||
{ className: "button primary", onClick: _asrouter_asrouter_content__WEBPACK_IMPORTED_MODULE_0__["ASRouterUtils"].getNextMessage },
|
null,
|
||||||
"Refresh Current Message"
|
"Targeting Utilities"
|
||||||
),
|
),
|
||||||
|
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
|
||||||
|
"button",
|
||||||
|
{ className: "button", onClick: this.expireCache },
|
||||||
|
"Expire Cache"
|
||||||
|
),
|
||||||
|
" (This expires the cache in ASR Targeting for bookmarks and top sites)",
|
||||||
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
|
react__WEBPACK_IMPORTED_MODULE_1___default.a.createElement(
|
||||||
"h2",
|
"h2",
|
||||||
null,
|
null,
|
||||||
@ -5144,6 +5157,8 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
|
|||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const { flowId, flowBeginTime } = yield response.json();
|
const { flowId, flowBeginTime } = yield response.json();
|
||||||
_this.setState({ flowId, flowBeginTime });
|
_this.setState({ flowId, flowBeginTime });
|
||||||
|
} else {
|
||||||
|
_this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT, data: { event: "FXA_METRICS_FETCH_ERROR", value: response.status } }));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
_this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT, data: { event: "FXA_METRICS_ERROR" } }));
|
_this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].OnlyToMain({ type: common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionTypes"].TELEMETRY_UNDESIRED_EVENT, data: { event: "FXA_METRICS_ERROR" } }));
|
||||||
@ -5183,15 +5198,24 @@ class _StartupOverlay extends react__WEBPACK_IMPORTED_MODULE_3___default.a.PureC
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: "SUBMIT_EMAIL" }));
|
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent(Object.assign({ event: "SUBMIT_EMAIL" }, this._getFormInfo())));
|
||||||
|
|
||||||
window.addEventListener("visibilitychange", this.removeOverlay);
|
window.addEventListener("visibilitychange", this.removeOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
clickSkip() {
|
clickSkip() {
|
||||||
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: "SKIPPED_SIGNIN" }));
|
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent(Object.assign({ event: "SKIPPED_SIGNIN" }, this._getFormInfo())));
|
||||||
this.removeOverlay();
|
this.removeOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report to telemetry additional information about the form submission.
|
||||||
|
*/
|
||||||
|
_getFormInfo() {
|
||||||
|
const value = { has_flow_params: this.state.flowId.length > 0 };
|
||||||
|
return { value };
|
||||||
|
}
|
||||||
|
|
||||||
onInputInvalid(e) {
|
onInputInvalid(e) {
|
||||||
let error = e.target.previousSibling;
|
let error = e.target.previousSibling;
|
||||||
error.classList.add("active");
|
error.classList.add("active");
|
||||||
|
File diff suppressed because one or more lines are too long
@ -235,7 +235,8 @@ and losing focus. | :one:
|
|||||||
| `icon_type` | [Optional] ("tippytop", "rich_icon", "screenshot_with_icon", "screenshot", "no_image") | :one:
|
| `icon_type` | [Optional] ("tippytop", "rich_icon", "screenshot_with_icon", "screenshot", "no_image") | :one:
|
||||||
| `region` | [Optional] A string maps to pref "browser.search.region", which is essentially the two letter ISO 3166-1 country code populated by the Firefox search service. Note that: 1). it reports "OTHER" for those regions with smaller Firefox user base (less than 10000) so that users cannot be uniquely identified; 2). it reports "UNSET" if this pref is missing; 3). it reports "EMPTY" if the value of this pref is an empty string. | :one:
|
| `region` | [Optional] A string maps to pref "browser.search.region", which is essentially the two letter ISO 3166-1 country code populated by the Firefox search service. Note that: 1). it reports "OTHER" for those regions with smaller Firefox user base (less than 10000) so that users cannot be uniquely identified; 2). it reports "UNSET" if this pref is missing; 3). it reports "EMPTY" if the value of this pref is an empty string. | :one:
|
||||||
| `profile_creation_date` | [Optional] An integer to record the age of the Firefox profile as the total number of days since the UNIX epoch. | :one:
|
| `profile_creation_date` | [Optional] An integer to record the age of the Firefox profile as the total number of days since the UNIX epoch. | :one:
|
||||||
|`message_id` | [required] A string identifier of the message in Activity Stream Router. | :one:
|
| `message_id` | [required] A string identifier of the message in Activity Stream Router. | :one:
|
||||||
|
| `has_flow_params` | [required] One of [true, false]. A boolean identifier that indicates if Firefox Accounts flow parameters are set or unset. | :one:
|
||||||
|
|
||||||
**Where:**
|
**Where:**
|
||||||
|
|
||||||
|
@ -342,6 +342,47 @@ A user event ping includes some basic metadata (tab id, addon version, etc.) as
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Onboarding user events on about:welcome
|
||||||
|
|
||||||
|
#### Form Submit Events
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"event": ["SUBMIT_EMAIL" | "SKIPPED_SIGNIN"],
|
||||||
|
"value": {
|
||||||
|
"has_flow_params": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic metadata
|
||||||
|
"action": "activity_stream_event",
|
||||||
|
"page": "about:welcome",
|
||||||
|
"client_id": "26288a14-5cc4-d14f-ae0a-bb01ef45be9c",
|
||||||
|
"session_id": "005deed0-e3e4-4c02-a041-17405fd703f6",
|
||||||
|
"addon_version": "20180710100040",
|
||||||
|
"locale": "en-US",
|
||||||
|
"user_prefs": 7
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Firefox Accounts Metrics flow errors
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"event": ["FXA_METRICS_FETCH_ERROR" | "FXA_METRICS_ERROR"],
|
||||||
|
"value": 500, // Only FXA_METRICS_FETCH_ERROR provides this value, this value is any valid HTTP status code except 200.
|
||||||
|
|
||||||
|
// Basic metadata
|
||||||
|
"action": "activity_stream_event",
|
||||||
|
"page": "about:welcome",
|
||||||
|
"client_id": "26288a14-5cc4-d14f-ae0a-bb01ef45be9c",
|
||||||
|
"session_id": "005deed0-e3e4-4c02-a041-17405fd703f6",
|
||||||
|
"addon_version": "20180710100040",
|
||||||
|
"locale": "en-US",
|
||||||
|
"user_prefs": 7
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Session end pings
|
## Session end pings
|
||||||
|
|
||||||
When a session ends, the browser will send a `"activity_stream_session"` ping to our metrics servers. This ping contains the length of the session, a unique reason for why the session ended, and some additional metadata.
|
When a session ends, the browser will send a `"activity_stream_session"` ping to our metrics servers. This ping contains the length of the session, a unique reason for why the session ended, and some additional metadata.
|
||||||
|
@ -20,6 +20,8 @@ ChromeUtils.defineModuleGetter(this, "ASRouterPreferences",
|
|||||||
"resource://activity-stream/lib/ASRouterPreferences.jsm");
|
"resource://activity-stream/lib/ASRouterPreferences.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "ASRouterTargeting",
|
ChromeUtils.defineModuleGetter(this, "ASRouterTargeting",
|
||||||
"resource://activity-stream/lib/ASRouterTargeting.jsm");
|
"resource://activity-stream/lib/ASRouterTargeting.jsm");
|
||||||
|
ChromeUtils.defineModuleGetter(this, "QueryCache",
|
||||||
|
"resource://activity-stream/lib/ASRouterTargeting.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "ASRouterTriggerListeners",
|
ChromeUtils.defineModuleGetter(this, "ASRouterTriggerListeners",
|
||||||
"resource://activity-stream/lib/ASRouterTriggerListeners.jsm");
|
"resource://activity-stream/lib/ASRouterTriggerListeners.jsm");
|
||||||
|
|
||||||
@ -242,6 +244,17 @@ const MessageLoaderUtils = {
|
|||||||
|
|
||||||
this.MessageLoaderUtils = MessageLoaderUtils;
|
this.MessageLoaderUtils = MessageLoaderUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hasLegacyOnboardingConflict - Checks if we need to turn off snippets because of
|
||||||
|
* legacy onboarding using the same UI space
|
||||||
|
*
|
||||||
|
* @param {Provider} provider
|
||||||
|
* @returns {boolean} Is there a conflict with legacy onboarding?
|
||||||
|
*/
|
||||||
|
function hasLegacyOnboardingConflict(provider) {
|
||||||
|
return provider.id === "snippets" && !Services.prefs.getBoolPref(ONBOARDING_FINISHED_PREF, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class _ASRouter - Keeps track of all messages, UI surfaces, and
|
* @class _ASRouter - Keeps track of all messages, UI surfaces, and
|
||||||
* handles blocking, rotation, etc. Inspecting ASRouter.state will
|
* handles blocking, rotation, etc. Inspecting ASRouter.state will
|
||||||
@ -293,6 +306,14 @@ class _ASRouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This will be removed when legacy onboarding is removed.
|
||||||
|
async observe(aSubject, aTopic, aPrefName) {
|
||||||
|
if (aPrefName === ONBOARDING_FINISHED_PREF) {
|
||||||
|
this._updateMessageProviders();
|
||||||
|
await this.loadMessagesFromAllProviders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update message providers and fetch new messages on pref change
|
// Update message providers and fetch new messages on pref change
|
||||||
async onPrefChange() {
|
async onPrefChange() {
|
||||||
this._updateMessageProviders();
|
this._updateMessageProviders();
|
||||||
@ -315,10 +336,17 @@ class _ASRouter {
|
|||||||
|
|
||||||
// Fetch and decode the message provider pref JSON, and update the message providers
|
// Fetch and decode the message provider pref JSON, and update the message providers
|
||||||
_updateMessageProviders() {
|
_updateMessageProviders() {
|
||||||
|
const previousProviders = this.state.providers;
|
||||||
const providers = [
|
const providers = [
|
||||||
// If we have added a `preview` provider, hold onto it
|
// If we have added a `preview` provider, hold onto it
|
||||||
...this.state.providers.filter(p => p.id === "preview"),
|
...previousProviders.filter(p => p.id === "preview"),
|
||||||
...ASRouterPreferences.providers.filter(p => p.enabled),
|
// The provider should be enabled and not have a user preference set to false
|
||||||
|
...ASRouterPreferences.providers.filter(p => (
|
||||||
|
p.enabled &&
|
||||||
|
ASRouterPreferences.getUserPreference(p.id) !== false) &&
|
||||||
|
// sorry this is crappy. will remove soon
|
||||||
|
!hasLegacyOnboardingConflict(p)
|
||||||
|
),
|
||||||
].map(_provider => {
|
].map(_provider => {
|
||||||
// make a copy so we don't modify the source of the pref
|
// make a copy so we don't modify the source of the pref
|
||||||
const provider = {..._provider};
|
const provider = {..._provider};
|
||||||
@ -339,6 +367,14 @@ class _ASRouter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const providerIDs = providers.map(p => p.id);
|
const providerIDs = providers.map(p => p.id);
|
||||||
|
|
||||||
|
// Clear old messages for providers that are no longer enabled
|
||||||
|
for (const prevProvider of previousProviders) {
|
||||||
|
if (!providerIDs.includes(prevProvider.id)) {
|
||||||
|
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "CLEAR_PROVIDER", data: {id: prevProvider.id}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.setState(prevState => ({
|
this.setState(prevState => ({
|
||||||
providers,
|
providers,
|
||||||
// Clear any messages from removed providers
|
// Clear any messages from removed providers
|
||||||
@ -436,6 +472,8 @@ class _ASRouter {
|
|||||||
this.dispatchToAS = dispatchToAS;
|
this.dispatchToAS = dispatchToAS;
|
||||||
this.dispatch = this.dispatch.bind(this);
|
this.dispatch = this.dispatch.bind(this);
|
||||||
|
|
||||||
|
// For watching legacy onboarding. To be removed when legacy onboarding is gone.
|
||||||
|
Services.prefs.addObserver(ONBOARDING_FINISHED_PREF, this);
|
||||||
ASRouterPreferences.init();
|
ASRouterPreferences.init();
|
||||||
ASRouterPreferences.addListener(this.onPrefChange);
|
ASRouterPreferences.addListener(this.onPrefChange);
|
||||||
|
|
||||||
@ -467,6 +505,8 @@ class _ASRouter {
|
|||||||
|
|
||||||
this.overrideOrEnableLegacyOnboarding();
|
this.overrideOrEnableLegacyOnboarding();
|
||||||
|
|
||||||
|
// For watching legacy onboarding. To be removed when legacy onboarding is gone.
|
||||||
|
Services.prefs.removeObserver(ONBOARDING_FINISHED_PREF, this);
|
||||||
ASRouterPreferences.removeListener(this.onPrefChange);
|
ASRouterPreferences.removeListener(this.onPrefChange);
|
||||||
ASRouterPreferences.uninit();
|
ASRouterPreferences.uninit();
|
||||||
|
|
||||||
@ -494,10 +534,15 @@ class _ASRouter {
|
|||||||
|
|
||||||
_onStateChanged(state) {
|
_onStateChanged(state) {
|
||||||
if (ASRouterPreferences.devtoolsEnabled) {
|
if (ASRouterPreferences.devtoolsEnabled) {
|
||||||
this.messageChannel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: this.state});
|
this._updateAdminState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_updateAdminState(target) {
|
||||||
|
const channel = target || this.messageChannel;
|
||||||
|
channel.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: this.state});
|
||||||
|
}
|
||||||
|
|
||||||
_handleTargetingError(type, error, message) {
|
_handleTargetingError(type, error, message) {
|
||||||
Cu.reportError(error);
|
Cu.reportError(error);
|
||||||
if (this.dispatchToAS) {
|
if (this.dispatchToAS) {
|
||||||
@ -907,8 +952,7 @@ class _ASRouter {
|
|||||||
await this.handleUserAction({data: action.data, target});
|
await this.handleUserAction({data: action.data, target});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "CONNECT_UI_REQUEST":
|
case "SNIPPETS_REQUEST":
|
||||||
case "GET_NEXT_MESSAGE":
|
|
||||||
case "TRIGGER":
|
case "TRIGGER":
|
||||||
// Wait for our initial message loading to be done before responding to any UI requests
|
// Wait for our initial message loading to be done before responding to any UI requests
|
||||||
await this.waitForInitialized;
|
await this.waitForInitialized;
|
||||||
@ -965,7 +1009,7 @@ class _ASRouter {
|
|||||||
this._addPreviewEndpoint(action.data.endpoint.url, target.portID);
|
this._addPreviewEndpoint(action.data.endpoint.url, target.portID);
|
||||||
await this.loadMessagesFromAllProviders();
|
await this.loadMessagesFromAllProviders();
|
||||||
} else {
|
} else {
|
||||||
target.sendAsyncMessage(OUTGOING_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: this.state});
|
this._updateAdminState(target);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "IMPRESSION":
|
case "IMPRESSION":
|
||||||
@ -976,6 +1020,9 @@ class _ASRouter {
|
|||||||
this.dispatchToAS(ac.ASRouterUserEvent(action.data));
|
this.dispatchToAS(ac.ASRouterUserEvent(action.data));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "EXPIRE_QUERY_CACHE":
|
||||||
|
QueryCache.expireAll();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ const DEFAULT_STATE = {
|
|||||||
_devtoolsPref: DEVTOOLS_PREF,
|
_devtoolsPref: DEVTOOLS_PREF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const USER_PREFERENCES = {snippets: "browser.newtabpage.activity-stream.feeds.snippets"};
|
||||||
|
|
||||||
class _ASRouterPreferences {
|
class _ASRouterPreferences {
|
||||||
constructor() {
|
constructor() {
|
||||||
Object.assign(this, DEFAULT_STATE);
|
Object.assign(this, DEFAULT_STATE);
|
||||||
@ -71,6 +73,13 @@ class _ASRouterPreferences {
|
|||||||
this._callbacks.forEach(cb => cb(aPrefName));
|
this._callbacks.forEach(cb => cb(aPrefName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUserPreference(providerId) {
|
||||||
|
if (!USER_PREFERENCES[providerId]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Services.prefs.getBoolPref(USER_PREFERENCES[providerId], true);
|
||||||
|
}
|
||||||
|
|
||||||
addListener(callback) {
|
addListener(callback) {
|
||||||
this._callbacks.add(callback);
|
this._callbacks.add(callback);
|
||||||
}
|
}
|
||||||
@ -85,6 +94,9 @@ class _ASRouterPreferences {
|
|||||||
}
|
}
|
||||||
Services.prefs.addObserver(this._providerPref, this);
|
Services.prefs.addObserver(this._providerPref, this);
|
||||||
Services.prefs.addObserver(this._devtoolsPref, this);
|
Services.prefs.addObserver(this._devtoolsPref, this);
|
||||||
|
for (const id of Object.keys(USER_PREFERENCES)) {
|
||||||
|
Services.prefs.addObserver(USER_PREFERENCES[id], this);
|
||||||
|
}
|
||||||
this._initialized = true;
|
this._initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +104,9 @@ class _ASRouterPreferences {
|
|||||||
if (this._initialized) {
|
if (this._initialized) {
|
||||||
Services.prefs.removeObserver(this._providerPref, this);
|
Services.prefs.removeObserver(this._providerPref, this);
|
||||||
Services.prefs.removeObserver(this._devtoolsPref, this);
|
Services.prefs.removeObserver(this._devtoolsPref, this);
|
||||||
|
for (const id of Object.keys(USER_PREFERENCES)) {
|
||||||
|
Services.prefs.removeObserver(USER_PREFERENCES[id], this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Object.assign(this, DEFAULT_STATE);
|
Object.assign(this, DEFAULT_STATE);
|
||||||
this._callbacks.clear();
|
this._callbacks.clear();
|
||||||
|
@ -27,8 +27,14 @@ const FRECENT_SITES_IGNORE_BLOCKED = false;
|
|||||||
const FRECENT_SITES_NUM_ITEMS = 25;
|
const FRECENT_SITES_NUM_ITEMS = 25;
|
||||||
const FRECENT_SITES_MIN_FRECENCY = 100;
|
const FRECENT_SITES_MIN_FRECENCY = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CachedTargetingGetter
|
||||||
|
* @param property {string} Name of the method called on ActivityStreamProvider
|
||||||
|
* @param options {{}?} Options object passsed to ActivityStreamProvider method
|
||||||
|
* @param updateInterval {number?} Update interval for query. Defaults to FRECENT_SITES_UPDATE_INTERVAL
|
||||||
|
*/
|
||||||
function CachedTargetingGetter(property, options = null, updateInterval = FRECENT_SITES_UPDATE_INTERVAL) {
|
function CachedTargetingGetter(property, options = null, updateInterval = FRECENT_SITES_UPDATE_INTERVAL) {
|
||||||
const targetingGetter = {
|
return {
|
||||||
_lastUpdated: 0,
|
_lastUpdated: 0,
|
||||||
_value: null,
|
_value: null,
|
||||||
// For testing
|
// For testing
|
||||||
@ -36,39 +42,44 @@ function CachedTargetingGetter(property, options = null, updateInterval = FRECEN
|
|||||||
this._lastUpdated = 0;
|
this._lastUpdated = 0;
|
||||||
this._value = null;
|
this._value = null;
|
||||||
},
|
},
|
||||||
};
|
get() {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
Object.defineProperty(targetingGetter, property, {
|
const now = Date.now();
|
||||||
get: () => new Promise(async (resolve, reject) => {
|
if (now - this._lastUpdated >= updateInterval) {
|
||||||
const now = Date.now();
|
try {
|
||||||
if (now - targetingGetter._lastUpdated >= updateInterval) {
|
this._value = await asProvider[property](options);
|
||||||
try {
|
this._lastUpdated = now;
|
||||||
targetingGetter._value = await asProvider[property](options);
|
} catch (e) {
|
||||||
targetingGetter._lastUpdated = now;
|
Cu.reportError(e);
|
||||||
} catch (e) {
|
reject(e);
|
||||||
Cu.reportError(e);
|
}
|
||||||
reject(e);
|
|
||||||
}
|
}
|
||||||
}
|
resolve(this._value);
|
||||||
resolve(targetingGetter._value);
|
});
|
||||||
}),
|
},
|
||||||
});
|
};
|
||||||
|
|
||||||
return targetingGetter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TopFrecentSitesCache = new CachedTargetingGetter(
|
const QueryCache = {
|
||||||
"getTopFrecentSites",
|
expireAll() {
|
||||||
{
|
Object.keys(this.queries).forEach(query => {
|
||||||
ignoreBlocked: FRECENT_SITES_IGNORE_BLOCKED,
|
this.queries[query].expire();
|
||||||
numItems: FRECENT_SITES_NUM_ITEMS,
|
});
|
||||||
topsiteFrecency: FRECENT_SITES_MIN_FRECENCY,
|
},
|
||||||
onePerDomain: true,
|
queries: {
|
||||||
includeFavicon: false,
|
TopFrecentSites: new CachedTargetingGetter(
|
||||||
}
|
"getTopFrecentSites",
|
||||||
);
|
{
|
||||||
|
ignoreBlocked: FRECENT_SITES_IGNORE_BLOCKED,
|
||||||
const TotalBookmarksCountCache = new CachedTargetingGetter("getTotalBookmarksCount");
|
numItems: FRECENT_SITES_NUM_ITEMS,
|
||||||
|
topsiteFrecency: FRECENT_SITES_MIN_FRECENCY,
|
||||||
|
onePerDomain: true,
|
||||||
|
includeFavicon: false,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
TotalBookmarksCount: new CachedTargetingGetter("getTotalBookmarksCount"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sortMessagesByWeightedRank
|
* sortMessagesByWeightedRank
|
||||||
@ -97,6 +108,12 @@ function sortMessagesByWeightedRank(messages) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TargetingGetters = {
|
const TargetingGetters = {
|
||||||
|
get locale() {
|
||||||
|
return Services.locale.appLocaleAsLangTag;
|
||||||
|
},
|
||||||
|
get localeLanguageCode() {
|
||||||
|
return Services.locale.appLocaleAsLangTag && Services.locale.appLocaleAsLangTag.substr(0, 2);
|
||||||
|
},
|
||||||
get browserSettings() {
|
get browserSettings() {
|
||||||
const {settings} = TelemetryEnvironment.currentEnvironment;
|
const {settings} = TelemetryEnvironment.currentEnvironment;
|
||||||
return {
|
return {
|
||||||
@ -173,7 +190,7 @@ const TargetingGetters = {
|
|||||||
return Services.prefs.getIntPref("devtools.selfxss.count");
|
return Services.prefs.getIntPref("devtools.selfxss.count");
|
||||||
},
|
},
|
||||||
get topFrecentSites() {
|
get topFrecentSites() {
|
||||||
return TopFrecentSitesCache.getTopFrecentSites.then(sites => sites.map(site => (
|
return QueryCache.queries.TopFrecentSites.get().then(sites => sites.map(site => (
|
||||||
{
|
{
|
||||||
url: site.url,
|
url: site.url,
|
||||||
host: (new URL(site.url)).hostname,
|
host: (new URL(site.url)).hostname,
|
||||||
@ -194,7 +211,7 @@ const TargetingGetters = {
|
|||||||
}, {});
|
}, {});
|
||||||
},
|
},
|
||||||
get totalBookmarksCount() {
|
get totalBookmarksCount() {
|
||||||
return TotalBookmarksCountCache.getTotalBookmarksCount;
|
return QueryCache.queries.TotalBookmarksCount.get();
|
||||||
},
|
},
|
||||||
get firefoxVersion() {
|
get firefoxVersion() {
|
||||||
return parseInt(AppConstants.MOZ_APP_VERSION.match(/\d+/), 10);
|
return parseInt(AppConstants.MOZ_APP_VERSION.match(/\d+/), 10);
|
||||||
@ -289,7 +306,6 @@ this.ASRouterTargeting = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Export for testing
|
// Export for testing
|
||||||
this.TopFrecentSitesCache = TopFrecentSitesCache;
|
this.QueryCache = QueryCache;
|
||||||
this.TotalBookmarksCountCache = TotalBookmarksCountCache;
|
|
||||||
this.CachedTargetingGetter = CachedTargetingGetter;
|
this.CachedTargetingGetter = CachedTargetingGetter;
|
||||||
this.EXPORTED_SYMBOLS = ["ASRouterTargeting", "TopFrecentSitesCache", "TotalBookmarksCountCache", "CachedTargetingGetter"];
|
this.EXPORTED_SYMBOLS = ["ASRouterTargeting", "QueryCache", "CachedTargetingGetter"];
|
||||||
|
@ -82,6 +82,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 1},
|
frequency: {lifetime: 1},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr == "one_per_day_amazon") &&
|
(providerCohorts.cfr == "one_per_day_amazon") &&
|
||||||
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${AMAZON_ASSISTANT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -124,6 +125,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 3},
|
frequency: {lifetime: 3},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr == "three_per_day_amazon") &&
|
(providerCohorts.cfr == "three_per_day_amazon") &&
|
||||||
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(AMAZON_ASSISTANT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${AMAZON_ASSISTANT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -166,6 +168,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 1},
|
frequency: {lifetime: 1},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
||||||
(${JSON.stringify(FACEBOOK_CONTAINER_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(FACEBOOK_CONTAINER_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${FACEBOOK_CONTAINER_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -208,6 +211,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 3},
|
frequency: {lifetime: 3},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr == "three_per_day") &&
|
(providerCohorts.cfr == "three_per_day") &&
|
||||||
(${JSON.stringify(FACEBOOK_CONTAINER_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(FACEBOOK_CONTAINER_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${FACEBOOK_CONTAINER_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -250,6 +254,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 1},
|
frequency: {lifetime: 1},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
||||||
(${JSON.stringify(GOOGLE_TRANSLATE_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(GOOGLE_TRANSLATE_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${GOOGLE_TRANSLATE_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -292,6 +297,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 3},
|
frequency: {lifetime: 3},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr == "three_per_day") &&
|
(providerCohorts.cfr == "three_per_day") &&
|
||||||
(${JSON.stringify(GOOGLE_TRANSLATE_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(GOOGLE_TRANSLATE_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${GOOGLE_TRANSLATE_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -334,6 +340,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 1},
|
frequency: {lifetime: 1},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
||||||
(${JSON.stringify(YOUTUBE_ENHANCE_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(YOUTUBE_ENHANCE_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${YOUTUBE_ENHANCE_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -376,6 +383,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 3},
|
frequency: {lifetime: 3},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr == "three_per_day") &&
|
(providerCohorts.cfr == "three_per_day") &&
|
||||||
(${JSON.stringify(YOUTUBE_ENHANCE_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(YOUTUBE_ENHANCE_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${YOUTUBE_ENHANCE_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -418,6 +426,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 1},
|
frequency: {lifetime: 1},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
||||||
(${JSON.stringify(WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -460,6 +469,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 3},
|
frequency: {lifetime: 3},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr == "three_per_day") &&
|
(providerCohorts.cfr == "three_per_day") &&
|
||||||
(${JSON.stringify(WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${WIKIPEDIA_CONTEXT_MENU_SEARCH_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -502,6 +512,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 1},
|
frequency: {lifetime: 1},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
(providerCohorts.cfr in ["one_per_day", "nightly"]) &&
|
||||||
(${JSON.stringify(REDDIT_ENHANCEMENT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(REDDIT_ENHANCEMENT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${REDDIT_ENHANCEMENT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
@ -544,6 +555,7 @@ const CFR_MESSAGES = [
|
|||||||
},
|
},
|
||||||
frequency: {lifetime: 3},
|
frequency: {lifetime: 3},
|
||||||
targeting: `
|
targeting: `
|
||||||
|
localeLanguageCode == "en" &&
|
||||||
(providerCohorts.cfr == "three_per_day") &&
|
(providerCohorts.cfr == "three_per_day") &&
|
||||||
(${JSON.stringify(REDDIT_ENHANCEMENT_PARAMS.existing_addons)} intersect addonsInfo.addons|keys)|length == 0 &&
|
(${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`,
|
(${JSON.stringify(REDDIT_ENHANCEMENT_PARAMS.open_urls)} intersect topFrecentSites[.frecency >= ${REDDIT_ENHANCEMENT_PARAMS.min_frecency}]|mapToProperty('host'))|length > 0`,
|
||||||
|
@ -11,6 +11,8 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||||||
const {actionTypes: at, actionUtils: au} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
const {actionTypes: at, actionUtils: au} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||||
const {Prefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
|
const {Prefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
|
||||||
|
|
||||||
|
ChromeUtils.defineModuleGetter(this, "ASRouterPreferences",
|
||||||
|
"resource://activity-stream/lib/ASRouterPreferences.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "perfService",
|
ChromeUtils.defineModuleGetter(this, "perfService",
|
||||||
"resource://activity-stream/common/PerfService.jsm");
|
"resource://activity-stream/common/PerfService.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "PingCentre",
|
ChromeUtils.defineModuleGetter(this, "PingCentre",
|
||||||
@ -41,7 +43,6 @@ const USER_PREFS_ENCODING = {
|
|||||||
const PREF_IMPRESSION_ID = "impressionId";
|
const PREF_IMPRESSION_ID = "impressionId";
|
||||||
const TELEMETRY_PREF = "telemetry";
|
const TELEMETRY_PREF = "telemetry";
|
||||||
const EVENTS_TELEMETRY_PREF = "telemetry.ut.events";
|
const EVENTS_TELEMETRY_PREF = "telemetry.ut.events";
|
||||||
const ROUTER_MESSAGE_PROVIDER_PREF = "asrouter.messageProviders";
|
|
||||||
|
|
||||||
this.TelemetryFeed = class TelemetryFeed {
|
this.TelemetryFeed = class TelemetryFeed {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
@ -55,8 +56,6 @@ this.TelemetryFeed = class TelemetryFeed {
|
|||||||
this._prefs.observe(TELEMETRY_PREF, this._onTelemetryPrefChange);
|
this._prefs.observe(TELEMETRY_PREF, this._onTelemetryPrefChange);
|
||||||
this._onEventsTelemetryPrefChange = this._onEventsTelemetryPrefChange.bind(this);
|
this._onEventsTelemetryPrefChange = this._onEventsTelemetryPrefChange.bind(this);
|
||||||
this._prefs.observe(EVENTS_TELEMETRY_PREF, this._onEventsTelemetryPrefChange);
|
this._prefs.observe(EVENTS_TELEMETRY_PREF, this._onEventsTelemetryPrefChange);
|
||||||
this._onRouterMessageProviderChange = this._onRouterMessageProviderChange.bind(this);
|
|
||||||
this._prefs.observe(ROUTER_MESSAGE_PROVIDER_PREF, this._onRouterMessageProviderChange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@ -119,28 +118,6 @@ this.TelemetryFeed = class TelemetryFeed {
|
|||||||
this.eventTelemetryEnabled = prefVal;
|
this.eventTelemetryEnabled = prefVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the CFR experiment cohort information by parsing the pref string of
|
|
||||||
* AS router message provider. The experiment cohort can be identified by the
|
|
||||||
* `cohort` field in the "cfr" provider.
|
|
||||||
*/
|
|
||||||
_parseCFRCohort(pref) {
|
|
||||||
try {
|
|
||||||
for (let provider of JSON.parse(pref)) {
|
|
||||||
if (provider.id === "cfr" && provider.enabled && provider.cohort) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Cu.reportError("Problem parsing JSON message provider pref for ASRouter");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_onRouterMessageProviderChange(prefVal) {
|
|
||||||
this._isInCFRCohort = this._parseCFRCohort(prefVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lazily initialize PingCentre for Activity Stream to send pings
|
* Lazily initialize PingCentre for Activity Stream to send pings
|
||||||
*/
|
*/
|
||||||
@ -190,14 +167,15 @@ this.TelemetryFeed = class TelemetryFeed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lazily parse the AS router pref to check if it is in the CFR experiment cohort
|
* Check if it is in the CFR experiment cohort. ASRouterPreferences lazily parses AS router pref.
|
||||||
*/
|
*/
|
||||||
get isInCFRCohort() {
|
get isInCFRCohort() {
|
||||||
if (this._isInCFRCohort === undefined) {
|
for (let provider of ASRouterPreferences.providers) {
|
||||||
const pref = this._prefs.get(ROUTER_MESSAGE_PROVIDER_PREF);
|
if (provider.id === "cfr" && provider.enabled && provider.cohort) {
|
||||||
this._isInCFRCohort = this._parseCFRCohort(pref);
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this._isInCFRCohort;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -585,7 +563,6 @@ this.TelemetryFeed = class TelemetryFeed {
|
|||||||
try {
|
try {
|
||||||
this._prefs.ignore(TELEMETRY_PREF, this._onTelemetryPrefChange);
|
this._prefs.ignore(TELEMETRY_PREF, this._onTelemetryPrefChange);
|
||||||
this._prefs.ignore(EVENTS_TELEMETRY_PREF, this._onEventsTelemetryPrefChange);
|
this._prefs.ignore(EVENTS_TELEMETRY_PREF, this._onEventsTelemetryPrefChange);
|
||||||
this._prefs.ignore(ROUTER_MESSAGE_PROVIDER_PREF, this._onRouterMessageProviderChange);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Cu.reportError(e);
|
Cu.reportError(e);
|
||||||
}
|
}
|
||||||
@ -599,5 +576,4 @@ const EXPORTED_SYMBOLS = [
|
|||||||
"PREF_IMPRESSION_ID",
|
"PREF_IMPRESSION_ID",
|
||||||
"TELEMETRY_PREF",
|
"TELEMETRY_PREF",
|
||||||
"EVENTS_TELEMETRY_PREF",
|
"EVENTS_TELEMETRY_PREF",
|
||||||
"ROUTER_MESSAGE_PROVIDER_PREF",
|
|
||||||
];
|
];
|
||||||
|
@ -94,7 +94,7 @@ prefs_home_description=Pilih konten yang ingin Anda tampilkan dalam Beranda Fire
|
|||||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||||
prefs_section_rows_option={num} baris;{num} baris
|
prefs_section_rows_option={num} baris
|
||||||
prefs_search_header=Pencarian Web
|
prefs_search_header=Pencarian Web
|
||||||
prefs_topsites_description=Situs yang sering Anda kunjungi
|
prefs_topsites_description=Situs yang sering Anda kunjungi
|
||||||
prefs_topstories_description2=Konten bermutu dari seluruh web, khusus untuk Anda
|
prefs_topstories_description2=Konten bermutu dari seluruh web, khusus untuk Anda
|
||||||
|
118
browser/components/newtab/locales/is/strings.properties
Normal file
118
browser/components/newtab/locales/is/strings.properties
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
newtab_page_title=Nýr flipi
|
||||||
|
|
||||||
|
header_highlights=Úrdrættir
|
||||||
|
# LOCALIZATION NOTE(header_recommended_by): This is followed by the name
|
||||||
|
# of the corresponding content provider.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE(context_menu_button_sr): This is for screen readers when
|
||||||
|
# the context menu button is focused/active. Title is the label or hostname of
|
||||||
|
# the site.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE(section_context_menu_button_sr): This is for screen readers when
|
||||||
|
# the section edit context menu button is focused/active.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (type_label_*): These labels are associated to pages to give
|
||||||
|
# context on how the element is related to the user, e.g. type indicates that
|
||||||
|
# the page is bookmarked, or is currently open on another device
|
||||||
|
type_label_visited=Heimsótt
|
||||||
|
type_label_bookmarked=Búið að bókamerkja
|
||||||
|
type_label_recommended=Vinsælt
|
||||||
|
type_label_pocket=Vistað í Pocket
|
||||||
|
type_label_downloaded=Niðurhalað
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (menu_action_*): These strings are displayed in a context
|
||||||
|
# menu and are meant as a call to action for a given page.
|
||||||
|
# LOCALIZATION NOTE (menu_action_bookmark): Bookmark is a verb, as in "Add to
|
||||||
|
# bookmarks"
|
||||||
|
menu_action_dismiss=Hafna
|
||||||
|
menu_action_delete=Eyða úr ferli
|
||||||
|
# LOCALIZATION NOTE (confirm_history_delete_notice_p2): this string is displayed in
|
||||||
|
# the same dialog as confirm_history_delete_p1. "This action" refers to deleting a
|
||||||
|
# page from history.
|
||||||
|
confirm_history_delete_notice_p2=Ekki er ekki hægt að bakfæra þessa aðgerð.
|
||||||
|
menu_action_save_to_pocket=Vista í Pocket
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (menu_action_show_file_*): These are platform specific strings
|
||||||
|
# found in the context menu of an item that has been downloaded. The intention behind
|
||||||
|
# "this action" is that it will show where the downloaded file exists on the file system
|
||||||
|
# for each operating system.
|
||||||
|
menu_action_show_file_mac_os=Sýna í Finder
|
||||||
|
menu_action_show_file_windows=Opna möppu
|
||||||
|
menu_action_show_file_linux=Opna möppu
|
||||||
|
menu_action_show_file_default=Sýna skrá
|
||||||
|
menu_action_open_file=Opna skrá
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (menu_action_copy_download_link, menu_action_go_to_download_page):
|
||||||
|
# "Download" here, in both cases, is not a verb, it is a noun. As in, "Copy the
|
||||||
|
# link that belongs to this downloaded item"
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (search_button): This is screenreader only text for the
|
||||||
|
# search button.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (search_header): Displayed at the top of the panel
|
||||||
|
# showing search suggestions. {search_engine_name} is replaced with the name of
|
||||||
|
# the current default search engine. e.g. 'Google Search'
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (search_web_placeholder): This is shown in the searchbox when
|
||||||
|
# the user hasn't typed anything yet.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (section_disclaimer_topstories): This is shown below
|
||||||
|
# the topstories section title to provide additional information about
|
||||||
|
# how the stories are selected.
|
||||||
|
# LOCALIZATION NOTE (section_disclaimer_topstories_buttontext): The text of
|
||||||
|
# the button used to acknowledge, and hide this disclaimer in the future.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (prefs_*, settings_*): These are shown in about:preferences
|
||||||
|
# for a "Firefox Home" section. "Firefox" should be treated as a brand and kept
|
||||||
|
# in English, while "Home" should be localized matching the about:preferences
|
||||||
|
# sidebar mozilla-central string for the panel that has preferences related to
|
||||||
|
# what is shown for the homepage, new windows, and new tabs.
|
||||||
|
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||||
|
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||||
|
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||||
|
# LOCALIZATION NOTE(settings_pane_snippets_header): For the "Snippets" feature
|
||||||
|
# traditionally on about:home. Alternative translation options: "Small Note" or
|
||||||
|
# something that expresses the idea of "a small message, shortened from
|
||||||
|
# something else, and non-essential but also not entirely trivial and useless."
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (edit_topsites_*): This is shown in the Edit Top Sites modal
|
||||||
|
# dialog.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (topsites_form_*): This is shown in the New/Edit Topsite modal.
|
||||||
|
# LOCALIZATION NOTE (topsites_form_*_button): These are verbs/actions.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (pocket_read_more): This is shown at the bottom of the
|
||||||
|
# trending stories section and precedes a list of links to popular topics.
|
||||||
|
# LOCALIZATION NOTE (pocket_read_even_more): This is shown as a link at the
|
||||||
|
# end of the list of popular topic links.
|
||||||
|
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||||
|
# in the space that would have shown a few stories, this is shown instead.
|
||||||
|
# {provider} is replaced by the name of the content provider for this section.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (manual_migration_explanation2): This message is shown to encourage users to
|
||||||
|
# import their browser profile from another browser they might be using.
|
||||||
|
# LOCALIZATION NOTE (manual_migration_cancel_button): This message is shown on a button that cancels the
|
||||||
|
# process of importing another browser’s profile into Firefox.
|
||||||
|
# LOCALIZATION NOTE (manual_migration_import_button): This message is shown on a button that starts the process
|
||||||
|
# of importing another browser’s profile profile into Firefox.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (error_fallback_default_*): This message and suggested
|
||||||
|
# action link are shown in each section of UI that fails to render
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (section_menu_action_*). These strings are displayed in the section
|
||||||
|
# context menu and are meant as a call to action for the given section.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (firstrun_*). These strings are displayed only once, on the
|
||||||
|
# firstrun of the browser, they give an introduction to Firefox and Sync.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (firstrun_form_header and firstrun_form_sub_header):
|
||||||
|
# firstrun_form_sub_header is a continuation of firstrun_form_header, they are one sentence.
|
||||||
|
# firstrun_form_header is displayed more boldly as the call to action.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and
|
||||||
|
# {privacy} is equal to firstrun_privacy_notice. {terms} and {privacy} are clickable links.
|
||||||
|
|
@ -145,6 +145,7 @@ pocket_read_more=Populære emne:
|
|||||||
pocket_read_even_more=Vis fleire saker
|
pocket_read_even_more=Vis fleire saker
|
||||||
|
|
||||||
pocket_learn_more=Les meir
|
pocket_learn_more=Les meir
|
||||||
|
pocket_cta_button=Last ned Pocket
|
||||||
|
|
||||||
highlights_empty_state=Begynn å surfe, og vi vil vise deg nokre av dei beste artiklane, videoane og andre sider du nyleg har besøkt eller bokmerka her.
|
highlights_empty_state=Begynn å surfe, og vi vil vise deg nokre av dei beste artiklane, videoane og andre sider du nyleg har besøkt eller bokmerka her.
|
||||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||||
|
@ -144,6 +144,8 @@ pocket_read_more=Tèmas populars :
|
|||||||
# end of the list of popular topic links.
|
# end of the list of popular topic links.
|
||||||
pocket_read_even_more=Veire mai d’articles
|
pocket_read_even_more=Veire mai d’articles
|
||||||
|
|
||||||
|
pocket_learn_more=Ne saber mai
|
||||||
|
|
||||||
highlights_empty_state=Començatz de navegar e aquí vos mostrarem los melhors articles, vidèos e autras paginas qu’avètz visitadas o apondudas als marcapaginas.
|
highlights_empty_state=Començatz de navegar e aquí vos mostrarem los melhors articles, vidèos e autras paginas qu’avètz visitadas o apondudas als marcapaginas.
|
||||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||||
# in the space that would have shown a few stories, this is shown instead.
|
# in the space that would have shown a few stories, this is shown instead.
|
||||||
|
@ -82,9 +82,15 @@ topsites_form_save_button=Zachowaj
|
|||||||
topsites_form_cancel_button=Anuluj
|
topsites_form_cancel_button=Anuluj
|
||||||
topsites_form_url_validation=Wymagany jest prawidłowy adres URL
|
topsites_form_url_validation=Wymagany jest prawidłowy adres URL
|
||||||
topsites_form_image_validation=Wczytanie obrazu nie powiodło się. Spróbuj innego adresu.
|
topsites_form_image_validation=Wczytanie obrazu nie powiodło się. Spróbuj innego adresu.
|
||||||
|
|
||||||
pocket_read_more=Popularne treści:
|
pocket_read_more=Popularne treści:
|
||||||
pocket_read_even_more=Pokaż więcej artykułów
|
pocket_read_even_more=Pokaż więcej artykułów
|
||||||
|
pocket_more_reccommendations=Więcej polecanych
|
||||||
|
pocket_learn_more=Więcej informacji
|
||||||
|
pocket_cta_button=Pobierz Pocket
|
||||||
|
pocket_cta_text=Zachowuj historie w Pocket, aby wrócić później do ich lektury.
|
||||||
pocket_description=Odkrywaj wysokiej jakości treści dzięki serwisowi Pocket, który jest teraz częścią Mozilli.
|
pocket_description=Odkrywaj wysokiej jakości treści dzięki serwisowi Pocket, który jest teraz częścią Mozilli.
|
||||||
|
|
||||||
highlights_empty_state=Zacznij przeglądać Internet, a pojawią się tutaj świetne artykuły, filmy oraz inne ostatnio odwiedzane strony i dodane zakładki.
|
highlights_empty_state=Zacznij przeglądać Internet, a pojawią się tutaj świetne artykuły, filmy oraz inne ostatnio odwiedzane strony i dodane zakładki.
|
||||||
topstories_empty_state=To na razie wszystko. {provider} później będzie mieć więcej popularnych artykułów. Nie możesz się doczekać? Wybierz popularny temat, aby znaleźć więcej treści z całego Internetu.
|
topstories_empty_state=To na razie wszystko. {provider} później będzie mieć więcej popularnych artykułów. Nie możesz się doczekać? Wybierz popularny temat, aby znaleźć więcej treści z całego Internetu.
|
||||||
manual_migration_explanation2=Wypróbuj program Firefox z zakładkami, historią i hasłami z innej przeglądarki.
|
manual_migration_explanation2=Wypróbuj program Firefox z zakładkami, historią i hasłami z innej przeglądarki.
|
||||||
|
@ -144,6 +144,10 @@ pocket_read_more=Tópicos populares:
|
|||||||
# end of the list of popular topic links.
|
# end of the list of popular topic links.
|
||||||
pocket_read_even_more=Ver mais histórias
|
pocket_read_even_more=Ver mais histórias
|
||||||
|
|
||||||
|
pocket_more_reccommendations=Mais recomendações
|
||||||
|
pocket_learn_more=Saiba mais
|
||||||
|
pocket_cta_text=Salve as histórias que você gosta no Pocket e abasteça sua mente com leituras fascinantes.
|
||||||
|
|
||||||
highlights_empty_state=Comece a navegar e nós mostraremos aqui alguns ótimos artigos, vídeos e outras páginas que você favoritou ou visitou recentemente.
|
highlights_empty_state=Comece a navegar e nós mostraremos aqui alguns ótimos artigos, vídeos e outras páginas que você favoritou ou visitou recentemente.
|
||||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||||
# in the space that would have shown a few stories, this is shown instead.
|
# in the space that would have shown a few stories, this is shown instead.
|
||||||
|
@ -147,6 +147,7 @@ pocket_read_even_more=Zobraziť ďalšie príbehy
|
|||||||
pocket_more_reccommendations=Ďalšie odporúčania
|
pocket_more_reccommendations=Ďalšie odporúčania
|
||||||
pocket_learn_more=Ďalšie informácie
|
pocket_learn_more=Ďalšie informácie
|
||||||
pocket_cta_button=Získajte Pocket
|
pocket_cta_button=Získajte Pocket
|
||||||
|
pocket_cta_text=Ukladajte si články do služby Pocket a užívajte si skvelé čítanie.
|
||||||
|
|
||||||
highlights_empty_state=Začnite s prehliadaním a my vám na tomto mieste ukážeme skvelé články, videá a ostatné stránky, ktoré ste nedávno navštívili alebo pridali medzi záložky.
|
highlights_empty_state=Začnite s prehliadaním a my vám na tomto mieste ukážeme skvelé články, videá a ostatné stránky, ktoré ste nedávno navštívili alebo pridali medzi záložky.
|
||||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||||
|
@ -46,7 +46,9 @@ menu_action_delete_pocket=Pocket سے جزف کریں
|
|||||||
# found in the context menu of an item that has been downloaded. The intention behind
|
# found in the context menu of an item that has been downloaded. The intention behind
|
||||||
# "this action" is that it will show where the downloaded file exists on the file system
|
# "this action" is that it will show where the downloaded file exists on the file system
|
||||||
# for each operating system.
|
# for each operating system.
|
||||||
|
menu_action_show_file_mac_os=تلاش کار میں دکھائیں
|
||||||
menu_action_show_file_windows=حامل پوشہ کھولیں
|
menu_action_show_file_windows=حامل پوشہ کھولیں
|
||||||
|
menu_action_show_file_linux=مشتمل فولڈر کھولیں
|
||||||
menu_action_show_file_default=مسل دکھائیں
|
menu_action_show_file_default=مسل دکھائیں
|
||||||
menu_action_open_file=مسل کھولیں
|
menu_action_open_file=مسل کھولیں
|
||||||
|
|
||||||
@ -54,6 +56,7 @@ menu_action_open_file=مسل کھولیں
|
|||||||
# "Download" here, in both cases, is not a verb, it is a noun. As in, "Copy the
|
# "Download" here, in both cases, is not a verb, it is a noun. As in, "Copy the
|
||||||
# link that belongs to this downloaded item"
|
# link that belongs to this downloaded item"
|
||||||
menu_action_copy_download_link=ڈاؤن لوڈ ربط نقل کریں
|
menu_action_copy_download_link=ڈاؤن لوڈ ربط نقل کریں
|
||||||
|
menu_action_go_to_download_page=ڈاؤن لوڈ صفحہ پر جائیں
|
||||||
menu_action_remove_download=سابقات سے ہٹائیں
|
menu_action_remove_download=سابقات سے ہٹائیں
|
||||||
|
|
||||||
# LOCALIZATION NOTE (search_button): This is screenreader only text for the
|
# LOCALIZATION NOTE (search_button): This is screenreader only text for the
|
||||||
@ -165,6 +168,7 @@ firstrun_form_header=اپنی ای میل داخل کریں
|
|||||||
|
|
||||||
firstrun_email_input_placeholder=ای میل
|
firstrun_email_input_placeholder=ای میل
|
||||||
|
|
||||||
|
firstrun_invalid_input=جائز ای میل کی ظرورت ہے
|
||||||
|
|
||||||
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and
|
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and
|
||||||
# {privacy} is equal to firstrun_privacy_notice. {terms} and {privacy} are clickable links.
|
# {privacy} is equal to firstrun_privacy_notice. {terms} and {privacy} are clickable links.
|
||||||
|
@ -40,7 +40,7 @@ window.gActivityStreamStrings = {
|
|||||||
"section_disclaimer_topstories_buttontext": "Oke, paham",
|
"section_disclaimer_topstories_buttontext": "Oke, paham",
|
||||||
"prefs_home_header": "Konten Beranda Firefox",
|
"prefs_home_header": "Konten Beranda Firefox",
|
||||||
"prefs_home_description": "Pilih konten yang ingin Anda tampilkan dalam Beranda Firefox.",
|
"prefs_home_description": "Pilih konten yang ingin Anda tampilkan dalam Beranda Firefox.",
|
||||||
"prefs_section_rows_option": "{num} baris;{num} baris",
|
"prefs_section_rows_option": "{num} baris",
|
||||||
"prefs_search_header": "Pencarian Web",
|
"prefs_search_header": "Pencarian Web",
|
||||||
"prefs_topsites_description": "Situs yang sering Anda kunjungi",
|
"prefs_topsites_description": "Situs yang sering Anda kunjungi",
|
||||||
"prefs_topstories_description2": "Konten bermutu dari seluruh web, khusus untuk Anda",
|
"prefs_topstories_description2": "Konten bermutu dari seluruh web, khusus untuk Anda",
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="is" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
|
||||||
|
<title>Nýr flipi</title>
|
||||||
|
<link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
|
||||||
|
<link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
|
||||||
|
<link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
|
||||||
|
</head>
|
||||||
|
<body class="activity-stream">
|
||||||
|
<div id="root"></div>
|
||||||
|
<div id="snippets-container">
|
||||||
|
<div id="snippets"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,110 @@
|
|||||||
|
// Note - this is a generated is file.
|
||||||
|
window.gActivityStreamStrings = {
|
||||||
|
"newtab_page_title": "Nýr flipi",
|
||||||
|
"header_top_sites": "Top Sites",
|
||||||
|
"header_highlights": "Úrdrættir",
|
||||||
|
"header_recommended_by": "Recommended by {provider}",
|
||||||
|
"context_menu_button_sr": "Open context menu for {title}",
|
||||||
|
"section_context_menu_button_sr": "Open the section context menu",
|
||||||
|
"type_label_visited": "Heimsótt",
|
||||||
|
"type_label_bookmarked": "Búið að bókamerkja",
|
||||||
|
"type_label_recommended": "Vinsælt",
|
||||||
|
"type_label_pocket": "Vistað í Pocket",
|
||||||
|
"type_label_downloaded": "Niðurhalað",
|
||||||
|
"menu_action_bookmark": "Bookmark",
|
||||||
|
"menu_action_remove_bookmark": "Remove Bookmark",
|
||||||
|
"menu_action_open_new_window": "Open in a New Window",
|
||||||
|
"menu_action_open_private_window": "Open in a New Private Window",
|
||||||
|
"menu_action_dismiss": "Hafna",
|
||||||
|
"menu_action_delete": "Eyða úr ferli",
|
||||||
|
"menu_action_pin": "Pin",
|
||||||
|
"menu_action_unpin": "Unpin",
|
||||||
|
"confirm_history_delete_p1": "Are you sure you want to delete every instance of this page from your history?",
|
||||||
|
"confirm_history_delete_notice_p2": "Ekki er ekki hægt að bakfæra þessa aðgerð.",
|
||||||
|
"menu_action_save_to_pocket": "Vista í Pocket",
|
||||||
|
"menu_action_delete_pocket": "Delete from Pocket",
|
||||||
|
"menu_action_archive_pocket": "Archive in Pocket",
|
||||||
|
"menu_action_show_file_mac_os": "Sýna í Finder",
|
||||||
|
"menu_action_show_file_windows": "Opna möppu",
|
||||||
|
"menu_action_show_file_linux": "Opna möppu",
|
||||||
|
"menu_action_show_file_default": "Sýna skrá",
|
||||||
|
"menu_action_open_file": "Opna skrá",
|
||||||
|
"menu_action_copy_download_link": "Copy Download Link",
|
||||||
|
"menu_action_go_to_download_page": "Go to Download Page",
|
||||||
|
"menu_action_remove_download": "Remove from History",
|
||||||
|
"search_button": "Search",
|
||||||
|
"search_header": "{search_engine_name} Search",
|
||||||
|
"search_web_placeholder": "Search the Web",
|
||||||
|
"section_disclaimer_topstories": "The most interesting stories on the web, selected based on what you read. From Pocket, now part of Mozilla.",
|
||||||
|
"section_disclaimer_topstories_linktext": "Learn how it works.",
|
||||||
|
"section_disclaimer_topstories_buttontext": "Okay, got it",
|
||||||
|
"prefs_home_header": "Firefox Home Content",
|
||||||
|
"prefs_home_description": "Choose what content you want on your Firefox Home screen.",
|
||||||
|
"prefs_section_rows_option": "{num} row;{num} rows",
|
||||||
|
"prefs_search_header": "Web Search",
|
||||||
|
"prefs_topsites_description": "The sites you visit most",
|
||||||
|
"prefs_topstories_description2": "Great content from around the web, personalized for you",
|
||||||
|
"prefs_topstories_options_sponsored_label": "Sponsored Stories",
|
||||||
|
"prefs_topstories_sponsored_learn_more": "Learn more",
|
||||||
|
"prefs_highlights_description": "A selection of sites that you’ve saved or visited",
|
||||||
|
"prefs_highlights_options_visited_label": "Visited Pages",
|
||||||
|
"prefs_highlights_options_download_label": "Most Recent Download",
|
||||||
|
"prefs_highlights_options_pocket_label": "Pages Saved to Pocket",
|
||||||
|
"prefs_snippets_description": "Updates from Mozilla and Firefox",
|
||||||
|
"settings_pane_button_label": "Customize your New Tab page",
|
||||||
|
"settings_pane_topsites_header": "Top Sites",
|
||||||
|
"settings_pane_highlights_header": "Highlights",
|
||||||
|
"settings_pane_highlights_options_bookmarks": "Bookmarks",
|
||||||
|
"settings_pane_snippets_header": "Snippets",
|
||||||
|
"edit_topsites_button_text": "Edit",
|
||||||
|
"edit_topsites_edit_button": "Edit this site",
|
||||||
|
"topsites_form_add_header": "New Top Site",
|
||||||
|
"topsites_form_edit_header": "Edit Top Site",
|
||||||
|
"topsites_form_title_label": "Title",
|
||||||
|
"topsites_form_title_placeholder": "Enter a title",
|
||||||
|
"topsites_form_url_label": "URL",
|
||||||
|
"topsites_form_image_url_label": "Custom Image URL",
|
||||||
|
"topsites_form_url_placeholder": "Type or paste a URL",
|
||||||
|
"topsites_form_use_image_link": "Use a custom image…",
|
||||||
|
"topsites_form_preview_button": "Preview",
|
||||||
|
"topsites_form_add_button": "Add",
|
||||||
|
"topsites_form_save_button": "Save",
|
||||||
|
"topsites_form_cancel_button": "Cancel",
|
||||||
|
"topsites_form_url_validation": "Valid URL required",
|
||||||
|
"topsites_form_image_validation": "Image failed to load. Try a different URL.",
|
||||||
|
"pocket_read_more": "Popular Topics:",
|
||||||
|
"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 we’ll show some of the great articles, videos, and other pages you’ve recently visited or bookmarked here.",
|
||||||
|
"topstories_empty_state": "You’ve caught up. Check back later for more top stories from {provider}. Can’t wait? Select a popular topic to find more great stories from around the web.",
|
||||||
|
"manual_migration_explanation2": "Try Firefox with the bookmarks, history and passwords from another browser.",
|
||||||
|
"manual_migration_cancel_button": "No Thanks",
|
||||||
|
"manual_migration_import_button": "Import Now",
|
||||||
|
"error_fallback_default_info": "Oops, something went wrong loading this content.",
|
||||||
|
"error_fallback_default_refresh_suggestion": "Refresh page to try again.",
|
||||||
|
"section_menu_action_remove_section": "Remove Section",
|
||||||
|
"section_menu_action_collapse_section": "Collapse Section",
|
||||||
|
"section_menu_action_expand_section": "Expand Section",
|
||||||
|
"section_menu_action_manage_section": "Manage Section",
|
||||||
|
"section_menu_action_manage_webext": "Manage Extension",
|
||||||
|
"section_menu_action_add_topsite": "Add Top Site",
|
||||||
|
"section_menu_action_add_search_engine": "Add Search Engine",
|
||||||
|
"section_menu_action_move_up": "Move Up",
|
||||||
|
"section_menu_action_move_down": "Move Down",
|
||||||
|
"section_menu_action_privacy_notice": "Privacy Notice",
|
||||||
|
"firstrun_title": "Take Firefox with You",
|
||||||
|
"firstrun_content": "Get your bookmarks, history, passwords and other settings on all your devices.",
|
||||||
|
"firstrun_learn_more_link": "Learn more about Firefox Accounts",
|
||||||
|
"firstrun_form_header": "Enter your email",
|
||||||
|
"firstrun_form_sub_header": "to continue to Firefox Sync",
|
||||||
|
"firstrun_email_input_placeholder": "Email",
|
||||||
|
"firstrun_invalid_input": "Valid email required",
|
||||||
|
"firstrun_extra_legal_links": "By proceeding, you agree to the {terms} and {privacy}.",
|
||||||
|
"firstrun_terms_of_service": "Terms of Service",
|
||||||
|
"firstrun_privacy_notice": "Privacy Notice",
|
||||||
|
"firstrun_continue_to_login": "Continue",
|
||||||
|
"firstrun_skip_login": "Skip this step"
|
||||||
|
};
|
@ -0,0 +1,39 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="is" dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
|
||||||
|
<title>Nýr flipi</title>
|
||||||
|
<link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
|
||||||
|
<link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
|
||||||
|
<link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
|
||||||
|
</head>
|
||||||
|
<body class="activity-stream">
|
||||||
|
<div id="root"></div>
|
||||||
|
<div id="snippets-container">
|
||||||
|
<div id="snippets"></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
// Don't directly load the following scripts as part of html to let the page
|
||||||
|
// finish loading to render the content sooner.
|
||||||
|
for (const src of [
|
||||||
|
"chrome://browser/content/contentSearchUI.js",
|
||||||
|
"chrome://browser/content/contentTheme.js",
|
||||||
|
"resource://activity-stream/vendor/react.js",
|
||||||
|
"resource://activity-stream/vendor/react-dom.js",
|
||||||
|
"resource://activity-stream/vendor/prop-types.js",
|
||||||
|
"resource://activity-stream/vendor/react-intl.js",
|
||||||
|
"resource://activity-stream/vendor/redux.js",
|
||||||
|
"resource://activity-stream/vendor/react-redux.js",
|
||||||
|
"resource://activity-stream/prerendered/is/activity-stream-strings.js",
|
||||||
|
"resource://activity-stream/data/content/activity-stream.bundle.js"
|
||||||
|
]) {
|
||||||
|
// These dynamically inserted scripts by default are async, but we need them
|
||||||
|
// to load in the desired order (i.e., bundle last).
|
||||||
|
const script = document.body.appendChild(document.createElement("script"));
|
||||||
|
script.async = false;
|
||||||
|
script.src = src;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -76,7 +76,7 @@ window.gActivityStreamStrings = {
|
|||||||
"pocket_read_even_more": "Vis fleire saker",
|
"pocket_read_even_more": "Vis fleire saker",
|
||||||
"pocket_more_reccommendations": "More Recommendations",
|
"pocket_more_reccommendations": "More Recommendations",
|
||||||
"pocket_learn_more": "Les meir",
|
"pocket_learn_more": "Les meir",
|
||||||
"pocket_cta_button": "Get Pocket",
|
"pocket_cta_button": "Last ned Pocket",
|
||||||
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
||||||
"highlights_empty_state": "Begynn å surfe, og vi vil vise deg nokre av dei beste artiklane, videoane og andre sider du nyleg har besøkt eller bokmerka her.",
|
"highlights_empty_state": "Begynn å surfe, og vi vil vise deg nokre av dei beste artiklane, videoane og andre sider du nyleg har besøkt eller bokmerka her.",
|
||||||
"topstories_empty_state": "Det finst ikkje fleire. Kom tilbake seinare for fleire topphistoriar frå {provider}. Kan du ikkje vente? Vel eit populært emne for å finne fleire gode artiklar frå heile nettet.",
|
"topstories_empty_state": "Det finst ikkje fleire. Kom tilbake seinare for fleire topphistoriar frå {provider}. Kan du ikkje vente? Vel eit populært emne for å finne fleire gode artiklar frå heile nettet.",
|
||||||
|
@ -75,7 +75,7 @@ window.gActivityStreamStrings = {
|
|||||||
"pocket_read_more": "Tèmas populars :",
|
"pocket_read_more": "Tèmas populars :",
|
||||||
"pocket_read_even_more": "Veire mai d’articles",
|
"pocket_read_even_more": "Veire mai d’articles",
|
||||||
"pocket_more_reccommendations": "More Recommendations",
|
"pocket_more_reccommendations": "More Recommendations",
|
||||||
"pocket_learn_more": "Learn More",
|
"pocket_learn_more": "Ne saber mai",
|
||||||
"pocket_cta_button": "Get Pocket",
|
"pocket_cta_button": "Get Pocket",
|
||||||
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
||||||
"highlights_empty_state": "Començatz de navegar e aquí vos mostrarem los melhors articles, vidèos e autras paginas qu’avètz visitadas o apondudas als marcapaginas.",
|
"highlights_empty_state": "Començatz de navegar e aquí vos mostrarem los melhors articles, vidèos e autras paginas qu’avètz visitadas o apondudas als marcapaginas.",
|
||||||
|
@ -74,10 +74,10 @@ window.gActivityStreamStrings = {
|
|||||||
"topsites_form_image_validation": "Wczytanie obrazu nie powiodło się. Spróbuj innego adresu.",
|
"topsites_form_image_validation": "Wczytanie obrazu nie powiodło się. Spróbuj innego adresu.",
|
||||||
"pocket_read_more": "Popularne treści:",
|
"pocket_read_more": "Popularne treści:",
|
||||||
"pocket_read_even_more": "Pokaż więcej artykułów",
|
"pocket_read_even_more": "Pokaż więcej artykułów",
|
||||||
"pocket_more_reccommendations": "More Recommendations",
|
"pocket_more_reccommendations": "Więcej polecanych",
|
||||||
"pocket_learn_more": "Learn More",
|
"pocket_learn_more": "Więcej informacji",
|
||||||
"pocket_cta_button": "Get Pocket",
|
"pocket_cta_button": "Pobierz Pocket",
|
||||||
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
"pocket_cta_text": "Zachowuj historie w Pocket, aby wrócić później do ich lektury.",
|
||||||
"highlights_empty_state": "Zacznij przeglądać Internet, a pojawią się tutaj świetne artykuły, filmy oraz inne ostatnio odwiedzane strony i dodane zakładki.",
|
"highlights_empty_state": "Zacznij przeglądać Internet, a pojawią się tutaj świetne artykuły, filmy oraz inne ostatnio odwiedzane strony i dodane zakładki.",
|
||||||
"topstories_empty_state": "To na razie wszystko. {provider} później będzie mieć więcej popularnych artykułów. Nie możesz się doczekać? Wybierz popularny temat, aby znaleźć więcej treści z całego Internetu.",
|
"topstories_empty_state": "To na razie wszystko. {provider} później będzie mieć więcej popularnych artykułów. Nie możesz się doczekać? Wybierz popularny temat, aby znaleźć więcej treści z całego Internetu.",
|
||||||
"manual_migration_explanation2": "Wypróbuj program Firefox z zakładkami, historią i hasłami z innej przeglądarki.",
|
"manual_migration_explanation2": "Wypróbuj program Firefox z zakładkami, historią i hasłami z innej przeglądarki.",
|
||||||
|
@ -75,9 +75,9 @@ window.gActivityStreamStrings = {
|
|||||||
"pocket_read_more": "Tópicos populares:",
|
"pocket_read_more": "Tópicos populares:",
|
||||||
"pocket_read_even_more": "Ver mais histórias",
|
"pocket_read_even_more": "Ver mais histórias",
|
||||||
"pocket_more_reccommendations": "Mais recomendações",
|
"pocket_more_reccommendations": "Mais recomendações",
|
||||||
"pocket_learn_more": "Saber mais",
|
"pocket_learn_more": "Saiba mais",
|
||||||
"pocket_cta_button": "Obter o Pocket",
|
"pocket_cta_button": "Obter o Pocket",
|
||||||
"pocket_cta_text": "Guarde as histórias que adora no Pocket, e abasteça a sua mente com leituras fascinantes.",
|
"pocket_cta_text": "Salve as histórias que você gosta no Pocket e abasteça sua mente com leituras fascinantes.",
|
||||||
"highlights_empty_state": "Comece a navegar e nós mostraremos aqui alguns ótimos artigos, vídeos e outras páginas que você favoritou ou visitou recentemente.",
|
"highlights_empty_state": "Comece a navegar e nós mostraremos aqui alguns ótimos artigos, vídeos e outras páginas que você favoritou ou visitou recentemente.",
|
||||||
"topstories_empty_state": "Você já viu tudo. Volte mais tarde para mais histórias do {provider}. Não consegue esperar? Escolha um assunto popular para encontrar mais grandes histórias através da web.",
|
"topstories_empty_state": "Você já viu tudo. Volte mais tarde para mais histórias do {provider}. Não consegue esperar? Escolha um assunto popular para encontrar mais grandes histórias através da web.",
|
||||||
"manual_migration_explanation2": "Experimente o Firefox com os favoritos, histórico e senhas salvas em outro navegador.",
|
"manual_migration_explanation2": "Experimente o Firefox com os favoritos, histórico e senhas salvas em outro navegador.",
|
||||||
|
@ -77,7 +77,7 @@ window.gActivityStreamStrings = {
|
|||||||
"pocket_more_reccommendations": "Ďalšie odporúčania",
|
"pocket_more_reccommendations": "Ďalšie odporúčania",
|
||||||
"pocket_learn_more": "Ďalšie informácie",
|
"pocket_learn_more": "Ďalšie informácie",
|
||||||
"pocket_cta_button": "Získajte Pocket",
|
"pocket_cta_button": "Získajte Pocket",
|
||||||
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
"pocket_cta_text": "Ukladajte si články do služby Pocket a užívajte si skvelé čítanie.",
|
||||||
"highlights_empty_state": "Začnite s prehliadaním a my vám na tomto mieste ukážeme skvelé články, videá a ostatné stránky, ktoré ste nedávno navštívili alebo pridali medzi záložky.",
|
"highlights_empty_state": "Začnite s prehliadaním a my vám na tomto mieste ukážeme skvelé články, videá a ostatné stránky, ktoré ste nedávno navštívili alebo pridali medzi záložky.",
|
||||||
"topstories_empty_state": "Už ste prečítali všetko. Ďalšie príbehy zo služby {provider} tu nájdete opäť neskôr. Nemôžete sa dočkať? Vyberte si populárnu tému a pozrite sa na ďalšie skvelé príbehy z celého webu.",
|
"topstories_empty_state": "Už ste prečítali všetko. Ďalšie príbehy zo služby {provider} tu nájdete opäť neskôr. Nemôžete sa dočkať? Vyberte si populárnu tému a pozrite sa na ďalšie skvelé príbehy z celého webu.",
|
||||||
"manual_migration_explanation2": "Vyskúšajte Firefox so záložkami, históriou prehliadania a heslami s iných prehliadačov.",
|
"manual_migration_explanation2": "Vyskúšajte Firefox so záložkami, históriou prehliadania a heslami s iných prehliadačov.",
|
||||||
|
@ -24,13 +24,13 @@ window.gActivityStreamStrings = {
|
|||||||
"menu_action_save_to_pocket": "Pocket میں محفوظ کریں",
|
"menu_action_save_to_pocket": "Pocket میں محفوظ کریں",
|
||||||
"menu_action_delete_pocket": "Pocket سے جزف کریں",
|
"menu_action_delete_pocket": "Pocket سے جزف کریں",
|
||||||
"menu_action_archive_pocket": "Archive in Pocket",
|
"menu_action_archive_pocket": "Archive in Pocket",
|
||||||
"menu_action_show_file_mac_os": "Show in Finder",
|
"menu_action_show_file_mac_os": "تلاش کار میں دکھائیں",
|
||||||
"menu_action_show_file_windows": "حامل پوشہ کھولیں",
|
"menu_action_show_file_windows": "حامل پوشہ کھولیں",
|
||||||
"menu_action_show_file_linux": "Open Containing Folder",
|
"menu_action_show_file_linux": "مشتمل فولڈر کھولیں",
|
||||||
"menu_action_show_file_default": "مسل دکھائیں",
|
"menu_action_show_file_default": "مسل دکھائیں",
|
||||||
"menu_action_open_file": "مسل کھولیں",
|
"menu_action_open_file": "مسل کھولیں",
|
||||||
"menu_action_copy_download_link": "ڈاؤن لوڈ ربط نقل کریں",
|
"menu_action_copy_download_link": "ڈاؤن لوڈ ربط نقل کریں",
|
||||||
"menu_action_go_to_download_page": "Go to Download Page",
|
"menu_action_go_to_download_page": "ڈاؤن لوڈ صفحہ پر جائیں",
|
||||||
"menu_action_remove_download": "سابقات سے ہٹائیں",
|
"menu_action_remove_download": "سابقات سے ہٹائیں",
|
||||||
"search_button": "تلاش",
|
"search_button": "تلاش",
|
||||||
"search_header": "{search_engine_name} پر تلاش کریں",
|
"search_header": "{search_engine_name} پر تلاش کریں",
|
||||||
@ -101,7 +101,7 @@ window.gActivityStreamStrings = {
|
|||||||
"firstrun_form_header": "اپنی ای میل داخل کریں",
|
"firstrun_form_header": "اپنی ای میل داخل کریں",
|
||||||
"firstrun_form_sub_header": "to continue to Firefox Sync",
|
"firstrun_form_sub_header": "to continue to Firefox Sync",
|
||||||
"firstrun_email_input_placeholder": "ای میل",
|
"firstrun_email_input_placeholder": "ای میل",
|
||||||
"firstrun_invalid_input": "Valid email required",
|
"firstrun_invalid_input": "جائز ای میل کی ظرورت ہے",
|
||||||
"firstrun_extra_legal_links": "By proceeding, you agree to the {terms} and {privacy}.",
|
"firstrun_extra_legal_links": "By proceeding, you agree to the {terms} and {privacy}.",
|
||||||
"firstrun_terms_of_service": "خدمت کی شرائط",
|
"firstrun_terms_of_service": "خدمت کی شرائط",
|
||||||
"firstrun_privacy_notice": "رازداری کا نوٹس",
|
"firstrun_privacy_notice": "رازداری کا نوٹس",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const {ASRouterTargeting, TopFrecentSitesCache, TotalBookmarksCountCache} =
|
const {ASRouterTargeting, QueryCache} =
|
||||||
ChromeUtils.import("resource://activity-stream/lib/ASRouterTargeting.jsm", {});
|
ChromeUtils.import("resource://activity-stream/lib/ASRouterTargeting.jsm", {});
|
||||||
const {AddonTestUtils} =
|
const {AddonTestUtils} =
|
||||||
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm", {});
|
ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm", {});
|
||||||
@ -90,6 +90,24 @@ add_task(async function check_other_error_handling() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ASRouterTargeting.Environment
|
// ASRouterTargeting.Environment
|
||||||
|
add_task(async function check_locale() {
|
||||||
|
ok(Services.locale.appLocaleAsLangTag, "Services.locale.appLocaleAsLangTag exists");
|
||||||
|
const message = {id: "foo", targeting: `locale == "${Services.locale.appLocaleAsLangTag}"`};
|
||||||
|
is(await ASRouterTargeting.findMatchingMessage({messages: [message]}), message,
|
||||||
|
"should select correct item when filtering by locale");
|
||||||
|
});
|
||||||
|
add_task(async function check_localeLanguageCode() {
|
||||||
|
const currentLanguageCode = Services.locale.appLocaleAsLangTag.substr(0, 2);
|
||||||
|
is(
|
||||||
|
Services.locale.negotiateLanguages([currentLanguageCode], [Services.locale.appLocaleAsLangTag])[0],
|
||||||
|
Services.locale.appLocaleAsLangTag,
|
||||||
|
"currentLanguageCode should resolve to the current locale (e.g en => en-US)"
|
||||||
|
);
|
||||||
|
const message = {id: "foo", targeting: `localeLanguageCode == "${currentLanguageCode}"`};
|
||||||
|
is(await ASRouterTargeting.findMatchingMessage({messages: [message]}), message,
|
||||||
|
"should select correct item when filtering by localeLanguageCode");
|
||||||
|
});
|
||||||
|
|
||||||
add_task(async function checkProfileAgeCreated() {
|
add_task(async function checkProfileAgeCreated() {
|
||||||
let profileAccessor = new ProfileAge();
|
let profileAccessor = new ProfileAge();
|
||||||
is(await ASRouterTargeting.Environment.profileAgeCreated, await profileAccessor.created,
|
is(await ASRouterTargeting.Environment.profileAgeCreated, await profileAccessor.created,
|
||||||
@ -135,8 +153,9 @@ add_task(async function check_totalBookmarksCount() {
|
|||||||
await clearHistoryAndBookmarks();
|
await clearHistoryAndBookmarks();
|
||||||
const message = {id: "foo", targeting: "totalBookmarksCount > 0"};
|
const message = {id: "foo", targeting: "totalBookmarksCount > 0"};
|
||||||
|
|
||||||
is(await ASRouterTargeting.findMatchingMessage({messages: [message]}), undefined,
|
const results = await ASRouterTargeting.findMatchingMessage({messages: [message]});
|
||||||
"Should not select any message because");
|
is(results ? JSON.stringify(results) : results, undefined,
|
||||||
|
"Should not select any message because bookmarks count is not 0");
|
||||||
|
|
||||||
const bookmark = await PlacesUtils.bookmarks.insert({
|
const bookmark = await PlacesUtils.bookmarks.insert({
|
||||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||||
@ -144,7 +163,7 @@ add_task(async function check_totalBookmarksCount() {
|
|||||||
url: "https://mozilla1.com/nowNew",
|
url: "https://mozilla1.com/nowNew",
|
||||||
});
|
});
|
||||||
|
|
||||||
TotalBookmarksCountCache.expire();
|
QueryCache.queries.TotalBookmarksCount.expire();
|
||||||
|
|
||||||
is(await ASRouterTargeting.findMatchingMessage({messages: [message]}), message,
|
is(await ASRouterTargeting.findMatchingMessage({messages: [message]}), message,
|
||||||
"Should select correct item after bookmarks are added.");
|
"Should select correct item after bookmarks are added.");
|
||||||
@ -305,7 +324,6 @@ add_task(async function checkFrecentSites() {
|
|||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
await clearHistoryAndBookmarks();
|
await clearHistoryAndBookmarks();
|
||||||
TopFrecentSitesCache.expire();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
add_task(async function check_firefox_version() {
|
add_task(async function check_firefox_version() {
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
|
ChromeUtils.defineModuleGetter(this, "PlacesTestUtils",
|
||||||
"resource://testing-common/PlacesTestUtils.jsm");
|
"resource://testing-common/PlacesTestUtils.jsm");
|
||||||
|
ChromeUtils.defineModuleGetter(this, "QueryCache",
|
||||||
|
"resource://activity-stream/lib/ASRouterTargeting.jsm");
|
||||||
|
|
||||||
function popPrefs() {
|
function popPrefs() {
|
||||||
return SpecialPowers.popPrefEnv();
|
return SpecialPowers.popPrefEnv();
|
||||||
@ -22,6 +24,7 @@ async function setDefaultTopSites() { // eslint-disable-line no-unused-vars
|
|||||||
async function clearHistoryAndBookmarks() { // eslint-disable-line no-unused-vars
|
async function clearHistoryAndBookmarks() { // eslint-disable-line no-unused-vars
|
||||||
await PlacesUtils.bookmarks.eraseEverything();
|
await PlacesUtils.bookmarks.eraseEverything();
|
||||||
await PlacesUtils.history.clear();
|
await PlacesUtils.history.clear();
|
||||||
|
QueryCache.expireAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +99,7 @@ export const UserEventAction = Joi.object().keys({
|
|||||||
icon_type: Joi.valid(["tippytop", "rich_icon", "screenshot_with_icon", "screenshot", "no_image"]),
|
icon_type: Joi.valid(["tippytop", "rich_icon", "screenshot_with_icon", "screenshot", "no_image"]),
|
||||||
card_type: Joi.valid(["bookmark", "trending", "pinned", "pocket", "search"]),
|
card_type: Joi.valid(["bookmark", "trending", "pinned", "pocket", "search"]),
|
||||||
search_vendor: Joi.valid(["google", "amazon"]),
|
search_vendor: Joi.valid(["google", "amazon"]),
|
||||||
|
has_flow_params: Joi.bool(),
|
||||||
}),
|
}),
|
||||||
}).required(),
|
}).required(),
|
||||||
meta: Joi.object().keys({
|
meta: Joi.object().keys({
|
||||||
|
@ -16,6 +16,7 @@ import {ASRouterTriggerListeners} from "lib/ASRouterTriggerListeners.jsm";
|
|||||||
import {CFRPageActions} from "lib/CFRPageActions.jsm";
|
import {CFRPageActions} from "lib/CFRPageActions.jsm";
|
||||||
import {GlobalOverrider} from "test/unit/utils";
|
import {GlobalOverrider} from "test/unit/utils";
|
||||||
import ProviderResponseSchema from "content-src/asrouter/schemas/provider-response.schema.json";
|
import ProviderResponseSchema from "content-src/asrouter/schemas/provider-response.schema.json";
|
||||||
|
import {QueryCache} from "lib/ASRouterTargeting.jsm";
|
||||||
|
|
||||||
const MESSAGE_PROVIDER_PREF_NAME = "browser.newtabpage.activity-stream.asrouter.messageProviders";
|
const MESSAGE_PROVIDER_PREF_NAME = "browser.newtabpage.activity-stream.asrouter.messageProviders";
|
||||||
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
|
const ONBOARDING_FINISHED_PREF = "browser.onboarding.notification.finished";
|
||||||
@ -201,6 +202,18 @@ describe("ASRouter", () => {
|
|||||||
assert.lengthOf(Router.state.providers, length);
|
assert.lengthOf(Router.state.providers, length);
|
||||||
assert.isDefined(provider);
|
assert.isDefined(provider);
|
||||||
});
|
});
|
||||||
|
it("should update the list of providers and load messages on legacy onboarding pref change", async () => {
|
||||||
|
sandbox.spy(Router, "_updateMessageProviders");
|
||||||
|
sandbox.spy(Router, "loadMessagesFromAllProviders");
|
||||||
|
// we do NOT want to set the onboarding pref again and cause an infinite loop
|
||||||
|
sandbox.stub(global.Services.prefs, "setBoolPref");
|
||||||
|
|
||||||
|
await Router.observe(null, null, ONBOARDING_FINISHED_PREF);
|
||||||
|
|
||||||
|
assert.calledOnce(Router._updateMessageProviders);
|
||||||
|
assert.calledOnce(Router.loadMessagesFromAllProviders);
|
||||||
|
assert.notCalled(global.Services.prefs.setBoolPref);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("setState", () => {
|
describe("setState", () => {
|
||||||
@ -219,7 +232,7 @@ describe("ASRouter", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("#overrideOrEnableLegacyOnboarding", () => {
|
describe("#overrideOrEnableLegacyOnboarding", () => {
|
||||||
it("should set the onboarding finished pref to true if it is true and ASRPreferences.allowLegacyOnboarding is false", async () => {
|
it("should set the onboarding finished pref to true if legacy onboarding is NOT allowed", async () => {
|
||||||
sandbox.stub(global.Services.prefs, "getBoolPref").withArgs(ONBOARDING_FINISHED_PREF).returns(false);
|
sandbox.stub(global.Services.prefs, "getBoolPref").withArgs(ONBOARDING_FINISHED_PREF).returns(false);
|
||||||
sandbox.stub(ASRouterPreferences, "specialConditions").get(() => ({allowLegacyOnboarding: false}));
|
sandbox.stub(ASRouterPreferences, "specialConditions").get(() => ({allowLegacyOnboarding: false}));
|
||||||
const setStub = sandbox.stub(global.Services.prefs, "setBoolPref");
|
const setStub = sandbox.stub(global.Services.prefs, "setBoolPref");
|
||||||
@ -227,9 +240,15 @@ describe("ASRouter", () => {
|
|||||||
Router.overrideOrEnableLegacyOnboarding();
|
Router.overrideOrEnableLegacyOnboarding();
|
||||||
assert.calledWith(setStub, ONBOARDING_FINISHED_PREF, true);
|
assert.calledWith(setStub, ONBOARDING_FINISHED_PREF, true);
|
||||||
});
|
});
|
||||||
it("should set the onboarding finished pref to false if it is false and ASRPreferences.allowLegacyOnboarding is true", async () => {
|
it("should set the onboarding finished pref to false if ASRPreferences.allowLegacyOnboarding is true and we previously override onboarding", async () => {
|
||||||
sandbox.stub(global.Services.prefs, "getBoolPref").withArgs(ONBOARDING_FINISHED_PREF).returns(true);
|
// First override the finished pref to be to true so we can reverse the overriding
|
||||||
sandbox.stub(ASRouterPreferences, "specialConditions").get(() => ({allowLegacyOnboarding: true}));
|
const onboardingPrefStub = sandbox.stub(global.Services.prefs, "getBoolPref").withArgs(ONBOARDING_FINISHED_PREF).returns(false);
|
||||||
|
const specialConditionsStub = sandbox.stub(ASRouterPreferences, "specialConditions").get(() => ({allowLegacyOnboarding: false}));
|
||||||
|
Router.overrideOrEnableLegacyOnboarding();
|
||||||
|
|
||||||
|
// Now reverse it
|
||||||
|
onboardingPrefStub.withArgs(ONBOARDING_FINISHED_PREF).returns(true);
|
||||||
|
specialConditionsStub.get(() => ({allowLegacyOnboarding: true}));
|
||||||
const setStub = sandbox.stub(global.Services.prefs, "setBoolPref");
|
const setStub = sandbox.stub(global.Services.prefs, "setBoolPref");
|
||||||
|
|
||||||
Router.overrideOrEnableLegacyOnboarding();
|
Router.overrideOrEnableLegacyOnboarding();
|
||||||
@ -365,6 +384,15 @@ describe("ASRouter", () => {
|
|||||||
assert.equal(Router.state.providers.length, 1);
|
assert.equal(Router.state.providers.length, 1);
|
||||||
assert.equal(Router.state.providers[0].id, providers[1].id);
|
assert.equal(Router.state.providers[0].id, providers[1].id);
|
||||||
});
|
});
|
||||||
|
it("should not add snippets if legacy onboarding is not finished", () => {
|
||||||
|
sandbox.stub(global.Services.prefs, "getBoolPref").withArgs(ONBOARDING_FINISHED_PREF).returns(false);
|
||||||
|
const providers = [
|
||||||
|
{id: "snippets", enabled: true, type: "remote", url: "https://www.foo.com/"},
|
||||||
|
];
|
||||||
|
setMessageProviderPref(providers);
|
||||||
|
Router._updateMessageProviders();
|
||||||
|
assert.equal(Router.state.providers.length, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("blocking", () => {
|
describe("blocking", () => {
|
||||||
@ -432,16 +460,16 @@ describe("ASRouter", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#onMessage: CONNECT_UI_REQUEST", () => {
|
describe("#onMessage: SNIPPETS_REQUEST", () => {
|
||||||
it("should set state.lastMessageId to a message id", async () => {
|
it("should set state.lastMessageId to a message id", async () => {
|
||||||
await Router.onMessage(fakeAsyncMessage({type: "CONNECT_UI_REQUEST"}));
|
await Router.onMessage(fakeAsyncMessage({type: "SNIPPETS_REQUEST"}));
|
||||||
|
|
||||||
assert.include(ALL_MESSAGE_IDS, Router.state.lastMessageId);
|
assert.include(ALL_MESSAGE_IDS, Router.state.lastMessageId);
|
||||||
});
|
});
|
||||||
it("should send a message back to the to the target", async () => {
|
it("should send a message back to the to the target", async () => {
|
||||||
// force the only message to be a regular message so getRandomItemFromArray picks it
|
// force the only message to be a regular message so getRandomItemFromArray picks it
|
||||||
await Router.setState({messages: [{id: "foo", template: "simple_template", content: {title: "Foo", body: "Foo123"}}]});
|
await Router.setState({messages: [{id: "foo", template: "simple_template", content: {title: "Foo", body: "Foo123"}}]});
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
const [currentMessage] = Router.state.messages.filter(message => message.id === Router.state.lastMessageId);
|
const [currentMessage] = Router.state.messages.filter(message => message.id === Router.state.lastMessageId);
|
||||||
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "SET_MESSAGE", data: currentMessage});
|
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "SET_MESSAGE", data: currentMessage});
|
||||||
@ -450,7 +478,7 @@ describe("ASRouter", () => {
|
|||||||
// force the only message to be a bundled message so getRandomItemFromArray picks it
|
// force the only message to be a bundled message so getRandomItemFromArray picks it
|
||||||
sandbox.stub(Router, "_findProvider").returns(null);
|
sandbox.stub(Router, "_findProvider").returns(null);
|
||||||
await Router.setState({messages: [{id: "foo1", template: "simple_template", bundled: 1, content: {title: "Foo1", body: "Foo123-1"}}]});
|
await Router.setState({messages: [{id: "foo1", template: "simple_template", bundled: 1, content: {title: "Foo1", body: "Foo123-1"}}]});
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
const [currentMessage] = Router.state.messages.filter(message => message.id === Router.state.lastMessageId);
|
const [currentMessage] = Router.state.messages.filter(message => message.id === Router.state.lastMessageId);
|
||||||
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME);
|
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME);
|
||||||
@ -463,7 +491,7 @@ describe("ASRouter", () => {
|
|||||||
const firstMessage = {id: "foo2", template: "simple_template", bundled: 2, order: 1, content: {title: "Foo2", body: "Foo123-2"}};
|
const firstMessage = {id: "foo2", template: "simple_template", bundled: 2, order: 1, content: {title: "Foo2", body: "Foo123-2"}};
|
||||||
const secondMessage = {id: "foo1", template: "simple_template", bundled: 2, order: 2, content: {title: "Foo1", body: "Foo123-1"}};
|
const secondMessage = {id: "foo1", template: "simple_template", bundled: 2, order: 2, content: {title: "Foo1", body: "Foo123-1"}};
|
||||||
await Router.setState({messages: [secondMessage, firstMessage]});
|
await Router.setState({messages: [secondMessage, firstMessage]});
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME);
|
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME);
|
||||||
assert.equal(msg.target.sendAsyncMessage.firstCall.args[1].type, "SET_BUNDLED_MESSAGES");
|
assert.equal(msg.target.sendAsyncMessage.firstCall.args[1].type, "SET_BUNDLED_MESSAGES");
|
||||||
@ -485,20 +513,20 @@ describe("ASRouter", () => {
|
|||||||
it("should send a CLEAR_ALL message if no bundle available", async () => {
|
it("should send a CLEAR_ALL message if no bundle available", async () => {
|
||||||
// force the only message to be a bundled message that needs 2 messages in the bundle
|
// force the only message to be a bundled message that needs 2 messages in the bundle
|
||||||
await Router.setState({messages: [{id: "foo1", template: "simple_template", bundled: 2, content: {title: "Foo1", body: "Foo123-1"}}]});
|
await Router.setState({messages: [{id: "foo1", template: "simple_template", bundled: 2, content: {title: "Foo1", body: "Foo123-1"}}]});
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "CLEAR_ALL"});
|
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "CLEAR_ALL"});
|
||||||
});
|
});
|
||||||
it("should send a CLEAR_ALL message if no messages are available", async () => {
|
it("should send a CLEAR_ALL message if no messages are available", async () => {
|
||||||
await Router.setState({messages: []});
|
await Router.setState({messages: []});
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "CLEAR_ALL"});
|
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "CLEAR_ALL"});
|
||||||
});
|
});
|
||||||
it("should make a request to the provided endpoint on CONNECT_UI_REQUEST", async () => {
|
it("should make a request to the provided endpoint on SNIPPETS_REQUEST", async () => {
|
||||||
const url = "https://snippets-admin.mozilla.org/foo";
|
const url = "https://snippets-admin.mozilla.org/foo";
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST", data: {endpoint: {url}}});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST", data: {endpoint: {url}}});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
assert.calledWith(global.fetch, url);
|
assert.calledWith(global.fetch, url);
|
||||||
@ -514,21 +542,21 @@ describe("ASRouter", () => {
|
|||||||
});
|
});
|
||||||
it("should dispatch SNIPPETS_PREVIEW_MODE when adding a preview endpoint", async () => {
|
it("should dispatch SNIPPETS_PREVIEW_MODE when adding a preview endpoint", async () => {
|
||||||
const url = "https://snippets-admin.mozilla.org/foo";
|
const url = "https://snippets-admin.mozilla.org/foo";
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST", data: {endpoint: {url}}});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST", data: {endpoint: {url}}});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
assert.calledWithExactly(Router.dispatchToAS, ac.OnlyToOneContent({type: "SNIPPETS_PREVIEW_MODE"}, msg.target.portID));
|
assert.calledWithExactly(Router.dispatchToAS, ac.OnlyToOneContent({type: "SNIPPETS_PREVIEW_MODE"}, msg.target.portID));
|
||||||
});
|
});
|
||||||
it("should not add a url that is not from a whitelisted host", async () => {
|
it("should not add a url that is not from a whitelisted host", async () => {
|
||||||
const url = "https://mozilla.org";
|
const url = "https://mozilla.org";
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST", data: {endpoint: {url}}});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST", data: {endpoint: {url}}});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
assert.lengthOf(Router.state.providers.filter(p => p.url === url), 0);
|
assert.lengthOf(Router.state.providers.filter(p => p.url === url), 0);
|
||||||
});
|
});
|
||||||
it("should reject bad urls", async () => {
|
it("should reject bad urls", async () => {
|
||||||
const url = "foo";
|
const url = "foo";
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST", data: {endpoint: {url}}});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST", data: {endpoint: {url}}});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
assert.lengthOf(Router.state.providers.filter(p => p.url === url), 0);
|
assert.lengthOf(Router.state.providers.filter(p => p.url === url), 0);
|
||||||
@ -621,15 +649,14 @@ describe("ASRouter", () => {
|
|||||||
it("should send a message containing the whole state", async () => {
|
it("should send a message containing the whole state", async () => {
|
||||||
const msg = fakeAsyncMessage({type: "ADMIN_CONNECT_STATE"});
|
const msg = fakeAsyncMessage({type: "ADMIN_CONNECT_STATE"});
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: Router.state});
|
assert.calledWith(msg.target.sendAsyncMessage, PARENT_TO_CHILD_MESSAGE_NAME, {type: "ADMIN_SET_STATE", data: Router.state});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#onMessage: CONNECT_UI_REQUEST", () => {
|
describe("#onMessage: SNIPPETS_REQUEST", () => {
|
||||||
it("should call sendNextMessage on CONNECT_UI_REQUEST", async () => {
|
it("should call sendNextMessage on SNIPPETS_REQUEST", async () => {
|
||||||
sandbox.stub(Router, "sendNextMessage").resolves();
|
sandbox.stub(Router, "sendNextMessage").resolves();
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
|
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
@ -686,7 +713,7 @@ describe("ASRouter", () => {
|
|||||||
});
|
});
|
||||||
it("should get the bundle and send the message if the message has a bundle", async () => {
|
it("should get the bundle and send the message if the message has a bundle", async () => {
|
||||||
sandbox.stub(Router, "sendNextMessage").resolves();
|
sandbox.stub(Router, "sendNextMessage").resolves();
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
msg.bundled = 2; // force this message to want to be bundled
|
msg.bundled = 2; // force this message to want to be bundled
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
assert.calledOnce(Router.sendNextMessage);
|
assert.calledOnce(Router.sendNextMessage);
|
||||||
@ -837,6 +864,17 @@ describe("ASRouter", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("#onMessage: EXPIRE_QUERY_CACHE", () => {
|
||||||
|
it("should clear all QueryCache getters", async () => {
|
||||||
|
const msg = fakeAsyncMessage({type: "EXPIRE_QUERY_CACHE"});
|
||||||
|
sandbox.stub(QueryCache, "expireAll");
|
||||||
|
|
||||||
|
await Router.onMessage(msg);
|
||||||
|
|
||||||
|
assert.calledOnce(QueryCache.expireAll);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("_triggerHandler", () => {
|
describe("_triggerHandler", () => {
|
||||||
it("should call #onMessage with the correct trigger", () => {
|
it("should call #onMessage with the correct trigger", () => {
|
||||||
sinon.spy(Router, "onMessage");
|
sinon.spy(Router, "onMessage");
|
||||||
@ -1139,7 +1177,7 @@ describe("ASRouter", () => {
|
|||||||
it("should dispatch an event when a targeting expression throws an error", async () => {
|
it("should dispatch an event when a targeting expression throws an error", async () => {
|
||||||
sandbox.stub(global.FilterExpressions, "eval").returns(Promise.reject(new Error("fake error")));
|
sandbox.stub(global.FilterExpressions, "eval").returns(Promise.reject(new Error("fake error")));
|
||||||
await Router.setState({messages: [{id: "foo", targeting: "foo2.[[("}]});
|
await Router.setState({messages: [{id: "foo", targeting: "foo2.[[("}]});
|
||||||
const msg = fakeAsyncMessage({type: "CONNECT_UI_REQUEST"});
|
const msg = fakeAsyncMessage({type: "SNIPPETS_REQUEST"});
|
||||||
dispatchStub.reset();
|
dispatchStub.reset();
|
||||||
|
|
||||||
await Router.onMessage(msg);
|
await Router.onMessage(msg);
|
||||||
|
@ -3,6 +3,14 @@ const FAKE_PROVIDERS = [{id: "foo"}, {id: "bar"}];
|
|||||||
|
|
||||||
const PROVIDER_PREF = "browser.newtabpage.activity-stream.asrouter.messageProviders";
|
const PROVIDER_PREF = "browser.newtabpage.activity-stream.asrouter.messageProviders";
|
||||||
const DEVTOOLS_PREF = "browser.newtabpage.activity-stream.asrouter.devtoolsEnabled";
|
const DEVTOOLS_PREF = "browser.newtabpage.activity-stream.asrouter.devtoolsEnabled";
|
||||||
|
const SNIPPETS_USER_PREF = "browser.newtabpage.activity-stream.feeds.snippets";
|
||||||
|
|
||||||
|
/** NUMBER_OF_PREFS_TO_OBSERVE includes:
|
||||||
|
* 1. asrouter.messageProvider
|
||||||
|
* 2. asrouter.devtoolsEnabled
|
||||||
|
* 3. browser.newtabpage.activity-stream.feeds.snippets (user preference - snippets)
|
||||||
|
*/
|
||||||
|
const NUMBER_OF_PREFS_TO_OBSERVE = 3;
|
||||||
|
|
||||||
describe("ASRouterPreferences", () => {
|
describe("ASRouterPreferences", () => {
|
||||||
let ASRouterPreferences;
|
let ASRouterPreferences;
|
||||||
@ -16,7 +24,7 @@ describe("ASRouterPreferences", () => {
|
|||||||
sandbox = sinon.sandbox.create();
|
sandbox = sinon.sandbox.create();
|
||||||
addObserverStub = sandbox.stub(global.Services.prefs, "addObserver");
|
addObserverStub = sandbox.stub(global.Services.prefs, "addObserver");
|
||||||
stringPrefStub = sandbox.stub(global.Services.prefs, "getStringPref").withArgs(PROVIDER_PREF).returns(JSON.stringify(FAKE_PROVIDERS));
|
stringPrefStub = sandbox.stub(global.Services.prefs, "getStringPref").withArgs(PROVIDER_PREF).returns(JSON.stringify(FAKE_PROVIDERS));
|
||||||
boolPrefStub = sandbox.stub(global.Services.prefs, "getBoolPref").withArgs(DEVTOOLS_PREF).returns(false);
|
boolPrefStub = sandbox.stub(global.Services.prefs, "getBoolPref").returns(false);
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
sandbox.restore();
|
sandbox.restore();
|
||||||
@ -29,12 +37,12 @@ describe("ASRouterPreferences", () => {
|
|||||||
ASRouterPreferences.init();
|
ASRouterPreferences.init();
|
||||||
assert.isTrue(ASRouterPreferences._initialized);
|
assert.isTrue(ASRouterPreferences._initialized);
|
||||||
});
|
});
|
||||||
it("should set two observers and not re-initialize if already initialized", () => {
|
it(`should set ${NUMBER_OF_PREFS_TO_OBSERVE} observers and not re-initialize if already initialized`, () => {
|
||||||
ASRouterPreferences.init();
|
ASRouterPreferences.init();
|
||||||
assert.calledTwice(addObserverStub);
|
assert.callCount(addObserverStub, NUMBER_OF_PREFS_TO_OBSERVE);
|
||||||
ASRouterPreferences.init();
|
ASRouterPreferences.init();
|
||||||
ASRouterPreferences.init();
|
ASRouterPreferences.init();
|
||||||
assert.calledTwice(addObserverStub);
|
assert.callCount(addObserverStub, NUMBER_OF_PREFS_TO_OBSERVE);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("#uninit", () => {
|
describe("#uninit", () => {
|
||||||
@ -64,7 +72,7 @@ describe("ASRouterPreferences", () => {
|
|||||||
// Tests to make sure we don't remove observers that weren't set
|
// Tests to make sure we don't remove observers that weren't set
|
||||||
ASRouterPreferences.uninit();
|
ASRouterPreferences.uninit();
|
||||||
|
|
||||||
assert.calledTwice(removeStub);
|
assert.callCount(removeStub, NUMBER_OF_PREFS_TO_OBSERVE);
|
||||||
assert.calledWith(removeStub, PROVIDER_PREF);
|
assert.calledWith(removeStub, PROVIDER_PREF);
|
||||||
assert.calledWith(removeStub, DEVTOOLS_PREF);
|
assert.calledWith(removeStub, DEVTOOLS_PREF);
|
||||||
assert.isEmpty(ASRouterPreferences._callbacks);
|
assert.isEmpty(ASRouterPreferences._callbacks);
|
||||||
@ -163,6 +171,12 @@ describe("ASRouterPreferences", () => {
|
|||||||
assert.isFalse(ASRouterPreferences.specialConditions.allowLegacySnippets);
|
assert.isFalse(ASRouterPreferences.specialConditions.allowLegacySnippets);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe("#getUserPreference(providerId)", () => {
|
||||||
|
it("should return the user preference for snippets", () => {
|
||||||
|
boolPrefStub.withArgs(SNIPPETS_USER_PREF).returns(true);
|
||||||
|
assert.isTrue(ASRouterPreferences.getUserPreference("snippets"));
|
||||||
|
});
|
||||||
|
});
|
||||||
describe("observer, listeners", () => {
|
describe("observer, listeners", () => {
|
||||||
it("should invalidate .providers when the pref is changed", () => {
|
it("should invalidate .providers when the pref is changed", () => {
|
||||||
const testProviders = [{id: "newstuff"}];
|
const testProviders = [{id: "newstuff"}];
|
||||||
|
@ -65,14 +65,14 @@ describe("#CachedTargetingGetter", () => {
|
|||||||
frecentStub.resolves();
|
frecentStub.resolves();
|
||||||
clock.tick(sixHours);
|
clock.tick(sixHours);
|
||||||
|
|
||||||
await topsitesCache.getTopFrecentSites; // eslint-disable-line no-unused-expressions
|
await topsitesCache.get();
|
||||||
await topsitesCache.getTopFrecentSites; // eslint-disable-line no-unused-expressions
|
await topsitesCache.get();
|
||||||
|
|
||||||
assert.calledOnce(global.NewTabUtils.activityStreamProvider.getTopFrecentSites);
|
assert.calledOnce(global.NewTabUtils.activityStreamProvider.getTopFrecentSites);
|
||||||
|
|
||||||
clock.tick(sixHours);
|
clock.tick(sixHours);
|
||||||
|
|
||||||
await topsitesCache.getTopFrecentSites; // eslint-disable-line no-unused-expressions
|
await topsitesCache.get();
|
||||||
|
|
||||||
assert.calledTwice(global.NewTabUtils.activityStreamProvider.getTopFrecentSites);
|
assert.calledTwice(global.NewTabUtils.activityStreamProvider.getTopFrecentSites);
|
||||||
});
|
});
|
||||||
@ -83,7 +83,7 @@ describe("#CachedTargetingGetter", () => {
|
|||||||
// assert.throws expect a function as the first parameter, try/catch is a
|
// assert.throws expect a function as the first parameter, try/catch is a
|
||||||
// workaround
|
// workaround
|
||||||
try {
|
try {
|
||||||
await topsitesCache.getTopFrecentSites; // eslint-disable-line no-unused-expressions
|
await topsitesCache.get();
|
||||||
assert.isTrue(false);
|
assert.isTrue(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
assert.calledOnce(global.Cu.reportError);
|
assert.calledOnce(global.Cu.reportError);
|
||||||
|
@ -23,7 +23,7 @@ describe("<StartupOverlay>", () => {
|
|||||||
|
|
||||||
assert.calledOnce(dispatch);
|
assert.calledOnce(dispatch);
|
||||||
assert.isUserEventAction(dispatch.firstCall.args[0]);
|
assert.isUserEventAction(dispatch.firstCall.args[0]);
|
||||||
assert.calledWith(dispatch, ac.UserEvent({event: at.SKIPPED_SIGNIN}));
|
assert.calledWith(dispatch, ac.UserEvent({event: at.SKIPPED_SIGNIN, value: {has_flow_params: false}}));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should emit UserEvent SUBMIT_EMAIL when you submit the form", () => {
|
it("should emit UserEvent SUBMIT_EMAIL when you submit the form", () => {
|
||||||
@ -33,6 +33,6 @@ describe("<StartupOverlay>", () => {
|
|||||||
|
|
||||||
assert.calledOnce(dispatch);
|
assert.calledOnce(dispatch);
|
||||||
assert.isUserEventAction(dispatch.firstCall.args[0]);
|
assert.isUserEventAction(dispatch.firstCall.args[0]);
|
||||||
assert.calledWith(dispatch, ac.UserEvent({event: at.SUBMIT_EMAIL}));
|
assert.calledWith(dispatch, ac.UserEvent({event: at.SUBMIT_EMAIL, value: {has_flow_params: false}}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -10,11 +10,12 @@ import {
|
|||||||
UserEventPing,
|
UserEventPing,
|
||||||
} from "test/schemas/pings";
|
} from "test/schemas/pings";
|
||||||
import {FakePrefs, GlobalOverrider} from "test/unit/utils";
|
import {FakePrefs, GlobalOverrider} from "test/unit/utils";
|
||||||
|
import {ASRouterPreferences} from "lib/ASRouterPreferences.jsm";
|
||||||
import injector from "inject!lib/TelemetryFeed.jsm";
|
import injector from "inject!lib/TelemetryFeed.jsm";
|
||||||
|
|
||||||
const FAKE_UUID = "{foo-123-foo}";
|
const FAKE_UUID = "{foo-123-foo}";
|
||||||
const FAKE_ROUTER_MESSAGE_PROVIDER = JSON.stringify([{id: "cfr", enabled: true}]);
|
const FAKE_ROUTER_MESSAGE_PROVIDER = [{id: "cfr", enabled: true}];
|
||||||
const FAKE_ROUTER_MESSAGE_PROVIDER_COHORT = JSON.stringify([{id: "cfr", enabled: true, cohort: "cohort_group"}]);
|
const FAKE_ROUTER_MESSAGE_PROVIDER_COHORT = [{id: "cfr", enabled: true, cohort: "cohort_group"}];
|
||||||
|
|
||||||
describe("TelemetryFeed", () => {
|
describe("TelemetryFeed", () => {
|
||||||
let globals;
|
let globals;
|
||||||
@ -38,7 +39,6 @@ describe("TelemetryFeed", () => {
|
|||||||
PREF_IMPRESSION_ID,
|
PREF_IMPRESSION_ID,
|
||||||
TELEMETRY_PREF,
|
TELEMETRY_PREF,
|
||||||
EVENTS_TELEMETRY_PREF,
|
EVENTS_TELEMETRY_PREF,
|
||||||
ROUTER_MESSAGE_PROVIDER_PREF,
|
|
||||||
} = injector({
|
} = injector({
|
||||||
"common/PerfService.jsm": {perfService},
|
"common/PerfService.jsm": {perfService},
|
||||||
"lib/UTEventReporting.jsm": {UTEventReporting},
|
"lib/UTEventReporting.jsm": {UTEventReporting},
|
||||||
@ -52,13 +52,14 @@ describe("TelemetryFeed", () => {
|
|||||||
globals.set("gUUIDGenerator", {generateUUID: () => FAKE_UUID});
|
globals.set("gUUIDGenerator", {generateUUID: () => FAKE_UUID});
|
||||||
globals.set("PingCentre", PingCentre);
|
globals.set("PingCentre", PingCentre);
|
||||||
globals.set("UTEventReporting", UTEventReporting);
|
globals.set("UTEventReporting", UTEventReporting);
|
||||||
FakePrefs.prototype.prefs[ROUTER_MESSAGE_PROVIDER_PREF] = FAKE_ROUTER_MESSAGE_PROVIDER;
|
sandbox.stub(ASRouterPreferences, "providers").get(() => FAKE_ROUTER_MESSAGE_PROVIDER);
|
||||||
instance = new TelemetryFeed();
|
instance = new TelemetryFeed();
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
clock.restore();
|
clock.restore();
|
||||||
globals.restore();
|
globals.restore();
|
||||||
FakePrefs.prototype.prefs = {};
|
FakePrefs.prototype.prefs = {};
|
||||||
|
ASRouterPreferences.uninit();
|
||||||
});
|
});
|
||||||
describe("#init", () => {
|
describe("#init", () => {
|
||||||
it("should add .pingCentre, a PingCentre instance", () => {
|
it("should add .pingCentre, a PingCentre instance", () => {
|
||||||
@ -117,20 +118,6 @@ describe("TelemetryFeed", () => {
|
|||||||
assert.propertyVal(instance, "eventTelemetryEnabled", true);
|
assert.propertyVal(instance, "eventTelemetryEnabled", true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("a-s router message provider cohort changes from false to true", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
FakePrefs.prototype.prefs = {};
|
|
||||||
instance = new TelemetryFeed();
|
|
||||||
|
|
||||||
assert.ok(!instance.isInCFRCohort);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set the _isInCFRCohort property to true", () => {
|
|
||||||
instance._prefs.set(ROUTER_MESSAGE_PROVIDER_PREF, FAKE_ROUTER_MESSAGE_PROVIDER_COHORT);
|
|
||||||
|
|
||||||
assert.ok(instance.isInCFRCohort);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe("#addSession", () => {
|
describe("#addSession", () => {
|
||||||
it("should add a session and return it", () => {
|
it("should add a session and return it", () => {
|
||||||
@ -488,18 +475,6 @@ describe("TelemetryFeed", () => {
|
|||||||
assert.propertyVal(ping, "tiles", tiles);
|
assert.propertyVal(ping, "tiles", tiles);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("#_parseCFRCohort", () => {
|
|
||||||
it("should return true if it is in the CFR cohort", () => {
|
|
||||||
assert.ok(instance._parseCFRCohort(FAKE_ROUTER_MESSAGE_PROVIDER_COHORT));
|
|
||||||
});
|
|
||||||
it("should return false if it is not in the CFR cohort", () => {
|
|
||||||
assert.ok(!instance._parseCFRCohort(FAKE_ROUTER_MESSAGE_PROVIDER));
|
|
||||||
});
|
|
||||||
it("should report an error given an invalid pref", () => {
|
|
||||||
assert.ok(!instance._parseCFRCohort("some in valid json string"));
|
|
||||||
assert.called(global.Cu.reportError);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe("#applyCFRPolicy", () => {
|
describe("#applyCFRPolicy", () => {
|
||||||
it("should use client_id and message_id in prerelease", () => {
|
it("should use client_id and message_id in prerelease", () => {
|
||||||
globals.set("UpdateUtils", {getUpdateChannel() { return "nightly"; }});
|
globals.set("UpdateUtils", {getUpdateChannel() { return "nightly"; }});
|
||||||
@ -539,7 +514,7 @@ describe("TelemetryFeed", () => {
|
|||||||
});
|
});
|
||||||
it("should use client_id and message_id in the experiment cohort in release", () => {
|
it("should use client_id and message_id in the experiment cohort in release", () => {
|
||||||
globals.set("UpdateUtils", {getUpdateChannel() { return "release"; }});
|
globals.set("UpdateUtils", {getUpdateChannel() { return "release"; }});
|
||||||
FakePrefs.prototype.prefs[ROUTER_MESSAGE_PROVIDER_PREF] = FAKE_ROUTER_MESSAGE_PROVIDER_COHORT;
|
sandbox.stub(ASRouterPreferences, "providers").get(() => FAKE_ROUTER_MESSAGE_PROVIDER_COHORT);
|
||||||
const data = {
|
const data = {
|
||||||
action: "cfr_user_event",
|
action: "cfr_user_event",
|
||||||
source: "CFR",
|
source: "CFR",
|
||||||
@ -750,15 +725,6 @@ describe("TelemetryFeed", () => {
|
|||||||
|
|
||||||
assert.notProperty(instance._prefs.observers, EVENTS_TELEMETRY_PREF);
|
assert.notProperty(instance._prefs.observers, EVENTS_TELEMETRY_PREF);
|
||||||
});
|
});
|
||||||
it("should remove the a-s router message provider listener", () => {
|
|
||||||
instance = new TelemetryFeed();
|
|
||||||
|
|
||||||
assert.property(instance._prefs.observers, ROUTER_MESSAGE_PROVIDER_PREF);
|
|
||||||
|
|
||||||
instance.uninit();
|
|
||||||
|
|
||||||
assert.notProperty(instance._prefs.observers, ROUTER_MESSAGE_PROVIDER_PREF);
|
|
||||||
});
|
|
||||||
it("should call Cu.reportError if this._prefs.ignore throws", () => {
|
it("should call Cu.reportError if this._prefs.ignore throws", () => {
|
||||||
globals.sandbox.stub(FakePrefs.prototype, "ignore").throws("Some Error");
|
globals.sandbox.stub(FakePrefs.prototype, "ignore").throws("Some Error");
|
||||||
instance = new TelemetryFeed();
|
instance = new TelemetryFeed();
|
||||||
|
Loading…
Reference in New Issue
Block a user