Bug 1800417 - Fix the use of both `toolbarbutton-1` and `subviewbutton` CSS classes in extension widgets. r=Itiel,mconley,dao,rpl

Depends on D169088

Differential Revision: https://phabricator.services.mozilla.com/D162712
This commit is contained in:
William Durand 2023-02-08 10:25:02 +00:00
Родитель b5a93c9176
Коммит 3ab4cbac72
5 изменённых файлов: 398 добавлений и 101 удалений

Просмотреть файл

@ -1258,16 +1258,21 @@ var gUnifiedExtensions = {
lazy.ExtensionPermissions.addListener(this.permListener);
gNavToolbox.addEventListener("customizationstarting", this);
CustomizableUI.addListener(this);
this._initialized = true;
},
uninit() {
if (this.permListener) {
lazy.ExtensionPermissions.removeListener(this.permListener);
this.permListener = null;
if (!this._initialized) {
return;
}
lazy.ExtensionPermissions.removeListener(this.permListener);
this.permListener = null;
gNavToolbox.removeEventListener("customizationstarting", this);
CustomizableUI.removeListener(this);
},
onLocationChange(browser, webProgress, _request, _uri, flags) {
@ -1622,4 +1627,74 @@ var gUnifiedExtensions = {
this.updateAttention();
},
onWidgetAdded(aWidgetId, aArea, aPosition) {
// When we pin a widget to the toolbar from a narrow window, the widget
// will be overflowed directly. In this case, we do not want to change the
// class name since it is going to be changed by `onWidgetOverflow()`
// below.
if (CustomizableUI.getWidget(aWidgetId)?.forWindow(window)?.overflowed) {
return;
}
const inPanel =
CustomizableUI.getAreaType(aArea) !== CustomizableUI.TYPE_TOOLBAR;
this._updateWidgetClassName(aWidgetId, inPanel);
},
onWidgetOverflow(aNode, aContainer) {
// We register a CUI listener for each window so we make sure that we
// handle the event for the right window here.
if (window !== aNode.ownerGlobal) {
return;
}
this._updateWidgetClassName(aNode.getAttribute("widget-id"), true);
},
onWidgetUnderflow(aNode, aContainer) {
// We register a CUI listener for each window so we make sure that we
// handle the event for the right window here.
if (window !== aNode.ownerGlobal) {
return;
}
this._updateWidgetClassName(aNode.getAttribute("widget-id"), false);
},
onAreaNodeRegistered(aArea, aContainer) {
// We register a CUI listener for each window so we make sure that we
// handle the event for the right window here.
if (window !== aContainer.ownerGlobal) {
return;
}
const inPanel =
CustomizableUI.getAreaType(aArea) !== CustomizableUI.TYPE_TOOLBAR;
for (const widgetId of CustomizableUI.getWidgetIdsInArea(aArea)) {
this._updateWidgetClassName(widgetId, inPanel);
}
},
// This internal method is used to change some CSS classnames on the action
// button of an extension (CUI) widget. When the widget is placed in the
// panel, the action button should have the `.subviewbutton` class and not
// the `.toolbarbutton-1` one. When NOT placed in the panel, it is the other
// way around.
_updateWidgetClassName(aWidgetId, inPanel) {
if (!CustomizableUI.isWebExtensionWidget(aWidgetId)) {
return;
}
const node = CustomizableUI.getWidget(aWidgetId)?.forWindow(window)?.node;
if (node) {
const actionButton = node.querySelector(
".unified-extensions-item-action-button"
);
actionButton.classList.toggle("subviewbutton", inPanel);
actionButton.classList.toggle("toolbarbutton-1", !inPanel);
}
},
};

Просмотреть файл

@ -219,11 +219,7 @@ this.browserAction = class extends ExtensionAPIPersistent {
// Ensure the extension context menuitems are available by setting this
// on all button children and the item.
button.setAttribute("data-extensionid", extension.id);
button.classList.add(
"toolbarbutton-1",
"unified-extensions-item-action-button",
"subviewbutton"
);
button.classList.add("unified-extensions-item-action-button");
let contents = document.createXULElement("vbox");
contents.classList.add("unified-extensions-item-contents");

Просмотреть файл

@ -1329,3 +1329,48 @@ add_task(async function test_temporary_access() {
}
);
});
add_task(async function test_action_button_css_class_with_new_window() {
const [extension] = createExtensions([
{
name: "an extension placed in the extensions panel",
browser_action: {
default_area: "menupanel",
},
},
]);
await extension.startup();
let aSecondWindow = await BrowserTestUtils.openNewBrowserWindow();
await ensureMaximizedWindow(aSecondWindow);
// Open and close the extensions panel in the newly created window to build
// the extensions panel and add the extension widget(s) to it.
await openExtensionsPanel(aSecondWindow);
await closeExtensionsPanel(aSecondWindow);
for (const { title, win } of [
{ title: "current window", win: window },
{ title: "second window", win: aSecondWindow },
]) {
const node = CustomizableUI.getWidget(
AppUiTestInternals.getBrowserActionWidgetId(extension.id)
).forWindow(win).node;
let actionButton = node.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButton.classList.contains("subviewbutton"),
`${title} - expected .subviewbutton CSS class on the action button`
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
`${title} - expected no .toolbarbutton-1 CSS class on the action button`
);
}
await BrowserTestUtils.closeWindow(aSecondWindow);
await extension.unload();
});

Просмотреть файл

@ -315,11 +315,21 @@ async function withWindowOverflowed(
async function verifyExtensionWidget(win, widget) {
Assert.ok(widget, "expected widget");
let actionButton = widget.firstElementChild;
let actionButton = widget.querySelector(
".unified-extensions-item-action-button"
);
Assert.ok(
actionButton.classList.contains("unified-extensions-item-action-button"),
"expected action class on the button"
);
ok(
actionButton.classList.contains("subviewbutton"),
"expected the .subviewbutton CSS class on the action button in the panel"
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
"expected no .toolbarbutton-1 CSS class on the action button in the panel"
);
let menuButton = widget.lastElementChild;
Assert.ok(
@ -401,10 +411,9 @@ async function verifyExtensionWidget(win, widget) {
* panel.
*/
add_task(async function test_overflowable_toolbar() {
let win = await BrowserTestUtils.openNewBrowserWindow();
let movedNode;
await withWindowOverflowed(win, {
await withWindowOverflowed(window, {
whenOverflowed: async (defaultList, unifiedExtensionList, extensionIDs) => {
// Ensure that there are 5 items in the Unified Extensions overflow
// list, and the default widgets should all be in the default overflow
@ -429,13 +438,13 @@ add_task(async function test_overflowable_toolbar() {
extensionIDs.includes(child.dataset.extensionid),
`Unified Extensions overflow list should have ${child.dataset.extensionid}`
);
await verifyExtensionWidget(win, child, true);
await verifyExtensionWidget(window, child, true);
}
let extensionWidgetID = AppUiTestInternals.getBrowserActionWidgetId(
extensionIDs.at(-1)
);
movedNode = CustomizableUI.getWidget(extensionWidgetID).forWindow(win)
movedNode = CustomizableUI.getWidget(extensionWidgetID).forWindow(window)
.node;
Assert.equal(movedNode.getAttribute("cui-areatype"), "toolbar");
@ -460,14 +469,10 @@ add_task(async function test_overflowable_toolbar() {
CustomizableUI.addWidgetToArea(movedNode.id, CustomizableUI.AREA_NAVBAR);
},
});
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_context_menu() {
let win = await BrowserTestUtils.openNewBrowserWindow();
await withWindowOverflowed(win, {
await withWindowOverflowed(window, {
whenOverflowed: async (defaultList, unifiedExtensionList, extensionIDs) => {
Assert.ok(
unifiedExtensionList.children.length,
@ -475,7 +480,7 @@ add_task(async function test_context_menu() {
);
// Open the extension panel.
await openExtensionsPanel(win);
await openExtensionsPanel();
// Let's verify the context menus for the following extensions:
//
@ -487,8 +492,7 @@ add_task(async function test_context_menu() {
const firstExtensionWidget = unifiedExtensionList.children[0];
Assert.ok(firstExtensionWidget, "expected extension widget");
let contextMenu = await openUnifiedExtensionsContextMenu(
firstExtensionWidget.dataset.extensionid,
win
firstExtensionWidget.dataset.extensionid
);
Assert.ok(contextMenu, "expected a context menu");
let visibleItems = getVisibleMenuItems(contextMenu);
@ -515,14 +519,13 @@ add_task(async function test_context_menu() {
"expected separator after last menu item created by the extension"
);
await closeChromeContextMenu(contextMenu.id, null, win);
await closeChromeContextMenu(contextMenu.id, null);
info("extension with browser action and a menu with submenu");
const secondExtensionWidget = unifiedExtensionList.children[1];
Assert.ok(secondExtensionWidget, "expected extension widget");
contextMenu = await openUnifiedExtensionsContextMenu(
secondExtensionWidget.dataset.extensionid,
win
secondExtensionWidget.dataset.extensionid
);
visibleItems = getVisibleMenuItems(contextMenu);
is(visibleItems.length, 7, "expected 7 menu items");
@ -536,7 +539,7 @@ add_task(async function test_context_menu() {
// The number of items in the (main) context menu should remain the same.
visibleItems = getVisibleMenuItems(contextMenu);
is(visibleItems.length, 7, "expected 7 menu items");
await closeChromeContextMenu(contextMenu.id, null, win);
await closeChromeContextMenu(contextMenu.id, null);
info("extension with no browser action and no menu");
// There is no context menu created by this extension, so there should
@ -545,27 +548,22 @@ add_task(async function test_context_menu() {
const thirdExtensionWidget = unifiedExtensionList.children[2];
Assert.ok(thirdExtensionWidget, "expected extension widget");
contextMenu = await openUnifiedExtensionsContextMenu(
thirdExtensionWidget.dataset.extensionid,
win
thirdExtensionWidget.dataset.extensionid
);
Assert.ok(contextMenu, "expected a context menu");
visibleItems = getVisibleMenuItems(contextMenu);
is(visibleItems.length, 5, "expected 5 menu items");
await closeChromeContextMenu(contextMenu.id, null, win);
await closeChromeContextMenu(contextMenu.id, null);
// We can close the unified extensions panel now.
await closeExtensionsPanel(win);
await closeExtensionsPanel();
},
});
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_message_deck() {
let win = await BrowserTestUtils.openNewBrowserWindow();
await withWindowOverflowed(win, {
await withWindowOverflowed(window, {
whenOverflowed: async (defaultList, unifiedExtensionList, extensionIDs) => {
Assert.ok(
unifiedExtensionList.children.length,
@ -581,15 +579,14 @@ add_task(async function test_message_deck() {
// Navigate to a page where `activeTab` is useful.
await BrowserTestUtils.withNewTab(
{ gBrowser: win.gBrowser, url: "https://example.com/" },
{ gBrowser, url: "https://example.com/" },
async () => {
// Open the extension panel.
await openExtensionsPanel(win);
await openExtensionsPanel();
info("verify message when focusing the action button");
const item = getUnifiedExtensionsItem(
firstExtensionWidget.dataset.extensionid,
win
firstExtensionWidget.dataset.extensionid
);
Assert.ok(item, "expected an item for the extension");
@ -609,7 +606,7 @@ add_task(async function test_message_deck() {
Assert.ok(messageDeck, "expected message deck");
is(
messageDeck.selectedIndex,
win.gUnifiedExtensions.MESSAGE_DECK_INDEX_DEFAULT,
gUnifiedExtensions.MESSAGE_DECK_INDEX_DEFAULT,
"expected selected message in the deck to be the default message"
);
@ -617,7 +614,7 @@ add_task(async function test_message_deck() {
".unified-extensions-item-message-default"
);
Assert.deepEqual(
win.document.l10n.getAttributes(defaultMessage),
document.l10n.getAttributes(defaultMessage),
{ id: "origin-controls-state-when-clicked", args: null },
"expected correct l10n attributes for the default message"
);
@ -630,7 +627,7 @@ add_task(async function test_message_deck() {
".unified-extensions-item-message-hover"
);
Assert.deepEqual(
win.document.l10n.getAttributes(hoverMessage),
document.l10n.getAttributes(hoverMessage),
{ id: "origin-controls-state-hover-run-visit-only", args: null },
"expected correct l10n attributes for the hover message"
);
@ -643,7 +640,7 @@ add_task(async function test_message_deck() {
".unified-extensions-item-message-hover-menu-button"
);
Assert.deepEqual(
win.document.l10n.getAttributes(hoverMenuButtonMessage),
document.l10n.getAttributes(hoverMenuButtonMessage),
{ id: "unified-extensions-item-message-manage", args: null },
"expected correct l10n attributes for the message when hovering the menu button"
);
@ -654,42 +651,42 @@ add_task(async function test_message_deck() {
// 1. Focus the action button of the first extension in the panel.
let focused = BrowserTestUtils.waitForEvent(actionButton, "focus");
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey("VK_TAB", {});
await focused;
is(
actionButton,
win.document.activeElement,
document.activeElement,
"expected action button of the first extension item to be focused"
);
is(
messageDeck.selectedIndex,
win.gUnifiedExtensions.MESSAGE_DECK_INDEX_HOVER,
gUnifiedExtensions.MESSAGE_DECK_INDEX_HOVER,
"expected selected message in the deck to be the hover message"
);
// 2. Focus the menu button, causing the action button to lose focus.
focused = BrowserTestUtils.waitForEvent(menuButton, "focus");
EventUtils.synthesizeKey("VK_TAB", {}, win);
EventUtils.synthesizeKey("VK_TAB", {});
await focused;
is(
menuButton,
win.document.activeElement,
document.activeElement,
"expected menu button of the first extension item to be focused"
);
is(
messageDeck.selectedIndex,
win.gUnifiedExtensions.MESSAGE_DECK_INDEX_MENU_HOVER,
gUnifiedExtensions.MESSAGE_DECK_INDEX_MENU_HOVER,
"expected selected message in the deck to be the message when focusing the menu button"
);
await closeExtensionsPanel(win);
await closeExtensionsPanel();
info("verify message when hovering the action button");
await openExtensionsPanel(win);
await openExtensionsPanel();
is(
messageDeck.selectedIndex,
win.gUnifiedExtensions.MESSAGE_DECK_INDEX_DEFAULT,
gUnifiedExtensions.MESSAGE_DECK_INDEX_DEFAULT,
"expected selected message in the deck to be the default message"
);
@ -698,40 +695,32 @@ add_task(async function test_message_deck() {
actionButton,
"mouseover"
);
EventUtils.synthesizeMouseAtCenter(
actionButton,
{ type: "mouseover" },
win
);
EventUtils.synthesizeMouseAtCenter(actionButton, {
type: "mouseover",
});
await hovered;
is(
messageDeck.selectedIndex,
win.gUnifiedExtensions.MESSAGE_DECK_INDEX_HOVER,
gUnifiedExtensions.MESSAGE_DECK_INDEX_HOVER,
"expected selected message in the deck to be the hover message"
);
// 2. Hover the menu button, causing the action button to no longer
// be hovered.
hovered = BrowserTestUtils.waitForEvent(menuButton, "mouseover");
EventUtils.synthesizeMouseAtCenter(
menuButton,
{ type: "mouseover" },
win
);
EventUtils.synthesizeMouseAtCenter(menuButton, { type: "mouseover" });
await hovered;
is(
messageDeck.selectedIndex,
win.gUnifiedExtensions.MESSAGE_DECK_INDEX_MENU_HOVER,
gUnifiedExtensions.MESSAGE_DECK_INDEX_MENU_HOVER,
"expected selected message in the deck to be the message when hovering the menu button"
);
await closeExtensionsPanel(win);
await closeExtensionsPanel();
}
);
},
});
await BrowserTestUtils.closeWindow(win);
});
/**
@ -740,11 +729,11 @@ add_task(async function test_message_deck() {
* button is put into the addons panel overflow list.
*/
add_task(async function test_pinning_to_toolbar_when_overflowed() {
let win = await BrowserTestUtils.openNewBrowserWindow();
let movedNode;
let extensionWidgetID;
let actionButton;
await withWindowOverflowed(win, {
await withWindowOverflowed(window, {
beforeOverflowed: async extensionIDs => {
// Before we overflow the toolbar, let's move the last item to the addons
// panel.
@ -752,15 +741,45 @@ add_task(async function test_pinning_to_toolbar_when_overflowed() {
extensionIDs.at(-1)
);
movedNode = CustomizableUI.getWidget(extensionWidgetID).forWindow(win)
movedNode = CustomizableUI.getWidget(extensionWidgetID).forWindow(window)
.node;
actionButton = movedNode.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButton.classList.contains("toolbarbutton-1"),
"expected .toolbarbutton-1 CSS class on the action button in the navbar"
);
ok(
!actionButton.classList.contains("subviewbutton"),
"expected no .subviewbutton CSS class on the action button in the navbar"
);
CustomizableUI.addWidgetToArea(
extensionWidgetID,
CustomizableUI.AREA_ADDONS
);
ok(
actionButton.classList.contains("subviewbutton"),
"expected .subviewbutton CSS class on the action button in the panel"
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
"expected no .toolbarbutton-1 CSS class on the action button in the panel"
);
},
whenOverflowed: async (defaultList, unifiedExtensionList, extensionIDs) => {
ok(
actionButton.classList.contains("subviewbutton"),
"expected .subviewbutton CSS class on the action button in the panel"
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
"expected no .toolbarbutton-1 CSS class on the action button in the panel"
);
// Now that the window is overflowed, let's move the widget in the addons
// panel back to the navbar. This should cause the widget to overflow back
// into the addons panel.
@ -776,10 +795,17 @@ add_task(async function test_pinning_to_toolbar_when_overflowed() {
unifiedExtensionList,
"Should have overflowed the extension button to the right list."
);
ok(
actionButton.classList.contains("subviewbutton"),
"expected no .subviewbutton CSS class on the action button in the panel"
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
"expected .toolbarbutton-1 CSS class on the action button in the panel"
);
},
});
await BrowserTestUtils.closeWindow(win);
});
/**
@ -789,11 +815,10 @@ add_task(async function test_pinning_to_toolbar_when_overflowed() {
* extension into the dedicated addons area of the panel, and that the item
* then does not underflow.
*/
add_task(async function test_() {
let win = await BrowserTestUtils.openNewBrowserWindow();
add_task(async function test_unpin_overflowed_widget() {
let extensionID;
await withWindowOverflowed(win, {
await withWindowOverflowed(window, {
whenOverflowed: async (defaultList, unifiedExtensionList, extensionIDs) => {
const firstExtensionWidget = unifiedExtensionList.children[0];
Assert.ok(firstExtensionWidget, "expected an extension widget");
@ -801,7 +826,7 @@ add_task(async function test_() {
let movedNode = CustomizableUI.getWidget(
firstExtensionWidget.id
).forWindow(win).node;
).forWindow(window).node;
Assert.equal(
movedNode.getAttribute("cui-areatype"),
"toolbar",
@ -811,15 +836,23 @@ add_task(async function test_() {
movedNode.hasAttribute("overflowedItem"),
"expected extension widget to be overflowed"
);
let actionButton = movedNode.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButton.classList.contains("subviewbutton"),
"expected the .subviewbutton CSS class on the action button in the panel"
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
"expected no .toolbarbutton-1 CSS class on the action button in the panel"
);
// Open the panel, then the context menu of the extension widget, verify
// the 'Pin to Toolbar' menu item, then click on this menu item to
// uncheck it (i.e. unpin the extension).
await openExtensionsPanel(win);
const contextMenu = await openUnifiedExtensionsContextMenu(
extensionID,
win
);
await openExtensionsPanel();
const contextMenu = await openUnifiedExtensionsContextMenu(extensionID);
Assert.ok(contextMenu, "expected a context menu");
const pinToToolbar = contextMenu.querySelector(
@ -839,7 +872,7 @@ add_task(async function test_() {
// Uncheck "Pin to Toolbar" menu item. Clicking a menu item in the
// context menu closes the unified extensions panel automatically.
const hidden = BrowserTestUtils.waitForEvent(
win.gUnifiedExtensions.panel,
gUnifiedExtensions.panel,
"popuphidden",
true
);
@ -863,15 +896,162 @@ add_task(async function test_() {
);
},
afterUnderflowed: async () => {
await openExtensionsPanel(win);
await openExtensionsPanel();
const item = getUnifiedExtensionsItem(extensionID, win);
const item = getUnifiedExtensionsItem(extensionID);
Assert.ok(
item,
"expected extension widget to be listed in the unified extensions panel"
);
let actionButton = item.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButton.classList.contains("subviewbutton"),
"expected the .subviewbutton CSS class on the action button in the panel"
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
"expected no .toolbarbutton-1 CSS class on the action button in the panel"
);
await closeExtensionsPanel(win);
await closeExtensionsPanel();
},
});
});
add_task(async function test_overflow_with_a_second_window() {
// Open a second window that will stay maximized. We want to be sure that
// overflowing a widget in one window isn't going to affect the other window
// since we have an instance (of a CUI widget) per window.
let win = await BrowserTestUtils.openNewBrowserWindow();
await ensureMaximizedWindow(win);
let extensionWidgetID;
let aNode;
let aNodeInSecondWindow;
await withWindowOverflowed(window, {
beforeOverflowed: async extensionIDs => {
extensionWidgetID = AppUiTestInternals.getBrowserActionWidgetId(
extensionIDs.at(-1)
);
// This is the DOM node for the current window that is overflowed.
aNode = CustomizableUI.getWidget(extensionWidgetID).forWindow(window)
.node;
Assert.ok(
!aNode.hasAttribute("overflowedItem"),
"expected extension widget to NOT be overflowed"
);
let actionButton = aNode.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButton.classList.contains("toolbarbutton-1"),
"expected .toolbarbutton-1 CSS class on the action button"
);
ok(
!actionButton.classList.contains("subviewbutton"),
"expected no .subviewbutton CSS class on the action button"
);
// This is the DOM node of the same CUI widget but in the maximized
// window opened before.
aNodeInSecondWindow = CustomizableUI.getWidget(
extensionWidgetID
).forWindow(win).node;
let actionButtonInSecondWindow = aNodeInSecondWindow.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButtonInSecondWindow.classList.contains("toolbarbutton-1"),
"expected .toolbarbutton-1 CSS class on the action button in the second window"
);
ok(
!actionButtonInSecondWindow.classList.contains("subviewbutton"),
"expected no .subviewbutton CSS class on the action button in the second window"
);
},
whenOverflowed: async (defaultList, unifiedExtensionList, extensionIDs) => {
// The DOM node should have been overflowed.
Assert.ok(
aNode.hasAttribute("overflowedItem"),
"expected extension widget to be overflowed"
);
Assert.equal(
aNode.getAttribute("widget-id"),
extensionWidgetID,
"expected the CUI widget ID to be set on the DOM node"
);
// When the node is overflowed, we swap the CSS class on the action
// button since the node is now placed in the extensions panel.
let actionButton = aNode.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButton.classList.contains("subviewbutton"),
"expected the .subviewbutton CSS class on the action button"
);
ok(
!actionButton.classList.contains("toolbarbutton-1"),
"expected no .toolbarbutton-1 CSS class on the action button"
);
// The DOM node in the other window should not have been overflowed.
Assert.ok(
!aNodeInSecondWindow.hasAttribute("overflowedItem"),
"expected extension widget to NOT be overflowed in the other window"
);
Assert.equal(
aNodeInSecondWindow.getAttribute("widget-id"),
extensionWidgetID,
"expected the CUI widget ID to be set on the DOM node"
);
// We expect no CSS class changes for the node in the other window.
let actionButtonInSecondWindow = aNodeInSecondWindow.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButtonInSecondWindow.classList.contains("toolbarbutton-1"),
"expected .toolbarbutton-1 CSS class on the action button in the second window"
);
ok(
!actionButtonInSecondWindow.classList.contains("subviewbutton"),
"expected no .subviewbutton CSS class on the action button in the second window"
);
},
afterUnderflowed: async () => {
// After underflow, we expect the CSS class on the action button of the
// DOM node of the current window to be updated.
let actionButton = aNode.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButton.classList.contains("toolbarbutton-1"),
"expected .toolbarbutton-1 CSS class on the action button in the panel"
);
ok(
!actionButton.classList.contains("subviewbutton"),
"expected no .subviewbutton CSS class on the action button in the panel"
);
// The DOM node of the other window should not be changed.
let actionButtonInSecondWindow = aNodeInSecondWindow.querySelector(
".unified-extensions-item-action-button"
);
ok(
actionButtonInSecondWindow.classList.contains("toolbarbutton-1"),
"expected .toolbarbutton-1 CSS class on the action button in the second window"
);
ok(
!actionButtonInSecondWindow.classList.contains("subviewbutton"),
"expected no .subviewbutton CSS class on the action button in the second window"
);
},
});

Просмотреть файл

@ -38,11 +38,11 @@ unified-extensions-item {
/* On the main unified extensions button, we draw the attention on the icon element. */
#unified-extensions-button[attention] > .toolbarbutton-icon,
/* For extension widgets placed in a toolbar, we use the stack element (containing the icon)
* of the action button to draw the attention dot.
/* For extension widgets placed in a toolbar, we use the stack element
* (containing the icon) of the action button to draw the attention dot.
* Otherwise (in the extensions panel), we use the action button itself. */
toolbar .unified-extensions-item[attention] > .unified-extensions-item-action-button > .toolbarbutton-badge-stack,
#unified-extensions-panel .unified-extensions-item[attention] > .unified-extensions-item-action-button {
.unified-extensions-item[attention] > .unified-extensions-item-action-button.toolbarbutton-1 > .toolbarbutton-badge-stack,
.unified-extensions-item[attention] > .unified-extensions-item-action-button.subviewbutton {
background-image: radial-gradient(circle, var(--uei-button-attention-dot-color), var(--uei-button-attention-dot-color) 2px, transparent 2px);
background-size: var(--uei-attention-dot-size) var(--uei-attention-dot-size);
background-repeat: no-repeat;
@ -50,17 +50,17 @@ toolbar .unified-extensions-item[attention] > .unified-extensions-item-action-bu
/* Adjust attention dots position in the toolbar. */
#unified-extensions-button[attention] > .toolbarbutton-icon,
toolbar .unified-extensions-item[attention] > .unified-extensions-item-action-button > .toolbarbutton-badge-stack {
.unified-extensions-item[attention] > .unified-extensions-item-action-button.toolbarbutton-1 > .toolbarbutton-badge-stack {
background-position: center bottom calc(var(--toolbarbutton-inner-padding) / 2 - var(--uei-attention-dot-size) / 2);
}
/* Adjust attention dots position in the unified extensions panel. */
#unified-extensions-panel .unified-extensions-item[attention] > .unified-extensions-item-action-button {
.unified-extensions-item[attention] > .unified-extensions-item-action-button.subviewbutton {
background-position: left var(--uei-dot-horizontal-position-in-panel) bottom var(--uei-dot-vertical-position-in-panel);
}
/* Adjust attention dots position in the unified extensions panel for RTL. */
#unified-extensions-panel .unified-extensions-item[attention] > .unified-extensions-item-action-button:-moz-locale-dir(rtl) {
.unified-extensions-item[attention] > .unified-extensions-item-action-button.subviewbutton:-moz-locale-dir(rtl) {
background-position-x: right var(--uei-dot-horizontal-position-in-panel);
}
@ -80,19 +80,19 @@ toolbar .unified-extensions-item[attention] > .unified-extensions-item-action-bu
color: var(--panel-description-color);
}
.unified-extensions-item-action-button[disabled] .unified-extensions-item-icon {
.unified-extensions-item-action-button[disabled] > .unified-extensions-item-icon {
opacity: 0.5;
}
.unified-extensions-item-icon,
#unified-extensions-panel .unified-extensions-item .webextension-browser-action > .toolbarbutton-badge-stack > .toolbarbutton-icon {
.unified-extensions-item .webextension-browser-action.subviewbutton > .toolbarbutton-badge-stack > .toolbarbutton-icon {
height: var(--uei-icon-size);
width: var(--uei-icon-size);
}
/* The first selector is for the custom elements icon, which appears only in the UEP. */
.unified-extensions-item-icon,
#unified-extensions-panel .unified-extensions-item .webextension-browser-action > .toolbarbutton-badge-stack {
.unified-extensions-item .webextension-browser-action.subviewbutton > .toolbarbutton-badge-stack {
margin-inline-end: 6px;
}
@ -130,12 +130,12 @@ toolbar .unified-extensions-item[attention] > .unified-extensions-item-action-bu
/* --- browser action CUI widget styles --- */
toolbar toolbaritem.unified-extensions-item .unified-extensions-item-menu-button {
display: none;
}
/* Hide unified extensions content by default. */
toolbar .unified-extensions-item .unified-extensions-item-contents {
/* Hide the menu button and the unified extensions content when the extension
* item is placed on the toolbar. */
.unified-extensions-item[cui-areatype="toolbar"]:not([overflowedItem="true"]) :is(
.unified-extensions-item-menu-button,
.unified-extensions-item-contents
) {
display: none;
}
@ -148,7 +148,8 @@ toolbaritem.unified-extensions-item .unified-extensions-item-menu-button.subview
/* --- browser action CUI widget styles in the extensions panel --- */
/* Align CUI widgets with the custom elements in the unified extensions panel. */
/* Align CUI widgets with the custom elements in the unified extensions panel,
* especially when the widgets overflow in the panel. */
#unified-extensions-panel toolbaritem.unified-extensions-item {
max-width: max-content;
}