Bug 1928132: Implement dynamic Unified Search Button mode r=desktop-theme-reviewers,daleharvey,dao,tabbrowser-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D228954
This commit is contained in:
@@ -453,6 +453,9 @@ pref("browser.urlbar.scotchBonnet.enableOverride", true);
|
|||||||
pref("browser.urlbar.scotchBonnet.enableOverride", false);
|
pref("browser.urlbar.scotchBonnet.enableOverride", false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Enable displaying dynamic Unified Search Button.
|
||||||
|
pref("browser.urlbar.usb.dynamic", true);
|
||||||
|
|
||||||
// Enable trending suggestions and recent searches.
|
// Enable trending suggestions and recent searches.
|
||||||
pref("browser.urlbar.trending.featureGate", true);
|
pref("browser.urlbar.trending.featureGate", true);
|
||||||
pref("browser.urlbar.trending.requireSearchMode", false);
|
pref("browser.urlbar.trending.requireSearchMode", false);
|
||||||
|
|||||||
@@ -463,8 +463,10 @@ ChromeUtils.defineLazyGetter(this, "PopupNotifications", () => {
|
|||||||
return anchorElement;
|
return anchorElement;
|
||||||
}
|
}
|
||||||
let fallback = [
|
let fallback = [
|
||||||
|
document.getElementById("searchmode-switcher-icon"),
|
||||||
document.getElementById("identity-icon"),
|
document.getElementById("identity-icon"),
|
||||||
gURLBar.querySelector(".urlbar-search-button"),
|
gURLBar.querySelector(".urlbar-search-button"),
|
||||||
|
document.getElementById("remote-control-icon"),
|
||||||
];
|
];
|
||||||
return fallback.find(element => element?.checkVisibility()) ?? null;
|
return fallback.find(element => element?.checkVisibility()) ?? null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,29 +16,31 @@ function test() {
|
|||||||
|
|
||||||
// Focusing on notification icon buttons is handled by the ToolbarKeyboardNavigator
|
// Focusing on notification icon buttons is handled by the ToolbarKeyboardNavigator
|
||||||
// component and arrow keys (see browser/base/content/browser-toolbarKeyNav.js).
|
// component and arrow keys (see browser/base/content/browser-toolbarKeyNav.js).
|
||||||
function focusNotificationAnchor(anchor) {
|
async function focusNotificationAnchor(anchor) {
|
||||||
let urlbarContainer = anchor.closest("#urlbar-container");
|
let urlbarContainer = anchor.closest("#urlbar-container");
|
||||||
urlbarContainer.querySelector("toolbartabstop").focus();
|
|
||||||
|
|
||||||
const searchModeSwitcher = urlbarContainer.querySelector(
|
// To happen focus event on urlbar, remove the focus once.
|
||||||
|
// We intentionally turn off this a11y check, because the following click is
|
||||||
|
// purposefully targeting a non-interactive element.
|
||||||
|
AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false });
|
||||||
|
EventUtils.synthesizeMouseAtCenter(document.getElementById("browser"), {});
|
||||||
|
AccessibilityUtils.resetEnv();
|
||||||
|
|
||||||
|
// Move focus to Unified Search Button.
|
||||||
|
let searchModeSwitcher = urlbarContainer.querySelector(
|
||||||
"#urlbar-searchmode-switcher"
|
"#urlbar-searchmode-switcher"
|
||||||
);
|
);
|
||||||
is(
|
EventUtils.synthesizeKey("l", { accelKey: true });
|
||||||
document.activeElement,
|
await BrowserTestUtils.waitForCondition(
|
||||||
searchModeSwitcher,
|
() => BrowserTestUtils.isVisible(searchModeSwitcher),
|
||||||
"Search mode switcher container is focused."
|
"Wait until Unified Search Button is shown"
|
||||||
|
);
|
||||||
|
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
|
||||||
|
await BrowserTestUtils.waitForCondition(
|
||||||
|
() => document.activeElement == searchModeSwitcher,
|
||||||
|
"Wait until the focus will move to Unified Search Button"
|
||||||
);
|
);
|
||||||
|
|
||||||
EventUtils.synthesizeKey("ArrowRight");
|
|
||||||
|
|
||||||
const trackingProtectionIconContainer = urlbarContainer.querySelector(
|
|
||||||
"#tracking-protection-icon-container"
|
|
||||||
);
|
|
||||||
is(
|
|
||||||
document.activeElement,
|
|
||||||
trackingProtectionIconContainer,
|
|
||||||
"tracking protection icon container is focused."
|
|
||||||
);
|
|
||||||
while (document.activeElement !== anchor) {
|
while (document.activeElement !== anchor) {
|
||||||
EventUtils.synthesizeKey("ArrowRight");
|
EventUtils.synthesizeKey("ArrowRight");
|
||||||
}
|
}
|
||||||
@@ -127,10 +129,10 @@ var tests = [
|
|||||||
});
|
});
|
||||||
this.notification = showNotification(this.notifyObj);
|
this.notification = showNotification(this.notifyObj);
|
||||||
},
|
},
|
||||||
onShown(popup) {
|
async onShown(popup) {
|
||||||
checkPopup(popup, this.notifyObj);
|
checkPopup(popup, this.notifyObj);
|
||||||
let anchor = document.getElementById(this.notifyObj.anchorID);
|
let anchor = document.getElementById(this.notifyObj.anchorID);
|
||||||
focusNotificationAnchor(anchor);
|
await focusNotificationAnchor(anchor);
|
||||||
EventUtils.sendString(" ");
|
EventUtils.sendString(" ");
|
||||||
is(document.activeElement, popup.children[0].closebutton);
|
is(document.activeElement, popup.children[0].closebutton);
|
||||||
this.notification.remove();
|
this.notification.remove();
|
||||||
@@ -171,7 +173,7 @@ var tests = [
|
|||||||
|
|
||||||
// Activate the anchor for notification 1 and wait until it's shown.
|
// Activate the anchor for notification 1 and wait until it's shown.
|
||||||
let anchor = document.getElementById(notifyObj1.anchorID);
|
let anchor = document.getElementById(notifyObj1.anchorID);
|
||||||
focusNotificationAnchor(anchor);
|
await focusNotificationAnchor(anchor);
|
||||||
is(document.activeElement, anchor);
|
is(document.activeElement, anchor);
|
||||||
opened = waitForNotificationPanel();
|
opened = waitForNotificationPanel();
|
||||||
EventUtils.sendString(" ");
|
EventUtils.sendString(" ");
|
||||||
@@ -182,7 +184,7 @@ var tests = [
|
|||||||
|
|
||||||
// Activate the anchor for notification 2 and wait until it's shown.
|
// Activate the anchor for notification 2 and wait until it's shown.
|
||||||
anchor = document.getElementById(notifyObj2.anchorID);
|
anchor = document.getElementById(notifyObj2.anchorID);
|
||||||
focusNotificationAnchor(anchor);
|
await focusNotificationAnchor(anchor);
|
||||||
is(document.activeElement, anchor);
|
is(document.activeElement, anchor);
|
||||||
opened = waitForNotificationPanel();
|
opened = waitForNotificationPanel();
|
||||||
EventUtils.sendString(" ");
|
EventUtils.sendString(" ");
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ function test() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const FALLBACK_ANCHOR = gURLBar.searchButton
|
|
||||||
? "urlbar-search-button"
|
|
||||||
: "identity-icon";
|
|
||||||
|
|
||||||
var tests = [
|
var tests = [
|
||||||
// Test that popupnotifications are anchored to the fallback anchor on
|
// Test that popupnotifications are anchored to the fallback anchor on
|
||||||
// about:blank, where anchor icons are hidden.
|
// about:blank, where anchor icons are hidden.
|
||||||
@@ -34,7 +30,7 @@ var tests = [
|
|||||||
this.notifyObj.anchorID = "geo-notification-icon";
|
this.notifyObj.anchorID = "geo-notification-icon";
|
||||||
this.notification = showNotification(this.notifyObj);
|
this.notification = showNotification(this.notifyObj);
|
||||||
},
|
},
|
||||||
onShown(popup) {
|
async onShown(popup) {
|
||||||
checkPopup(popup, this.notifyObj);
|
checkPopup(popup, this.notifyObj);
|
||||||
is(
|
is(
|
||||||
document.getElementById("geo-notification-icon").getBoundingClientRect()
|
document.getElementById("geo-notification-icon").getBoundingClientRect()
|
||||||
@@ -42,11 +38,7 @@ var tests = [
|
|||||||
0,
|
0,
|
||||||
"geo anchor shouldn't be visible"
|
"geo anchor shouldn't be visible"
|
||||||
);
|
);
|
||||||
is(
|
assertFallbackAnchorNode(popup.anchorNode);
|
||||||
popup.anchorNode.id,
|
|
||||||
FALLBACK_ANCHOR,
|
|
||||||
"notification anchored to fallback anchor"
|
|
||||||
);
|
|
||||||
dismissNotification(popup);
|
dismissNotification(popup);
|
||||||
},
|
},
|
||||||
onHidden() {
|
onHidden() {
|
||||||
@@ -84,11 +76,7 @@ var tests = [
|
|||||||
0,
|
0,
|
||||||
"geo anchor shouldn't be visible"
|
"geo anchor shouldn't be visible"
|
||||||
);
|
);
|
||||||
is(
|
assertFallbackAnchorNode(popup.anchorNode);
|
||||||
popup.anchorNode.id,
|
|
||||||
FALLBACK_ANCHOR,
|
|
||||||
"notification anchored to fallback anchor"
|
|
||||||
);
|
|
||||||
dismissNotification(popup);
|
dismissNotification(popup);
|
||||||
},
|
},
|
||||||
onHidden() {
|
onHidden() {
|
||||||
@@ -185,11 +173,7 @@ var tests = [
|
|||||||
EventUtils.synthesizeKey("KEY_Tab");
|
EventUtils.synthesizeKey("KEY_Tab");
|
||||||
await shown;
|
await shown;
|
||||||
|
|
||||||
is(
|
assertFallbackAnchorNode(PopupNotifications.panel.anchorNode);
|
||||||
PopupNotifications.panel.anchorNode.id,
|
|
||||||
FALLBACK_ANCHOR,
|
|
||||||
"notification anchored to fallback anchor"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Moving focus to the location bar should hide the notification again.
|
// Moving focus to the location bar should hide the notification again.
|
||||||
hidden = waitForNotificationPanelHidden();
|
hidden = waitForNotificationPanelHidden();
|
||||||
@@ -292,3 +276,17 @@ var tests = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function assertFallbackAnchorNode(anchorNode) {
|
||||||
|
if (anchorNode.id == "searchmode-switcher-icon") {
|
||||||
|
Assert.ok(true, "The anchor is searchmode-switcher-icon");
|
||||||
|
} else if (anchorNode.id == "identity-icon") {
|
||||||
|
Assert.ok(true, "The anchor is identity-icon");
|
||||||
|
} else if (anchorNode.id == "remote-control-icon") {
|
||||||
|
Assert.ok(true, "The anchor is remote-control-icon");
|
||||||
|
} else if (anchorNode.classList.contains("urlbar-search-button")) {
|
||||||
|
Assert.ok(true, "The anchor is urlbar-search-button");
|
||||||
|
} else {
|
||||||
|
Assert.ok(false, "The anchor is unexpected element");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,18 +40,16 @@ add_task(async function changeSelectionUsingKeyboard() {
|
|||||||
is(document.activeElement, gURLBar.inputField, "urlbar should be focused");
|
is(document.activeElement, gURLBar.inputField, "urlbar should be focused");
|
||||||
|
|
||||||
info("Move focus to the selected tab using the keyboard");
|
info("Move focus to the selected tab using the keyboard");
|
||||||
let trackingProtectionIconContainer = document.querySelector(
|
let unifiedSearchButton = document.getElementById(
|
||||||
"#tracking-protection-icon-container"
|
"urlbar-searchmode-switcher"
|
||||||
);
|
|
||||||
await synthesizeKeyAndWaitForFocus(
|
|
||||||
trackingProtectionIconContainer,
|
|
||||||
"VK_TAB",
|
|
||||||
{ shiftKey: true }
|
|
||||||
);
|
);
|
||||||
|
await synthesizeKeyAndWaitForFocus(unifiedSearchButton, "VK_TAB", {
|
||||||
|
shiftKey: true,
|
||||||
|
});
|
||||||
is(
|
is(
|
||||||
document.activeElement,
|
document.activeElement,
|
||||||
trackingProtectionIconContainer,
|
unifiedSearchButton,
|
||||||
"tracking protection icon container should be focused"
|
"Unified Search Button should be focused"
|
||||||
);
|
);
|
||||||
await synthesizeKeyAndWaitForFocus(
|
await synthesizeKeyAndWaitForFocus(
|
||||||
document.getElementById("reload-button"),
|
document.getElementById("reload-button"),
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export class SearchModeSwitcher {
|
|||||||
#popup;
|
#popup;
|
||||||
#input;
|
#input;
|
||||||
#toolbarbutton;
|
#toolbarbutton;
|
||||||
|
#navbar;
|
||||||
|
|
||||||
constructor(input) {
|
constructor(input) {
|
||||||
this.#input = input;
|
this.#input = input;
|
||||||
@@ -41,6 +42,8 @@ export class SearchModeSwitcher {
|
|||||||
"#urlbar-searchmode-switcher"
|
"#urlbar-searchmode-switcher"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.#navbar = input.document.getElementById("nav-bar");
|
||||||
|
|
||||||
if (lazy.UrlbarPrefs.get("scotchBonnet.enableOverride")) {
|
if (lazy.UrlbarPrefs.get("scotchBonnet.enableOverride")) {
|
||||||
this.#enableObservers();
|
this.#enableObservers();
|
||||||
}
|
}
|
||||||
@@ -160,6 +163,20 @@ export class SearchModeSwitcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleEvent(event) {
|
handleEvent(event) {
|
||||||
|
if (event.type == "focus") {
|
||||||
|
this.#input.toggleAttribute("usb-available", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.type == "blur") {
|
||||||
|
if (
|
||||||
|
(this.#popup.state == "closed" || this.#popup.state == "hiding") &&
|
||||||
|
!isAncestor(this.#navbar, event.relatedTarget)
|
||||||
|
) {
|
||||||
|
this.#input.toggleAttribute("usb-available", false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.keyCode == KeyEvent.DOM_VK_TAB && this.#input.view.isOpen) {
|
if (event.keyCode == KeyEvent.DOM_VK_TAB && this.#input.view.isOpen) {
|
||||||
// The urlbar view is opening, which means the unified search button got
|
// The urlbar view is opening, which means the unified search button got
|
||||||
// focus by tab key from urlbar. So, move the focus to urlbar view to make
|
// focus by tab key from urlbar. So, move the focus to urlbar view to make
|
||||||
@@ -225,6 +242,14 @@ export class SearchModeSwitcher {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "usb.dynamic": {
|
||||||
|
if (lazy.UrlbarPrefs.get("usb.dynamic")) {
|
||||||
|
this.#enableObserversForDynamicUSB();
|
||||||
|
} else {
|
||||||
|
this.#disableObserversForDynamicUSB();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +265,12 @@ export class SearchModeSwitcher {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const inSearchMode = this.#input.searchMode;
|
const inSearchMode = this.#input.searchMode;
|
||||||
if (!inSearchMode) {
|
if (lazy.UrlbarPrefs.get("usb.dynamic")) {
|
||||||
|
const keywordEnabled = lazy.UrlbarPrefs.get("keyword.enabled");
|
||||||
|
if (!keywordEnabled && !inSearchMode) {
|
||||||
|
icon = SearchModeSwitcher.DEFAULT_ICON;
|
||||||
|
}
|
||||||
|
} else if (!inSearchMode) {
|
||||||
// Use default icon set in CSS.
|
// Use default icon set in CSS.
|
||||||
icon = null;
|
icon = null;
|
||||||
}
|
}
|
||||||
@@ -455,6 +485,8 @@ export class SearchModeSwitcher {
|
|||||||
prefsbutton.addEventListener("command", this);
|
prefsbutton.addEventListener("command", this);
|
||||||
prefsbutton.addEventListener("keypress", this);
|
prefsbutton.addEventListener("keypress", this);
|
||||||
|
|
||||||
|
this.#enableObserversForDynamicUSB();
|
||||||
|
|
||||||
this.#input.window.addEventListener(
|
this.#input.window.addEventListener(
|
||||||
"MozAfterPaint",
|
"MozAfterPaint",
|
||||||
() => this.#updateSearchIcon(),
|
() => this.#updateSearchIcon(),
|
||||||
@@ -479,5 +511,37 @@ export class SearchModeSwitcher {
|
|||||||
);
|
);
|
||||||
prefsbutton.removeEventListener("command", this);
|
prefsbutton.removeEventListener("command", this);
|
||||||
prefsbutton.removeEventListener("keypress", this);
|
prefsbutton.removeEventListener("keypress", this);
|
||||||
|
|
||||||
|
this.#disableObserversForDynamicUSB();
|
||||||
|
}
|
||||||
|
|
||||||
|
#enableObserversForDynamicUSB() {
|
||||||
|
if (
|
||||||
|
!lazy.UrlbarPrefs.get("scotchBonnet.enableOverride") ||
|
||||||
|
!lazy.UrlbarPrefs.get("usb.dynamic")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#navbar.addEventListener("focus", this, { capture: true });
|
||||||
|
this.#navbar.addEventListener("blur", this, { capture: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
#disableObserversForDynamicUSB() {
|
||||||
|
this.#navbar.removeEventListener("focus", this);
|
||||||
|
this.#navbar.removeEventListener("blur", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAncestor(ancestor, descendant) {
|
||||||
|
if (!descendant) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let element = descendant; element; element = element.parentElement) {
|
||||||
|
if (ancestor == element) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3915,6 +3915,24 @@ export class UrlbarInput {
|
|||||||
this.logger.debug("Focus Event");
|
this.logger.debug("Focus Event");
|
||||||
if (!this._hideFocus) {
|
if (!this._hideFocus) {
|
||||||
this.toggleAttribute("focused", true);
|
this.toggleAttribute("focused", true);
|
||||||
|
|
||||||
|
// Prevent from showing USB until finishing user's operation if the focus
|
||||||
|
// is moved by mouse since user might select the urlbar value.
|
||||||
|
if (
|
||||||
|
lazy.UrlbarPrefs.get("usb.dynamic") &&
|
||||||
|
Services.focus.getLastFocusMethod(this.window) ==
|
||||||
|
Services.focus.FLAG_BYMOUSE &&
|
||||||
|
this.getAttribute("pageproxystate") == "valid"
|
||||||
|
) {
|
||||||
|
this.toggleAttribute("usb-focus-processing", true);
|
||||||
|
this.window.addEventListener(
|
||||||
|
"mouseup",
|
||||||
|
() => {
|
||||||
|
this.removeAttribute("usb-focus-processing");
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the value was trimmed, check whether we should untrim it.
|
// If the value was trimmed, check whether we should untrim it.
|
||||||
|
|||||||
@@ -542,6 +542,9 @@ const PREF_URLBAR_DEFAULTS = new Map([
|
|||||||
// Note: This pref will be removed once the feature is stable.
|
// Note: This pref will be removed once the feature is stable.
|
||||||
["untrimOnUserInteraction.featureGate", false],
|
["untrimOnUserInteraction.featureGate", false],
|
||||||
|
|
||||||
|
// Enable displaying dynamic Unified Search Button.
|
||||||
|
["usb.dynamic", false],
|
||||||
|
|
||||||
// Feature gate pref for weather suggestions in the urlbar.
|
// Feature gate pref for weather suggestions in the urlbar.
|
||||||
["weather.featureGate", false],
|
["weather.featureGate", false],
|
||||||
|
|
||||||
|
|||||||
@@ -447,6 +447,9 @@ support-files = ["dummy_page.html"]
|
|||||||
|
|
||||||
["browser_searchModeSwitcher_basic.js"]
|
["browser_searchModeSwitcher_basic.js"]
|
||||||
|
|
||||||
|
["browser_searchModeSwitcher_dynamicUSB.js"]
|
||||||
|
support-files = ["has-a-link.html"]
|
||||||
|
|
||||||
["browser_searchModeSwitcher_keyNavigation.js"]
|
["browser_searchModeSwitcher_keyNavigation.js"]
|
||||||
|
|
||||||
["browser_searchMode_alias_replacement.js"]
|
["browser_searchMode_alias_replacement.js"]
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const TEST_URL = `${TEST_BASE_URL}has-a-link.html`;
|
||||||
|
|
||||||
|
ChromeUtils.defineESModuleGetters(this, {
|
||||||
|
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
|
});
|
||||||
|
|
||||||
|
add_setup(async function setup() {
|
||||||
|
await SpecialPowers.pushPrefEnv({
|
||||||
|
set: [["browser.urlbar.scotchBonnet.enableOverride", true]],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_usb_visibility_by_tab() {
|
||||||
|
for (const shiftKey of [false, true]) {
|
||||||
|
info(`Test for shiftKey:${shiftKey}`);
|
||||||
|
|
||||||
|
info("Open pageproxystate valid page");
|
||||||
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
|
||||||
|
Assert.equal(gURLBar.getAttribute("pageproxystate"), "valid");
|
||||||
|
info("Ensure to move focus to browser element");
|
||||||
|
focusOnBrowserElement();
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
info("Focus on urlabr");
|
||||||
|
EventUtils.synthesizeKey("l", { accelKey: true });
|
||||||
|
await UrlbarTestUtils.promiseSearchComplete(window);
|
||||||
|
await assertUSBVisibility(true);
|
||||||
|
Assert.equal(document.activeElement.id, "urlbar-input");
|
||||||
|
Assert.ok(gURLBar.view.isOpen);
|
||||||
|
Assert.ok(!gURLBar.view.selectedElement);
|
||||||
|
|
||||||
|
info("Move the focus until urlbar has it again");
|
||||||
|
let ok = false;
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
let previousActiveElement = document.activeElement;
|
||||||
|
EventUtils.synthesizeKey("KEY_Tab", { shiftKey });
|
||||||
|
await BrowserTestUtils.waitForCondition(
|
||||||
|
() => previousActiveElement != document.activeElement,
|
||||||
|
"Wait until the active element is changed"
|
||||||
|
);
|
||||||
|
await assertUSBVisibility(!!document.activeElement.closest("#nav-bar"));
|
||||||
|
Assert.ok(true, "USB visibility is correct");
|
||||||
|
|
||||||
|
ok = document.activeElement.id == "urlbar-input";
|
||||||
|
if (ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.ok(ok, "Focus was moved back to urlabr via other components");
|
||||||
|
await BrowserTestUtils.removeTab(tab);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_usb_visibility_by_mouse() {
|
||||||
|
info("Open pageproxystate valid page");
|
||||||
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||||
|
gBrowser,
|
||||||
|
"https://example.com/"
|
||||||
|
);
|
||||||
|
Assert.equal(gURLBar.getAttribute("pageproxystate"), "valid");
|
||||||
|
info("Ensure to move focus to browser element");
|
||||||
|
focusOnBrowserElement();
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
info("Click on urlbar");
|
||||||
|
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {});
|
||||||
|
await assertUSBVisibility(true);
|
||||||
|
|
||||||
|
info("Click on browser element");
|
||||||
|
focusOnBrowserElement();
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
info("Click on urlbar again");
|
||||||
|
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {});
|
||||||
|
await assertUSBVisibility(true);
|
||||||
|
|
||||||
|
info("Simulate to lost focus from the current window");
|
||||||
|
let newWin = await BrowserTestUtils.openNewBrowserWindow();
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
await BrowserTestUtils.closeWindow(newWin);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_usb_visibility_by_mouse_drag() {
|
||||||
|
info("Open pageproxystate valid page");
|
||||||
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||||
|
gBrowser,
|
||||||
|
"https://example.com/"
|
||||||
|
);
|
||||||
|
Assert.equal(gURLBar.getAttribute("pageproxystate"), "valid");
|
||||||
|
info("Ensure to move focus to browser element");
|
||||||
|
focusOnBrowserElement();
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
info("Mouse down on urlbar");
|
||||||
|
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mousedown" });
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
info("Hold mouse down 1sec");
|
||||||
|
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
||||||
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
info("Mouse up on urlbar");
|
||||||
|
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, { type: "mouseup" });
|
||||||
|
await assertUSBVisibility(true);
|
||||||
|
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_usb_visibility_during_popup() {
|
||||||
|
info("Open pageproxystate valid page");
|
||||||
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
||||||
|
gBrowser,
|
||||||
|
"https://example.com/"
|
||||||
|
);
|
||||||
|
Assert.equal(gURLBar.getAttribute("pageproxystate"), "valid");
|
||||||
|
info("Ensure to move focus to browser element");
|
||||||
|
focusOnBrowserElement();
|
||||||
|
await assertUSBVisibility(false);
|
||||||
|
|
||||||
|
info("Focus on urlabr");
|
||||||
|
EventUtils.synthesizeKey("l", { accelKey: true });
|
||||||
|
await UrlbarTestUtils.promiseSearchComplete(window);
|
||||||
|
await assertUSBVisibility(true);
|
||||||
|
|
||||||
|
info("Open popup");
|
||||||
|
await UrlbarTestUtils.openSearchModeSwitcher(window);
|
||||||
|
await assertUSBVisibility(true);
|
||||||
|
|
||||||
|
info("Close popup");
|
||||||
|
let popupHidden = UrlbarTestUtils.searchModeSwitcherPopupClosed(window);
|
||||||
|
EventUtils.synthesizeKey("KEY_Escape");
|
||||||
|
await popupHidden;
|
||||||
|
await assertUSBVisibility(true);
|
||||||
|
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function assertUSBVisibility(expected) {
|
||||||
|
let switcher = document.getElementById("urlbar-searchmode-switcher");
|
||||||
|
await BrowserTestUtils.waitForCondition(
|
||||||
|
() => BrowserTestUtils.isVisible(switcher) == expected,
|
||||||
|
`Wait until USB visibility will be changed to ${expected}`
|
||||||
|
);
|
||||||
|
Assert.ok(true, "USB visibility is correct");
|
||||||
|
}
|
||||||
|
|
||||||
|
function focusOnBrowserElement() {
|
||||||
|
// We intentionally turn off this a11y check, because the following click is
|
||||||
|
// purposefully targeting a non-interactive element.
|
||||||
|
AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false });
|
||||||
|
EventUtils.synthesizeMouseAtCenter(document.getElementById("browser"), {});
|
||||||
|
AccessibilityUtils.resetEnv();
|
||||||
|
}
|
||||||
@@ -289,7 +289,7 @@ async function test_focus_order_with_no_results({ input, shiftKey }) {
|
|||||||
|
|
||||||
add_task(async function test_focus_order_by_tab_with_no_selected_element() {
|
add_task(async function test_focus_order_by_tab_with_no_selected_element() {
|
||||||
for (const shiftKey of [false, true]) {
|
for (const shiftKey of [false, true]) {
|
||||||
info(`Test for shifrKey:${shiftKey}`);
|
info(`Test for shiftKey:${shiftKey}`);
|
||||||
|
|
||||||
info("Open urlbar results");
|
info("Open urlbar results");
|
||||||
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
await UrlbarTestUtils.promiseAutocompleteResultPopup({
|
||||||
|
|||||||
1
browser/components/urlbar/tests/browser/has-a-link.html
Normal file
1
browser/components/urlbar/tests/browser/has-a-link.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<a href="#">link</a>
|
||||||
@@ -386,10 +386,23 @@ async function searchWithTab(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function focusSwitcher(win = window) {
|
async function focusSwitcher(win = window) {
|
||||||
if (!win.gURLBar.focused) {
|
// To happen focus event on urlbar, remove the focus once.
|
||||||
let focus = BrowserTestUtils.waitForEvent(win.gURLBar.inputField, "focus");
|
// We intentionally turn off this a11y check, because the following click is
|
||||||
EventUtils.synthesizeKey("l", { accelKey: true }, win);
|
// purposefully targeting a non-interactive element.
|
||||||
await focus;
|
AccessibilityUtils.setEnv({ mustHaveAccessibleRule: false });
|
||||||
}
|
EventUtils.synthesizeMouseAtCenter(
|
||||||
|
win.document.getElementById("browser"),
|
||||||
|
{},
|
||||||
|
win
|
||||||
|
);
|
||||||
|
AccessibilityUtils.resetEnv();
|
||||||
|
|
||||||
|
let focus = BrowserTestUtils.waitForEvent(win.gURLBar.inputField, "focus");
|
||||||
|
EventUtils.synthesizeKey("l", { accelKey: true }, win);
|
||||||
|
await focus;
|
||||||
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true }, win);
|
EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true }, win);
|
||||||
|
let switcher = win.document.getElementById("urlbar-searchmode-switcher");
|
||||||
|
await BrowserTestUtils.waitForCondition(
|
||||||
|
() => win.document.activeElement == switcher
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ body {
|
|||||||
/* This should be used for icons and chiclets inside the input field. It makes
|
/* This should be used for icons and chiclets inside the input field. It makes
|
||||||
the gap around them more uniform when they are close to the field edges */
|
the gap around them more uniform when they are close to the field edges */
|
||||||
--urlbar-icon-border-radius: calc(var(--toolbarbutton-border-radius) - 1px);
|
--urlbar-icon-border-radius: calc(var(--toolbarbutton-border-radius) - 1px);
|
||||||
--urlbar-searchmodeswitcher-spacing: 6px;
|
--urlbar-searchmodeswitcher-inline-padding: 6px;
|
||||||
|
|
||||||
--pocket-icon-fill: #ef4056;
|
--pocket-icon-fill: #ef4056;
|
||||||
|
|
||||||
|
|||||||
@@ -1117,7 +1117,7 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
|
|||||||
border-radius: var(--urlbar-icon-border-radius);
|
border-radius: var(--urlbar-icon-border-radius);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-inline-end: var(--urlbar-icon-padding);
|
margin-inline-end: var(--urlbar-icon-padding);
|
||||||
padding-inline: var(--urlbar-searchmodeswitcher-spacing);
|
padding-inline: var(--urlbar-searchmodeswitcher-inline-padding);
|
||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
outline: var(--focus-outline);
|
outline: var(--focus-outline);
|
||||||
@@ -1193,7 +1193,7 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
|
|||||||
#searchmode-switcher-close {
|
#searchmode-switcher-close {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
margin-inline: var(--urlbar-searchmodeswitcher-spacing);
|
margin-inline: var(--urlbar-searchmodeswitcher-inline-padding);
|
||||||
|
|
||||||
#urlbar[searchmode] & {
|
#urlbar[searchmode] & {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
@@ -1223,4 +1223,25 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after {
|
|||||||
#urlbar[searchmode] > .urlbar-input-container > #urlbar-search-mode-indicator {
|
#urlbar[searchmode] > .urlbar-input-container > #urlbar-search-mode-indicator {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* stylelint-disable-next-line media-query-no-invalid */
|
||||||
|
@media (-moz-bool-pref: "browser.urlbar.usb.dynamic") {
|
||||||
|
#urlbar-searchmode-switcher {
|
||||||
|
background-color: var(--urlbar-box-bgcolor);
|
||||||
|
#urlbar:is([usb-focus-processing], :not([usb-available], [pageproxystate=invalid])) & {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchmode-switcher-dropmarker {
|
||||||
|
margin-inline-start: var(--urlbar-searchmodeswitcher-inline-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
#urlbar[pageproxystate=invalid] {
|
||||||
|
#identity-box,
|
||||||
|
#tracking-protection-icon-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user