mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 23:35:34 +00:00
dde1e1b541
Reuse existing "show" event object to track which primary button was shown on the first screen. Update Events.yaml with longer description of expected values. Differential Revision: https://phabricator.services.mozilla.com/D112837
221 lines
7.3 KiB
JavaScript
221 lines
7.3 KiB
JavaScript
/* 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/. */
|
|
|
|
const {
|
|
AddonManager,
|
|
document: gDoc,
|
|
getShellService,
|
|
Services,
|
|
} = window.docShell.chromeEventHandler.ownerGlobal;
|
|
|
|
const SHELL = getShellService();
|
|
const IS_DEFAULT = SHELL.isDefaultBrowser();
|
|
const NEED_PIN = SHELL.doesAppNeedPin();
|
|
|
|
// Strings for various elements with matching ids on each screen.
|
|
const PIN_OR_THEME_STRING = NEED_PIN.then(pin =>
|
|
pin
|
|
? "upgrade-dialog-new-primary-pin-button"
|
|
: "upgrade-dialog-new-primary-theme-button"
|
|
);
|
|
const PRIMARY_OR_DEFAULT_STRING = NEED_PIN.then(pin =>
|
|
pin
|
|
? "upgrade-dialog-new-primary-primary-button"
|
|
: "upgrade-dialog-new-primary-default-button"
|
|
);
|
|
const SCREEN_STRINGS = [
|
|
{
|
|
title: "upgrade-dialog-new-title",
|
|
primary: IS_DEFAULT ? PIN_OR_THEME_STRING : PRIMARY_OR_DEFAULT_STRING,
|
|
secondary: "upgrade-dialog-new-secondary-button",
|
|
},
|
|
{
|
|
title: "upgrade-dialog-theme-title",
|
|
primary: "upgrade-dialog-theme-primary-button",
|
|
secondary: "upgrade-dialog-theme-secondary-button",
|
|
},
|
|
];
|
|
|
|
// Themes that can be selected by the button with matching index.
|
|
const THEME_IDS = [
|
|
"default-theme@mozilla.org",
|
|
"firefox-compact-light@mozilla.org",
|
|
"firefox-compact-dark@mozilla.org",
|
|
"firefox-alpenglow@mozilla.org",
|
|
];
|
|
|
|
// Callbacks to run when the dialog closes (both from this file or externally).
|
|
const CLEANUP = [];
|
|
addEventListener("pagehide", () => CLEANUP.forEach(f => f()), { once: true });
|
|
|
|
// Save the previous theme to revert to it.
|
|
let gPrevTheme = AddonManager.getAddonsByTypes(["theme"]).then(addons => {
|
|
for (const { id, isActive, screenshots } of addons) {
|
|
if (isActive) {
|
|
// Only show the "keep" theme option for "other" themes.
|
|
if (!THEME_IDS.includes(id)) {
|
|
THEME_IDS.push(id);
|
|
}
|
|
|
|
// Assume we need to revert the theme unless cleared.
|
|
CLEANUP.push(() => gPrevTheme && enableTheme(id));
|
|
return {
|
|
id,
|
|
swatch: screenshots?.[0].url,
|
|
};
|
|
}
|
|
}
|
|
|
|
// If there were no active themes, the default will be selected.
|
|
return { id: THEME_IDS[0] };
|
|
});
|
|
|
|
// Helper to switch themes.
|
|
async function enableTheme(id) {
|
|
(await AddonManager.getAddonByID(id)).enable();
|
|
}
|
|
|
|
// Helper to show the theme in chrome with an adjusted modal backdrop.
|
|
function adjustModalBackdrop() {
|
|
const { classList } = gDoc.getElementById("window-modal-dialog");
|
|
classList.add("showToolbar");
|
|
CLEANUP.push(() => classList.remove("showToolbar"));
|
|
}
|
|
|
|
// Helper to record various events from the dialog content.
|
|
function recordEvent(obj, val) {
|
|
Services.telemetry.recordEvent("upgrade_dialog", "content", obj, `${val}`);
|
|
}
|
|
|
|
// Assume the dialog closes from an external trigger unless this helper is used.
|
|
let gCloseReason = "external";
|
|
CLEANUP.push(() => recordEvent("close", gCloseReason));
|
|
function closeDialog(reason) {
|
|
gCloseReason = reason;
|
|
close();
|
|
}
|
|
|
|
// Detect quit requests to proactively dismiss to allow the quit prompt to show
|
|
// as otherwise gDialogBox queues the prompt as these share the same display.
|
|
const QUIT_TOPIC = "quit-application-requested";
|
|
const QUIT_OBSERVER = () => closeDialog(QUIT_TOPIC);
|
|
Services.obs.addObserver(QUIT_OBSERVER, QUIT_TOPIC);
|
|
CLEANUP.push(() => Services.obs.removeObserver(QUIT_OBSERVER, QUIT_TOPIC));
|
|
|
|
// Hook up dynamic behaviors of the dialog.
|
|
function onLoad(ready) {
|
|
const title = document.getElementById("title");
|
|
const subtitle = document.getElementById("subtitle");
|
|
const items = document.querySelector(".items");
|
|
const themes = document.querySelector(".themes");
|
|
const primary = document.getElementById("primary");
|
|
const secondary = document.getElementById("secondary");
|
|
const steps = document.querySelector(".steps");
|
|
|
|
// Update the screen content and handle actions.
|
|
let current = -1;
|
|
(async function advance({ target } = {}) {
|
|
// Record which button was clicked.
|
|
if (target) {
|
|
recordEvent("button", target.dataset.l10nId);
|
|
}
|
|
|
|
// Move to the next screen and perform screen-specific behavior.
|
|
switch (++current) {
|
|
case 0:
|
|
// Wait for main button clicks on each screen.
|
|
primary.addEventListener("click", advance);
|
|
secondary.addEventListener("click", advance);
|
|
break;
|
|
|
|
case 1:
|
|
// Handle first screen conditional actions.
|
|
if (target === primary) {
|
|
if (!IS_DEFAULT) {
|
|
SHELL.setAsDefault();
|
|
}
|
|
SHELL.pinToTaskbar();
|
|
} else if (target === secondary && IS_DEFAULT && !(await NEED_PIN)) {
|
|
closeDialog("early");
|
|
return;
|
|
}
|
|
|
|
// Prepare the initial theme selection and wait for theme button clicks.
|
|
const { id, swatch } = await gPrevTheme;
|
|
themes.children[THEME_IDS.indexOf(id)].checked = true;
|
|
themes.addEventListener("click", ({ target: button }) => {
|
|
// Ignore clicks on whitespace of the container around theme buttons.
|
|
if (button.parentNode === themes) {
|
|
// Enable the theme of the corresponding button position.
|
|
const index = [...themes.children].indexOf(button);
|
|
enableTheme(THEME_IDS[index]);
|
|
recordEvent("theme", index);
|
|
}
|
|
});
|
|
|
|
// Remove the last "keep" theme option if the user didn't customize.
|
|
if (themes.childElementCount > THEME_IDS.length) {
|
|
themes.removeChild(themes.lastElementChild);
|
|
} else if (swatch) {
|
|
themes.lastElementChild.style.setProperty(
|
|
"--theme-swatch",
|
|
`url("${swatch}")`
|
|
);
|
|
}
|
|
|
|
// Update content and backdrop for theme screen.
|
|
subtitle.remove();
|
|
items.remove();
|
|
themes.classList.remove("hidden");
|
|
steps.appendChild(steps.firstChild);
|
|
adjustModalBackdrop();
|
|
break;
|
|
|
|
case 2:
|
|
// New theme is confirmed, so don't revert to previous.
|
|
if (target === primary) {
|
|
gPrevTheme = null;
|
|
}
|
|
|
|
closeDialog("complete");
|
|
return;
|
|
}
|
|
|
|
// Update strings for reused elements that change between screens.
|
|
const strings = SCREEN_STRINGS[current];
|
|
document.l10n.setAttributes(title, strings.title);
|
|
document.l10n.setAttributes(primary, await strings.primary);
|
|
document.l10n.setAttributes(secondary, strings.secondary);
|
|
|
|
// Wait for initial translations to load before getting sizing information.
|
|
await document.l10n.ready;
|
|
requestAnimationFrame(() => {
|
|
// Ensure the primary button is focused on each screen.
|
|
primary.focus();
|
|
|
|
// Save first screen height, so later screens can flex and anchor content.
|
|
if (current === 0) {
|
|
document.body.style.minHeight = getComputedStyle(document.body).height;
|
|
|
|
// Record which of four primary button was shown for the first screen.
|
|
recordEvent("show", primary.dataset.l10nId);
|
|
|
|
// Indicate to SubDialog that we're done sizing the first screen.
|
|
ready();
|
|
}
|
|
|
|
// Let testing know the screen is ready to continue.
|
|
dispatchEvent(new CustomEvent("ready"));
|
|
});
|
|
|
|
// Record that the screen was shown.
|
|
recordEvent("show", current);
|
|
})();
|
|
}
|
|
document.mozSubdialogReady = new Promise(resolve =>
|
|
document.addEventListener("DOMContentLoaded", () => onLoad(resolve), {
|
|
once: true,
|
|
})
|
|
);
|