* feat: Waterfox custom CSS on non-default themes by default * feat: Table of Contents to preferences * feat: DoOH checkbox to privacy preferences * feat panel and menu transparency options * feat: Look & Feel about:preferences item
447 lines
15 KiB
JavaScript
447 lines
15 KiB
JavaScript
/* 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/. */
|
|
|
|
const { PrefUtils } = ChromeUtils.importESModule(
|
|
"resource:///modules/PrefUtils.sys.mjs"
|
|
);
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(
|
|
this,
|
|
"styleSheetService",
|
|
"@mozilla.org/content/style-sheet-service;1",
|
|
"nsIStyleSheetService"
|
|
);
|
|
|
|
const _gThemePane = {
|
|
WATERFOX_THEME_PREF: "browser.theme.enableWaterfoxCustomizations",
|
|
WATERFOX_CUSTOMIZATIONS_PREF: "browser.theme.enableWaterfoxCustomizations",
|
|
WATERFOX_DEFAULT_THEMES: [
|
|
"default-theme@mozilla.org",
|
|
"firefox-compact-light@mozilla.org",
|
|
"firefox-compact-dark@mozilla.org",
|
|
"firefox-alpenglow@mozilla.org",
|
|
],
|
|
|
|
_prefObservers: [],
|
|
|
|
get preferences() {
|
|
return [
|
|
// == Theme ==============================================================
|
|
{ id: "browser.theme.enableWaterfoxCustomizations", type: "int" },
|
|
|
|
// Appearance
|
|
{ id: "userChrome.theme.proton_color.dark_blue_accent", type: "bool" },
|
|
{ id: "userContent.page.proton_color.dark_blue_accent", type: "bool" },
|
|
|
|
{ id: "userContent.page.proton_color.system_accent", type: "bool" },
|
|
{ id: "widget.non-native-theme.use-theme-accent", type: "bool" },
|
|
|
|
{ id: "userChrome.theme.transparent.panel", type: "bool" },
|
|
{ id: "userChrome.theme.transparent.menu", type: "bool" },
|
|
|
|
// Icons
|
|
{ id: "userChrome.icon.disabled", type: "bool" },
|
|
{ id: "userChrome.hidden.tab_icon", type: "bool" },
|
|
{ id: "userChrome.icon.menu.full", type: "bool" },
|
|
{ id: "userChrome.icon.global_menu.mac", type: "bool" },
|
|
|
|
// Fonts
|
|
{ id: "userContent.page.monospace", type: "bool" },
|
|
{ id: "userChrome.theme.monospace", type: "bool" },
|
|
|
|
// Animations
|
|
{ id: "userChrome.decoration.disable_panel_animate", type: "bool" },
|
|
{ id: "userChrome.decoration.disable_sidebar_animate", type: "bool" },
|
|
|
|
// == Interface Components ===============================================
|
|
// Tab Bar
|
|
{ id: "userChrome.tab.photon_like_contextline", type: "bool" },
|
|
{ id: "userChrome.padding.drag_space", type: "bool" },
|
|
{ id: "userChrome.tab.close_button_at_hover", type: "bool" },
|
|
|
|
// Nav Bar
|
|
{ id: "userChrome.padding.urlView_expanding", type: "bool" },
|
|
|
|
// Panels
|
|
{ id: "userChrome.padding.menu_compact", type: "bool" },
|
|
{ id: "userChrome.padding.bookmark_menu.compact", type: "bool" },
|
|
{ id: "userChrome.padding.panel_header", type: "bool" },
|
|
{ id: "userChrome.panel.remove_strip", type: "bool" },
|
|
{ id: "userChrome.panel.full_width_separator", type: "bool" },
|
|
|
|
// == Rounding ===========================================================
|
|
// Tab Bar
|
|
{ id: "userChrome.rounding.square_tab", type: "bool" },
|
|
{ id: "userChrome.tab.bottom_rounded_corner", type: "bool" },
|
|
{ id: "userChrome.tab.squareTabCorners", type: "bool" },
|
|
|
|
// Nav Bar
|
|
{ id: "userChrome.rounding.square_button", type: "bool" },
|
|
|
|
// Panels
|
|
{ id: "userChrome.rounding.square_panel", type: "bool" },
|
|
{ id: "userChrome.rounding.square_panelitem", type: "bool" },
|
|
{ id: "userChrome.rounding.square_menupopup", type: "bool" },
|
|
{ id: "userChrome.rounding.square_menuitem", type: "bool" },
|
|
{ id: "userChrome.rounding.square_field", type: "bool" },
|
|
{ id: "userChrome.rounding.square_checklabel", type: "bool" },
|
|
|
|
// == Autohide & Hidden ==================================================
|
|
// Tab Bar
|
|
{ id: "userChrome.autohide.tab", type: "bool" },
|
|
{ id: "userChrome.autohide.tab.blur", type: "bool" },
|
|
{ id: "userChrome.autohide.tabbar", type: "bool" },
|
|
|
|
// Nav Bar
|
|
{ id: "userChrome.autohide.back_button", type: "bool" },
|
|
{ id: "userChrome.autohide.forward_button", type: "bool" },
|
|
{ id: "userChrome.autohide.page_action", type: "bool" },
|
|
{ id: "userChrome.hidden.urlbar_iconbox", type: "bool" },
|
|
|
|
// Bookmarks Bar
|
|
{ id: "userChrome.autohide.bookmarkbar", type: "bool" },
|
|
{ id: "userChrome.hidden.bookmarkbar_icon", type: "bool" },
|
|
{ id: "userChrome.hidden.bookmarkbar_label", type: "bool" },
|
|
|
|
// Panels
|
|
{ id: "userChrome.hidden.disabled_menu", type: "bool" },
|
|
|
|
// Sidebar
|
|
{ id: "userChrome.autohide.sidebar", type: "bool" },
|
|
{ id: "userChrome.hidden.sidebar_header", type: "bool" },
|
|
|
|
// == Center =============================================================
|
|
// Tab Bar
|
|
{ id: "userChrome.centered.tab", type: "bool" },
|
|
{ id: "userChrome.centered.tab.label", type: "bool" },
|
|
|
|
// Nav Bar
|
|
{ id: "userChrome.centered.urlbar", type: "bool" },
|
|
];
|
|
},
|
|
|
|
get nestedPrefs() {
|
|
return [
|
|
{
|
|
id: "autoBlurTabs",
|
|
pref: "userChrome.autohide.tab",
|
|
},
|
|
{
|
|
id: "centerTabLabel",
|
|
pref: "userChrome.centered.tab",
|
|
},
|
|
];
|
|
},
|
|
|
|
get presets() {
|
|
return [
|
|
{
|
|
id: "waterfoxDefaults",
|
|
on: [
|
|
{ id: "userChrome.tab.connect_to_window", value: true },
|
|
{ id: "userChrome.tab.color_like_toolbar", value: true },
|
|
|
|
{ id: "userChrome.tab.lepton_like_padding", value: false },
|
|
{ id: "userChrome.tab.photon_like_padding", value: true },
|
|
|
|
{ id: "userChrome.tab.dynamic_separator", value: false },
|
|
{ id: "userChrome.tab.static_separator", value: true },
|
|
{
|
|
id: "userChrome.tab.static_separator.selected_accent",
|
|
value: false,
|
|
},
|
|
{ id: "userChrome.tab.bar_separator", value: false },
|
|
|
|
{ id: "userChrome.tab.newtab_button_like_tab", value: false },
|
|
{ id: "userChrome.tab.newtab_button_smaller", value: true },
|
|
{ id: "userChrome.tab.newtab_button_proton", value: false },
|
|
|
|
{ id: "userChrome.icon.panel_full", value: false },
|
|
{ id: "userChrome.icon.panel_photon", value: true },
|
|
|
|
{ id: "userChrome.tab.box_shadow", value: false },
|
|
{ id: "userChrome.tab.bottom_rounded_corner", value: false },
|
|
|
|
{ id: "userChrome.tab.photon_like_contextline", value: true },
|
|
{ id: "userChrome.rounding.square_tab", value: true },
|
|
],
|
|
},
|
|
{
|
|
id: "leptonStyle",
|
|
on: [
|
|
{ id: "userChrome.tab.connect_to_window", value: true },
|
|
{ id: "userChrome.tab.color_like_toolbar", value: true },
|
|
|
|
{ id: "userChrome.tab.lepton_like_padding", value: true },
|
|
{ id: "userChrome.tab.photon_like_padding", value: false },
|
|
|
|
{ id: "userChrome.tab.dynamic_separator", value: true },
|
|
{ id: "userChrome.tab.static_separator", value: false },
|
|
{
|
|
id: "userChrome.tab.static_separator.selected_accent",
|
|
value: false,
|
|
},
|
|
{ id: "userChrome.tab.bar_separator", value: false },
|
|
|
|
{ id: "userChrome.tab.newtab_button_like_tab", value: true },
|
|
{ id: "userChrome.tab.newtab_button_smaller", value: false },
|
|
{ id: "userChrome.tab.newtab_button_proton", value: false },
|
|
|
|
{ id: "userChrome.icon.panel_full", value: true },
|
|
{ id: "userChrome.icon.panel_photon", value: false },
|
|
|
|
{ id: "userChrome.tab.box_shadow", value: true },
|
|
{ id: "userChrome.tab.bottom_rounded_corner", value: true },
|
|
|
|
{ id: "userChrome.tab.photon_like_contextline", value: false },
|
|
{ id: "userChrome.rounding.square_tab", value: false },
|
|
],
|
|
},
|
|
{
|
|
id: "protonStyle",
|
|
on: [
|
|
{ id: "userChrome.tab.connect_to_window", value: false },
|
|
{ id: "userChrome.tab.color_like_toolbar", value: false },
|
|
|
|
{ id: "userChrome.tab.lepton_like_padding", value: false },
|
|
{ id: "userChrome.tab.photon_like_padding", value: false },
|
|
|
|
{ id: "userChrome.tab.dynamic_separator", value: true },
|
|
{ id: "userChrome.tab.static_separator", value: false },
|
|
{
|
|
id: "userChrome.tab.static_separator.selected_accent",
|
|
value: false,
|
|
},
|
|
{ id: "userChrome.tab.bar_separator", value: false },
|
|
|
|
{ id: "userChrome.tab.newtab_button_like_tab", value: false },
|
|
{ id: "userChrome.tab.newtab_button_smaller", value: false },
|
|
{ id: "userChrome.tab.newtab_button_proton", value: true },
|
|
|
|
{ id: "userChrome.icon.panel_full", value: true },
|
|
{ id: "userChrome.icon.panel_photon", value: false },
|
|
|
|
{ id: "userChrome.tab.box_shadow", value: false },
|
|
{ id: "userChrome.tab.bottom_rounded_corner", value: false },
|
|
|
|
{ id: "userChrome.tab.photon_like_contextline", value: false },
|
|
{ id: "userChrome.rounding.square_tab", value: false },
|
|
],
|
|
},
|
|
];
|
|
},
|
|
|
|
get accentPrefs() {
|
|
return {
|
|
0: [
|
|
{ id: "userChrome.theme.proton_color.dark_blue_accent", value: true },
|
|
{ id: "userContent.page.proton_color.dark_blue_accent", value: true },
|
|
|
|
{ id: "userContent.page.proton_color.system_accent", value: false },
|
|
{ id: "widget.non-native-theme.use-theme-accent", value: false },
|
|
],
|
|
|
|
1: [
|
|
{ id: "userChrome.theme.proton_color.dark_blue_accent", value: false },
|
|
{ id: "userContent.page.proton_color.dark_blue_accent", value: false },
|
|
|
|
{ id: "userContent.page.proton_color.system_accent", value: false },
|
|
{ id: "widget.non-native-theme.use-theme-accent", value: false },
|
|
],
|
|
|
|
2: [
|
|
{ id: "userChrome.theme.proton_color.dark_blue_accent", value: false },
|
|
{ id: "userContent.page.proton_color.dark_blue_accent", value: false },
|
|
|
|
{ id: "userContent.page.proton_color.system_accent", value: true },
|
|
{ id: "widget.non-native-theme.use-theme-accent", value: true },
|
|
],
|
|
};
|
|
},
|
|
|
|
init() {
|
|
// Initialize prefs
|
|
window.Preferences.addAll(this.preferences);
|
|
const _userChromeEnabled = PrefUtils.get(this.WATERFOX_THEME_PREF);
|
|
for (const pref of this.preferences) {
|
|
this._prefObservers.push(
|
|
PrefUtils.addObserver(pref.id, (_) => {
|
|
this.refreshTheme();
|
|
})
|
|
);
|
|
}
|
|
|
|
// Init presets
|
|
for (const preset of this.presets) {
|
|
const button = document.getElementById(preset.id);
|
|
if (button) {
|
|
button.addEventListener("click", (_event) => {
|
|
for (const pref of preset.on) {
|
|
PrefUtils.set(pref.id, pref.value);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Init default button
|
|
const defaultButton = document.getElementById("waterfoxDefaults");
|
|
if (defaultButton) {
|
|
defaultButton.addEventListener("click", this);
|
|
}
|
|
|
|
// Init popups
|
|
const popups = document.getElementsByClassName("popup-container");
|
|
for (const popup of popups) {
|
|
popup.addEventListener("mouseover", this);
|
|
popup.addEventListener("mouseout", this);
|
|
}
|
|
|
|
// Init AccentColor
|
|
this.initAccentColor();
|
|
|
|
// Init Tab Rounding
|
|
this.initTabRounding();
|
|
|
|
// Init Nested Prefs
|
|
for (const el of this.nestedPrefs) {
|
|
this.initNestedPrefs(el.id, el.pref);
|
|
}
|
|
|
|
// Register unload listener
|
|
window.addEventListener("unload", this);
|
|
},
|
|
|
|
destroy() {
|
|
window.removeEventListener("unload", this);
|
|
for (const obs of this._prefObservers) {
|
|
PrefUtils.removeObserver(obs);
|
|
}
|
|
},
|
|
|
|
// nsIDOMEventListener
|
|
handleEvent(event) {
|
|
switch (event.type) {
|
|
case "mouseover":
|
|
case "mouseout":
|
|
event.target.nextElementSibling?.classList.toggle("show");
|
|
break;
|
|
case "click":
|
|
switch (event.target.id) {
|
|
case "waterfoxDefaults":
|
|
this.preferences.map((pref) => {
|
|
Services.prefs.clearUserPref(pref.id);
|
|
});
|
|
this.refreshTheme();
|
|
break;
|
|
}
|
|
break;
|
|
case "unload":
|
|
this.destroy();
|
|
break;
|
|
}
|
|
},
|
|
|
|
async refreshTheme() {
|
|
// Only refresh theme if Waterfox customizations should be applied
|
|
if (
|
|
PrefUtils.get(this.WATERFOX_CUSTOMIZATIONS_PREF, 0) === 0 ||
|
|
(PrefUtils.get(this.WATERFOX_CUSTOMIZATIONS_PREF, 0) === 1 &&
|
|
this.WATERFOX_DEFAULT_THEMES.includes(
|
|
PrefUtils.get("extensions.activeThemeID", "")
|
|
))
|
|
) {
|
|
const userChromeSheet = "chrome://browser/skin/userChrome.css";
|
|
const userContentSheet = "chrome://browser/skin/userContent.css";
|
|
|
|
this.unregisterStylesheet(userChromeSheet);
|
|
this.unregisterStylesheet(userContentSheet);
|
|
this.registerStylesheet(userContentSheet);
|
|
}
|
|
},
|
|
|
|
registerStylesheet(uri) {
|
|
const url = Services.io.newURI(uri);
|
|
const type = styleSheetService.USER_SHEET;
|
|
styleSheetService.loadAndRegisterSheet(url, type);
|
|
},
|
|
|
|
unregisterStylesheet(uri) {
|
|
const url = Services.io.newURI(uri);
|
|
const type = styleSheetService.USER_SHEET;
|
|
styleSheetService.unregisterSheet(url, type);
|
|
},
|
|
|
|
async initAccentColor() {
|
|
let menulist = document.getElementById("accentColor");
|
|
// If it doesn't exist yet, try again.
|
|
while (!menulist) {
|
|
const wait = (ms) => new Promise((res) => setTimeout(res, ms, {}));
|
|
await wait(500);
|
|
menulist = document.getElementById("accentColor");
|
|
}
|
|
|
|
menulist?.addEventListener("command", () => {
|
|
if (["0", "1", "2"].includes(menulist.value)) {
|
|
for (const pref of this.accentPrefs[menulist.value]) {
|
|
PrefUtils.set(pref.id, pref.value);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
async initTabRounding() {
|
|
let checkbox = document.getElementById("squareTabCorners");
|
|
// If it doesn't exist yet, try again.
|
|
while (!checkbox) {
|
|
const wait = (ms) => new Promise((res) => setTimeout(res, ms, {}));
|
|
await wait(500);
|
|
checkbox = document.getElementById("squareTabCorners");
|
|
}
|
|
|
|
// Update the checkbox initially, and observe pref changes.
|
|
this.updateTabRoundingCheckbox();
|
|
this._prefObservers.push(
|
|
PrefUtils.addObserver("userChrome.tab.squareTabCorners", (square) => {
|
|
PrefUtils.set("userChrome.rounding.square_tab", square);
|
|
PrefUtils.set("userChrome.tab.bottom_rounded_corner", !square);
|
|
})
|
|
);
|
|
},
|
|
|
|
updateTabRoundingCheckbox() {
|
|
const checkbox = document.getElementById("squareTabCorners");
|
|
const enabled = PrefUtils.get(
|
|
"userChrome.tab.squareTabCorners",
|
|
PrefUtils.get("userChrome.rounding.square_tab", false) &&
|
|
PrefUtils.set("userChrome.tab.bottom_rounded_corner", true)
|
|
);
|
|
|
|
checkbox.checked = enabled;
|
|
},
|
|
|
|
async initNestedPrefs(id, controllingPref) {
|
|
let checkbox = document.getElementById(id);
|
|
// If it doesn't exist yet, try again.
|
|
while (!checkbox) {
|
|
const wait = (ms) => new Promise((res) => setTimeout(res, ms, {}));
|
|
await wait(500);
|
|
checkbox = document.getElementById(id);
|
|
}
|
|
const enabled = PrefUtils.get(controllingPref, false);
|
|
|
|
checkbox.setAttribute("disabled", !enabled);
|
|
|
|
this._prefObservers.push(
|
|
PrefUtils.addObserver(controllingPref, (enabled, pref) => {
|
|
// We need this as observer fires for pref and pref.<some sub path>
|
|
if (pref !== controllingPref) {
|
|
return;
|
|
}
|
|
const checkbox = document.getElementById(id);
|
|
checkbox.setAttribute("disabled", !enabled);
|
|
})
|
|
);
|
|
},
|
|
};
|