зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1659169 - RTAMO custom onboarding r=fluent-reviewers,Mardak,flod
Differential Revision: https://phabricator.services.mozilla.com/D91667
This commit is contained in:
Родитель
af00a62acd
Коммит
c02f6a2ed9
|
@ -41,6 +41,7 @@ module.exports = {
|
|||
"content-src/aboutwelcome/components/HeroText.jsx",
|
||||
"content-src/aboutwelcome/components/Zap.jsx",
|
||||
"content-src/aboutwelcome/components/MultiStageAboutWelcome.jsx",
|
||||
"content-src/aboutwelcome/components/ReturnToAMO.jsx",
|
||||
"content-src/asrouter/templates/OnboardingMessage/**",
|
||||
"content-src/asrouter/templates/FirstRun/**",
|
||||
"content-src/components/TopSites/**",
|
||||
|
|
|
@ -160,14 +160,18 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
|||
exportFunctions() {
|
||||
let window = this.contentWindow;
|
||||
|
||||
Cu.exportFunction(this.AWGetStartupData.bind(this), window, {
|
||||
defineAs: "AWGetStartupData",
|
||||
Cu.exportFunction(this.AWGetExperimentData.bind(this), window, {
|
||||
defineAs: "AWGetExperimentData",
|
||||
});
|
||||
|
||||
Cu.exportFunction(this.AWGetAttributionData.bind(this), window, {
|
||||
defineAs: "AWGetAttributionData",
|
||||
});
|
||||
|
||||
// For local dev, checks for JSON content inside pref browser.aboutwelcome.overrideContent
|
||||
// that is used to override default 3 cards welcome UI with multistage welcome
|
||||
Cu.exportFunction(this.AWGetMultiStageScreens.bind(this), window, {
|
||||
defineAs: "AWGetMultiStageScreens",
|
||||
// that is used to override default welcome UI
|
||||
Cu.exportFunction(this.AWGetWelcomeOverrideContent.bind(this), window, {
|
||||
defineAs: "AWGetWelcomeOverrideContent",
|
||||
});
|
||||
|
||||
Cu.exportFunction(this.AWGetFxAMetricsFlowURI.bind(this), window, {
|
||||
|
@ -219,7 +223,7 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
|||
/**
|
||||
* Send multistage welcome JSON data read from aboutwelcome.overrideConetent pref to page
|
||||
*/
|
||||
AWGetMultiStageScreens() {
|
||||
AWGetWelcomeOverrideContent() {
|
||||
return Cu.cloneInto(
|
||||
multiStageAboutWelcomeContent || {},
|
||||
this.contentWindow
|
||||
|
@ -232,10 +236,70 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
|||
);
|
||||
}
|
||||
|
||||
async getAddonInfo(attrbObj) {
|
||||
let { content, source } = attrbObj;
|
||||
try {
|
||||
if (!content || source !== "addons.mozilla.org") {
|
||||
return null;
|
||||
}
|
||||
// Attribution data can be double encoded
|
||||
while (content.includes("%")) {
|
||||
try {
|
||||
const result = decodeURIComponent(content);
|
||||
if (result === content) {
|
||||
break;
|
||||
}
|
||||
content = result;
|
||||
} catch (e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return await this.sendQuery("AWPage:GET_ADDON_FROM_REPOSITORY", content);
|
||||
} catch (e) {
|
||||
Cu.reportError(
|
||||
"Failed to get the latest add-on version for Return to AMO"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
isRTAMO(attributionData) {
|
||||
// RTAMO Attribution
|
||||
return (
|
||||
attributionData &&
|
||||
attributionData.campaign === "non-fx-button" &&
|
||||
attributionData.source === "addons.mozilla.org"
|
||||
);
|
||||
}
|
||||
|
||||
async formatAttributionData(attribution) {
|
||||
let result = {};
|
||||
if (this.isRTAMO(attribution)) {
|
||||
result = {
|
||||
template: "return_to_amo",
|
||||
extraProps: await this.getAddonInfo(attribution),
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async getAttributionData() {
|
||||
return Cu.cloneInto(
|
||||
await this.formatAttributionData(
|
||||
await this.sendQuery("AWPage:GET_ATTRIBUTION_DATA")
|
||||
),
|
||||
this.contentWindow
|
||||
);
|
||||
}
|
||||
|
||||
AWGetAttributionData() {
|
||||
return this.wrapPromise(this.getAttributionData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Send initial data to page including experiment information
|
||||
*/
|
||||
AWGetStartupData() {
|
||||
AWGetExperimentData() {
|
||||
let experimentData;
|
||||
try {
|
||||
// Note that we specifically don't wait for experiments to be loaded from disk so if
|
||||
|
|
|
@ -13,6 +13,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||
AddonRepository: "resource://gre/modules/addons/AddonRepository.jsm",
|
||||
FxAccounts: "resource://gre/modules/FxAccounts.jsm",
|
||||
MigrationUtils: "resource:///modules/MigrationUtils.jsm",
|
||||
OS: "resource://gre/modules/osfile.jsm",
|
||||
|
@ -20,6 +21,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
"resource://messaging-system/lib/SpecialMessageActions.jsm",
|
||||
AboutWelcomeTelemetry:
|
||||
"resource://activity-stream/aboutwelcome/lib/AboutWelcomeTelemetry.jsm",
|
||||
AttributionCode: "resource:///modules/AttributionCode.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||
|
@ -185,6 +187,8 @@ class AboutWelcomeParent extends JSWindowActorParent {
|
|||
break;
|
||||
case "AWPage:FXA_METRICS_FLOW_URI":
|
||||
return FxAccounts.config.promiseMetricsFlowURI("aboutwelcome");
|
||||
case "AWPage:GET_ATTRIBUTION_DATA":
|
||||
return AttributionCode.getAttrDataAsync();
|
||||
case "AWPage:IMPORTABLE_SITES":
|
||||
return getImportableSites();
|
||||
case "AWPage:TELEMETRY_EVENT":
|
||||
|
@ -194,6 +198,16 @@ class AboutWelcomeParent extends JSWindowActorParent {
|
|||
this.AboutWelcomeObserver.terminateReason =
|
||||
AWTerminate.ADDRESS_BAR_NAVIGATED;
|
||||
break;
|
||||
case "AWPage:GET_ADDON_FROM_REPOSITORY":
|
||||
const [addonInfo] = await AddonRepository.getAddonsByIDs([data]);
|
||||
if (addonInfo.sourceURI.scheme !== "https") {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
name: addonInfo.name,
|
||||
url: addonInfo.sourceURI.spec,
|
||||
iconURL: addonInfo.icons["64"] || addonInfo.icons["32"],
|
||||
};
|
||||
case "AWPage:SELECT_THEME":
|
||||
return AddonManager.getAddonByID(
|
||||
LIGHT_WEIGHT_THEMES[data]
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
.ReturnToAMOOverlay {
|
||||
background: #F9F9FA;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOText {
|
||||
color: #0C0C0D;
|
||||
line-height: 32px;
|
||||
font-size: 23px;
|
||||
width: 100%; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOText img {
|
||||
margin-inline: 2px;
|
||||
width: 20px;
|
||||
height: 20px; }
|
||||
.ReturnToAMOOverlay h2 {
|
||||
color: #4A4A4F;
|
||||
font-weight: 100;
|
||||
margin: 0 0 36px;
|
||||
font-size: 36px;
|
||||
line-height: 48px;
|
||||
letter-spacing: 1.2px; }
|
||||
.ReturnToAMOOverlay p {
|
||||
color: #4A4A4F;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin-bottom: 16px; }
|
||||
.ReturnToAMOOverlay button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
border: 0; }
|
||||
.ReturnToAMOOverlay .puffy {
|
||||
border-radius: 4px;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
font-size: 15px; }
|
||||
.ReturnToAMOOverlay .blue {
|
||||
color: #FFF;
|
||||
background-color: #0060DF; }
|
||||
.ReturnToAMOOverlay .blue:hover {
|
||||
box-shadow: none;
|
||||
background-color: #003EAA; }
|
||||
.ReturnToAMOOverlay .blue:active {
|
||||
background-color: #002275; }
|
||||
.ReturnToAMOOverlay .default {
|
||||
border-radius: 2px;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
font-size: 15px; }
|
||||
.ReturnToAMOOverlay .grey {
|
||||
color: #000;
|
||||
background-color: rgba(12, 12, 13, 0.1); }
|
||||
.ReturnToAMOOverlay .grey:hover {
|
||||
box-shadow: none;
|
||||
background-color: rgba(12, 12, 13, 0.2); }
|
||||
.ReturnToAMOOverlay .grey:active {
|
||||
background-color: rgba(12, 12, 13, 0.3); }
|
||||
.ReturnToAMOOverlay .ReturnToAMOGetStarted {
|
||||
margin-top: 40px;
|
||||
float: inline-end; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOAddExtension {
|
||||
margin-top: 20px; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOContainer {
|
||||
width: 960px;
|
||||
background: #FFF;
|
||||
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
padding: 64px 64px 72px; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOAddonContents {
|
||||
width: 560px;
|
||||
margin-top: 32px;
|
||||
margin-inline-end: 24px; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOIcon {
|
||||
width: 292px;
|
||||
height: 254px;
|
||||
background-size: 292px 254px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/gift-extension.svg"); }
|
|
@ -102,7 +102,8 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
|
||||
/* harmony import */ var _components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
||||
/* harmony import */ var _components_SimpleAboutWelcome__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
|
||||
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6);
|
||||
/* harmony import */ var _components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(12);
|
||||
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6);
|
||||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
|
@ -114,6 +115,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|||
|
||||
|
||||
|
||||
|
||||
class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -133,7 +135,7 @@ class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
|
|||
componentDidMount() {
|
||||
this.fetchFxAFlowUri(); // Record impression with performance data after allowing the page to load
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
const recordImpression = domState => {
|
||||
const {
|
||||
domComplete,
|
||||
domInteractive
|
||||
|
@ -144,21 +146,32 @@ class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
|
|||
domComplete,
|
||||
domInteractive,
|
||||
mountStart: performance.getEntriesByName("mount").pop().startTime,
|
||||
domState,
|
||||
source: this.props.UTMTerm,
|
||||
page: "about:welcome"
|
||||
},
|
||||
message_id: this.props.messageId
|
||||
});
|
||||
}, {
|
||||
once: true
|
||||
}); // Captures user has seen about:welcome by setting
|
||||
};
|
||||
|
||||
if (document.readyState === "complete") {
|
||||
// Page might have already triggered a load event because it waited for async data,
|
||||
// e.g., attribution, so the dom load timing could be of a empty content
|
||||
// with domState in telemetry captured as 'complete'
|
||||
recordImpression(document.readyState);
|
||||
} else {
|
||||
window.addEventListener("load", () => recordImpression("load"), {
|
||||
once: true
|
||||
});
|
||||
} // Captures user has seen about:welcome by setting
|
||||
// firstrun.didSeeAboutWelcome pref to true and capturing welcome UI unique messageId
|
||||
|
||||
|
||||
window.AWSendToParent("SET_WELCOME_MESSAGE_SEEN", this.props.messageId);
|
||||
}
|
||||
|
||||
handleStartBtnClick() {
|
||||
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__["AboutWelcomeUtils"].handleUserAction(this.props.startButton.action);
|
||||
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_5__["AboutWelcomeUtils"].handleUserAction(this.props.startButton.action);
|
||||
const ping = {
|
||||
event: "CLICK_BUTTON",
|
||||
event_context: {
|
||||
|
@ -187,6 +200,13 @@ class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
|
|||
startButton: props.startButton,
|
||||
handleStartBtnClick: this.handleStartBtnClick
|
||||
});
|
||||
} else if (props.template === "return_to_amo") {
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_ReturnToAMO__WEBPACK_IMPORTED_MODULE_4__["ReturnToAMO"], {
|
||||
message_id: props.messageId,
|
||||
name: props.name,
|
||||
url: props.url,
|
||||
iconURL: props.iconURL
|
||||
});
|
||||
}
|
||||
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_MultiStageAboutWelcome__WEBPACK_IMPORTED_MODULE_2__["MultiStageAboutWelcome"], {
|
||||
|
@ -199,14 +219,14 @@ class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp
|
|||
|
||||
}
|
||||
|
||||
AboutWelcome.defaultProps = _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__["DEFAULT_WELCOME_CONTENT"];
|
||||
AboutWelcome.defaultProps = _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_5__["DEFAULT_WELCOME_CONTENT"]; // Computes messageId and UTMTerm info used in telemetry
|
||||
|
||||
function ComputeMessageId(experimentId, branchId, settings) {
|
||||
let messageId = "DEFAULT_ABOUTWELCOME";
|
||||
function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
||||
let messageId = welcomeContent.template === "return_to_amo" ? "RTAMO_DEFAULT_WELCOME" : "DEFAULT_ABOUTWELCOME";
|
||||
let UTMTerm = "default";
|
||||
|
||||
if (settings.id && settings.screens) {
|
||||
messageId = settings.id.toUpperCase();
|
||||
if (welcomeContent.id) {
|
||||
messageId = welcomeContent.id.toUpperCase();
|
||||
}
|
||||
|
||||
if (experimentId && branchId) {
|
||||
|
@ -219,26 +239,67 @@ function ComputeMessageId(experimentId, branchId, settings) {
|
|||
};
|
||||
}
|
||||
|
||||
async function mount() {
|
||||
async function retrieveRenderContent() {
|
||||
var _aboutWelcomeProps;
|
||||
|
||||
// Check for override content in pref browser.aboutwelcome.overrideContent
|
||||
let aboutWelcomeProps = await window.AWGetWelcomeOverrideContent();
|
||||
|
||||
if ((_aboutWelcomeProps = aboutWelcomeProps) === null || _aboutWelcomeProps === void 0 ? void 0 : _aboutWelcomeProps.template) {
|
||||
let {
|
||||
messageId,
|
||||
UTMTerm
|
||||
} = ComputeTelemetryInfo(aboutWelcomeProps);
|
||||
return {
|
||||
aboutWelcomeProps,
|
||||
messageId,
|
||||
UTMTerm
|
||||
};
|
||||
} // Check for experiment and retrieve content
|
||||
|
||||
|
||||
const {
|
||||
slug,
|
||||
branch
|
||||
} = await window.AWGetStartupData();
|
||||
let settings = (branch === null || branch === void 0 ? void 0 : branch.feature) ? branch.feature.value : {};
|
||||
} = await window.AWGetExperimentData();
|
||||
aboutWelcomeProps = (branch === null || branch === void 0 ? void 0 : branch.feature) ? branch.feature.value : {}; // Check if there is any attribution data, this could take a while to await in series
|
||||
// especially when there is an add-on that requires remote lookup
|
||||
// Moving RTAMO as part of another screen of multistage is one option to fix the delay
|
||||
// as it will allow the initial page to be fast while we fetch attribution data in parallel for a later screen.
|
||||
|
||||
if (!(branch === null || branch === void 0 ? void 0 : branch.feature)) {
|
||||
// Check for override content in pref browser.aboutwelcome.overrideContent
|
||||
settings = await window.AWGetMultiStageScreens();
|
||||
const attribution = await window.AWGetAttributionData();
|
||||
|
||||
if (attribution === null || attribution === void 0 ? void 0 : attribution.template) {
|
||||
var _aboutWelcomeProps2;
|
||||
|
||||
aboutWelcomeProps = { ...aboutWelcomeProps,
|
||||
// If part of an experiment, render experiment template
|
||||
template: ((_aboutWelcomeProps2 = aboutWelcomeProps) === null || _aboutWelcomeProps2 === void 0 ? void 0 : _aboutWelcomeProps2.template) ? aboutWelcomeProps.template : attribution.template,
|
||||
...attribution.extraProps
|
||||
};
|
||||
}
|
||||
|
||||
let {
|
||||
messageId,
|
||||
UTMTerm
|
||||
} = ComputeMessageId(slug, branch && branch.slug, settings);
|
||||
} = ComputeTelemetryInfo(aboutWelcomeProps, slug, branch && branch.slug);
|
||||
return {
|
||||
aboutWelcomeProps,
|
||||
messageId,
|
||||
UTMTerm
|
||||
};
|
||||
}
|
||||
|
||||
async function mount() {
|
||||
let {
|
||||
aboutWelcomeProps,
|
||||
messageId,
|
||||
UTMTerm
|
||||
} = await retrieveRenderContent();
|
||||
react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render(react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(AboutWelcome, _extends({
|
||||
messageId: messageId,
|
||||
UTMTerm: UTMTerm
|
||||
}, settings)), document.getElementById("root"));
|
||||
}, aboutWelcomeProps)), document.getElementById("root"));
|
||||
}
|
||||
|
||||
performance.mark("mount");
|
||||
|
@ -774,6 +835,7 @@ const Zap = props => {
|
|||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AboutWelcomeUtils", function() { return AboutWelcomeUtils; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEFAULT_RTAMO_CONTENT", function() { return DEFAULT_RTAMO_CONTENT; });
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEFAULT_WELCOME_CONTENT", function() { return DEFAULT_WELCOME_CONTENT; });
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
|
@ -844,6 +906,41 @@ const AboutWelcomeUtils = {
|
|||
}
|
||||
|
||||
};
|
||||
const DEFAULT_RTAMO_CONTENT = {
|
||||
template: "return_to_amo",
|
||||
content: {
|
||||
header: {
|
||||
string_id: "onboarding-welcome-header"
|
||||
},
|
||||
subtitle: {
|
||||
string_id: "return-to-amo-subtitle"
|
||||
},
|
||||
text: {
|
||||
string_id: "return-to-amo-addon-title"
|
||||
},
|
||||
primary_button: {
|
||||
label: {
|
||||
string_id: "return-to-amo-add-extension-label"
|
||||
},
|
||||
action: {
|
||||
type: "INSTALL_ADDON_FROM_URL",
|
||||
data: {
|
||||
url: null,
|
||||
telemetrySource: "rtamo"
|
||||
}
|
||||
}
|
||||
},
|
||||
startButton: {
|
||||
label: {
|
||||
string_id: "onboarding-start-browsing-button-label"
|
||||
},
|
||||
message_id: "RTAMO_START_BROWSING_BUTTON",
|
||||
action: {
|
||||
type: "OPEN_AWESOME_BAR"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const DEFAULT_WELCOME_CONTENT = {
|
||||
template: "multistage",
|
||||
screens: [{
|
||||
|
@ -1276,5 +1373,123 @@ class OnboardingCard extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCo
|
|||
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
/* 12 */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ReturnToAMO", function() { return ReturnToAMO; });
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
||||
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
||||
/* harmony import */ var _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
|
||||
/* harmony import */ var _MSLocalized__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4);
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
|
||||
class ReturnToAMO extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClickAddExtension = this.onClickAddExtension.bind(this);
|
||||
this.handleStartBtnClick = this.handleStartBtnClick.bind(this);
|
||||
}
|
||||
|
||||
onClickAddExtension() {
|
||||
var _content$primary_butt, _content$primary_butt2;
|
||||
|
||||
const {
|
||||
content,
|
||||
message_id,
|
||||
url
|
||||
} = this.props;
|
||||
|
||||
if (!(content === null || content === void 0 ? void 0 : (_content$primary_butt = content.primary_button) === null || _content$primary_butt === void 0 ? void 0 : (_content$primary_butt2 = _content$primary_butt.action) === null || _content$primary_butt2 === void 0 ? void 0 : _content$primary_butt2.data)) {
|
||||
return;
|
||||
} // Set add-on url in action.data.url property from JSON
|
||||
|
||||
|
||||
content.primary_button.action.data.url = url;
|
||||
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__["AboutWelcomeUtils"].handleUserAction(content.primary_button.action);
|
||||
const ping = {
|
||||
event: "INSTALL",
|
||||
event_context: {
|
||||
source: "ADD_EXTENSION_BUTTON",
|
||||
page: "about:welcome"
|
||||
},
|
||||
message_id
|
||||
};
|
||||
window.AWSendEventTelemetry(ping);
|
||||
}
|
||||
|
||||
handleStartBtnClick() {
|
||||
const {
|
||||
content,
|
||||
message_id
|
||||
} = this.props;
|
||||
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__["AboutWelcomeUtils"].handleUserAction(content.startButton.action);
|
||||
const ping = {
|
||||
event: "CLICK_BUTTON",
|
||||
event_context: {
|
||||
source: content.startButton.message_id,
|
||||
page: "about:welcome"
|
||||
},
|
||||
message_id
|
||||
};
|
||||
window.AWSendEventTelemetry(ping);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
content
|
||||
} = this.props;
|
||||
|
||||
if (!content) {
|
||||
return null;
|
||||
} // For experiments, when needed below rendered UI allows settings hard coded strings
|
||||
// directly inside JSON except for ReturnToAMOText which picks add-on name and icon from fluent string
|
||||
|
||||
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "ReturnToAMOOverlay"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__["Localized"], {
|
||||
text: content.header
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h2", null)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "ReturnToAMOContainer"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "ReturnToAMOAddonContents"
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__["Localized"], {
|
||||
text: content.subtitle
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__["Localized"], {
|
||||
text: content.text
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "ReturnToAMOText",
|
||||
"data-l10n-args": this.props.name ? JSON.stringify({
|
||||
"addon-name": this.props.name
|
||||
}) : null
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("img", {
|
||||
"data-l10n-name": "icon",
|
||||
src: this.props.iconURL,
|
||||
alt: ""
|
||||
}))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__["Localized"], {
|
||||
text: content.primary_button.label
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
|
||||
onClick: this.onClickAddExtension,
|
||||
className: "puffy blue ReturnToAMOAddExtension"
|
||||
}))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
|
||||
className: "ReturnToAMOIcon"
|
||||
})), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_MSLocalized__WEBPACK_IMPORTED_MODULE_2__["Localized"], {
|
||||
text: content.startButton.label
|
||||
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("button", {
|
||||
onClick: this.handleStartBtnClick,
|
||||
className: "default grey ReturnToAMOGetStarted"
|
||||
}))));
|
||||
}
|
||||
|
||||
}
|
||||
ReturnToAMO.defaultProps = _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_1__["DEFAULT_RTAMO_CONTENT"];
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
|
@ -531,3 +531,90 @@ body {
|
|||
opacity: 0.25; }
|
||||
.multistageContainer .steps .indicator.current {
|
||||
opacity: 1; }
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
.ReturnToAMOOverlay {
|
||||
background: #F9F9FA;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOText {
|
||||
color: #0C0C0D;
|
||||
line-height: 32px;
|
||||
font-size: 23px;
|
||||
width: 100%; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOText img {
|
||||
margin-inline: 2px;
|
||||
width: 20px;
|
||||
height: 20px; }
|
||||
.ReturnToAMOOverlay h2 {
|
||||
color: #4A4A4F;
|
||||
font-weight: 100;
|
||||
margin: 0 0 36px;
|
||||
font-size: 36px;
|
||||
line-height: 48px;
|
||||
letter-spacing: 1.2px; }
|
||||
.ReturnToAMOOverlay p {
|
||||
color: #4A4A4F;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin-bottom: 16px; }
|
||||
.ReturnToAMOOverlay button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
border: 0; }
|
||||
.ReturnToAMOOverlay .puffy {
|
||||
border-radius: 4px;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
font-size: 15px; }
|
||||
.ReturnToAMOOverlay .blue {
|
||||
color: #FFF;
|
||||
background-color: #0060DF; }
|
||||
.ReturnToAMOOverlay .blue:hover {
|
||||
box-shadow: none;
|
||||
background-color: #003EAA; }
|
||||
.ReturnToAMOOverlay .blue:active {
|
||||
background-color: #002275; }
|
||||
.ReturnToAMOOverlay .default {
|
||||
border-radius: 2px;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
font-size: 15px; }
|
||||
.ReturnToAMOOverlay .grey {
|
||||
color: #000;
|
||||
background-color: rgba(12, 12, 13, 0.1); }
|
||||
.ReturnToAMOOverlay .grey:hover {
|
||||
box-shadow: none;
|
||||
background-color: rgba(12, 12, 13, 0.2); }
|
||||
.ReturnToAMOOverlay .grey:active {
|
||||
background-color: rgba(12, 12, 13, 0.3); }
|
||||
.ReturnToAMOOverlay .ReturnToAMOGetStarted {
|
||||
margin-top: 40px;
|
||||
float: inline-end; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOAddExtension {
|
||||
margin-top: 20px; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOContainer {
|
||||
width: 960px;
|
||||
background: #FFF;
|
||||
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
padding: 64px 64px 72px; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOAddonContents {
|
||||
width: 560px;
|
||||
margin-top: 32px;
|
||||
margin-inline-end: 24px; }
|
||||
.ReturnToAMOOverlay .ReturnToAMOIcon {
|
||||
width: 292px;
|
||||
height: 254px;
|
||||
background-size: 292px 254px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("chrome://activity-stream/content/data/content/assets/gift-extension.svg"); }
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
// sass-lint:disable no-css-comments
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
.ReturnToAMOOverlay {
|
||||
// sass-lint:disable no-color-literals
|
||||
background: #F9F9FA;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.ReturnToAMOText {
|
||||
color: #0C0C0D;
|
||||
line-height: 32px;
|
||||
font-size: 23px;
|
||||
width: 100%;
|
||||
|
||||
img {
|
||||
margin-inline: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #4A4A4F;
|
||||
font-weight: 100;
|
||||
margin: 0 0 36px;
|
||||
font-size: 36px;
|
||||
line-height: 48px;
|
||||
letter-spacing: 1.2px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #4A4A4F;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.puffy {
|
||||
border-radius: 4px;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.blue {
|
||||
color: #FFF;
|
||||
background-color: #0060DF;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
background-color: #003EAA;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #002275;
|
||||
}
|
||||
}
|
||||
|
||||
.default {
|
||||
border-radius: 2px;
|
||||
height: 40px;
|
||||
padding: 0 12px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.grey {
|
||||
color: #000;
|
||||
background-color: rgba(#0C0C0D, 0.1);
|
||||
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
background-color: rgba(#0C0C0D, 0.2);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: rgba(#0C0C0D, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.ReturnToAMOGetStarted {
|
||||
margin-top: 40px;
|
||||
float: inline-end;
|
||||
}
|
||||
|
||||
.ReturnToAMOAddExtension {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.ReturnToAMOContainer {
|
||||
width: 960px;
|
||||
background: #FFF;
|
||||
box-shadow: 0 1px 15px 0 rgba(#000, 0.3);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
padding: 64px 64px 72px;
|
||||
}
|
||||
|
||||
.ReturnToAMOAddonContents {
|
||||
width: 560px;
|
||||
margin-top: 32px;
|
||||
margin-inline-end: 24px;
|
||||
}
|
||||
|
||||
.ReturnToAMOIcon {
|
||||
width: 292px;
|
||||
height: 254px;
|
||||
background-size: 292px 254px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('chrome://activity-stream/content/data/content/assets/gift-extension.svg');
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import React from "react";
|
|||
import ReactDOM from "react-dom";
|
||||
import { MultiStageAboutWelcome } from "./components/MultiStageAboutWelcome";
|
||||
import { SimpleAboutWelcome } from "./components/SimpleAboutWelcome";
|
||||
import { ReturnToAMO } from "./components/ReturnToAMO";
|
||||
|
||||
import {
|
||||
AboutWelcomeUtils,
|
||||
|
@ -28,26 +29,33 @@ class AboutWelcome extends React.PureComponent {
|
|||
this.fetchFxAFlowUri();
|
||||
|
||||
// Record impression with performance data after allowing the page to load
|
||||
window.addEventListener(
|
||||
"load",
|
||||
() => {
|
||||
const { domComplete, domInteractive } = performance
|
||||
.getEntriesByType("navigation")
|
||||
.pop();
|
||||
window.AWSendEventTelemetry({
|
||||
event: "IMPRESSION",
|
||||
event_context: {
|
||||
domComplete,
|
||||
domInteractive,
|
||||
mountStart: performance.getEntriesByName("mount").pop().startTime,
|
||||
source: this.props.UTMTerm,
|
||||
page: "about:welcome",
|
||||
},
|
||||
message_id: this.props.messageId,
|
||||
});
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
const recordImpression = domState => {
|
||||
const { domComplete, domInteractive } = performance
|
||||
.getEntriesByType("navigation")
|
||||
.pop();
|
||||
window.AWSendEventTelemetry({
|
||||
event: "IMPRESSION",
|
||||
event_context: {
|
||||
domComplete,
|
||||
domInteractive,
|
||||
mountStart: performance.getEntriesByName("mount").pop().startTime,
|
||||
domState,
|
||||
source: this.props.UTMTerm,
|
||||
page: "about:welcome",
|
||||
},
|
||||
message_id: this.props.messageId,
|
||||
});
|
||||
};
|
||||
if (document.readyState === "complete") {
|
||||
// Page might have already triggered a load event because it waited for async data,
|
||||
// e.g., attribution, so the dom load timing could be of a empty content
|
||||
// with domState in telemetry captured as 'complete'
|
||||
recordImpression(document.readyState);
|
||||
} else {
|
||||
window.addEventListener("load", () => recordImpression("load"), {
|
||||
once: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Captures user has seen about:welcome by setting
|
||||
// firstrun.didSeeAboutWelcome pref to true and capturing welcome UI unique messageId
|
||||
|
@ -83,6 +91,15 @@ class AboutWelcome extends React.PureComponent {
|
|||
handleStartBtnClick={this.handleStartBtnClick}
|
||||
/>
|
||||
);
|
||||
} else if (props.template === "return_to_amo") {
|
||||
return (
|
||||
<ReturnToAMO
|
||||
message_id={props.messageId}
|
||||
name={props.name}
|
||||
url={props.url}
|
||||
iconURL={props.iconURL}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -98,12 +115,16 @@ class AboutWelcome extends React.PureComponent {
|
|||
|
||||
AboutWelcome.defaultProps = DEFAULT_WELCOME_CONTENT;
|
||||
|
||||
function ComputeMessageId(experimentId, branchId, settings) {
|
||||
let messageId = "DEFAULT_ABOUTWELCOME";
|
||||
// Computes messageId and UTMTerm info used in telemetry
|
||||
function ComputeTelemetryInfo(welcomeContent, experimentId, branchId) {
|
||||
let messageId =
|
||||
welcomeContent.template === "return_to_amo"
|
||||
? "RTAMO_DEFAULT_WELCOME"
|
||||
: "DEFAULT_ABOUTWELCOME";
|
||||
let UTMTerm = "default";
|
||||
|
||||
if (settings.id && settings.screens) {
|
||||
messageId = settings.id.toUpperCase();
|
||||
if (welcomeContent.id) {
|
||||
messageId = welcomeContent.id.toUpperCase();
|
||||
}
|
||||
|
||||
if (experimentId && branchId) {
|
||||
|
@ -115,23 +136,50 @@ function ComputeMessageId(experimentId, branchId, settings) {
|
|||
};
|
||||
}
|
||||
|
||||
async function mount() {
|
||||
const { slug, branch } = await window.AWGetStartupData();
|
||||
let settings = branch?.feature ? branch.feature.value : {};
|
||||
|
||||
if (!branch?.feature) {
|
||||
// Check for override content in pref browser.aboutwelcome.overrideContent
|
||||
settings = await window.AWGetMultiStageScreens();
|
||||
async function retrieveRenderContent() {
|
||||
// Check for override content in pref browser.aboutwelcome.overrideContent
|
||||
let aboutWelcomeProps = await window.AWGetWelcomeOverrideContent();
|
||||
if (aboutWelcomeProps?.template) {
|
||||
let { messageId, UTMTerm } = ComputeTelemetryInfo(aboutWelcomeProps);
|
||||
return { aboutWelcomeProps, messageId, UTMTerm };
|
||||
}
|
||||
|
||||
let { messageId, UTMTerm } = ComputeMessageId(
|
||||
slug,
|
||||
branch && branch.slug,
|
||||
settings
|
||||
);
|
||||
// Check for experiment and retrieve content
|
||||
const { slug, branch } = await window.AWGetExperimentData();
|
||||
aboutWelcomeProps = branch?.feature ? branch.feature.value : {};
|
||||
|
||||
// Check if there is any attribution data, this could take a while to await in series
|
||||
// especially when there is an add-on that requires remote lookup
|
||||
// Moving RTAMO as part of another screen of multistage is one option to fix the delay
|
||||
// as it will allow the initial page to be fast while we fetch attribution data in parallel for a later screen.
|
||||
const attribution = await window.AWGetAttributionData();
|
||||
if (attribution?.template) {
|
||||
aboutWelcomeProps = {
|
||||
...aboutWelcomeProps,
|
||||
// If part of an experiment, render experiment template
|
||||
template: aboutWelcomeProps?.template
|
||||
? aboutWelcomeProps.template
|
||||
: attribution.template,
|
||||
...attribution.extraProps,
|
||||
};
|
||||
}
|
||||
|
||||
let { messageId, UTMTerm } = ComputeTelemetryInfo(
|
||||
aboutWelcomeProps,
|
||||
slug,
|
||||
branch && branch.slug
|
||||
);
|
||||
return { aboutWelcomeProps, messageId, UTMTerm };
|
||||
}
|
||||
|
||||
async function mount() {
|
||||
let { aboutWelcomeProps, messageId, UTMTerm } = await retrieveRenderContent();
|
||||
ReactDOM.render(
|
||||
<AboutWelcome messageId={messageId} UTMTerm={UTMTerm} {...settings} />,
|
||||
<AboutWelcome
|
||||
messageId={messageId}
|
||||
UTMTerm={UTMTerm}
|
||||
{...aboutWelcomeProps}
|
||||
/>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
}
|
||||
|
|
|
@ -650,3 +650,5 @@ body {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@import './ReturnToAMO';
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
AboutWelcomeUtils,
|
||||
DEFAULT_RTAMO_CONTENT,
|
||||
} from "../../lib/aboutwelcome-utils";
|
||||
import { Localized } from "./MSLocalized";
|
||||
|
||||
export class ReturnToAMO extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onClickAddExtension = this.onClickAddExtension.bind(this);
|
||||
this.handleStartBtnClick = this.handleStartBtnClick.bind(this);
|
||||
}
|
||||
|
||||
onClickAddExtension() {
|
||||
const { content, message_id, url } = this.props;
|
||||
if (!content?.primary_button?.action?.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set add-on url in action.data.url property from JSON
|
||||
content.primary_button.action.data.url = url;
|
||||
AboutWelcomeUtils.handleUserAction(content.primary_button.action);
|
||||
const ping = {
|
||||
event: "INSTALL",
|
||||
event_context: {
|
||||
source: "ADD_EXTENSION_BUTTON",
|
||||
page: "about:welcome",
|
||||
},
|
||||
message_id,
|
||||
};
|
||||
window.AWSendEventTelemetry(ping);
|
||||
}
|
||||
|
||||
handleStartBtnClick() {
|
||||
const { content, message_id } = this.props;
|
||||
AboutWelcomeUtils.handleUserAction(content.startButton.action);
|
||||
const ping = {
|
||||
event: "CLICK_BUTTON",
|
||||
event_context: {
|
||||
source: content.startButton.message_id,
|
||||
page: "about:welcome",
|
||||
},
|
||||
message_id,
|
||||
};
|
||||
window.AWSendEventTelemetry(ping);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { content } = this.props;
|
||||
if (!content) {
|
||||
return null;
|
||||
}
|
||||
// For experiments, when needed below rendered UI allows settings hard coded strings
|
||||
// directly inside JSON except for ReturnToAMOText which picks add-on name and icon from fluent string
|
||||
return (
|
||||
<div className="ReturnToAMOOverlay">
|
||||
<div>
|
||||
<Localized text={content.header}>
|
||||
<h2 />
|
||||
</Localized>
|
||||
<div className="ReturnToAMOContainer">
|
||||
<div className="ReturnToAMOAddonContents">
|
||||
<Localized text={content.subtitle}>
|
||||
<p />
|
||||
</Localized>
|
||||
<Localized text={content.text}>
|
||||
<div
|
||||
className="ReturnToAMOText"
|
||||
data-l10n-args={
|
||||
this.props.name
|
||||
? JSON.stringify({ "addon-name": this.props.name })
|
||||
: null
|
||||
}
|
||||
>
|
||||
<img data-l10n-name="icon" src={this.props.iconURL} alt="" />
|
||||
</div>
|
||||
</Localized>
|
||||
<Localized text={content.primary_button.label}>
|
||||
<button
|
||||
onClick={this.onClickAddExtension}
|
||||
className="puffy blue ReturnToAMOAddExtension"
|
||||
/>
|
||||
</Localized>
|
||||
</div>
|
||||
<div className="ReturnToAMOIcon" />
|
||||
</div>
|
||||
<Localized text={content.startButton.label}>
|
||||
<button
|
||||
onClick={this.handleStartBtnClick}
|
||||
className="default grey ReturnToAMOGetStarted"
|
||||
/>
|
||||
</Localized>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReturnToAMO.defaultProps = DEFAULT_RTAMO_CONTENT;
|
|
@ -54,6 +54,33 @@ export const AboutWelcomeUtils = {
|
|||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_RTAMO_CONTENT = {
|
||||
template: "return_to_amo",
|
||||
content: {
|
||||
header: { string_id: "onboarding-welcome-header" },
|
||||
subtitle: { string_id: "return-to-amo-subtitle" },
|
||||
text: {
|
||||
string_id: "return-to-amo-addon-title",
|
||||
},
|
||||
primary_button: {
|
||||
label: { string_id: "return-to-amo-add-extension-label" },
|
||||
action: {
|
||||
type: "INSTALL_ADDON_FROM_URL",
|
||||
data: { url: null, telemetrySource: "rtamo" },
|
||||
},
|
||||
},
|
||||
startButton: {
|
||||
label: {
|
||||
string_id: "onboarding-start-browsing-button-label",
|
||||
},
|
||||
message_id: "RTAMO_START_BROWSING_BUTTON",
|
||||
action: {
|
||||
type: "OPEN_AWESOME_BAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_WELCOME_CONTENT = {
|
||||
template: "multistage",
|
||||
screens: [
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
После Ширина: | Высота: | Размер: 53 KiB |
|
@ -17,6 +17,7 @@ prefs =
|
|||
[browser_aboutwelcome_actors.js]
|
||||
[browser_aboutwelcome_simplified.js]
|
||||
[browser_aboutwelcome_multistage.js]
|
||||
[browser_aboutwelcome_rtamo.js]
|
||||
skip-if = fission
|
||||
[browser_aboutwelcome_observer.js]
|
||||
[browser_as_load_location.js]
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
"use strict";
|
||||
|
||||
const ABOUT_WELCOME_OVERRIDE_CONTENT_PREF =
|
||||
"browser.aboutwelcome.overrideContent";
|
||||
|
||||
const TEST_RTAMO_WELCOME_CONTENT = {
|
||||
template: "return_to_amo",
|
||||
name: "Test add on",
|
||||
url: "https://test.xpi",
|
||||
iconURL: "https://test.svg",
|
||||
content: {
|
||||
header: { string_id: "onboarding-welcome-header" },
|
||||
subtitle: { string_id: "return-to-amo-subtitle" },
|
||||
text: {
|
||||
string_id: "return-to-amo-addon-title",
|
||||
},
|
||||
primary_button: {
|
||||
label: { string_id: "return-to-amo-add-extension-label" },
|
||||
action: {
|
||||
type: "INSTALL_ADDON_FROM_URL",
|
||||
data: { url: null, telemetrySource: "rtamo" },
|
||||
},
|
||||
},
|
||||
startButton: {
|
||||
label: {
|
||||
string_id: "onboarding-start-browsing-button-label",
|
||||
},
|
||||
message_id: "RTAMO_START_BROWSING_BUTTON",
|
||||
action: {
|
||||
type: "OPEN_AWESOME_BAR",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const TEST_RTAMO_WELCOME_JSON = JSON.stringify(TEST_RTAMO_WELCOME_CONTENT);
|
||||
|
||||
async function setAboutWelcomeOverride(value) {
|
||||
return pushPrefs([ABOUT_WELCOME_OVERRIDE_CONTENT_PREF, value]);
|
||||
}
|
||||
|
||||
async function openRTAMOWelcomePage() {
|
||||
await setAboutWelcomeOverride(TEST_RTAMO_WELCOME_JSON);
|
||||
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||
gBrowser,
|
||||
"about:welcome",
|
||||
true
|
||||
);
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
return tab.linkedBrowser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup and test RTAMO welcome UI
|
||||
*/
|
||||
async function test_screen_content(
|
||||
browser,
|
||||
experiment,
|
||||
expectedSelectors = [],
|
||||
unexpectedSelectors = []
|
||||
) {
|
||||
await ContentTask.spawn(
|
||||
browser,
|
||||
{ expectedSelectors, experiment, unexpectedSelectors },
|
||||
async ({
|
||||
expectedSelectors: expected,
|
||||
experiment: experimentName,
|
||||
unexpectedSelectors: unexpected,
|
||||
}) => {
|
||||
for (let selector of expected) {
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => content.document.querySelector(selector),
|
||||
`Should render ${selector} in ${experimentName}`
|
||||
);
|
||||
}
|
||||
for (let selector of unexpected) {
|
||||
ok(
|
||||
!content.document.querySelector(selector),
|
||||
`Should not render ${selector} in ${experimentName}`
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function onButtonClick(browser, elementId) {
|
||||
await ContentTask.spawn(
|
||||
browser,
|
||||
{ elementId },
|
||||
async ({ elementId: buttonId }) => {
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => content.document.querySelector(buttonId),
|
||||
buttonId
|
||||
);
|
||||
let button = content.document.querySelector(buttonId);
|
||||
button.click();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the RTAMO welcome UI
|
||||
*/
|
||||
add_task(async function test_rtamo_aboutwelcome() {
|
||||
let browser = await openRTAMOWelcomePage();
|
||||
|
||||
await test_screen_content(
|
||||
browser,
|
||||
"RTAMO UI",
|
||||
// Expected selectors:
|
||||
[
|
||||
"div.ReturnToAMOContainer",
|
||||
"div.ReturnToAMOText",
|
||||
"div[data-l10n-id='return-to-amo-addon-title']",
|
||||
"img[data-l10n-name='icon']",
|
||||
"button.puffy.blue.ReturnToAMOAddExtension",
|
||||
"button.default.grey.ReturnToAMOGetStarted",
|
||||
],
|
||||
// Unexpected selectors:
|
||||
[
|
||||
"div.multistageContainer",
|
||||
"main.AW_STEP1",
|
||||
"main.AW_STEP2",
|
||||
"main.AW_STEP3",
|
||||
"div.tiles-container.info",
|
||||
]
|
||||
);
|
||||
|
||||
await onButtonClick(browser, "button.default.grey.ReturnToAMOGetStarted");
|
||||
Assert.ok(gURLBar.focused, "Focus should be on awesome bar");
|
||||
|
||||
let windowGlobalParent = browser.browsingContext.currentWindowGlobal;
|
||||
let aboutWelcomeActor = windowGlobalParent.getActor("AboutWelcome");
|
||||
const sandbox = sinon.createSandbox();
|
||||
// Stub AboutWelcomeParent Content Message Handler
|
||||
sandbox.stub(aboutWelcomeActor, "onContentMessage");
|
||||
registerCleanupFunction(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
await onButtonClick(browser, "button.puffy.blue.ReturnToAMOAddExtension");
|
||||
const { callCount } = aboutWelcomeActor.onContentMessage;
|
||||
ok(
|
||||
callCount === 2,
|
||||
`${callCount} Stub called twice to install extension and send telemetry`
|
||||
);
|
||||
|
||||
const installExtensionCall = aboutWelcomeActor.onContentMessage.getCall(0);
|
||||
Assert.equal(
|
||||
installExtensionCall.args[0],
|
||||
"AWPage:SPECIAL_ACTION",
|
||||
"send special action to install add on"
|
||||
);
|
||||
Assert.equal(
|
||||
installExtensionCall.args[1].type,
|
||||
"INSTALL_ADDON_FROM_URL",
|
||||
"Special action type is INSTALL_ADDON_FROM_URL"
|
||||
);
|
||||
Assert.equal(
|
||||
installExtensionCall.args[1].data.url,
|
||||
"https://test.xpi",
|
||||
"Install add on url"
|
||||
);
|
||||
Assert.equal(
|
||||
installExtensionCall.args[1].data.telemetrySource,
|
||||
"rtamo",
|
||||
"Install add on telemetry source"
|
||||
);
|
||||
const telemetryCall = aboutWelcomeActor.onContentMessage.getCall(1);
|
||||
Assert.equal(
|
||||
telemetryCall.args[0],
|
||||
"AWPage:TELEMETRY_EVENT",
|
||||
"send add extension telemetry"
|
||||
);
|
||||
Assert.equal(
|
||||
telemetryCall.args[1].event,
|
||||
"INSTALL",
|
||||
"Telemetry event sent as INSTALL"
|
||||
);
|
||||
Assert.equal(
|
||||
telemetryCall.args[1].event_context.source,
|
||||
"ADD_EXTENSION_BUTTON",
|
||||
"Source of the event is Add Extension Button"
|
||||
);
|
||||
Assert.equal(
|
||||
telemetryCall.args[1].message_id,
|
||||
"RTAMO_DEFAULT_WELCOME",
|
||||
"Message Id sent in telemetry for default RTAMO"
|
||||
);
|
||||
});
|
|
@ -14,6 +14,16 @@ onboarding-cards-dismiss =
|
|||
.title = Dismiss
|
||||
.aria-label = Dismiss
|
||||
|
||||
## Custom Return To AMO onboarding strings
|
||||
|
||||
return-to-amo-subtitle = Great, you’ve got { -brand-short-name }
|
||||
# <img data-l10n-name="icon"/> will be replaced with the icon belonging to the extension
|
||||
#
|
||||
# Variables:
|
||||
# $addon-name (String) - Name of the add-on
|
||||
return-to-amo-addon-title = Now let’s get you <img data-l10n-name="icon"/> <b>{ $addon-name }</b>.
|
||||
return-to-amo-add-extension-label = Add the Extension
|
||||
|
||||
## Multistage 3-screen onboarding flow strings (about:welcome pages)
|
||||
|
||||
# The <span data-l10n-name="zap"></span> in this string allows a "zap" underline style to be
|
||||
|
|
Загрузка…
Ссылка в новой задаче