summaryrefslogtreecommitdiffstats
path: root/toolkit/content/widgets
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:37 +0000
commita90a5cba08fdf6c0ceb95101c275108a152a3aed (patch)
tree532507288f3defd7f4dcf1af49698bcb76034855 /toolkit/content/widgets
parentAdding debian version 126.0.1-1. (diff)
downloadfirefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.tar.xz
firefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/content/widgets')
-rw-r--r--toolkit/content/widgets/arrowscrollbox.js4
-rw-r--r--toolkit/content/widgets/autocomplete-richlistitem.js4
-rw-r--r--toolkit/content/widgets/datetimebox.js28
-rw-r--r--toolkit/content/widgets/message-bar.css219
-rw-r--r--toolkit/content/widgets/message-bar.js91
-rw-r--r--toolkit/content/widgets/moz-button-group/moz-button-group.css3
-rw-r--r--toolkit/content/widgets/moz-button-group/moz-button-group.mjs25
-rw-r--r--toolkit/content/widgets/moz-button/moz-button.css26
-rw-r--r--toolkit/content/widgets/moz-button/moz-button.mjs21
-rw-r--r--toolkit/content/widgets/moz-button/moz-button.stories.mjs29
-rw-r--r--toolkit/content/widgets/moz-message-bar/moz-message-bar.mjs12
-rw-r--r--toolkit/content/widgets/moz-page-nav/README.stories.md46
-rw-r--r--toolkit/content/widgets/moz-page-nav/moz-page-nav-button.css23
-rw-r--r--toolkit/content/widgets/moz-page-nav/moz-page-nav.mjs86
-rw-r--r--toolkit/content/widgets/moz-page-nav/moz-page-nav.stories.mjs32
-rw-r--r--toolkit/content/widgets/moz-support-link/moz-support-link.mjs6
-rw-r--r--toolkit/content/widgets/notificationbox.js3
-rw-r--r--toolkit/content/widgets/panel-list/panel-list.js4
-rw-r--r--toolkit/content/widgets/popupnotification.js2
-rw-r--r--toolkit/content/widgets/videocontrols.js17
20 files changed, 276 insertions, 405 deletions
diff --git a/toolkit/content/widgets/arrowscrollbox.js b/toolkit/content/widgets/arrowscrollbox.js
index 7109891faf..5983435d06 100644
--- a/toolkit/content/widgets/arrowscrollbox.js
+++ b/toolkit/content/widgets/arrowscrollbox.js
@@ -21,7 +21,7 @@
return `
<html:link rel="stylesheet" href="chrome://global/skin/toolbarbutton.css"/>
<html:link rel="stylesheet" href="chrome://global/skin/arrowscrollbox.css"/>
- <toolbarbutton id="scrollbutton-up" part="scrollbutton-up" keyNav="false" data-l10n-id="overflow-scroll-button-up"/>
+ <toolbarbutton id="scrollbutton-up" part="scrollbutton-up" keyNav="false" data-l10n-id="overflow-scroll-button-backwards"/>
<spacer part="overflow-start-indicator"/>
<box class="scrollbox-clip" part="scrollbox-clip" flex="1">
<scrollbox part="scrollbox" flex="1">
@@ -29,7 +29,7 @@
</scrollbox>
</box>
<spacer part="overflow-end-indicator"/>
- <toolbarbutton id="scrollbutton-down" part="scrollbutton-down" keyNav="false" data-l10n-id="overflow-scroll-button-down"/>
+ <toolbarbutton id="scrollbutton-down" part="scrollbutton-down" keyNav="false" data-l10n-id="overflow-scroll-button-forwards"/>
`;
}
diff --git a/toolkit/content/widgets/autocomplete-richlistitem.js b/toolkit/content/widgets/autocomplete-richlistitem.js
index b339ab1e27..0ec8a19243 100644
--- a/toolkit/content/widgets/autocomplete-richlistitem.js
+++ b/toolkit/content/widgets/autocomplete-richlistitem.js
@@ -832,9 +832,7 @@
setTimeout(() => {
let selectedIndex = popup ? popup.selectedIndex : -1;
- actor.manager
- .getActor("FormAutofill")
- .sendAsyncMessage("FormAutofill:PreviewProfile", { selectedIndex });
+ actor.previewAutofillProfile(selectedIndex);
}, 0);
}
diff --git a/toolkit/content/widgets/datetimebox.js b/toolkit/content/widgets/datetimebox.js
index 04ed398bd7..1c63b09269 100644
--- a/toolkit/content/widgets/datetimebox.js
+++ b/toolkit/content/widgets/datetimebox.js
@@ -650,6 +650,10 @@ this.DateTimeBoxWidget = class {
onKeyDown(aEvent) {
this.log("onKeyDown key: " + aEvent.key);
+ if (aEvent.defaultPrevented) {
+ return;
+ }
+
switch (aEvent.key) {
// Toggle the picker on Space/Enter on Calendar button or Space on input,
// close on Escape anywhere.
@@ -691,21 +695,17 @@ this.DateTimeBoxWidget = class {
aEvent.preventDefault();
break;
}
- if (this.isEditable()) {
- // TODO(emilio, bug 1571533): These functions should look at
- // defaultPrevented.
- // Ctrl+Backspace/Delete on non-macOS and
- // Cmd+Backspace/Delete on macOS to clear the field
- if (aEvent.getModifierState("Accel")) {
- // Clear the input's value
- this.clearInputFields(false);
- } else {
- let targetField = aEvent.originalTarget;
- this.clearFieldValue(targetField);
- this.setInputValueFromFields();
- }
- aEvent.preventDefault();
+ // Ctrl+Backspace/Delete on non-macOS and
+ // Cmd+Backspace/Delete on macOS to clear the field
+ if (aEvent.getModifierState("Accel")) {
+ // Clear the input's value
+ this.clearInputFields(false);
+ } else {
+ let targetField = aEvent.originalTarget;
+ this.clearFieldValue(targetField);
+ this.setInputValueFromFields();
}
+ aEvent.preventDefault();
break;
}
case "ArrowRight":
diff --git a/toolkit/content/widgets/message-bar.css b/toolkit/content/widgets/message-bar.css
deleted file mode 100644
index eddc5a3ae6..0000000000
--- a/toolkit/content/widgets/message-bar.css
+++ /dev/null
@@ -1,219 +0,0 @@
-/* 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/. */
-
-:host {
- --info-icon-url: url("chrome://global/skin/icons/info-filled.svg");
- --warn-icon-url: url("chrome://global/skin/icons/warning.svg");
- --success-icon-url: url("chrome://global/skin/icons/check.svg");
- --error-icon-url: url("chrome://global/skin/icons/error.svg");
- --close-icon-url: url("chrome://global/skin/icons/close-12.svg");
- --close-fill-color: var(--in-content-icon-color);
- --icon-size: 16px;
- --close-icon-size: 28px;
-}
-
-:host {
- --message-bar-background-color: var(--in-content-box-info-background);
- --message-bar-text-color: var(--in-content-text-color);
- --message-bar-icon-url: var(--info-icon-url);
- /* The default values of --in-content-button* are sufficient, even for dark themes */
-}
-
-:host([type=warning]) {
- --message-bar-icon-url: var(--warn-icon-url);
-}
-
-:host([type=success]) {
- --message-bar-icon-url: var(--success-icon-url);
-}
-
-:host([type=error]),
-:host([type=critical]) {
- --message-bar-icon-url: var(--error-icon-url);
-}
-
-:host {
- border: 1px solid transparent;
- border-radius: 4px;
-}
-
-/* Make the host to behave as a block by default, but allow hidden to hide it. */
-:host(:not([hidden])) {
- display: block;
-}
-
-::slotted(button) {
- /* Enforce micro-button width. */
- min-width: -moz-fit-content !important;
-}
-
-/* MessageBar Grid Layout */
-
-.container {
- background: var(--message-bar-background-color);
- color: var(--message-bar-text-color);
-
- padding: 3px 7px;
- position: relative;
-
- border-radius: 4px;
-
- display: flex;
- /* Ensure that the message bar shadow dom elements are vertically aligned. */
- align-items: center;
-}
-
-:host([align="center"]) .container {
- justify-content: center;
-}
-
-.content {
- margin: 0 4px;
- display: inline-block;
- /* Ensure that the message bar content is vertically aligned. */
- align-items: center;
- /* Ensure that the message bar content is wrapped. */
- word-break: break-word;
-}
-
-/* MessageBar icon style */
-
-.icon {
- padding: 4px;
- width: var(--icon-size);
- height: var(--icon-size);
- flex-shrink: 0;
-}
-
-.icon::after {
- display: inline-block;
- appearance: none;
- -moz-context-properties: fill, stroke;
- fill: currentColor;
- stroke: currentColor;
- content: "";
- background-image: var(--message-bar-icon-url);
- background-size: var(--icon-size);
- width: var(--icon-size);
- height: var(--icon-size);
-}
-
-/* Use a spacer to position the close button at the end, but also support
- * centering if required. */
-.spacer {
- flex-grow: 1;
-}
-
-/* Close icon styles */
-
-:host(:not([dismissable])) .close {
- display: none;
-}
-
-.close {
- background-image: var(--close-icon-url);
- background-repeat: no-repeat;
- background-position: center center;
- -moz-context-properties: fill;
- fill: currentColor;
- min-width: auto;
- min-height: auto;
- width: var(--close-icon-size);
- height: var(--close-icon-size);
- padding: 0;
- flex-shrink: 0;
- margin: 4px 8px;
- background-size: 12px;
-}
-
-@media (prefers-contrast) {
- :host {
- border-color: CanvasText;
- }
-}
-
-@media not (prefers-contrast) {
- /* MessageBar colors by message type */
- /* Colors from: https://design.firefox.com/photon/components/message-bars.html#type-specific-style */
-
- :host([type=warning]) {
- /* Ensure colors within the bar are adjusted and controls are readable */
- color-scheme: light;
-
- --message-bar-background-color: var(--yellow-50);
- --message-bar-text-color: var(--yellow-90);
-
- --in-content-button-background: var(--yellow-60);
- --in-content-button-background-hover: var(--yellow-70);
- --in-content-button-background-active: var(--yellow-80);
-
- --close-fill-color: var(--message-bar-text-color);
- }
-
- :host([type=success]) {
- /* Ensure colors within the bar are adjusted and controls are readable */
- color-scheme: light;
-
- --message-bar-background-color: var(--green-50);
- --message-bar-text-color: var(--green-90);
-
- --in-content-button-background: var(--green-60);
- --in-content-button-background-hover: var(--green-70);
- --in-content-button-background-active: var(--green-80);
- }
-
- :host([type=error]) {
- --message-bar-background-color: var(--red-60);
- --message-bar-text-color: #ffffff;
-
- --in-content-button-background: var(--red-70);
- --in-content-button-background-hover: var(--red-80);
- --in-content-button-background-active: var(--red-90);
- }
-
- :host([type=info]) .icon {
- color: rgb(0,144,237);
- }
-
- :host([type=warning]) .icon {
- color: rgb(255,164,54);
- }
-
- :host([type=critical]) .icon {
- color: rgb(226,40,80);
- }
-
- .close {
- fill: var(--close-fill-color);
- }
-
- @media (prefers-color-scheme: dark) {
- /* Don't set the background in prefers-contrast mode or macOS can end up
- * with black on black text. */
- :host([type=info]) .icon {
- color: rgb(128,235,255);
- }
-
- :host([type=warning]) .icon {
- color: rgb(255,189,79);
- }
-
- :host([type=critical]) .icon {
- color: rgb(255,154,162);
- }
- }
-}
-
-strong {
- font-weight: 600;
-}
-
-.text-link:hover {
- cursor: pointer;
-}
-
-@keyframes spin {
- from { transform: rotate(0); }
- to { transform: rotate(360deg); }
-}
diff --git a/toolkit/content/widgets/message-bar.js b/toolkit/content/widgets/message-bar.js
deleted file mode 100644
index d38347b40a..0000000000
--- a/toolkit/content/widgets/message-bar.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/* 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";
-
-// This is loaded into chrome windows with the subscript loader. Wrap in
-// a block to prevent accidentally leaking globals onto `window`.
-{
- class MessageBarElement extends HTMLElement {
- constructor() {
- super();
- const shadowRoot = this.attachShadow({ mode: "open" });
- window.MozXULElement?.insertFTLIfNeeded(
- "toolkit/global/notification.ftl"
- );
- document.l10n.connectRoot(this.shadowRoot);
- const content = this.constructor.template.content.cloneNode(true);
- shadowRoot.append(content);
- this.closeButton.addEventListener("click", () => this.dismiss(), {
- once: true,
- });
- }
-
- disconnectedCallback() {
- this.dispatchEvent(new CustomEvent("message-bar:close"));
- }
-
- get closeButton() {
- return this.shadowRoot.querySelector("button.close");
- }
-
- static get template() {
- const template = document.createElement("template");
-
- const commonStyles = document.createElement("link");
- commonStyles.rel = "stylesheet";
- commonStyles.href = "chrome://global/skin/in-content/common.css";
- const messageBarStyles = document.createElement("link");
- messageBarStyles.rel = "stylesheet";
- messageBarStyles.href =
- "chrome://global/content/elements/message-bar.css";
- template.content.append(commonStyles, messageBarStyles);
-
- // A container for the entire message bar content,
- // most of the css rules needed to provide the
- // expected message bar layout is applied on this
- // element.
- const container = document.createElement("div");
- container.part = "container";
- container.classList.add("container");
- template.content.append(container);
-
- const icon = document.createElement("span");
- icon.classList.add("icon");
- icon.part = "icon";
- container.append(icon);
-
- const barcontent = document.createElement("span");
- barcontent.classList.add("content");
- barcontent.append(document.createElement("slot"));
- container.append(barcontent);
-
- const spacer = document.createElement("span");
- spacer.classList.add("spacer");
- container.append(spacer);
-
- const closeIcon = document.createElement("button");
- closeIcon.classList.add("close", "ghost-button");
- document.l10n.setAttributes(closeIcon, "notification-close-button");
- container.append(closeIcon);
-
- Object.defineProperty(this, "template", {
- value: template,
- });
-
- return template;
- }
-
- dismiss() {
- this.dispatchEvent(new CustomEvent("message-bar:user-dismissed"));
- this.close();
- }
-
- close() {
- this.remove();
- }
- }
-
- customElements.define("message-bar", MessageBarElement);
-}
diff --git a/toolkit/content/widgets/moz-button-group/moz-button-group.css b/toolkit/content/widgets/moz-button-group/moz-button-group.css
index ba79d69e12..5b6f7deace 100644
--- a/toolkit/content/widgets/moz-button-group/moz-button-group.css
+++ b/toolkit/content/widgets/moz-button-group/moz-button-group.css
@@ -11,6 +11,7 @@
margin: 0 !important;
}
-::slotted(button:not(:first-child, .popup-notification-dropmarker)) {
+::slotted(button:not(:first-child, .popup-notification-dropmarker)),
+::slotted(moz-button:not(:first-child)) {
margin-inline-start: var(--space-small) !important;
}
diff --git a/toolkit/content/widgets/moz-button-group/moz-button-group.mjs b/toolkit/content/widgets/moz-button-group/moz-button-group.mjs
index 8bf553c23d..6858367ab7 100644
--- a/toolkit/content/widgets/moz-button-group/moz-button-group.mjs
+++ b/toolkit/content/widgets/moz-button-group/moz-button-group.mjs
@@ -50,15 +50,22 @@ export default class MozButtonGroup extends MozLitElement {
// Text nodes won't support classList or getAttribute.
continue;
}
- // Bug 1791816: These should check moz-button instead of button.
- if (
- child.localName == "button" &&
- (child.classList.contains("primary") ||
- child.getAttribute("type") == "submit" ||
- child.hasAttribute("autofocus") ||
- child.hasAttribute("default"))
- ) {
- child.slot = "primary";
+ switch (child.localName) {
+ case "button":
+ if (
+ child.classList.contains("primary") ||
+ child.getAttribute("type") == "submit" ||
+ child.hasAttribute("autofocus") ||
+ child.hasAttribute("default")
+ ) {
+ child.slot = "primary";
+ }
+ break;
+ case "moz-button":
+ if (child.type == "primary" || child.type == "destructive") {
+ child.slot = "primary";
+ }
+ break;
}
}
this.#reorderLightDom();
diff --git a/toolkit/content/widgets/moz-button/moz-button.css b/toolkit/content/widgets/moz-button/moz-button.css
index 71d57ea93a..4eb6839e06 100644
--- a/toolkit/content/widgets/moz-button/moz-button.css
+++ b/toolkit/content/widgets/moz-button/moz-button.css
@@ -23,6 +23,10 @@ button {
/* Ensure font-size isn't overridden by widget styling (e.g. in forms.css) */
font-size: var(--button-font-size);
width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: var(--space-small);
&[size=small] {
min-height: var(--button-min-height-small);
@@ -125,21 +129,33 @@ button {
}
}
- &[type~=icon] {
+ &[type~=icon]:not(.labelled) {
background-size: var(--icon-size-default);
background-position: center;
background-repeat: no-repeat;
- -moz-context-properties: fill, stroke;
- fill: currentColor;
- stroke: currentColor;
+ }
+
+ &[type~=icon]:not(.labelled),
+ &:not(.labelled):has(img) {
width: var(--button-size-icon);
height: var(--button-size-icon);
padding: var(--button-padding-icon);
- color: var(--icon-color);
&[size=small] {
width: var(--button-size-icon-small);
height: var(--button-size-icon-small);
}
}
+
+ img,
+ &[type~=icon]:not(.labelled) {
+ -moz-context-properties: fill, fill-opacity, stroke;
+ fill: currentColor;
+ stroke: currentColor;
+ }
+
+ img {
+ width: var(--icon-size-default);
+ height: var(--icon-size-default);
+ }
}
diff --git a/toolkit/content/widgets/moz-button/moz-button.mjs b/toolkit/content/widgets/moz-button/moz-button.mjs
index a951dbf5d8..9a239d4e56 100644
--- a/toolkit/content/widgets/moz-button/moz-button.mjs
+++ b/toolkit/content/widgets/moz-button/moz-button.mjs
@@ -2,7 +2,7 @@
* 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/. */
-import { html, ifDefined } from "../vendor/lit.all.mjs";
+import { html, ifDefined, classMap } from "../vendor/lit.all.mjs";
import { MozLitElement } from "../lit-utils.mjs";
/**
@@ -19,8 +19,11 @@ import { MozLitElement } from "../lit-utils.mjs";
* @property {string} titleAttribute - Internal, map title attribute to the title JS property.
* @property {string} tooltipText - Set the title property, the title attribute will be used first.
* @property {string} ariaLabel - The button's arial-label attribute, used in shadow DOM and therefore not as an attribute on moz-button.
+ * @property {string} iconSrc - Path to the icon that should be displayed in the button.
* @property {string} ariaLabelAttribute - Internal, map aria-label attribute to the ariaLabel JS property.
+ * @property {string} hasVisibleLabel - Internal, tracks whether or not the button has a visible label.
* @property {HTMLButtonElement} buttonEl - The internal button element in the shadow DOM.
+ * @property {HTMLButtonElement} slotEl - The internal slot element in the shadow DOM.
* @slot default - The button's content, overrides label property.
* @fires click - The click event.
*/
@@ -44,10 +47,13 @@ export default class MozButton extends MozLitElement {
reflect: true,
},
ariaLabel: { type: String, state: true },
+ iconSrc: { type: String },
+ hasVisibleLabel: { type: Boolean, state: true },
};
static queries = {
buttonEl: "button",
+ slotEl: "slot",
};
constructor() {
@@ -55,6 +61,7 @@ export default class MozButton extends MozLitElement {
this.type = "default";
this.size = "default";
this.disabled = false;
+ this.hasVisibleLabel = !!this.label;
}
willUpdate(changes) {
@@ -73,6 +80,12 @@ export default class MozButton extends MozLitElement {
this.buttonEl.click();
}
+ checkForLabelText() {
+ this.hasVisibleLabel = this.slotEl
+ .assignedNodes()
+ .some(node => node.textContent.trim());
+ }
+
render() {
return html`
<link
@@ -86,8 +99,12 @@ export default class MozButton extends MozLitElement {
title=${ifDefined(this.title || this.tooltipText)}
aria-label=${ifDefined(this.ariaLabel)}
part="button"
+ class=${classMap({ labelled: this.label || this.hasVisibleLabel })}
>
- <slot>${this.label}</slot>
+ ${this.iconSrc
+ ? html`<img src=${this.iconSrc} role="presentation" />`
+ : ""}
+ <slot @slotchange=${this.checkForLabelText}>${this.label}</slot>
</button>
`;
}
diff --git a/toolkit/content/widgets/moz-button/moz-button.stories.mjs b/toolkit/content/widgets/moz-button/moz-button.stories.mjs
index 52a459e807..dd8d6369db 100644
--- a/toolkit/content/widgets/moz-button/moz-button.stories.mjs
+++ b/toolkit/content/widgets/moz-button/moz-button.stories.mjs
@@ -2,7 +2,7 @@
* 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/. */
-import { html } from "../vendor/lit.all.mjs";
+import { html, ifDefined } from "../vendor/lit.all.mjs";
// eslint-disable-next-line import/no-unassigned-import
import "./moz-button.mjs";
@@ -22,6 +22,10 @@ export default {
options: ["default", "small"],
control: { type: "radio" },
},
+ type: {
+ options: ["default", "primary", "destructive", "icon", "icon ghost"],
+ control: { type: "select" },
+ },
},
parameters: {
actions: {
@@ -40,17 +44,13 @@ moz-button-aria-labelled =
},
};
-const Template = ({ type, size, l10nId, iconUrl, disabled }) => html`
- <style>
- moz-button[type~="icon"]::part(button) {
- background-image: url("${iconUrl}");
- }
- </style>
+const Template = ({ type, size, l10nId, iconSrc, disabled }) => html`
<moz-button
data-l10n-id=${l10nId}
type=${type}
size=${size}
?disabled=${disabled}
+ iconSrc=${ifDefined(iconSrc)}
></moz-button>
`;
@@ -59,7 +59,7 @@ Default.args = {
type: "default",
size: "default",
l10nId: "moz-button-labelled",
- iconUrl: "chrome://global/skin/icons/more.svg",
+ iconSrc: "",
disabled: false,
};
export const DefaultSmall = Template.bind({});
@@ -67,7 +67,7 @@ DefaultSmall.args = {
type: "default",
size: "small",
l10nId: "moz-button-labelled",
- iconUrl: "chrome://global/skin/icons/more.svg",
+ iconSrc: "",
disabled: false,
};
export const Primary = Template.bind({});
@@ -85,7 +85,7 @@ Destructive.args = {
export const Icon = Template.bind({});
Icon.args = {
...Default.args,
- type: "icon",
+ iconSrc: "chrome://global/skin/icons/more.svg",
l10nId: "moz-button-titled",
};
export const IconSmall = Template.bind({});
@@ -96,5 +96,12 @@ IconSmall.args = {
export const IconGhost = Template.bind({});
IconGhost.args = {
...Icon.args,
- type: "icon ghost",
+ type: "ghost",
+};
+export const IconText = Template.bind({});
+IconText.args = {
+ type: "default",
+ size: "default",
+ iconSrc: "chrome://global/skin/icons/edit-copy.svg",
+ l10nId: "moz-button-labelled",
};
diff --git a/toolkit/content/widgets/moz-message-bar/moz-message-bar.mjs b/toolkit/content/widgets/moz-message-bar/moz-message-bar.mjs
index 8f0c997149..9a186b41c9 100644
--- a/toolkit/content/widgets/moz-message-bar/moz-message-bar.mjs
+++ b/toolkit/content/widgets/moz-message-bar/moz-message-bar.mjs
@@ -49,10 +49,10 @@ const messageTypeToIconData = {
export default class MozMessageBar extends MozLitElement {
static queries = {
- actionsSlotEl: "slot[name=actions]",
+ actionsSlot: "slot[name=actions]",
actionsEl: ".actions",
- closeButtonEl: "moz-button.close",
- supportLinkSlotEl: "slot[name=support-link]",
+ closeButton: "moz-button.close",
+ supportLinkSlot: "slot[name=support-link]",
};
static properties = {
@@ -72,13 +72,13 @@ export default class MozMessageBar extends MozLitElement {
}
onSlotchange() {
- let actions = this.actionsSlotEl.assignedNodes();
+ let actions = this.actionsSlot.assignedNodes();
this.actionsEl.classList.toggle("active", actions.length);
}
connectedCallback() {
super.connectedCallback();
- this.setAttribute("role", "status");
+ this.setAttribute("role", "alert");
}
disconnectedCallback() {
@@ -87,7 +87,7 @@ export default class MozMessageBar extends MozLitElement {
}
get supportLinkEls() {
- return this.supportLinkSlotEl.assignedElements();
+ return this.supportLinkSlot.assignedElements();
}
iconTemplate() {
diff --git a/toolkit/content/widgets/moz-page-nav/README.stories.md b/toolkit/content/widgets/moz-page-nav/README.stories.md
index 800d446478..c2f1b37bb5 100644
--- a/toolkit/content/widgets/moz-page-nav/README.stories.md
+++ b/toolkit/content/widgets/moz-page-nav/README.stories.md
@@ -4,7 +4,7 @@
intended to change the selected view, provide a heading, and have links to external resources.
```html story
-<moz-page-nav heading="This is a nav" style={{ '--page-nav-margin-top': 0, '--page-nav-margin-bottom': 0, height: '200px' }}>
+<moz-page-nav heading="This is a nav" style={{ '--page-nav-margin-top': 0, '--page-nav-margin-bottom': 0, height: '275px' }}>
<moz-page-nav-button
view="view-one"
iconSrc="chrome://browser/skin/preferences/category-general.svg"
@@ -23,13 +23,27 @@ intended to change the selected view, provide a heading, and have links to exter
>
<p style={{ margin: 0 }}>Test 3</p>
</moz-page-nav-button>
+ <moz-page-nav-button
+ support-page="test"
+ iconSrc="chrome://browser/skin/preferences/category-general.svg"
+ slot="secondary-nav"
+ >
+ <p style={{ margin: 0 }}>Support Link</p>
+ </moz-page-nav-button>
+ <moz-page-nav-button
+ href="https://www.example.com"
+ iconSrc="chrome://browser/skin/preferences/category-general.svg"
+ slot="secondary-nav"
+ >
+ <p style={{ margin: 0 }}>External Link</p>
+ </moz-page-nav-button>
</moz-page-nav>
```
## When to use
* Use moz-page-nav for single-page navigation to switch between different views.
-* moz-page-nav will also support footer buttons for external support links in the future (See [bug 1877826](https://bugzilla.mozilla.org/show_bug.cgi?id=1877826))
+* moz-page-nav also supports footer buttons for external and support links
* This component will be used in about: pages such as about:firefoxview, about:preferences, about:addons, about:debugging, etc.
## When not to use
@@ -53,18 +67,34 @@ And used as follows:
```html
<moz-page-nav>
- <moz-page-nav-button
+ <moz-page-nav-button
view="A name for the first view"
iconSrc="A url for the icon for the first navigation button">
- </moz-page-nav-button>
- <moz-page-nav-button
+ </moz-page-nav-button>
+ <moz-page-nav-button
view="A name for the second view"
iconSrc="A url for the icon for the second navigation button">
- </moz-page-nav-button>
- <moz-page-nav-button
+ </moz-page-nav-button>
+ <moz-page-nav-button
view="A name for the third view"
iconSrc="A url for the icon for the third navigation button">
- </moz-page-nav-button>
+ </moz-page-nav-button>
+
+ <!-- Footer Links -->
+
+ <!-- Support Link -->
+ <moz-page-nav-button
+ support-page="A name for a support link"
+ iconSrc="A url for the icon for the third navigation button"
+ slot="secondary-nav">
+ </moz-page-nav-button>
+
+ <!-- External Link -->
+ <moz-page-nav-button
+ href="A url for an external link"
+ iconSrc="A url for the icon for the third navigation button"
+ slot="secondary-nav">
+ </moz-page-nav-button>
</moz-page-nav>
```
diff --git a/toolkit/content/widgets/moz-page-nav/moz-page-nav-button.css b/toolkit/content/widgets/moz-page-nav/moz-page-nav-button.css
index 5d00198d65..781398056a 100644
--- a/toolkit/content/widgets/moz-page-nav/moz-page-nav-button.css
+++ b/toolkit/content/widgets/moz-page-nav/moz-page-nav-button.css
@@ -4,11 +4,13 @@
:host {
border-radius: var(--border-radius-small);
+ font-size: var(--font-size-large);
&:focus-visible {
outline-offset: var(--page-nav-focus-outline-inset);
}
}
+a[href],
button {
background-color: var(--page-nav-button-background-color);
border: 1px solid var(--page-nav-border-color);
@@ -28,11 +30,17 @@ button {
padding: var(--page-nav-button-padding);
}
+a[href] {
+ text-decoration: none;
+ box-sizing: border-box;
+}
+
button:hover {
cursor: pointer;
}
@media not (prefers-contrast) {
+ a[href],
button {
position: relative;
}
@@ -55,6 +63,7 @@ button:hover {
background-color: var(--icon-color);
}
+ a[href]:hover,
button:hover,
button[selected]:hover {
background-color: var(--page-nav-button-background-color-hover);
@@ -72,6 +81,7 @@ button:hover {
}
}
+a[href]:focus-visible,
button:focus-visible,
button[selected]:focus-visible {
outline: var(--focus-outline);
@@ -86,13 +96,24 @@ button[selected]:focus-visible {
fill: currentColor;
}
+:host(.secondary-nav-item) {
+ font-size: var(--font-size-small);
+
+ & .page-nav-icon {
+ height: var(--icon-size-default);
+ width: var(--icon-size-default);
+ }
+}
+
@media (prefers-contrast) {
+ a[href],
button {
transition: none;
border-color: ButtonText;
background-color: var(--button-background-color);
}
+ a[href]:hover,
button:hover {
color: SelectedItem;
}
@@ -105,13 +126,13 @@ button[selected]:focus-visible {
}
slot {
- font-size: var(--font-size-large);
margin: 0;
padding-inline-start: 0;
user-select: none;
}
@media (max-width: 52rem) {
+ a[href],
button {
grid-template-columns: min-content;
justify-content: center;
diff --git a/toolkit/content/widgets/moz-page-nav/moz-page-nav.mjs b/toolkit/content/widgets/moz-page-nav/moz-page-nav.mjs
index f998ee735f..c720e76e26 100644
--- a/toolkit/content/widgets/moz-page-nav/moz-page-nav.mjs
+++ b/toolkit/content/widgets/moz-page-nav/moz-page-nav.mjs
@@ -4,6 +4,8 @@
import { html } from "chrome://global/content/vendor/lit.all.mjs";
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+// eslint-disable-next-line import/no-unassigned-import
+import "chrome://global/content/elements/moz-support-link.mjs";
/**
* A grouping of navigation buttons that is displayed at the page level,
@@ -35,6 +37,14 @@ export default class MozPageNav extends MozLitElement {
);
}
+ get secondaryNavButtons() {
+ return this.secondaryNavGroupSlot
+ .assignedNodes()
+ .filter(
+ node => node?.localName === "moz-page-nav-button" && !node.hidden
+ );
+ }
+
onChangeView(e) {
this.currentView = e.target.view;
}
@@ -69,6 +79,12 @@ export default class MozPageNav extends MozLitElement {
}
}
+ onSecondaryNavChange() {
+ this.secondaryNavGroupSlot.assignedElements()?.forEach(el => {
+ el.classList.add("secondary-nav-item");
+ });
+ }
+
render() {
return html`
<link
@@ -89,7 +105,10 @@ export default class MozPageNav extends MozLitElement {
></slot>
</div>
<div id="secondary-nav-group" role="group">
- <slot name="secondary-nav" @keydown=${this.handleFocus}></slot>
+ <slot
+ name="secondary-nav"
+ @slotchange=${this.onSecondaryNavChange}
+ ></slot>
</div>
</nav>
`;
@@ -114,16 +133,18 @@ customElements.define("moz-page-nav", MozPageNav);
* A navigation button intended to change the selected view within a page.
*
* @tagname moz-page-nav-button
+ * @property {string} href - (optional) The url for an external link if not a support page URL
* @property {string} iconSrc - The chrome:// url for the icon used for the button.
- * @property {string} l10nId - The fluent ID for the button's text
* @property {boolean} selected - Whether or not the button is currently selected.
+ * @property {string} supportPage - (optional) The short name for the support page a secondary link should launch to
* @slot [default] - Used to append the l10n string to the button.
*/
export class MozPageNavButton extends MozLitElement {
static properties = {
iconSrc: { type: String },
- l10nId: { type: String },
+ href: { type: String },
selected: { type: Boolean },
+ supportPage: { type: String, attribute: "support-page" },
};
connectedCallback() {
@@ -133,6 +154,7 @@ export class MozPageNavButton extends MozLitElement {
static queries = {
buttonEl: "button",
+ linkEl: "a",
};
get view() {
@@ -148,12 +170,15 @@ export class MozPageNavButton extends MozLitElement {
);
}
- render() {
+ itemTemplate() {
+ if (this.href || this.supportPage) {
+ return this.linkTemplate();
+ }
+ return this.buttonTemplate();
+ }
+
+ buttonTemplate() {
return html`
- <link
- rel="stylesheet"
- href="chrome://global/content/elements/moz-page-nav-button.css"
- />
<button
aria-selected=${this.selected}
tabindex=${this.selected ? 0 : -1}
@@ -161,10 +186,51 @@ export class MozPageNavButton extends MozLitElement {
?selected=${this.selected}
@click=${this.activate}
>
- <img class="page-nav-icon" src=${this.iconSrc} />
- <slot></slot>
+ ${this.innerContentTemplate()}
</button>
`;
}
+
+ linkTemplate() {
+ if (this.supportPage) {
+ return html`
+ <a
+ is="moz-support-link"
+ class="moz-page-nav-link"
+ support-page=${this.supportPage}
+ >
+ ${this.innerContentTemplate()}
+ </a>
+ `;
+ }
+ return html`
+ <a href=${this.href} class="moz-page-nav-link" target="_blank">
+ ${this.innerContentTemplate()}
+ </a>
+ `;
+ }
+
+ innerContentTemplate() {
+ return html`
+ ${this.iconSrc
+ ? html`<img
+ class="page-nav-icon"
+ src=${this.iconSrc}
+ role="presentation"
+ />`
+ : ""}
+ <slot></slot>
+ `;
+ }
+
+ render() {
+ return html`
+ <link
+ rel="stylesheet"
+ href="chrome://global/content/elements/moz-page-nav-button.css"
+ />
+ ${this.itemTemplate()}
+ `;
+ }
}
customElements.define("moz-page-nav-button", MozPageNavButton);
diff --git a/toolkit/content/widgets/moz-page-nav/moz-page-nav.stories.mjs b/toolkit/content/widgets/moz-page-nav/moz-page-nav.stories.mjs
index 4ac7b455cf..d1c565efe9 100644
--- a/toolkit/content/widgets/moz-page-nav/moz-page-nav.stories.mjs
+++ b/toolkit/content/widgets/moz-page-nav/moz-page-nav.stories.mjs
@@ -2,7 +2,7 @@
* 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/. */
-import { html } from "../vendor/lit.all.mjs";
+import { html, when } from "../vendor/lit.all.mjs";
// eslint-disable-next-line import/no-unassigned-import
import "./moz-page-nav.mjs";
@@ -21,15 +21,17 @@ moz-page-nav-button-two = View 2
.title = View 2
moz-page-nav-button-three = View 3
.title = View 3
-moz-page-link-one = Support Page
- .title = Support Page
+moz-page-nav-button-four = Support Link
+ .title = Support Link
+moz-page-nav-button-five = External Link
+ .title = External Link
moz-page-nav-heading =
.heading = Heading
`,
},
};
-const Template = () => html`
+const Template = ({ hasFooterLinks }) => html`
<style>
#page {
height: 100%;
@@ -68,10 +70,30 @@ const Template = () => html`
iconSrc="chrome://browser/skin/preferences/category-general.svg"
>
</moz-page-nav-button>
+ ${when(
+ hasFooterLinks,
+ () => html` <moz-page-nav-button
+ support-page="test"
+ data-l10n-id="moz-page-nav-button-four"
+ iconSrc="chrome://browser/skin/preferences/category-general.svg"
+ slot="secondary-nav"
+ >
+ </moz-page-nav-button>
+ <moz-page-nav-button
+ href="https://www.example.com"
+ data-l10n-id="moz-page-nav-button-five"
+ iconSrc="chrome://browser/skin/preferences/category-general.svg"
+ slot="secondary-nav"
+ >
+ </moz-page-nav-button>`
+ )}
</moz-page-nav>
<main></main>
</div>
`;
export const Default = Template.bind({});
-Default.args = {};
+Default.args = { hasFooterLinks: false };
+
+export const WithFooterLinks = Template.bind({});
+WithFooterLinks.args = { hasFooterLinks: true };
diff --git a/toolkit/content/widgets/moz-support-link/moz-support-link.mjs b/toolkit/content/widgets/moz-support-link/moz-support-link.mjs
index 9d2d6ffac2..df6ebac2a5 100644
--- a/toolkit/content/widgets/moz-support-link/moz-support-link.mjs
+++ b/toolkit/content/widgets/moz-support-link/moz-support-link.mjs
@@ -29,6 +29,10 @@ export default class MozSupportLink extends HTMLAnchorElement {
*/
#register() {
if (window.document.nodePrincipal?.isSystemPrincipal) {
+ ChromeUtils.defineESModuleGetters(MozSupportLink, {
+ BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
+ });
+
// eslint-disable-next-line no-shadow
let { XPCOMUtils } = window.XPCOMUtils
? window
@@ -72,7 +76,7 @@ export default class MozSupportLink extends HTMLAnchorElement {
handleEvent(e) {
if (e.type == "click") {
if (window.openTrustedLinkIn) {
- let where = whereToOpenLink(e, false, true);
+ let where = MozSupportLink.BrowserUtils.whereToOpenLink(e, false, true);
if (where == "current") {
where = "tab";
}
diff --git a/toolkit/content/widgets/notificationbox.js b/toolkit/content/widgets/notificationbox.js
index 8cfc7b865c..fc3e553ca4 100644
--- a/toolkit/content/widgets/notificationbox.js
+++ b/toolkit/content/widgets/notificationbox.js
@@ -621,7 +621,7 @@
customElements.define("notification", MozElements.Notification);
async function createNotificationMessageElement() {
- await window.ensureCustomElements("moz-message-bar");
+ document.createElement("moz-message-bar");
let MozMessageBar = await customElements.whenDefined("moz-message-bar");
class NotificationMessage extends MozMessageBar {
static queries = {
@@ -772,7 +772,6 @@
let buttonElem;
if (button.hasOwnProperty("supportPage")) {
- window.ensureCustomElements("moz-support-link");
buttonElem = document.createElement("a", {
is: "moz-support-link",
});
diff --git a/toolkit/content/widgets/panel-list/panel-list.js b/toolkit/content/widgets/panel-list/panel-list.js
index 2e93b4ddc3..a2b6cb1a00 100644
--- a/toolkit/content/widgets/panel-list/panel-list.js
+++ b/toolkit/content/widgets/panel-list/panel-list.js
@@ -439,10 +439,6 @@
// using the mouse. Ignore the first focusin event if it's on the
// triggering target.
this.focusHasChanged = true;
- } else if (!target || !inPanelList) {
- // If the target isn't in the panel, hide. This will close when focus
- // moves out of the panel.
- this.hide();
} else {
// Just record that there was a focusin event.
this.focusHasChanged = true;
diff --git a/toolkit/content/widgets/popupnotification.js b/toolkit/content/widgets/popupnotification.js
index 835151496c..7dfa47728b 100644
--- a/toolkit/content/widgets/popupnotification.js
+++ b/toolkit/content/widgets/popupnotification.js
@@ -116,8 +116,6 @@
MozXULElement.insertFTLIfNeeded("toolkit/global/popupnotification.ftl");
this.appendChild(this.constructor.fragment);
- window.ensureCustomElements("moz-button-group");
-
this.button = this.querySelector(".popup-notification-primary-button");
if (
this.hasAttribute("buttonlabel") ||
diff --git a/toolkit/content/widgets/videocontrols.js b/toolkit/content/widgets/videocontrols.js
index 73a32164aa..8d7b52c344 100644
--- a/toolkit/content/widgets/videocontrols.js
+++ b/toolkit/content/widgets/videocontrols.js
@@ -417,10 +417,9 @@ this.VideoControlsImplWidget = class {
}
// We have to check again if the media has audio here.
- if (!this.isAudioOnly && !this.video.mozHasAudio) {
- this.muteButton.setAttribute("noAudio", "true");
- this.muteButton.disabled = true;
- }
+ let noAudio = !this.isAudioOnly && !this.video.mozHasAudio;
+ this.muteButton.toggleAttribute("noAudio", noAudio);
+ this.muteButton.disabled = noAudio;
}
// The video itself might not be fullscreen, but part of the
@@ -755,7 +754,7 @@ this.VideoControlsImplWidget = class {
);
}
break;
- case "loadedmetadata":
+ case "loadedmetadata": {
// If a <video> doesn't have any video data, treat it as <audio>
// and show the controls (they won't fade back out)
if (
@@ -771,13 +770,13 @@ this.VideoControlsImplWidget = class {
Math.round(this.video.currentTime * 1000),
Math.round(this.video.duration * 1000)
);
- if (!this.isAudioOnly && !this.video.mozHasAudio) {
- this.muteButton.setAttribute("noAudio", "true");
- this.muteButton.disabled = true;
- }
+ let noAudio = !this.isAudioOnly && !this.video.mozHasAudio;
+ this.muteButton.toggleAttribute("noAudio", noAudio);
+ this.muteButton.disabled = noAudio;
this.adjustControlSize();
this.updatePictureInPictureToggleDisplay();
break;
+ }
case "durationchange":
this.updatePictureInPictureToggleDisplay();
break;