From fd8a3f0cf3ff0d9c486b50e250a59b9a612f9a85 Mon Sep 17 00:00:00 2001 From: Kate Hudson Date: Fri, 28 Feb 2020 14:36:31 +0000 Subject: [PATCH] Bug 1617783 - Add JSWindowActors to about:welcome r=mconley,pdahiya Differential Revision: https://phabricator.services.mozilla.com/D64082 --HG-- extra : moz-landing-system : lando --- browser/app/profile/firefox.js | 5 + browser/components/BrowserGlue.jsm | 45 +++++++++ .../newtab/aboutwelcome/AboutWelcomeChild.jsm | 91 +++++++++++++++++++ .../aboutwelcome/AboutWelcomeParent.jsm | 63 +++++++++++++ .../content/aboutwelcome.bundle.js | 71 +++++++++------ .../aboutwelcome/lib/AboutWelcomeLog.jsm | 22 +++++ .../content-src/aboutwelcome/aboutwelcome.jsx | 18 ++-- .../aboutwelcome/components/FxCards.jsx | 8 +- .../content-src/lib/aboutwelcome-utils.js | 44 ++++----- browser/components/newtab/jar.mn | 1 + browser/components/newtab/moz.build | 5 + 11 files changed, 313 insertions(+), 60 deletions(-) create mode 100644 browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm create mode 100644 browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm create mode 100644 browser/components/newtab/aboutwelcome/lib/AboutWelcomeLog.jsm diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 0a856115bfe8..3f67f57ce814 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1319,6 +1319,11 @@ pref("browser.newtabpage.activity-stream.discoverystream.personalization.modelKe pref("trailhead.firstrun.branches", ""); +// Separate about welcome +pref("browser.aboutwelcome.enabled", false); +// See Console.jsm LOG_LEVELS for all possible values +pref("browser.aboutwelcome.log", "warn"); + // The pref that controls if the What's New panel is enabled. pref("browser.messaging-system.whatsNewPanel.enabled", true); // Used for CFR messages with scores. See Bug 1594422. diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index a153ecba1a6d..8fe21eb51386 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -405,6 +405,51 @@ let LEGACY_ACTORS = { }, }; +// See Bug 1618306 +// This should be moved to BrowserGlue.jsm and this file should be deleted +// when we turn on separate about:welcome for all users. +const ACTOR_CONFIG = { + parent: { + moduleURI: "resource:///actors/AboutWelcomeParent.jsm", + }, + child: { + moduleURI: "resource:///actors/AboutWelcomeChild.jsm", + events: { + // This is added so the actor instantiates immediately and makes + // methods available to the page js on load. + DOMWindowCreated: {}, + }, + }, + matches: ["about:welcome"], +}; + +const AboutWelcomeActorHelper = { + register() { + ChromeUtils.registerWindowActor("AboutWelcome", ACTOR_CONFIG); + }, + unregister() { + ChromeUtils.unregisterWindowActor("AboutWelcome"); + }, +}; + +XPCOMUtils.defineLazyPreferenceGetter( + this, + "isSeparateAboutWelcome", + "browser.aboutwelcome.enabled", + false, + (prefName, prevValue, isEnabled) => { + if (isEnabled) { + AboutWelcomeActorHelper.register(); + } else { + AboutWelcomeActorHelper.unregister(); + } + } +); + +if (isSeparateAboutWelcome) { + AboutWelcomeActorHelper.register(); +} + (function earlyBlankFirstPaint() { if ( AppConstants.platform == "macosx" || diff --git a/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm b/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm new file mode 100644 index 000000000000..886ad0104383 --- /dev/null +++ b/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm @@ -0,0 +1,91 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["AboutWelcomeChild"]; + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); + +XPCOMUtils.defineLazyGetter(this, "log", () => { + const { AboutWelcomeLog } = ChromeUtils.import( + "resource://activity-stream/aboutwelcome/lib/AboutWelcomeLog.jsm" + ); + return new AboutWelcomeLog("AboutWelcomeChild.jsm"); +}); + +class AboutWelcomeChild extends JSWindowActorChild { + actorCreated() { + this.exportFunctions(); + } + + /** + * Send event that can be handled by the page + * @param {{type: string, data?: any}} action + */ + sendToPage(action) { + log.debug(`Sending to page: ${action.type}`); + const win = this.document.defaultView; + const event = new win.CustomEvent("AboutWelcomeChromeToContent", { + detail: Cu.cloneInto(action, win), + }); + win.dispatchEvent(event); + } + + /** + * Export functions that can be called by page js + */ + exportFunctions() { + let window = this.contentWindow; + + Cu.exportFunction(this.AWGetStartupData.bind(this), window, { + defineAs: "AWGetStartupData", + }); + + Cu.exportFunction(this.AWSendEventTelemetry.bind(this), window, { + defineAs: "AWSendEventTelemetry", + }); + + Cu.exportFunction(this.AWSendToParent.bind(this), window, { + defineAs: "AWSendToParent", + }); + } + + /** + * Send initial data to page including experiment information + */ + AWGetStartupData() { + // TODO: Fetch this from Experiments + const experimentData = {}; + return Cu.cloneInto(experimentData, this.contentWindow); + } + + /** + * Send Event Telemetry + * @param {object} eventData + */ + AWSendEventTelemetry(eventData) { + // TODO: Send event Telemetry with Services.telemetry + log.debug("Sending event telemetry:", eventData); + } + + /** + * Send message that can be handled by AboutWelcomeParent.jsm + * @param {string} type + * @param {any=} data + */ + AWSendToParent(type, data) { + this.sendAsyncMessage(`AWPage:${type}`, data); + } + + /** + * @param {{type: string, detail?: any}} event + * @override + */ + handleEvent(event) { + log.debug(`Received page event ${event.type}`); + } +} diff --git a/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm b/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm new file mode 100644 index 000000000000..ee2770070fc1 --- /dev/null +++ b/browser/components/newtab/aboutwelcome/AboutWelcomeParent.jsm @@ -0,0 +1,63 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["AboutWelcomeParent"]; + +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); + +XPCOMUtils.defineLazyModuleGetters(this, { + MigrationUtils: "resource:///modules/MigrationUtils.jsm", +}); + +XPCOMUtils.defineLazyGetter(this, "log", () => { + const { AboutWelcomeLog } = ChromeUtils.import( + "resource://activity-stream/aboutwelcome/lib/AboutWelcomeLog.jsm" + ); + return new AboutWelcomeLog("AboutWelcomeParent.jsm"); +}); + +class AboutWelcomeParent extends JSWindowActorParent { + /** + * Handle messages from AboutWelcomeChild.jsm + * + * @param {string} type + * @param {any=} data + * @param {Browser} browser + * @param {Window} window + */ + onContentMessage(type, data, browser, window) { + log.debug(`Received content event: ${type}`); + switch (type) { + case "AWPage:SHOW_MIGRATION_WIZARD": + MigrationUtils.showMigrationWizard(window, [ + MigrationUtils.MIGRATION_ENTRYPOINT_NEWTAB, + ]); + break; + default: + log.debug(`Unexpected event ${type} was not handled.`); + } + } + + /** + * @param {{name: string, data?: any}} message + * @override + */ + receiveMessage(message) { + const { name, data } = message; + let browser; + let window; + + if (this.manager.rootFrameLoader) { + browser = this.manager.rootFrameLoader.ownerElement; + window = browser.ownerGlobal; + this.onContentMessage(name, data, browser, window); + } else { + log.warn(`Not handling ${name} because the browser doesn't exist.`); + } + } +} diff --git a/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js b/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js index 601deacad17d..7f5a28a6a344 100644 --- a/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js +++ b/browser/components/newtab/aboutwelcome/content/aboutwelcome.bundle.js @@ -113,9 +113,6 @@ __webpack_require__.r(__webpack_exports__); class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent { - sendTelemetry(ping) {// TBD: Handle telemetry messages - } - render() { const { props @@ -129,14 +126,22 @@ class AboutWelcome extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComp subtitle: props.subtitle }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(_components_FxCards__WEBPACK_IMPORTED_MODULE_3__["FxCards"], { cards: props.cards, - sendTelemetry: this.sendTelemetry + sendTelemetry: window.AWSendEventTelemetry }))); } } AboutWelcome.defaultProps = _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_4__["DEFAULT_WELCOME_CONTENT"]; -react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render(react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(AboutWelcome, null), document.getElementById("root")); + +function mount(settings) { + react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render(react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(AboutWelcome, { + title: settings.title, + subtitle: settings.subtitle + }), document.getElementById("root")); +} + +mount(window.AWGetStartupData()); /***/ }), /* 1 */ @@ -196,23 +201,23 @@ function _extends() { _extends = Object.assign || function (target) { for (var i class FxCards extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureComponent { onCardAction(action) { - let actionUpdates = {}; + let { + type, + data + } = action; let UTMTerm = "utm_term_separate_welcome"; if (action.type === "OPEN_URL") { let url = new URL(action.data.args); Object(_asrouter_templates_FirstRun_addUtmParams__WEBPACK_IMPORTED_MODULE_1__["addUtmParams"])(url, UTMTerm); - actionUpdates = { - data: { ...action.data, - args: url.toString() - } + data = { ...data, + args: url.toString() }; } _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_3__["AboutWelcomeUtils"].handleUserAction({ - data: { ...action, - ...actionUpdates - } + type, + data }); } @@ -347,14 +352,23 @@ __webpack_require__.r(__webpack_exports__); * 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/. */ const AboutWelcomeUtils = { - handleUserAction({ - data: action - }) { + handleUserAction(action) { switch (action.type) { case "OPEN_URL": window.open(action.data.args); break; + + case "SHOW_MIGRATION_WIZARD": + window.AWSendToParent("SHOW_MIGRATION_WIZARD"); + break; } + }, + + sendEvent(type, detail) { + document.dispatchEvent(new CustomEvent(`AWPage:${type}`, { + bubbles: true, + detail + })); } }; @@ -417,30 +431,31 @@ const DEFAULT_WELCOME_CONTENT = { order: 2, blockOnClick: false }, { + id: "TRAILHEAD_CARD_11", + template: "onboarding", + bundled: 3, + order: 0, content: { title: { - string_id: "onboarding-mobile-phone-title" + string_id: "onboarding-import-browser-settings-title" }, text: { - string_id: "onboarding-mobile-phone-text" + string_id: "onboarding-import-browser-settings-text" }, - icon: "mobile", + icon: "import", primary_button: { label: { - string_id: "onboarding-mobile-phone-button" + string_id: "onboarding-import-browser-settings-button" }, action: { - type: "OPEN_URL", - data: { - args: "https://www.mozilla.org/firefox/mobile/", - where: "tabshifted" - } + type: "SHOW_MIGRATION_WIZARD" } } }, - id: "TRAILHEAD_CARD_6", - order: 6, - blockOnClick: false + targeting: "trailheadTriplet == 'dynamic_chrome'", + trigger: { + id: "showOnboarding" + } }] }; diff --git a/browser/components/newtab/aboutwelcome/lib/AboutWelcomeLog.jsm b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeLog.jsm new file mode 100644 index 000000000000..ef4a60f56e76 --- /dev/null +++ b/browser/components/newtab/aboutwelcome/lib/AboutWelcomeLog.jsm @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const EXPORTED_SYMBOLS = ["AboutWelcomeLog"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { ConsoleAPI } = ChromeUtils.import("resource://gre/modules/Console.jsm"); + +const LOGGING_PREF = "browser.aboutwelcome.log"; + +class AboutWelcomeLog extends ConsoleAPI { + constructor(name) { + let consoleOptions = { + prefix: name, + maxLogLevel: Services.prefs.getCharPref(LOGGING_PREF, "warn"), + maxLogLevelPref: LOGGING_PREF, + }; + super(consoleOptions); + } +} diff --git a/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx b/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx index c10be74a1ab8..990eaea9fb4e 100644 --- a/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx +++ b/browser/components/newtab/content-src/aboutwelcome/aboutwelcome.jsx @@ -9,17 +9,16 @@ import { FxCards } from "./components/FxCards"; import { DEFAULT_WELCOME_CONTENT } from "../lib/aboutwelcome-utils"; class AboutWelcome extends React.PureComponent { - sendTelemetry(ping) { - // TBD: Handle telemetry messages - } - render() { const { props } = this; return (
- +
); @@ -28,4 +27,11 @@ class AboutWelcome extends React.PureComponent { AboutWelcome.defaultProps = DEFAULT_WELCOME_CONTENT; -ReactDOM.render(, document.getElementById("root")); +function mount(settings) { + ReactDOM.render( + , + document.getElementById("root") + ); +} + +mount(window.AWGetStartupData()); diff --git a/browser/components/newtab/content-src/aboutwelcome/components/FxCards.jsx b/browser/components/newtab/content-src/aboutwelcome/components/FxCards.jsx index ce02436ed89a..2dc79833690a 100644 --- a/browser/components/newtab/content-src/aboutwelcome/components/FxCards.jsx +++ b/browser/components/newtab/content-src/aboutwelcome/components/FxCards.jsx @@ -9,18 +9,16 @@ import { AboutWelcomeUtils } from "../../lib/aboutwelcome-utils"; export class FxCards extends React.PureComponent { onCardAction(action) { - let actionUpdates = {}; + let { type, data } = action; let UTMTerm = "utm_term_separate_welcome"; if (action.type === "OPEN_URL") { let url = new URL(action.data.args); addUtmParams(url, UTMTerm); - actionUpdates = { data: { ...action.data, args: url.toString() } }; + data = { ...data, args: url.toString() }; } - AboutWelcomeUtils.handleUserAction({ - data: { ...action, ...actionUpdates }, - }); + AboutWelcomeUtils.handleUserAction({ type, data }); } render() { diff --git a/browser/components/newtab/content-src/lib/aboutwelcome-utils.js b/browser/components/newtab/content-src/lib/aboutwelcome-utils.js index 0e3235d74fa1..dea14678c3b6 100644 --- a/browser/components/newtab/content-src/lib/aboutwelcome-utils.js +++ b/browser/components/newtab/content-src/lib/aboutwelcome-utils.js @@ -3,13 +3,24 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ export const AboutWelcomeUtils = { - handleUserAction({ data: action }) { + handleUserAction(action) { switch (action.type) { case "OPEN_URL": window.open(action.data.args); break; + case "SHOW_MIGRATION_WIZARD": + window.AWSendToParent("SHOW_MIGRATION_WIZARD"); + break; } }, + sendEvent(type, detail) { + document.dispatchEvent( + new CustomEvent(`AWPage:${type}`, { + bubbles: true, + detail, + }) + ); + }, }; export const DEFAULT_WELCOME_CONTENT = { @@ -75,30 +86,21 @@ export const DEFAULT_WELCOME_CONTENT = { blockOnClick: false, }, { + id: "TRAILHEAD_CARD_11", + template: "onboarding", + bundled: 3, + order: 0, content: { - title: { - string_id: "onboarding-mobile-phone-title", - }, - text: { - string_id: "onboarding-mobile-phone-text", - }, - icon: "mobile", + title: { string_id: "onboarding-import-browser-settings-title" }, + text: { string_id: "onboarding-import-browser-settings-text" }, + icon: "import", primary_button: { - label: { - string_id: "onboarding-mobile-phone-button", - }, - action: { - type: "OPEN_URL", - data: { - args: "https://www.mozilla.org/firefox/mobile/", - where: "tabshifted", - }, - }, + label: { string_id: "onboarding-import-browser-settings-button" }, + action: { type: "SHOW_MIGRATION_WIZARD" }, }, }, - id: "TRAILHEAD_CARD_6", - order: 6, - blockOnClick: false, + targeting: "trailheadTriplet == 'dynamic_chrome'", + trigger: { id: "showOnboarding" }, }, ], }; diff --git a/browser/components/newtab/jar.mn b/browser/components/newtab/jar.mn index 1b22f084185b..5bee7dcaa12d 100644 --- a/browser/components/newtab/jar.mn +++ b/browser/components/newtab/jar.mn @@ -7,6 +7,7 @@ browser.jar: res/activity-stream/lib/ (./lib/*) res/activity-stream/common/ (./common/*) res/activity-stream/aboutwelcome/ (./aboutwelcome/content/*) + res/activity-stream/aboutwelcome/lib/ (./aboutwelcome/lib/*) res/activity-stream/vendor/Redux.jsm (./vendor/Redux.jsm) res/activity-stream/vendor/react.js (./vendor/react.js) res/activity-stream/vendor/react-dom.js (./vendor/react-dom.js) diff --git a/browser/components/newtab/moz.build b/browser/components/newtab/moz.build index f537c7322533..7c9efa5f9f8e 100644 --- a/browser/components/newtab/moz.build +++ b/browser/components/newtab/moz.build @@ -26,6 +26,11 @@ EXTRA_JS_MODULES += [ 'AboutNewTabService.jsm', ] +FINAL_TARGET_FILES.actors += [ + 'aboutwelcome/AboutWelcomeChild.jsm', + 'aboutwelcome/AboutWelcomeParent.jsm', +] + XPCOM_MANIFESTS += [ 'components.conf', ]