Bug 1377439 - Should adapt the oboarding UI to the hight-contrast display mode, r=mossop
This patch makes the mininmum and the important elements and images visible in the high-constrast mode, including
- making button have border (using the given default grey border in the high-constrast mode)
- making the upper-left overlay button's fox image visible
- making the images of the X close buttons on the notification bar and on the overlay visible
- making that the navigation item of the current tour on the overlay's right side would have outline
- making the hovered navigation item on the overlay's right side would have outline
- making sure using <button> element for buttons for a better semantic
- changing #onboarding-overlay-icon to #onboarding-overlay-button for a better semantic
MozReview-Commit-ID: Aj6wndb4to9
--- a/browser/base/content/test/newtab/browser_newtab_focus.js
+++ b/browser/base/content/test/newtab/browser_newtab_focus.js
@@ -3,17 +3,17 @@
/*
* These tests make sure that focusing the 'New Tab Page' works as expected.
*/
add_task(async function() {
await pushPrefs(["accessibility.tabfocus", 7]);
// When the onboarding component is enabled, it would inject extra tour notification into
- // the newtab page so there would be 2 more notification close button and action button
+ // the newtab page so there would be 3 more overlay button, notification close button and action button
let onbardingEnabled = AppConstants.NIGHTLY_BUILD && Services.prefs.getBoolPref("browser.onboarding.enabled");
// Focus count in new tab page.
// 30 = 9 * 3 + 3 = 9 sites, each with link, pin and remove buttons; search
// bar; search button; and toggle button. Additionaly there may or may not be
// a scroll bar caused by fix to 1180387, which will eat an extra focus
let FOCUS_COUNT = 30;
@@ -21,28 +21,28 @@ add_task(async function() {
await setLinks("0,1,2,3,4,5,6,7,8");
setPinnedLinks("");
if (onbardingEnabled) {
await promiseNoMuteNotificationOnFirstSession();
}
let tab = await addNewTabPageTab();
if (onbardingEnabled) {
- FOCUS_COUNT += 2;
+ FOCUS_COUNT += 3;
await promiseTourNotificationOpened(tab.linkedBrowser);
}
gURLBar.focus();
// Count the focus with the enabled page.
countFocus(FOCUS_COUNT);
// Disable page and count the focus with the disabled page.
NewTabUtils.allPages.enabled = false;
let expectedCount = 4;
if (onbardingEnabled) {
- expectedCount += 2;
+ expectedCount += 3;
}
countFocus(expectedCount);
NewTabUtils.allPages.enabled = true;
});
/**
* Focus the urlbar and count how many focus stops to return again to the urlbar.
--- a/browser/extensions/onboarding/content/onboarding.css
+++ b/browser/extensions/onboarding/content/onboarding.css
@@ -18,74 +18,84 @@
background: rgb(54, 57, 89, 0.8); /* #363959, 0.8 opacity */
display: none;
}
#onboarding-overlay.onboarding-opened {
display: block;
}
-#onboarding-overlay-icon {
- width: 36px;
- height: 29px;
+#onboarding-overlay-button {
position: absolute;
cursor: pointer;
top: 30px;
offset-inline-start: 30px;
- background: url("img/overlay-icon.svg") no-repeat;
+ border: none;
+ /* Set to none so no grey contrast background in the high-contrast mode */
+ background: none;
+}
+
+#onboarding-overlay-button-icon {
+ width: 36px;
}
#onboarding-notification-icon::after,
-#onboarding-overlay-icon::after {
+#onboarding-overlay-button::after {
background: #5ce6e6;
position: absolute;
font-size: 12px;
border: 1px solid #fff;
text-align: center;
color: #10404a;
box-sizing: content-box;
}
-#onboarding-overlay-icon::after {
+#onboarding-overlay-button::after {
content: attr(aria-label);
top: -6px;
offset-inline-start: 39px;
border-radius: 22px;
padding: 5px 8px;
min-width: 100px;
}
#onboarding-overlay-dialog,
.onboarding-hidden {
display: none;
}
-#onboarding-overlay-close-btn,
-#onboarding-notification-close-btn {
- position: absolute;
- top: 15px;
- offset-inline-end: 15px;
- cursor: pointer;
- width: 16px;
- height: 16px;
- background-image: url(chrome://browser/skin/sidebar/close.svg);
- background-position: center center;
- background-repeat: no-repeat;
- padding: 12px;
+.onboarding-close-btn {
+ position: absolute;
+ top: 15px;
+ offset-inline-end: 15px;
+ cursor: pointer;
+ width: 16px;
+ height: 16px;
+ padding: 12px;
+ border: none;
+ background: var(--onboarding-overlay-dialog-background-color);
+ }
+
+.onboarding-close-btn::before {
+ content: url(chrome://browser/skin/sidebar/close.svg);
+ display: block;
+ margin-top: -8px;
+ margin-inline-start: -8px;
}
-#onboarding-overlay-close-btn:hover,
+.onboarding-close-btn:hover,
#onboarding-notification-close-btn:hover {
background-color: rgba(204, 204, 204, 0.6);
}
#onboarding-overlay.onboarding-opened > #onboarding-overlay-dialog {
+ --onboarding-overlay-dialog-background-color: #f5f5f7;
width: 960px;
height: 510px;
- background: #f5f5f7;
+ background: var(--onboarding-overlay-dialog-background-color);
border: 1px solid rgba(9, 6, 13, 0.1); /* #09060D, 0.1 opacity */
border-radius: 3px;
position: relative;
margin: 0 calc(50% - 480px);
top: calc(50% - 255px);
display: grid;
grid-template-rows: [dialog-start] 70px [page-start] 1fr [footer-start] 30px [dialog-end];
grid-template-columns: [dialog-start] 230px [page-start] 1fr [dialog-end];
@@ -131,20 +141,23 @@
/* Onboarding tour list */
#onboarding-tour-list {
margin: 40px 0 0 0;
padding: 0;
}
#onboarding-tour-list > li {
+ --padding-inline-start: 49px;
+ --padding-top: 14px;
+ --padding-bottom: 14px;
list-style: none;
- padding-inline-start: 49px;
- padding-top: 14px;
- padding-bottom: 14px;
+ padding-inline-start: var(--padding-inline-start);
+ padding-top: var(--padding-top);
+ padding-bottom: var(--padding-bottom);
margin-inline-start: 16px;
margin-bottom: 9px;
background-repeat: no-repeat;
background-position: left 17px top 14px;
background-size: 20px;
font-size: 16px;
cursor: pointer;
}
@@ -157,22 +170,29 @@
content: url("img/icons_tour-complete.svg");
position: relative;
offset-inline-start: 3px;
top: -10px;
float: inline-start;
}
#onboarding-tour-list > li.onboarding-complete {
- padding-inline-start: 29px;
+ --padding-inline-start: 29px;
}
#onboarding-tour-list > li.onboarding-active,
#onboarding-tour-list > li:hover {
color: #0A84FF;
+ /* With 1px transparent border, could see a border in the high-constrast mode */
+ border: 1px solid transparent;
+ /* Substract 1px for the 1px transparent or a 1px shift would happen */
+ padding-inline-start: calc(var(--padding-inline-start) - 1px);
+ padding-top: calc(var(--padding-top) - 1px);
+ padding-bottom: calc(var(--padding-bottom) - 1px);
+ background-color: #fff;
}
/* Default browser tour */
#onboarding-tour-is-default-browser-msg {
font-size: 16px;
line-height: 21px;
float: inline-end;
margin-inline-end: 26px;
@@ -279,17 +299,18 @@
}
.onboarding-tour-action-button {
padding: 10px 20px;
font-size: 15px;
font-weight: 600;
line-height: 21px;
background: #0a84ff;
- border: none;
+ /* With 1px transparent border, could see a border in the high-constrast mode */
+ border: 1px solid transparent;
border-radius: 0;
color: #fff;
float: inline-end;
margin-inline-end: 26px;
margin-top: -32px;
}
.onboarding-tour-action-button:hover:not([disabled]) ,
@@ -384,24 +405,25 @@
}
#onboarding-notification-bar[data-target-tour-id=onboarding-tour-sync] #onboarding-notification-tour-icon {
background-image: url("img/icons_sync-notification.svg");
}
/* Tour Notifications */
#onboarding-notification-bar {
+ --onboarding-notification-bar-background-color: rgba(255, 255, 255, 0.97);
position: fixed;
z-index: 20998; /* We want this always under #onboarding-overlay */
left: 0;
bottom: 0;
width: 100%;
height: 122px;
min-width: 640px;
- background: rgba(255, 255, 255, 0.97);
+ background: var(--onboarding-notification-bar-background-color);
border-top: 2px solid #e9e9e9;
transition: transform 0.8s;
transform: translateY(122px);
}
#onboarding-notification-bar.onboarding-opened {
transition: none;
transform: translateY(0px);
@@ -429,18 +451,17 @@
top: 0;
offset-inline-start: 73px;
line-height: calc(var(--height) - var(--vpadding) * 2);
border-radius: calc(var(--height) / 2);
padding: var(--vpadding) 10px;
}
#onboarding-notification-close-btn {
- background-color: rgba(255, 255, 255, 0.97);
- border: none;
+ background: var(--onboarding-notification-bar-background-color);
position: absolute;
offset-block-start: 50%;
offset-inline-end: 34px;
transform: translateY(-50%);
}
#onboarding-notification-message-section {
height: 100%;
@@ -475,17 +496,18 @@
min-width: 64px;
height: 64px;
background-size: 64px;
background-repeat: no-repeat;
}
#onboarding-notification-action-btn {
background: #0a84ff;
- border: none;
+ /* With 1px transparent border, could see a border in the high-constrast mode */
+ border: 1px solid transparent;
border-radius: 0;
padding: 10px 20px;
font-size: 14px;
color: #fff;
}
@media all and (max-width: 960px) {
#onboarding-notification-icon {
--- a/browser/extensions/onboarding/content/onboarding.js
+++ b/browser/extensions/onboarding/content/onboarding.js
@@ -280,17 +280,17 @@ class Onboarding {
_initUI() {
if (this.uiInitialized) {
return;
}
this.uiInitialized = true;
this._tourItems = [];
this._tourPages = [];
- this._overlayIcon = this._renderOverlayIcon();
+ this._overlayIcon = this._renderOverlayButton();
this._overlayIcon.addEventListener("click", this);
this._window.document.body.appendChild(this._overlayIcon);
this._overlay = this._renderOverlay();
this._overlay.addEventListener("click", this);
this._window.document.body.appendChild(this._overlay);
this._loadJS(TOUR_AGENT_JS_URI);
@@ -369,17 +369,17 @@ class Onboarding {
this._window.cancelIdleCallback(this._resizeTimerId);
this._resizeTimerId =
this._window.requestIdleCallback(() => this._resizeUI());
return;
}
switch (evt.target.id) {
- case "onboarding-overlay-icon":
+ case "onboarding-overlay-button":
case "onboarding-overlay-close-btn":
// If the clicking target is directly on the outer-most overlay,
// that means clicking outside the tour content area.
// Let's toggle the overlay.
case "onboarding-overlay":
this.toggleOverlay();
break;
case "onboarding-notification-close-btn":
@@ -648,17 +648,17 @@ class Onboarding {
<section id="onboarding-notification-message-section">
<div id="onboarding-notification-tour-icon"></div>
<div id="onboarding-notification-body">
<h6 id="onboarding-notification-tour-title"></h6>
<span id="onboarding-notification-tour-message"></span>
</div>
<button id="onboarding-notification-action-btn"></button>
</section>
- <button id="onboarding-notification-close-btn"></button>
+ <button id="onboarding-notification-close-btn" class="onboarding-close-btn"></button>
`;
let toolTip = this._bundle.formatStringFromName(
this._tourType === "new" ? "onboarding.notification-icon-tool-tip" :
"onboarding.notification-icon-tooltip-updated",
[BRAND_SHORT_NAME], 1);
div.querySelector("#onboarding-notification-icon").setAttribute("data-tooltip", toolTip);
return div;
}
@@ -679,17 +679,17 @@ class Onboarding {
_renderOverlay() {
let div = this._window.document.createElement("div");
div.id = "onboarding-overlay";
// We use `innerHTML` for more friendly reading.
// The security should be fine because this is not from an external input.
div.innerHTML = `
<div id="onboarding-overlay-dialog">
- <span id="onboarding-overlay-close-btn"></span>
+ <button id="onboarding-overlay-close-btn" class="onboarding-close-btn"></button>
<header id="onboarding-header"></header>
<nav>
<ul id="onboarding-tour-list"></ul>
</nav>
<footer id="onboarding-footer">
<input type="checkbox" id="onboarding-tour-hidden-checkbox" /><label for="onboarding-tour-hidden-checkbox"></label>
</footer>
</div>
@@ -697,26 +697,28 @@ class Onboarding {
div.querySelector("label[for='onboarding-tour-hidden-checkbox']").textContent =
this._bundle.GetStringFromName("onboarding.hidden-checkbox-label-text");
div.querySelector("#onboarding-header").textContent =
this._bundle.GetStringFromName("onboarding.overlay-title2");
return div;
}
- _renderOverlayIcon() {
- let img = this._window.document.createElement("div");
- let tooltip = this._bundle.formatStringFromName(
- this._tourType === "new" ? "onboarding.overlay-icon-tooltip" :
- "onboarding.overlay-icon-tooltip-updated",
- [BRAND_SHORT_NAME], 1);
-
- img.setAttribute("aria-label", tooltip);
- img.id = "onboarding-overlay-icon";
- return img;
+ _renderOverlayButton() {
+ let button = this._window.document.createElement("button");
+ let tooltipStringId = this._tourType === "new" ?
+ "onboarding.overlay-icon-tooltip" : "onboarding.overlay-icon-tooltip-updated";
+ let tooltip = this._bundle.formatStringFromName(tooltipStringId, [BRAND_SHORT_NAME], 1);
+ button.setAttribute("aria-label", tooltip);
+ button.id = "onboarding-overlay-button";
+ let img = this._window.document.createElement("img");
+ img.id = "onboarding-overlay-button-icon";
+ img.src = "resource://onboarding/img/overlay-icon.svg";
+ button.appendChild(img);
+ return button;
}
_loadTours(tours) {
let itemsFrag = this._window.document.createDocumentFragment();
let pagesFrag = this._window.document.createDocumentFragment();
for (let tour of tours) {
// Create tour navigation items dynamically
let li = this._window.document.createElement("li");
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tours.js
@@ -2,17 +2,17 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function assertOnboardingDestroyed(browser) {
return ContentTask.spawn(browser, {}, function() {
let expectedRemovals = [
"#onboarding-overlay",
- "#onboarding-overlay-icon"
+ "#onboarding-overlay-button"
];
for (let selector of expectedRemovals) {
let removal = content.document.querySelector(selector);
ok(!removal, `Should remove ${selector} onboarding element`);
}
});
}
@@ -31,17 +31,17 @@ add_task(async function test_hide_onboar
resetOnboardingDefaultState();
let tourIds = TOUR_IDs;
let tabs = [];
for (let url of URLs) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
- await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-icon", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
await promiseOnboardingOverlayOpened(tab.linkedBrowser);
tabs.push(tab);
}
let expectedPrefUpdates = [
promisePrefUpdated("browser.onboarding.hidden", true),
promisePrefUpdated("browser.onboarding.notification.finished", true)
];
@@ -62,17 +62,17 @@ add_task(async function test_click_actio
resetOnboardingDefaultState();
let tourIds = TOUR_IDs;
let tabs = [];
for (let url of URLs) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
- await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-icon", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
await promiseOnboardingOverlayOpened(tab.linkedBrowser);
tabs.push(tab);
}
let completedTourId = tourIds[0];
let expectedPrefUpdate = promisePrefUpdated(`browser.onboarding.tour.${completedTourId}.completed`, true);
await BrowserTestUtils.synthesizeMouseAtCenter(`#${completedTourId}-page .onboarding-tour-action-button`, {}, gBrowser.selectedBrowser);
await expectedPrefUpdate;
@@ -96,17 +96,17 @@ add_task(async function test_set_right_t
setTourCompletedState(tourIds[i], i % 2 == 0);
}
let tabs = [];
for (let url of URLs) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
- await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-icon", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
await promiseOnboardingOverlayOpened(tab.linkedBrowser);
tabs.push(tab);
}
for (let i = tabs.length - 1; i >= 0; --i) {
let tab = tabs[i];
for (let j = 0; j < tourIds.length; ++j) {
await assertTourCompletedStyle(tourIds[j], j % 2 == 0, tab.linkedBrowser);
--- a/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
+++ b/browser/extensions/onboarding/test/browser/browser_onboarding_tourset.js
@@ -5,17 +5,17 @@
add_task(async function test_onboarding_default_new_tourset() {
resetOnboardingDefaultState();
let tabs = [];
for (let url of URLs) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
- await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-icon", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
await promiseOnboardingOverlayOpened(tab.linkedBrowser);
tabs.push(tab);
}
let doc = content && content.document;
let doms = doc.querySelectorAll(".onboarding-tour-item");
is(doms.length, TOUR_IDs.length, "has exact tour numbers");
doms.forEach((dom, idx) => {
@@ -43,17 +43,17 @@ add_task(async function test_onboarding_
["browser.onboarding.newtour", "private,addons,customize"],
]});
let tabs = [];
for (let url of URLs) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
- await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-icon", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
await promiseOnboardingOverlayOpened(tab.linkedBrowser);
tabs.push(tab);
}
let doc = content && content.document;
let doms = doc.querySelectorAll(".onboarding-tour-item");
is(doms.length, CUSTOM_NEW_TOURs.length, "has exact tour numbers");
doms.forEach((dom, idx) => {
@@ -80,17 +80,17 @@ add_task(async function test_onboarding_
["browser.onboarding.updatetour", "customize,private,addons"],
]});
let tabs = [];
for (let url of URLs) {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserTestUtils.loadURI(tab.linkedBrowser, url);
await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
- await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-icon", {}, tab.linkedBrowser);
+ await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
await promiseOnboardingOverlayOpened(tab.linkedBrowser);
tabs.push(tab);
}
let doc = content && content.document;
let doms = doc.querySelectorAll(".onboarding-tour-item");
is(doms.length, CUSTOM_UPDATE_TOURs.length, "has exact tour numbers");
doms.forEach((dom, idx) => {