commit 0f4ed28089e6a2914ce5190f80e80f5119f09dd6
parent fac6ae44934cc89d98dffd8b6cc1fdc2ad6cbe44
Author: Mark Striemer <mstriemer@mozilla.com>
Date: Thu, 20 Nov 2025 00:02:51 +0000
Bug 2000303 - Hide setting-group/groupbox without the hidden attribute r=desktop-theme-reviewers,tgiles
When a setting-group has no visible settings within it we will hide it.
Similarly, if it has visible settings it will try to make itself
visible.
This was conflicting with the page level visibility changes used for
hiding and showing elements on a specific pane using the data-category
and hidden attributes.
Avoid changing the hidden attribute when changing the setting-group or
groupbox visibility so that both can function independently.
Differential Revision: https://phabricator.services.mozilla.com/D272722
Diffstat:
3 files changed, 118 insertions(+), 33 deletions(-)
diff --git a/browser/components/preferences/tests/chrome/test_setting_group.html b/browser/components/preferences/tests/chrome/test_setting_group.html
@@ -9,6 +9,10 @@
href="chrome://mochikit/content/tests/SimpleTest/test.css"
/>
<link rel="stylesheet" href="chrome://global/skin/global.css" />
+ <link
+ rel="stylesheet"
+ href="chrome://browser/content/preferences/widgets/setting-group.css"
+ />
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script src="../../../../../toolkit/content/tests/widgets/lit-test-helpers.js"></script>
<script src="./head.js"></script>
@@ -146,40 +150,74 @@
`);
}
- async function assertVisibilityChanges(group, staysHidden = false) {
+ async function assertVisibilityChanges(
+ group,
+ staysHidden = false,
+ hiddenElsewhere = false
+ ) {
await waitForRenderUpdate();
ok(group, "setting-group is created");
let [control1, control2] = group.querySelectorAll("setting-control");
- is(control1.hidden, true, "First setting-control should be hidden");
- is(control2.hidden, true, "Second setting-control should be hidden");
-
ok(
- group.hidden,
+ BrowserTestUtils.isHidden(control1),
+ "First setting-control should be hidden"
+ );
+ ok(
+ BrowserTestUtils.isHidden(control2),
+ "Second setting-control should be hidden"
+ );
+ ok(
+ BrowserTestUtils.isHidden(group),
"setting-group should be hidden since its controls are hidden"
);
+ let initialHiddenValue = group.hidden;
+
+ if (hiddenElsewhere) {
+ ok(
+ !group.hasAttribute("data-hidden-from-search"),
+ "setting-group is not hidden from search when hidden elsewhere"
+ );
+ } else {
+ is(
+ group.getAttribute("data-hidden-from-search"),
+ "true",
+ "setting-group is hidden from search when hidden"
+ );
+ }
is(
- group.getAttribute("data-hidden-from-search"),
- "true",
- "setting-group is hidden from search when hidden"
+ group.hidden,
+ initialHiddenValue,
+ "setting-group should not change hidden attribute"
);
- info(group.hasAttribute("data-hidden-by-setting-group"));
Services.prefs.setBoolPref(PREF_ONE, true);
await waitForRenderUpdate();
+ is(
+ group.hidden,
+ initialHiddenValue,
+ "setting-group should not change hidden attribute"
+ );
if (staysHidden) {
ok(BrowserTestUtils.isHidden(group), "Group should stay hidden");
- is(
- group.getAttribute("data-hidden-from-search"),
- "true",
- "setting-group is hidden from search when hidden"
- );
+ if (hiddenElsewhere) {
+ ok(
+ !group.hasAttribute("data-hidden-from-search"),
+ "setting-group is not hidden from search when hidden elsewhere"
+ );
+ } else {
+ is(
+ group.getAttribute("data-hidden-from-search"),
+ "true",
+ "setting-group is hidden from search when hidden"
+ );
+ }
} else {
ok(
!control1.hidden,
"Control 1 should be visible after changing pref value"
);
ok(
- !group.hidden,
+ BrowserTestUtils.isVisible(group),
"Group should be visible since one of the controls is visible"
);
ok(
@@ -194,23 +232,38 @@
}
Services.prefs.setBoolPref(PREF_TWO, true);
await waitForRenderUpdate();
+ is(
+ group.hidden,
+ initialHiddenValue,
+ "setting-group should not change hidden attribute"
+ );
if (staysHidden) {
ok(
BrowserTestUtils.isHidden(group),
"Group should still stay hidden"
);
- is(
- group.getAttribute("data-hidden-from-search"),
- "true",
- "setting-group is hidden from search when hidden"
- );
+ if (hiddenElsewhere) {
+ ok(
+ !group.hasAttribute("data-hidden-from-search"),
+ "setting-group is not hidden from search when hidden elsewhere"
+ );
+ } else {
+ is(
+ group.getAttribute("data-hidden-from-search"),
+ "true",
+ "setting-group is hidden from search when hidden"
+ );
+ }
} else {
ok(
!control2.hidden,
"Control 2 should be visible after changing pref value"
);
ok(!control1.hidden, "Control 1 should still be visible");
- ok(!group.hidden, "Group should still be visible");
+ ok(
+ BrowserTestUtils.isVisible(group),
+ "Group should still be visible"
+ );
ok(
!group.hasAttribute("data-hidden-from-search"),
"setting-group is not hidden from search when visible"
@@ -221,6 +274,11 @@
Services.prefs.setBoolPref(PREF_TWO, false);
await waitForRenderUpdate();
+ is(
+ group.hidden,
+ initialHiddenValue,
+ "setting-group should not change hidden attribute"
+ );
ok(
control1.hidden,
"Control 1 should be hidden after changing pref value"
@@ -230,7 +288,7 @@
"Control 2 should be hidden after changing pref value"
);
ok(
- group.hidden,
+ BrowserTestUtils.isHidden(group),
"Group should be hidden now that the controls are hidden"
);
is(
@@ -272,6 +330,17 @@
info("-- assertVisibilityChanges setting-group --");
await assertVisibilityChanges(group);
+ // Without a groupbox, initially hidden, settings visible
+ result = await renderTemplate(config);
+ group = result.querySelector("setting-group");
+ // Make a setting visible so the group would be visible
+ Services.prefs.setBoolPref(PREF_TWO, true);
+ await waitForRenderUpdate();
+ // Hide the group, as if it's on a hidden setting pane
+ group.hidden = true;
+ info("-- assertVisibilityChanges setting-group hidden --");
+ await assertVisibilityChanges(group, true, true);
+
// Check with an initially visible groupbox
result = await renderTemplateInGroupbox(config);
group = result.querySelector("groupbox");
diff --git a/browser/components/preferences/widgets/setting-group/setting-group.css b/browser/components/preferences/widgets/setting-group/setting-group.css
@@ -6,3 +6,7 @@ setting-group:not([hidden]) {
display: flex;
flex-direction: column;
}
+
+[data-hidden-by-setting-group] {
+ display: none !important;
+}
diff --git a/browser/components/preferences/widgets/setting-group/setting-group.mjs b/browser/components/preferences/widgets/setting-group/setting-group.mjs
@@ -31,6 +31,17 @@ const CLICK_HANDLERS = new Set([
"moz-box-group",
]);
+/**
+ * Enumish of attribute names used for changing setting-group and groupbox
+ * visibilities based on the visibility of child setting-controls.
+ */
+const HiddenAttr = Object.freeze({
+ /** Attribute used to hide elements without using the hidden attribute. */
+ Self: "data-hidden-by-setting-group",
+ /** Attribute used to signal that this element should not be searchable. */
+ Search: "data-hidden-from-search",
+});
+
export class SettingGroup extends SettingElement {
constructor() {
super();
@@ -64,21 +75,22 @@ export class SettingGroup extends SettingElement {
await this.updateComplete;
// @ts-expect-error bug 1997478
let hasVisibleControls = [...this.controlEls].some(el => !el.hidden);
- this.hidden = !hasVisibleControls;
let groupbox = /** @type {XULElement} */ (this.closest("groupbox"));
if (hasVisibleControls) {
- this.removeAttribute("data-hidden-from-search");
- if (groupbox && groupbox.hasAttribute("data-hidden-by-setting-group")) {
- groupbox.removeAttribute("data-hidden-from-search");
- groupbox.removeAttribute("data-hidden-by-setting-group");
- groupbox.hidden = false;
+ if (this.hasAttribute(HiddenAttr.Self)) {
+ this.removeAttribute(HiddenAttr.Self);
+ this.removeAttribute(HiddenAttr.Search);
+ }
+ if (groupbox && groupbox.hasAttribute(HiddenAttr.Self)) {
+ groupbox.removeAttribute(HiddenAttr.Search);
+ groupbox.removeAttribute(HiddenAttr.Self);
}
} else {
- this.setAttribute("data-hidden-from-search", "true");
- if (groupbox && !groupbox.hasAttribute("data-hidden-from-search")) {
- groupbox.setAttribute("data-hidden-from-search", "true");
- groupbox.setAttribute("data-hidden-by-setting-group", "");
- groupbox.hidden = true;
+ this.setAttribute(HiddenAttr.Self, "");
+ this.setAttribute(HiddenAttr.Search, "true");
+ if (groupbox && !groupbox.hasAttribute(HiddenAttr.Search)) {
+ groupbox.setAttribute(HiddenAttr.Search, "true");
+ groupbox.setAttribute(HiddenAttr.Self, "");
}
}
}