fix: Start working on more eslint rules, p=#11874

* fix: Start working on more eslint rules, b=no-bug, c=common, mods, workspaces

* chore: Continue migration, b=no-bug, c=workflows, windows, glance, mods, welcome, workspaces, common, compact-mode, folders, tests, kbs, media, split-view, tabs

* chore: Finish, b=no-bug, c=common, compact-mode, folders, glance, tests, kbs, media, mods, split-view, tabs, workspaces, welcome

* fix: Fix installing deps, b=no-bug, c=common

* feat: Dont initialize git on download checks, b=no-bug, c=workflows

* feat: Remove empty JS docs, b=no-bug, c=common, compact-mode, folders, glance, kbs, media, mods, split-view, tabs, tests, workspaces

* chore: Run lint, b=no-bug, c=common, folders, glance, kbs, mods, split-view, tabs, workspaces
This commit is contained in:
mr. m
2026-01-12 15:11:43 +01:00
committed by GitHub
parent fd82ad95b7
commit 37eed5fcfe
200 changed files with 15153 additions and 12664 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
@namespace html 'http://www.w3.org/1999/xhtml';
@namespace html "http://www.w3.org/1999/xhtml";
:root {
--in-content-box-background: var(--zen-colors-tertiary) !important;
@@ -78,7 +78,7 @@ groupbox h2 {
}
#categories > .category[selected]::before {
content: '';
content: "";
display: block;
height: 70%;
width: 5px;
@@ -89,7 +89,7 @@ groupbox h2 {
}
#languagesGroup::before {
content: '';
content: "";
display: block;
height: 1px;
background-color: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
@@ -123,7 +123,7 @@ groupbox h2 {
}
#category-zen-looks > .category-icon {
list-style-image: url('chrome://browser/skin/customize.svg');
list-style-image: url("chrome://browser/skin/customize.svg");
}
#zenLooksAndFeelGroup > html|div:last-of-type {
@@ -176,7 +176,7 @@ groupbox h2 {
/* Workspace */
#category-zen-tabs-management > .category-icon {
list-style-image: url('chrome://browser/skin/window.svg');
list-style-image: url("chrome://browser/skin/window.svg");
}
#zenTabsUnloadDelayContainer {
@@ -191,7 +191,7 @@ groupbox h2 {
/* CKS */
#category-zen-CKS > .category-icon {
list-style-image: url('chrome://browser/skin/quickactions.svg');
list-style-image: url("chrome://browser/skin/quickactions.svg");
}
.zenCKSOption-input {
@@ -325,7 +325,7 @@ groupbox h2 {
/* THemes marketplace */
#category-zen-marketplace > .category-icon {
list-style-image: url('chrome://mozapps/skin/extensions/category-themes.svg');
list-style-image: url("chrome://mozapps/skin/extensions/category-themes.svg");
}
.zenThemeMarketplaceItem {
@@ -347,14 +347,14 @@ groupbox h2 {
cursor: pointer;
&::before {
content: '';
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 18px;
height: 18px;
background-image: url('chrome://browser/skin/home.svg');
background-image: url("chrome://browser/skin/home.svg");
background-repeat: no-repeat;
background-size: cover;
fill: currentColor;
@@ -369,14 +369,14 @@ groupbox h2 {
cursor: pointer;
&::before {
content: '';
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 15px;
height: 15px;
background-image: url('chrome://global/skin/icons/settings.svg');
background-image: url("chrome://global/skin/icons/settings.svg");
background-repeat: no-repeat;
background-size: cover;
}
@@ -493,7 +493,7 @@ groupbox h2 {
font-weight: 600;
cursor: pointer;
&[disabled='true'] {
&[disabled="true"] {
opacity: 0.7;
cursor: not-allowed;
}
@@ -532,16 +532,16 @@ groupbox h2 {
.sync-engine-workspaces .checkbox-icon,
.sync-engine-workspaces.sync-engine-image {
list-style-image: url('chrome://devtools/skin/images/tool-storage.svg');
list-style-image: url("chrome://devtools/skin/images/tool-storage.svg");
}
@media -moz-pref('zen.theme.disable-lightweight') {
html|div[data-l10n-id='preferences-web-appearance-footer'] {
@media -moz-pref("zen.theme.disable-lightweight") {
html|div[data-l10n-id="preferences-web-appearance-footer"] {
display: none;
}
}
@media -moz-pref('zen.urlbar.replace-newtab') {
@media -moz-pref("zen.urlbar.replace-newtab") {
#category-home {
display: none !important;
}

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@
/// <reference types="./lib.gecko.esnext.d.ts" />
/// <reference types="./lib.gecko.tweaks.d.ts" />
import type {} from './lib.gecko.augmentations.d.ts';
import type {} from "./lib.gecko.augmentations.d.ts";
declare global {
const Cc: nsXPCComponents_Classes;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,7 @@ interface CanonicalBrowsingContext extends LoadContextMixin {
}
declare namespace ChromeUtils {
type Modules = import('./generated/lib.gecko.modules').Modules;
type Modules = import("./generated/lib.gecko.modules").Modules;
function importESModule<T extends keyof Modules>(
aResourceURI: T,
@@ -29,15 +29,15 @@ interface ChromeWindow extends Window {
}
interface Document {
createXULElement(name: 'browser'): MozBrowser;
createXULElement(name: "browser"): MozBrowser;
}
type nsIGleanPingNoReason = {
[K in keyof nsIGleanPing]: K extends 'submit' ? (_?: never) => void : nsIGleanPing[K];
[K in keyof nsIGleanPing]: K extends "submit" ? (_?: never) => void : nsIGleanPing[K];
};
type nsIGleanPingWithReason<T> = {
[K in keyof nsIGleanPing]: K extends 'submit' ? (reason: T) => void : nsIGleanPing[K];
[K in keyof nsIGleanPing]: K extends "submit" ? (reason: T) => void : nsIGleanPing[K];
};
interface MessageListenerManagerMixin {

View File

@@ -18,8 +18,8 @@
/// <reference types="../lib.gecko.tweaks.d.ts" />
/// <reference types="../lib.gecko.nsresult.d.ts" />
declare var window: Window;
declare var Components: nsIXPCComponents;
declare let window: Window;
declare let Components: nsIXPCComponents;
declare var Cu: nsIXPCComponents_Utils;
declare var Ci: nsIXPCComponents_Interfaces;
declare var Services: JSServices;
@@ -72,10 +72,10 @@ declare namespace MockedExports {
* This interface teaches ChromeUtils.importESModule how to find modules.
*/
interface KnownModules {
Services: typeof import('Services');
'resource://gre/modules/AppConstants.sys.mjs': typeof import('resource://gre/modules/AppConstants.sys.mjs');
'resource:///modules/CustomizableUI.sys.mjs': typeof import('resource:///modules/CustomizableUI.sys.mjs');
'resource:///modules/CustomizableWidgets.sys.mjs': typeof import('resource:///modules/CustomizableWidgets.sys.mjs');
Services: typeof import("Services");
"resource://gre/modules/AppConstants.sys.mjs": typeof import("resource://gre/modules/AppConstants.sys.mjs");
"resource:///modules/CustomizableUI.sys.mjs": typeof import("resource:///modules/CustomizableUI.sys.mjs");
"resource:///modules/CustomizableWidgets.sys.mjs": typeof import("resource:///modules/CustomizableWidgets.sys.mjs");
}
interface ChromeUtils {
@@ -166,7 +166,7 @@ declare namespace MockedExports {
type PrefObserverFunction = (
aSubject: nsIPrefBranch,
aTopic: 'nsPref:changed',
aTopic: "nsPref:changed",
aData: string
) => unknown;
type PrefObserver = PrefObserverFunction | { observe: PrefObserverFunction };
@@ -310,7 +310,7 @@ declare namespace MockedExports {
}
interface Cc {
'@mozilla.org/filepicker;1': {
"@mozilla.org/filepicker;1": {
createInstance(instance: nsIFilePicker): FilePicker;
};
}
@@ -339,17 +339,17 @@ interface PathUtilsInterface {
isAbsolute: (path: string) => boolean;
}
declare module 'Services' {
declare module "Services" {
export = MockedExports.Services;
}
declare module 'ChromeUtils' {
declare module "ChromeUtils" {
export = ChromeUtils;
}
declare var ChromeUtils: MockedExports.ChromeUtils;
declare let ChromeUtils: MockedExports.ChromeUtils;
declare var PathUtils: PathUtilsInterface;
declare let PathUtils: PathUtilsInterface;
// These global objects can be used directly in JSM files only.
declare var Cu: MockedExports.Cu;
@@ -365,7 +365,7 @@ declare interface ChromeDocument extends Document {
* Create a XUL element of a specific type. Right now this function
* only refines iframes, but more tags could be added.
*/
createXULElement: ((type: 'iframe') => XULIframeElement) & ((type: string) => XULElement);
createXULElement: ((type: "iframe") => XULIframeElement) & ((type: string) => XULElement);
/**
* This is a fluent instance connected to this document.
@@ -400,7 +400,7 @@ declare interface Window {
browsingContext: MockedExports.BrowsingContext;
openWebLinkIn: (
url: string,
where: 'current' | 'tab' | 'tabshifted' | 'window' | 'save',
where: "current" | "tab" | "tabshifted" | "window" | "save",
options?: Partial<{
// Not all possible options are present, please add more if/when needed.
userContextId: number;
@@ -411,7 +411,7 @@ declare interface Window {
) => void;
openTrustedLinkIn: (
url: string,
where: 'current' | 'tab' | 'tabshifted' | 'window' | 'save',
where: "current" | "tab" | "tabshifted" | "window" | "save",
options?: Partial<{
// Not all possible options are present, please add more if/when needed.
userContextId: number;
@@ -435,12 +435,12 @@ declare interface XULCommandEvent extends Event {
declare interface XULElementWithCommandHandler {
addEventListener: (
type: 'command',
type: "command",
handler: (event: XULCommandEvent) => void,
isCapture?: boolean
) => void;
removeEventListener: (
type: 'command',
type: "command",
handler: (event: XULCommandEvent) => void,
isCapture?: boolean
) => void;

View File

@@ -3,7 +3,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// prettier-ignore
// eslint-disable-next-line no-lone-blocks
{
Services.scriptloader.loadSubScript("chrome://browser/content/zen-components/ZenWorkspaceBookmarksStorage.js", this);

View File

@@ -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 { nsZenDOMOperatedFeature } from 'chrome://browser/content/zen-components/ZenCommonUtils.mjs';
import { nsZenDOMOperatedFeature } from "chrome://browser/content/zen-components/ZenCommonUtils.mjs";
// prettier-ignore
const SVG_ICONS = [
@@ -41,31 +41,31 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
#currentPromiseReject = null;
init() {
this.#panel = document.getElementById('PanelUI-zen-emojis-picker');
this.#panel.addEventListener('popupshowing', this);
this.#panel.addEventListener('popuphidden', this);
this.#panel.addEventListener('command', this);
this.searchInput.addEventListener('input', this);
this.#panel = document.getElementById("PanelUI-zen-emojis-picker");
this.#panel.addEventListener("popupshowing", this);
this.#panel.addEventListener("popuphidden", this);
this.#panel.addEventListener("command", this);
this.searchInput.addEventListener("input", this);
}
handleEvent(event) {
switch (event.type) {
case 'popupshowing':
case "popupshowing":
this.#onPopupShowing(event);
break;
case 'popuphidden':
case "popuphidden":
this.#onPopupHidden(event);
break;
case 'command':
if (event.target.id === 'PanelUI-zen-emojis-picker-none') {
case "command":
if (event.target.id === "PanelUI-zen-emojis-picker-none") {
this.#selectEmoji(null);
} else if (event.target.id === 'PanelUI-zen-emojis-picker-change-emojis') {
} else if (event.target.id === "PanelUI-zen-emojis-picker-change-emojis") {
this.#changePage(false);
} else if (event.target.id === 'PanelUI-zen-emojis-picker-change-svg') {
} else if (event.target.id === "PanelUI-zen-emojis-picker-change-svg") {
this.#changePage(true);
}
break;
case 'input':
case "input":
this.#onSearchInput(event);
break;
}
@@ -77,42 +77,43 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
}
const lazy = {};
Services.scriptloader.loadSubScript(
'chrome://browser/content/zen-components/ZenEmojisData.min.mjs',
"chrome://browser/content/zen-components/ZenEmojisData.min.mjs",
lazy
);
/* eslint-disable mozilla/valid-lazy */
this._emojis = lazy.ZenEmojisData;
return this._emojis;
}
get emojiList() {
return document.getElementById('PanelUI-zen-emojis-picker-list');
return document.getElementById("PanelUI-zen-emojis-picker-list");
}
get svgList() {
return document.getElementById('PanelUI-zen-emojis-picker-svgs');
return document.getElementById("PanelUI-zen-emojis-picker-svgs");
}
get searchInput() {
return document.getElementById('PanelUI-zen-emojis-picker-search');
return document.getElementById("PanelUI-zen-emojis-picker-search");
}
#changePage(toSvg = false) {
const itemToScroll = toSvg
? this.svgList
: document.getElementById('PanelUI-zen-emojis-picker-pages').querySelector('[emojis="true"]');
: document.getElementById("PanelUI-zen-emojis-picker-pages").querySelector('[emojis="true"]');
itemToScroll.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'start',
behavior: "smooth",
block: "nearest",
inline: "start",
});
const button = document.getElementById(
`PanelUI-zen-emojis-picker-change-${toSvg ? 'svg' : 'emojis'}`
`PanelUI-zen-emojis-picker-change-${toSvg ? "svg" : "emojis"}`
);
const otherButton = document.getElementById(
`PanelUI-zen-emojis-picker-change-${toSvg ? 'emojis' : 'svg'}`
`PanelUI-zen-emojis-picker-change-${toSvg ? "emojis" : "svg"}`
);
button.classList.add('selected');
otherButton.classList.remove('selected');
button.classList.add("selected");
otherButton.classList.remove("selected");
}
#clearEmojis() {
@@ -129,7 +130,7 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
})
.sort((a, b) => a.order - b.order);
for (const button of this.emojiList.children) {
const buttonEmoji = button.getAttribute('label');
const buttonEmoji = button.getAttribute("label");
const emojiObject = filteredEmojis.find((emoji) => emoji.emoji === buttonEmoji);
if (emojiObject) {
button.hidden = !emojiObject.tags.some((tag) => tag.toLowerCase().includes(value));
@@ -142,17 +143,19 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
// note: It's async on purpose so we can render the popup before processing the emojis
async #onPopupShowing(event) {
if (event.target !== this.#panel) return;
this.searchInput.value = '';
const allowEmojis = !this.#panel.hasAttribute('only-svg-icons');
if (event.target !== this.#panel) {
return;
}
this.searchInput.value = "";
const allowEmojis = !this.#panel.hasAttribute("only-svg-icons");
if (allowEmojis) {
const emojiList = this.emojiList;
for (const emoji of this.#emojis) {
const item = document.createXULElement('toolbarbutton');
item.className = 'toolbarbutton-1 zen-emojis-picker-emoji';
item.setAttribute('label', emoji.emoji);
item.setAttribute('tooltiptext', '');
item.addEventListener('command', () => {
const item = document.createXULElement("toolbarbutton");
item.className = "toolbarbutton-1 zen-emojis-picker-emoji";
item.setAttribute("label", emoji.emoji);
item.setAttribute("tooltiptext", "");
item.addEventListener("command", () => {
this.#selectEmoji(emoji.emoji);
});
emojiList.appendChild(item);
@@ -163,13 +166,13 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
}
const svgList = this.svgList;
for (const icon of SVG_ICONS) {
const item = document.createXULElement('toolbarbutton');
item.className = 'toolbarbutton-1 zen-emojis-picker-svg';
item.setAttribute('label', icon);
item.setAttribute('tooltiptext', '');
const item = document.createXULElement("toolbarbutton");
item.className = "toolbarbutton-1 zen-emojis-picker-svg";
item.setAttribute("label", icon);
item.setAttribute("tooltiptext", "");
item.style.listStyleImage = `url(${this.getSVGURL(icon)})`;
item.setAttribute('icon', icon);
item.addEventListener('command', () => {
item.setAttribute("icon", icon);
item.addEventListener("command", () => {
this.#selectEmoji(this.getSVGURL(icon));
});
svgList.appendChild(item);
@@ -177,31 +180,33 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
}
#onPopupHidden(event) {
if (event.target !== this.#panel) return;
if (event.target !== this.#panel) {
return;
}
this.#clearEmojis();
this.#changePage(false);
const emojiList = this.emojiList;
emojiList.innerHTML = '';
emojiList.innerHTML = "";
this.svgList.innerHTML = '';
this.svgList.innerHTML = "";
if (this.#currentPromiseReject) {
this.#currentPromiseReject(new Error('Emoji picker closed without selection'));
this.#currentPromiseReject(new Error("Emoji picker closed without selection"));
}
this.#currentPromise = null;
this.#currentPromiseResolve = null;
this.#currentPromiseReject = null;
this.#anchor.removeAttribute('zen-emoji-open');
this.#anchor.parentElement.removeAttribute('zen-emoji-open');
this.#anchor.removeAttribute("zen-emoji-open");
this.#anchor.parentElement.removeAttribute("zen-emoji-open");
this.#anchor = null;
}
#selectEmoji(emoji) {
if (this.#emojiAsSVG && emoji && !emoji.startsWith('chrome://')) {
if (this.#emojiAsSVG && emoji && !emoji.startsWith("chrome://")) {
emoji = `data:image/svg+xml;base64,${btoa(
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><text y="28" font-size="28" x="0">${unescape(
encodeURIComponent(emoji)
@@ -222,14 +227,14 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
this.#currentPromiseReject = reject;
});
this.#anchor = anchor;
this.#anchor.setAttribute('zen-emoji-open', 'true');
this.#anchor.parentElement.setAttribute('zen-emoji-open', 'true');
this.#anchor.setAttribute("zen-emoji-open", "true");
this.#anchor.parentElement.setAttribute("zen-emoji-open", "true");
if (onlySvgIcons) {
this.#panel.setAttribute('only-svg-icons', 'true');
this.#panel.setAttribute("only-svg-icons", "true");
} else {
this.#panel.removeAttribute('only-svg-icons');
this.#panel.removeAttribute("only-svg-icons");
}
this.#panel.openPopup(anchor, 'after_start', 0, 0, false, false);
this.#panel.openPopup(anchor, "after_start", 0, 0, false, false);
return this.#currentPromise;
}

File diff suppressed because one or more lines are too long

View File

@@ -4,9 +4,9 @@
window.gZenOperatingSystemCommonUtils = {
kZenOSToSmallName: {
WINNT: 'windows',
Darwin: 'macos',
Linux: 'linux',
WINNT: "windows",
Darwin: "macos",
Linux: "linux",
},
get currentOperatingSystem() {
@@ -19,11 +19,11 @@ export class nsZenMultiWindowFeature {
constructor() {}
static get browsers() {
return Services.wm.getEnumerator('navigator:browser');
return Services.wm.getEnumerator("navigator:browser");
}
static get currentBrowser() {
return Services.wm.getMostRecentWindow('navigator:browser');
return Services.wm.getMostRecentWindow("navigator:browser");
}
static get isActiveWindow() {
@@ -38,13 +38,15 @@ export class nsZenMultiWindowFeature {
if (!nsZenMultiWindowFeature.isActiveWindow) {
return;
}
return this.forEachWindow(callback);
await this.forEachWindow(callback);
}
async forEachWindow(callback) {
for (const browser of nsZenMultiWindowFeature.browsers) {
try {
if (browser.closed) continue;
if (browser.closed) {
continue;
}
await callback(browser);
} catch (e) {
console.error(e);
@@ -55,7 +57,9 @@ export class nsZenMultiWindowFeature {
forEachWindowSync(callback) {
for (const browser of nsZenMultiWindowFeature.browsers) {
try {
if (browser.closed) continue;
if (browser.closed) {
continue;
}
callback(browser);
} catch (e) {
console.error(e);
@@ -67,14 +71,14 @@ export class nsZenMultiWindowFeature {
export class nsZenDOMOperatedFeature {
constructor() {
var initBound = this.init.bind(this);
document.addEventListener('DOMContentLoaded', initBound, { once: true });
document.addEventListener("DOMContentLoaded", initBound, { once: true });
}
}
export class nsZenPreloadedFeature {
constructor() {
var initBound = this.init.bind(this);
document.addEventListener('MozBeforeInitialXULLayout', initBound, { once: true });
document.addEventListener("MozBeforeInitialXULLayout", initBound, { once: true });
}
}
@@ -84,15 +88,17 @@ window.gZenCommonActions = {
const displaySpec = currentUrl.displaySpec;
ClipboardHelper.copyString(displaySpec);
let button;
if (Services.zen.canShare() && displaySpec.startsWith('http')) {
/* eslint-disable mozilla/valid-services */
if (Services.zen.canShare() && displaySpec.startsWith("http")) {
button = {
id: 'zen-copy-current-url-button',
id: "zen-copy-current-url-button",
command: (event) => {
const buttonRect = event.target.getBoundingClientRect();
/* eslint-disable mozilla/valid-services */
Services.zen.share(
currentUrl,
'',
'',
"",
"",
buttonRect.left,
window.innerHeight - buttonRect.bottom,
buttonRect.width,
@@ -101,7 +107,7 @@ window.gZenCommonActions = {
},
};
}
gZenUIManager.showToast('zen-copy-current-url-confirmation', { button, timeout: 3000 });
gZenUIManager.showToast("zen-copy-current-url-confirmation", { button, timeout: 3000 });
},
copyCurrentURLAsMarkdownToClipboard() {
@@ -109,7 +115,7 @@ window.gZenCommonActions = {
const tabTitle = gBrowser.selectedTab.label;
const markdownLink = `[${tabTitle}](${currentUrl.displaySpec})`;
ClipboardHelper.copyString(markdownLink);
gZenUIManager.showToast('zen-copy-current-url-confirmation', { timeout: 3000 });
gZenUIManager.showToast("zen-copy-current-url-confirmation", { timeout: 3000 });
},
throttle(f, delay) {
@@ -125,13 +131,13 @@ window.gZenCommonActions = {
* Only tabs with an owner that are not pinned and not empty are eligible.
* Respects the user preference zen.tabs.close-on-back-with-no-history.
*
* @return {boolean} True if the tab should be closed on back
* @returns {boolean} True if the tab should be closed on back
*/
shouldCloseTabOnBack() {
if (!Services.prefs.getBoolPref('zen.tabs.close-on-back-with-no-history', true)) {
if (!Services.prefs.getBoolPref("zen.tabs.close-on-back-with-no-history", true)) {
return false;
}
const tab = gBrowser.selectedTab;
return Boolean(tab.owner && !tab.pinned && !tab.hasAttribute('zen-empty-tab'));
return Boolean(tab.owner && !tab.pinned && !tab.hasAttribute("zen-empty-tab"));
},
};

View File

@@ -9,13 +9,16 @@ class nsHasPolyfill {
}
/**
* @param {{selector: string, exists: boolean}} descendantSelectors
* @param {HTMLElement} element
* @param {Array<{selector: string, exists: boolean}>} descendantSelectors
* @param {string} stateAttribute
* @param {Array<string>} attributeFilter
*/
observeSelectorExistence(element, descendantSelectors, stateAttribute, attributeFilter = []) {
const updateState = () => {
const exists = descendantSelectors.some(({ selector }) => {
let selected = element.querySelector(selector);
if (selected?.tagName?.toLowerCase() === 'menu') {
if (selected?.tagName?.toLowerCase() === "menu") {
return null;
}
return selected;
@@ -25,10 +28,8 @@ class nsHasPolyfill {
if (!element.hasAttribute(stateAttribute)) {
gZenCompactModeManager._setElementExpandAttribute(element, true, stateAttribute);
}
} else {
if (element.hasAttribute(stateAttribute)) {
gZenCompactModeManager._setElementExpandAttribute(element, false, stateAttribute);
}
} else if (element.hasAttribute(stateAttribute)) {
gZenCompactModeManager._setElementExpandAttribute(element, false, stateAttribute);
}
};
@@ -70,6 +71,6 @@ class nsHasPolyfill {
}
const hasPolyfillInstance = new nsHasPolyfill();
window.addEventListener('unload', () => hasPolyfillInstance.destroy(), { once: true });
window.addEventListener("unload", () => hasPolyfillInstance.destroy(), { once: true });
window.ZenHasPolyfill = hasPolyfillInstance;

View File

@@ -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/.
const WINDOW_SCHEME_PREF = 'zen.view.window.scheme';
const WINDOW_SCHEME_PREF = "zen.view.window.scheme";
const WINDOW_SCHEME_MAPPING = {
dark: 0,
light: 1,
@@ -25,31 +25,33 @@ class nsZenMenuBar {
<menuitem data-l10n-id="zen-menubar-appearance-dark" data-type="dark" type="radio" />
</menupopup>
</menu>`);
const menu = appearanceMenu.querySelector('menu');
menu.addEventListener('command', (event) => {
const type = event.target.getAttribute('data-type');
const menu = appearanceMenu.querySelector("menu");
menu.addEventListener("command", (event) => {
const type = event.target.getAttribute("data-type");
const schemeValue = WINDOW_SCHEME_MAPPING[type];
Services.prefs.setIntPref(WINDOW_SCHEME_PREF, schemeValue);
});
const parent = document.getElementById('view-menu');
const parentPopup = parent.querySelector('menupopup');
parentPopup.prepend(document.createXULElement('menuseparator'));
const viewMenu = document.getElementById("view-menu");
const parentPopup = viewMenu.querySelector("menupopup");
parentPopup.prepend(document.createXULElement("menuseparator"));
parentPopup.prepend(menu);
const sibling = document.getElementById('viewSidebarMenuMenu');
const sibling = document.getElementById("viewSidebarMenuMenu");
const togglePinnedItem = window.MozXULElement.parseXULToFragment(
'<menuitem data-l10n-id="zen-menubar-toggle-pinned-tabs" />'
).querySelector('menuitem');
if (!gZenWorkspaces.privateWindowOrDisabled) sibling.after(togglePinnedItem);
).querySelector("menuitem");
if (!gZenWorkspaces.privateWindowOrDisabled) {
sibling.after(togglePinnedItem);
}
parentPopup.addEventListener('popupshowing', () => {
parentPopup.addEventListener("popupshowing", () => {
const currentScheme = Services.prefs.getIntPref(WINDOW_SCHEME_PREF);
for (const [type, value] of Object.entries(WINDOW_SCHEME_MAPPING)) {
let menuItem = menu.querySelector(`menuitem[data-type="${type}"]`);
if (value === currentScheme) {
menuItem.setAttribute('checked', 'true');
menuItem.setAttribute("checked", "true");
} else {
menuItem.removeAttribute('checked');
menuItem.removeAttribute("checked");
}
}
const pinnedAreCollapsed =
@@ -58,13 +60,13 @@ class nsZenMenuBar {
document.l10n.setArgs(togglePinnedItem, args);
});
togglePinnedItem.addEventListener('command', () => {
togglePinnedItem.addEventListener("command", () => {
gZenWorkspaces.activeWorkspaceElement?.collapsiblePins.toggle();
});
}
#initSpacesMenu() {
let menubar = window.MozXULElement.parseXULToFragment(`
let spacesMenubar = window.MozXULElement.parseXULToFragment(`
<menu id="zen-spaces-menubar" data-l10n-id="zen-panel-ui-spaces-label">
<menupopup>
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation"/>
@@ -82,8 +84,8 @@ class nsZenMenuBar {
key="zen-workspace-backward"/>
</menupopup>
</menu>`);
document.getElementById('view-menu').after(menubar);
document.getElementById('zen-spaces-menubar').addEventListener('popupshowing', () => {
document.getElementById("view-menu").after(spacesMenubar);
document.getElementById("zen-spaces-menubar").addEventListener("popupshowing", () => {
gZenWorkspaces.updateWorkspacesChangeContextMenu();
});
}

View File

@@ -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 { nsZenPreloadedFeature } from 'chrome://browser/content/zen-components/ZenCommonUtils.mjs';
import { nsZenPreloadedFeature } from "chrome://browser/content/zen-components/ZenCommonUtils.mjs";
class ZenSessionStore extends nsZenPreloadedFeature {
init() {
@@ -15,11 +15,11 @@ class ZenSessionStore extends nsZenPreloadedFeature {
restoreInitialTabData(tab, tabData) {
if (tabData.zenWorkspace) {
tab.setAttribute('zen-workspace-id', tabData.zenWorkspace);
tab.setAttribute("zen-workspace-id", tabData.zenWorkspace);
}
// Keep for now, for backward compatibility for window sync to work.
if (tabData.zenSyncId || tabData.zenPinnedId) {
tab.setAttribute('id', tabData.zenSyncId || tabData.zenPinnedId);
tab.setAttribute("id", tabData.zenSyncId || tabData.zenPinnedId);
}
if (tabData.zenStaticLabel) {
tab.zenStaticLabel = tabData.zenStaticLabel;
@@ -28,10 +28,10 @@ class ZenSessionStore extends nsZenPreloadedFeature {
tab.zenStaticIcon = tabData.image;
}
if (tabData.zenEssential) {
tab.setAttribute('zen-essential', 'true');
tab.setAttribute("zen-essential", "true");
}
if (tabData.zenDefaultUserContextId) {
tab.setAttribute('zenDefaultUserContextId', 'true');
tab.setAttribute("zenDefaultUserContextId", "true");
}
if (tabData._zenPinnedInitialState) {
tab._zenPinnedInitialState = tabData._zenPinnedInitialState;

View File

@@ -2,14 +2,14 @@
* 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 'chrome://global/content/vendor/lit.all.mjs';
import { MozLitElement } from 'chrome://global/content/lit-utils.mjs';
import { html } from "chrome://global/content/vendor/lit.all.mjs";
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
const lazy = {};
ChromeUtils.defineLazyGetter(lazy, 'siblingElement', () => {
ChromeUtils.defineLazyGetter(lazy, "siblingElement", () => {
// All our notifications should be attached after the media controls toolbar
return document.getElementById('zen-media-controls-toolbar');
return document.getElementById("zen-media-controls-toolbar");
});
/**
@@ -17,8 +17,6 @@ ChromeUtils.defineLazyGetter(lazy, 'siblingElement', () => {
*
* Displays and takes care of animations for notifications that
* appear in the sidebar.
*
* @properties {headingL10nId} - The L10n ID for the heading text.
*/
class ZenSidebarNotification extends MozLitElement {
static properties = {
@@ -26,7 +24,7 @@ class ZenSidebarNotification extends MozLitElement {
links: { type: Array },
};
constructor({ headingL10nId = '', links = [] } = {}) {
constructor({ headingL10nId = "", links = [] } = {}) {
super();
this.headingL10nId = headingL10nId;
this.links = links;
@@ -54,7 +52,7 @@ class ZenSidebarNotification extends MozLitElement {
<label
class="zen-sidebar-notification-heading"
flex="1"
data-l10n-id="${this.headingL10nId}"></label>
data-l10n-id=${this.headingL10nId}></label>
<div class="zen-sidebar-notification-close-button" @click=${() => this.remove()}>
<img src="chrome://browser/skin/zen-icons/close.svg" />
</div>
@@ -71,13 +69,13 @@ class ZenSidebarNotification extends MozLitElement {
link.action();
return;
}
window.openLinkIn(link.url, 'tab', {
window.openLinkIn(link.url, "tab", {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
forceForeground: true,
});
this.remove();
}}>
<img class="zen-sidebar-notification-link-icon" src="${link.icon}" />
<img class="zen-sidebar-notification-link-icon" src=${link.icon} />
<label
class="zen-sidebar-notification-link-text"
data-l10n-id="${link.l10nId}-label"></label>
@@ -89,7 +87,7 @@ class ZenSidebarNotification extends MozLitElement {
}
#animateIn() {
this.style.opacity = '0';
this.style.opacity = "0";
return gZenUIManager.motion.animate(
this,
{
@@ -121,8 +119,8 @@ export default function createSidebarNotification(args) {
const notification = new ZenSidebarNotification(args);
lazy.siblingElement.insertAdjacentElement('afterend', notification);
lazy.siblingElement.insertAdjacentElement("afterend", notification);
return notification;
}
customElements.define('zen-sidebar-notification', ZenSidebarNotification);
customElements.define("zen-sidebar-notification", ZenSidebarNotification);

View File

@@ -4,10 +4,10 @@
import checkForZenUpdates, {
createWindowUpdateAnimation,
} from 'chrome://browser/content/ZenUpdates.mjs';
} from "chrome://browser/content/ZenUpdates.mjs";
class ZenStartup {
#watermarkIgnoreElements = ['zen-toast-container'];
#watermarkIgnoreElements = ["zen-toast-container"];
#hasInitializedLayout = false;
isReady = false;
@@ -20,38 +20,42 @@ class ZenStartup {
}
#initBrowserBackground() {
const background = document.createXULElement('box');
background.id = 'zen-browser-background';
background.classList.add('zen-browser-generic-background');
const grain = document.createXULElement('box');
grain.classList.add('zen-browser-grain');
const background = document.createXULElement("box");
background.id = "zen-browser-background";
background.classList.add("zen-browser-generic-background");
const grain = document.createXULElement("box");
grain.classList.add("zen-browser-grain");
background.appendChild(grain);
document.getElementById('browser').prepend(background);
document.getElementById("browser").prepend(background);
const toolbarBackground = background.cloneNode(true);
toolbarBackground.removeAttribute('id');
toolbarBackground.classList.add('zen-toolbar-background');
document.getElementById('titlebar').prepend(toolbarBackground);
toolbarBackground.removeAttribute("id");
toolbarBackground.classList.add("zen-toolbar-background");
document.getElementById("titlebar").prepend(toolbarBackground);
}
#zenInitBrowserLayout() {
if (this.#hasInitializedLayout) return;
if (this.#hasInitializedLayout) {
return;
}
this.#hasInitializedLayout = true;
gZenKeyboardShortcutsManager.beforeInit();
try {
const kNavbarItems = ['nav-bar', 'PersonalToolbar'];
const kNewContainerId = 'zen-appcontent-navbar-container';
const kNavbarItems = ["nav-bar", "PersonalToolbar"];
const kNewContainerId = "zen-appcontent-navbar-container";
let newContainer = document.getElementById(kNewContainerId);
for (let id of kNavbarItems) {
const node = document.getElementById(id);
console.assert(node, 'Could not find node with id: ' + id);
if (!node) continue;
if (!node) {
console.error("Could not find node with id: " + id);
continue;
}
newContainer.appendChild(node);
}
// Fix notification deck
const deckTemplate = document.getElementById('tab-notification-deck-template');
const deckTemplate = document.getElementById("tab-notification-deck-template");
if (deckTemplate) {
document.getElementById('zen-appcontent-wrapper').prepend(deckTemplate);
document.getElementById("zen-appcontent-wrapper").prepend(deckTemplate);
}
gZenWorkspaces.init();
@@ -60,20 +64,20 @@ class ZenStartup {
this.#checkForWelcomePage();
}, 0);
} catch (e) {
console.error('ZenThemeModifier: Error initializing browser layout', e);
console.error("ZenThemeModifier: Error initializing browser layout", e);
}
if (gBrowserInit.delayedStartupFinished) {
this.delayedStartupFinished();
} else {
Services.obs.addObserver(this, 'browser-delayed-startup-finished');
Services.obs.addObserver(this, "browser-delayed-startup-finished");
}
}
observe(aSubject, aTopic) {
// This nsIObserver method allows us to defer initialization until after
// this window has finished painting and starting up.
if (aTopic == 'browser-delayed-startup-finished' && aSubject == window) {
Services.obs.removeObserver(this, 'browser-delayed-startup-finished');
if (aTopic == "browser-delayed-startup-finished" && aSubject == window) {
Services.obs.removeObserver(this, "browser-delayed-startup-finished");
this.delayedStartupFinished();
}
}
@@ -86,35 +90,35 @@ class ZenStartup {
this.#initSearchBar();
gZenCompactModeManager.init();
// Fix for https://github.com/zen-browser/desktop/issues/7605, specially in compact mode
if (gURLBar.hasAttribute('breakout-extend')) {
if (gURLBar.hasAttribute("breakout-extend")) {
gURLBar.focus();
}
// A bit of a hack to make sure the tabs toolbar is updated.
// Just in case we didn't get the right size.
gZenUIManager.updateTabsToolbar();
this.closeWatermark();
document.getElementById('tabbrowser-arrowscrollbox').setAttribute('orient', 'vertical');
document.getElementById("tabbrowser-arrowscrollbox").setAttribute("orient", "vertical");
this.isReady = true;
});
}
openWatermark() {
if (!Services.prefs.getBoolPref('zen.watermark.enabled', false)) {
document.documentElement.removeAttribute('zen-before-loaded');
if (!Services.prefs.getBoolPref("zen.watermark.enabled", false)) {
document.documentElement.removeAttribute("zen-before-loaded");
return;
}
for (let elem of document.querySelectorAll('#browser > *, #urlbar')) {
for (let elem of document.querySelectorAll("#browser > *, #urlbar")) {
elem.style.opacity = 0;
}
}
closeWatermark() {
document.documentElement.removeAttribute('zen-before-loaded');
if (Services.prefs.getBoolPref('zen.watermark.enabled', false)) {
let elementsToIgnore = this.#watermarkIgnoreElements.map((id) => '#' + id).join(', ');
document.documentElement.removeAttribute("zen-before-loaded");
if (Services.prefs.getBoolPref("zen.watermark.enabled", false)) {
let elementsToIgnore = this.#watermarkIgnoreElements.map((id) => "#" + id).join(", ");
gZenUIManager.motion
.animate(
'#browser > *:not(' + elementsToIgnore + '), #urlbar, #tabbrowser-tabbox > *',
"#browser > *:not(" + elementsToIgnore + "), #urlbar, #tabbrowser-tabbox > *",
{
opacity: [0, 1],
},
@@ -124,24 +128,24 @@ class ZenStartup {
)
.then(() => {
for (let elem of document.querySelectorAll(
'#browser > *, #urlbar, #tabbrowser-tabbox > *'
"#browser > *, #urlbar, #tabbrowser-tabbox > *"
)) {
elem.style.removeProperty('opacity');
elem.style.removeProperty("opacity");
}
});
}
window.requestAnimationFrame(() => {
window.dispatchEvent(new window.Event('resize')); // To recalculate the layout
window.dispatchEvent(new window.Event("resize")); // To recalculate the layout
});
}
#changeSidebarLocation() {
const kElementsToAppend = ['sidebar-splitter', 'sidebar-box'];
const kElementsToAppend = ["sidebar-splitter", "sidebar-box"];
const browser = document.getElementById('browser');
const browser = document.getElementById("browser");
browser.prepend(gNavToolbox);
const sidebarPanelWrapper = document.getElementById('tabbrowser-tabbox');
const sidebarPanelWrapper = document.getElementById("tabbrowser-tabbox");
for (let id of kElementsToAppend) {
const elem = document.getElementById(id);
if (elem) {
@@ -156,12 +160,12 @@ class ZenStartup {
}
#checkForWelcomePage() {
if (!Services.prefs.getBoolPref('zen.welcome-screen.seen', false)) {
Services.prefs.setBoolPref('zen.welcome-screen.seen', true);
Services.prefs.setStringPref('zen.updates.last-build-id', Services.appinfo.appBuildID);
Services.prefs.setStringPref('zen.updates.last-version', Services.appinfo.version);
if (!Services.prefs.getBoolPref("zen.welcome-screen.seen", false)) {
Services.prefs.setBoolPref("zen.welcome-screen.seen", true);
Services.prefs.setStringPref("zen.updates.last-build-id", Services.appinfo.appBuildID);
Services.prefs.setStringPref("zen.updates.last-version", Services.appinfo.version);
Services.scriptloader.loadSubScript(
'chrome://browser/content/zen-components/ZenWelcome.mjs',
"chrome://browser/content/zen-components/ZenWelcome.mjs",
window
);
} else {
@@ -178,7 +182,7 @@ class ZenStartup {
window.gZenStartup = new ZenStartup();
window.addEventListener(
'MozBeforeInitialXULLayout',
"MozBeforeInitialXULLayout",
() => {
gZenStartup.init();
},

File diff suppressed because it is too large Load Diff

View File

@@ -2,37 +2,37 @@
// 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 createSidebarNotification from 'chrome://browser/content/zen-components/ZenSidebarNotification.mjs';
import createSidebarNotification from "chrome://browser/content/zen-components/ZenSidebarNotification.mjs";
const ZEN_UPDATE_PREF = 'zen.updates.last-version';
const ZEN_BUILD_ID_PREF = 'zen.updates.last-build-id';
const ZEN_UPDATE_SHOW = 'zen.updates.show-update-notification';
const ZEN_UPDATE_PREF = "zen.updates.last-version";
const ZEN_BUILD_ID_PREF = "zen.updates.last-build-id";
const ZEN_UPDATE_SHOW = "zen.updates.show-update-notification";
export default function checkForZenUpdates() {
const version = Services.appinfo.version;
const lastVersion = Services.prefs.getStringPref(ZEN_UPDATE_PREF, '');
const lastVersion = Services.prefs.getStringPref(ZEN_UPDATE_PREF, "");
Services.prefs.setStringPref(ZEN_UPDATE_PREF, version);
if (
version !== lastVersion &&
!gZenUIManager.testingEnabled &&
Services.prefs.getBoolPref(ZEN_UPDATE_SHOW, true)
) {
const updateUrl = Services.prefs.getStringPref('app.releaseNotesURL.prompt', '');
const updateUrl = Services.prefs.getStringPref("app.releaseNotesURL.prompt", "");
createSidebarNotification({
headingL10nId: 'zen-sidebar-notification-updated-heading',
headingL10nId: "zen-sidebar-notification-updated-heading",
links: [
{
url: Services.urlFormatter.formatURL(updateUrl.replace('%VERSION%', version)),
l10nId: 'zen-sidebar-notification-updated',
url: Services.urlFormatter.formatURL(updateUrl.replace("%VERSION%", version)),
l10nId: "zen-sidebar-notification-updated",
special: true,
icon: 'chrome://browser/skin/zen-icons/heart-circle-fill.svg',
icon: "chrome://browser/skin/zen-icons/heart-circle-fill.svg",
},
{
action: () => {
Services.obs.notifyObservers(window, 'restart-in-safe-mode');
Services.obs.notifyObservers(window, "restart-in-safe-mode");
},
l10nId: 'zen-sidebar-notification-restart-safe-mode',
icon: 'chrome://browser/skin/zen-icons/security-broken.svg',
l10nId: "zen-sidebar-notification-restart-safe-mode",
icon: "chrome://browser/skin/zen-icons/security-broken.svg",
},
],
});
@@ -42,18 +42,18 @@ export default function checkForZenUpdates() {
export async function createWindowUpdateAnimation() {
const appID = Services.appinfo.appBuildID;
if (
Services.prefs.getStringPref(ZEN_BUILD_ID_PREF, '') === appID ||
Services.prefs.getStringPref(ZEN_BUILD_ID_PREF, "") === appID ||
gZenUIManager.testingEnabled
) {
return;
}
Services.prefs.setStringPref(ZEN_BUILD_ID_PREF, appID);
await gZenWorkspaces.promiseInitialized;
const appWrapper = document.getElementById('zen-main-app-wrapper');
const element = document.createElement('div');
element.id = 'zen-update-animation';
const elementBorder = document.createElement('div');
elementBorder.id = 'zen-update-animation-border';
const appWrapper = document.getElementById("zen-main-app-wrapper");
const element = document.createElement("div");
element.id = "zen-update-animation";
const elementBorder = document.createElement("div");
elementBorder.id = "zen-update-animation-border";
requestIdleCallback(() => {
if (gReduceMotion) {
return;
@@ -62,9 +62,9 @@ export async function createWindowUpdateAnimation() {
appWrapper.appendChild(elementBorder);
Promise.all([
gZenUIManager.motion.animate(
'#zen-update-animation',
"#zen-update-animation",
{
top: ['100%', '-50%'],
top: ["100%", "-50%"],
opacity: [0.5, 1],
},
{
@@ -72,9 +72,9 @@ export async function createWindowUpdateAnimation() {
}
),
gZenUIManager.motion.animate(
'#zen-update-animation-border',
"#zen-update-animation-border",
{
'--background-top': ['150%', '-50%'],
"--background-top": ["150%", "-50%"],
},
{
duration: 0.35,

View File

@@ -75,11 +75,7 @@
@keyframes zen-urlbar-searchmode {
0% {
box-shadow: 0 0 20px
color-mix(
in srgb,
color-mix(in srgb, var(--zen-primary-color), var(--toolbox-textcolor) 20%),
light-dark(rgba(0, 0, 0, 0.3), transparent) 50%
);
color-mix(in srgb, color-mix(in srgb, var(--zen-primary-color), var(--toolbox-textcolor) 20%), light-dark(rgba(0, 0, 0, 0.3), transparent) 50%);
}
100% {

View File

@@ -5,25 +5,25 @@
*/
@font-face {
font-family: 'Zen-Junicode';
src: url('chrome://browser/content/zen-fonts/JunicodeVF-Roman.woff2') format('woff2');
font-family: "Zen-Junicode";
src: url("chrome://browser/content/zen-fonts/JunicodeVF-Roman.woff2") format("woff2");
}
@font-face {
font-family: 'Zen-Junicode-Italic';
src: url('chrome://browser/content/zen-fonts/JunicodeVF-Italic.woff2') format('woff2');
font-family: "Zen-Junicode-Italic";
src: url("chrome://browser/content/zen-fonts/JunicodeVF-Italic.woff2") format("woff2");
}
.zen-branding-title {
font-size: 6rem;
line-height: 0.9;
margin-bottom: 0.4rem;
font-family: 'Zen-Junicode', serif;
font-family: "Zen-Junicode", serif;
font-weight: 400;
font-style: normal;
font-feature-settings: 'swsh' 1;
font-feature-settings: "swsh" 1;
& .zen-branding-title-italic {
font-family: 'Zen-Junicode-Italic', serif;
font-family: "Zen-Junicode-Italic", serif;
}
}

View File

@@ -3,33 +3,33 @@
* 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/.
*/
:root:not([inDOMFullscreen='true']):not([chromehidden~='location']):not([chromehidden~='toolbar']) {
:root:not([inDOMFullscreen="true"]):not([chromehidden~="location"]):not([chromehidden~="toolbar"]) {
& #tabbrowser-tabbox #tabbrowser-tabpanels .browserSidebarContainer {
overflow: clip;
:root:not([zen-no-padding='true']) &:not(.zen-glance-overlay) {
:root:not([zen-no-padding="true"]) &:not(.zen-glance-overlay) {
border-radius: var(--zen-native-inner-radius);
box-shadow: var(--zen-big-shadow);
}
& browser[type='content'] {
&:not([transparent='true']) {
& browser[type="content"] {
&:not([transparent="true"]) {
background: light-dark(rgb(255, 255, 255), rgb(32, 32, 32));
}
&[transparent='true'] {
&[transparent="true"] {
background: light-dark(rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0.1));
}
}
@media not -moz-pref('layout.css.prefers-color-scheme.content-override', 2) {
& browser[type='content'] {
@media not -moz-pref("layout.css.prefers-color-scheme.content-override", 2) {
& browser[type="content"] {
color-scheme: env(-moz-content-preferred-color-scheme);
}
}
@media -moz-pref('zen.theme.acrylic-elements') {
& browser[type='content'] {
@media -moz-pref("zen.theme.acrylic-elements") {
& browser[type="content"] {
/* For the rendering engine to apply layering optimizations. This
* is a hacky solution, but it works for now. */
will-change: transform;
@@ -37,11 +37,11 @@
}
}
@media (not -moz-pref('zen.view.shift-down-site-on-hover')) and (not ((-moz-pref('zen.view.experimental-no-window-controls') or (not -moz-pref('zen.view.hide-window-controls'))) and -moz-pref('zen.view.use-single-toolbar'))) {
.browserSidebarContainer:is(.deck-selected, [zen-split='true']) .browserContainer {
@media (not -moz-pref("zen.view.shift-down-site-on-hover")) and (not ((-moz-pref("zen.view.experimental-no-window-controls") or (not -moz-pref("zen.view.hide-window-controls"))) and -moz-pref("zen.view.use-single-toolbar"))) {
.browserSidebarContainer:is(.deck-selected, [zen-split="true"]) .browserContainer {
transition: margin var(--zen-hidden-toolbar-transition);
:root[zen-single-toolbar='true'] & {
:root[zen-single-toolbar="true"] & {
transition-delay: 0.2s;
--zen-toolbar-height: 34px;
}
@@ -49,10 +49,8 @@
#tabbrowser-tabpanels[has-toolbar-hovered] & {
--margin-top-fix: calc(-1 * var(--zen-toolbar-height) + var(--zen-element-separation));
:root:not([zen-single-toolbar='true']) & {
--margin-top-fix: calc(
-1 * var(--zen-toolbar-height-with-bookmarks) + var(--zen-element-separation)
);
:root:not([zen-single-toolbar="true"]) & {
--margin-top-fix: calc(-1 * var(--zen-toolbar-height-with-bookmarks) + var(--zen-element-separation));
}
margin-top: var(--margin-top-fix);
@@ -69,6 +67,6 @@
z-index: 2;
}
browser[zen-pseudo-hidden='true'] {
browser[zen-pseudo-hidden="true"] {
-moz-subtree-hidden-only-visually: 1 !important;
}

View File

@@ -19,15 +19,15 @@
position: inherit;
}
:root:is([inDOMFullscreen='true'], [chromehidden~='location'], [chromehidden~='toolbar']) {
:root:is([inDOMFullscreen="true"], [chromehidden~="location"], [chromehidden~="toolbar"]) {
#navigator-toolbox,
#zen-sidebar-splitter {
visibility: collapse;
}
}
:root[zen-before-loaded='true'] #browser > *:not(#zen-toast-container),
:root[zen-before-loaded='true'] #urlbar {
:root[zen-before-loaded="true"] #browser > *:not(#zen-toast-container),
:root[zen-before-loaded="true"] #urlbar {
opacity: 0 !important;
}
@@ -47,7 +47,7 @@
&::after,
&::before {
content: '';
content: "";
position: absolute;
inset: 0;
z-index: 0;
@@ -80,7 +80,7 @@
}
}
:root:not([animating-background='true']) &::before {
:root:not([animating-background="true"]) &::before {
transition: background-color var(--inactive-window-transition);
}
@@ -88,7 +88,7 @@
display: none;
}
:root[zen-show-grainy-background='true'] & .zen-browser-grain {
:root[zen-show-grainy-background="true"] & .zen-browser-grain {
display: flex;
width: 100%;
height: 100%;
@@ -97,7 +97,7 @@
z-index: 1;
opacity: var(--zen-grainy-background-opacity, 0);
mix-blend-mode: overlay;
:root:not([swipe-gesture='true']) & {
:root:not([swipe-gesture="true"]) & {
/* note: Keep in sync with kGlobalAnimationDuration */
transition: opacity 0.2s ease-in-out;
}
@@ -127,14 +127,14 @@
border: none;
}
:root:not([zen-single-toolbar='true']) #zen-appcontent-wrapper {
:root:not([zen-single-toolbar="true"]) #zen-appcontent-wrapper {
z-index: 3;
}
#nav-bar {
border-top-color: transparent !important;
:root[zen-single-toolbar='true'] & {
:root[zen-single-toolbar="true"] & {
border-top: none !important;
--zen-toolbar-height: 37px;
}
@@ -145,7 +145,7 @@
/* See bug #8814, don't an overflow here as it causes issues
* with firefox's rendering of the tab bar */
@media (-moz-pref('zen.view.grey-out-inactive-windows')) {
@media (-moz-pref("zen.view.grey-out-inactive-windows")) {
&:-moz-window-inactive {
background: InactiveCaption;
}
@@ -155,7 +155,7 @@
z-index: 1;
}
@media (-moz-windows-accent-color-in-titlebar) and ((-moz-windows-mica) or -moz-pref('browser.theme.windows.accent-color-in-tabs.enabled')) {
@media (-moz-windows-accent-color-in-titlebar) and ((-moz-windows-mica) or -moz-pref("browser.theme.windows.accent-color-in-tabs.enabled")) {
background: ActiveCaption;
color: CaptionText;
}
@@ -169,17 +169,17 @@
min-width: 1px;
}
:root:not([inDOMFullscreen='true']):not([chromehidden~='location']):not([chromehidden~='toolbar']) {
:root:not([inDOMFullscreen="true"]):not([chromehidden~="location"]):not([chromehidden~="toolbar"]) {
& #zen-tabbox-wrapper {
margin: var(--zen-element-separation);
margin-top: 0;
}
&:not([zen-right-side='true']) #zen-tabbox-wrapper {
&:not([zen-right-side="true"]) #zen-tabbox-wrapper {
margin-left: 0;
}
&[zen-right-side='true'] #zen-tabbox-wrapper {
&[zen-right-side="true"] #zen-tabbox-wrapper {
margin-right: 0;
}
}
@@ -207,7 +207,7 @@
}
}
@media -moz-pref('zen.widget.mac.mono-window-controls') {
@media -moz-pref("zen.widget.mac.mono-window-controls") {
.titlebar-buttonbox-container {
color: var(--toolbox-textcolor);
@@ -219,11 +219,7 @@
/* Draw 3 dots as background to represent the window controls,
all with the same cololr as the titlebar */
background-image: radial-gradient(
circle,
var(--zen-toolbar-element-bg) var(--zen-traffic-light-size),
transparent 0.5px
);
background-image: radial-gradient(circle, var(--zen-toolbar-element-bg) var(--zen-traffic-light-size), transparent 0.5px);
background-size: 20px 22px;
background-position: 53% 50%;
@@ -232,7 +228,7 @@
background-position: 52% 50%;
}
&:not([zen-has-hover='true']) > .titlebar-buttonbox {
&:not([zen-has-hover="true"]) > .titlebar-buttonbox {
opacity: 0;
}
}
@@ -240,13 +236,13 @@
}
@media (-moz-platform: macos) {
:root[zen-window-buttons-reversed='true'][zen-right-side='true'] .titlebar-buttonbox-container {
:root[zen-window-buttons-reversed="true"][zen-right-side="true"] .titlebar-buttonbox-container {
margin-inline-start: max(calc(var(--zen-element-separation) - 3px), 4px);
margin-block: auto;
}
}
.zen-split-view-splitter[orient='vertical'],
.zen-split-view-splitter[orient="vertical"],
#zen-sidebar-splitter {
position: absolute;
top: 0;
@@ -258,7 +254,7 @@
cursor: ew-resize;
z-index: 3;
&:is(.zen-split-view-splitter[orient='vertical']) {
&:is(.zen-split-view-splitter[orient="vertical"]) {
/* Bit of a hacky solution, but it works */
width: var(--zen-split-row-gap);
margin-left: calc(var(--zen-element-separation) * -1 - 1px);
@@ -271,7 +267,7 @@
width: 2px;
background: var(--button-primary-bgcolor);
border-radius: 2px;
content: '';
content: "";
position: absolute;
top: 50%;
left: 50%;
@@ -284,13 +280,13 @@
opacity: 1;
}
}
.zen-split-view-splitter[orient='horizontal'] {
.zen-split-view-splitter[orient="horizontal"] {
&::before {
height: 2px;
width: 50px;
background: var(--button-primary-bgcolor);
border-radius: 2px;
content: '';
content: "";
position: absolute;
top: 40%;
left: 50%;
@@ -337,12 +333,12 @@
z-index: 1;
& #zen-sidebar-top-buttons {
max-width: fit-content;
:root[zen-right-side='true'] & {
:root[zen-right-side="true"] & {
order: 1;
}
}
}
:root[zen-right-side='true'] #zen-appcontent-navbar-wrapper #PanelUI-button {
:root[zen-right-side="true"] #zen-appcontent-navbar-wrapper #PanelUI-button {
order: 2;
}

View File

@@ -4,8 +4,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
@namespace html 'http://www.w3.org/1999/xhtml';
@namespace xul 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
@namespace html "http://www.w3.org/1999/xhtml";
@namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
/** This file is used to override UI inside "common-shared.css" */

View File

@@ -9,8 +9,8 @@
padding-block: 0 !important;
}
:root[zen-single-toolbar='true'] {
& #urlbar:not([breakout-extend='true']) {
:root[zen-single-toolbar="true"] {
& #urlbar:not([breakout-extend="true"]) {
padding: 1px;
--toolbarbutton-border-radius: 6px;
}
@@ -27,7 +27,7 @@
--urlbar-margin-inline: 5px;
--urlbar-container-padding: 4px;
&[breakout-extend='true'] {
&[breakout-extend="true"] {
--urlbar-container-padding: 0px;
}
@@ -36,12 +36,12 @@
visibility: visible;
}
:root[zen-single-toolbar='true'] &[breakout-extend='true'],
&[zen-floating-urlbar='true'] {
:root[zen-single-toolbar="true"] &[breakout-extend="true"],
&[zen-floating-urlbar="true"] {
--urlbar-container-padding: 3px;
--urlbar-margin-inline: 11px;
&:not([zen-floating-urlbar='true']) {
&:not([zen-floating-urlbar="true"]) {
--urlbar-container-height: 52px !important;
}
}
@@ -62,7 +62,7 @@
border-radius: var(--border-radius-medium);
outline: none !important;
#urlbar:not([breakout-extend='true']) & {
#urlbar:not([breakout-extend="true"]) & {
margin: 1px;
}
@@ -70,20 +70,20 @@
box-shadow: none !important;
}
#urlbar[focused='true']:not([suppress-focus-border]) > .urlbar-background,
#urlbar[focused="true"]:not([suppress-focus-border]) > .urlbar-background,
#searchbar:focus-within {
outline: none !important;
outline-offset: none !important;
outline-color: none !important;
}
#urlbar:not([breakout-extend='true']) {
#urlbar:not([breakout-extend="true"]) {
&:hover .urlbar-background {
background-color: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.2)) !important;
}
}
#identity-box.chromeUI:not([pageproxystate='invalid']) {
#identity-box.chromeUI:not([pageproxystate="invalid"]) {
& #identity-icon-box {
background: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1)) !important;
}
@@ -101,7 +101,7 @@
padding-inline-start: 8px !important;
}
#urlbar:not([extend='true']) #identity-box #identity-icon-box {
#urlbar:not([extend="true"]) #identity-box #identity-icon-box {
position: relative;
}
@@ -112,7 +112,7 @@
margin-bottom: auto;
padding: 6px 8px !important;
:root:not([zen-single-toolbar='true']) & {
:root:not([zen-single-toolbar="true"]) & {
padding-block: 2px !important;
}
}
@@ -125,14 +125,14 @@
font-weight: 500;
}
:root[zen-single-toolbar='true'] #urlbar:not([breakout-extend='true']) {
:root[zen-single-toolbar="true"] #urlbar:not([breakout-extend="true"]) {
& #urlbar-input {
cursor: default;
}
& #identity-box {
margin-inline-end: 0 !important;
&.chromeUI:not([pageproxystate='invalid']) #identity-icon-box {
&.chromeUI:not([pageproxystate="invalid"]) #identity-icon-box {
border-radius: 10px !important;
}
}
@@ -143,25 +143,23 @@
height: 100%; /* To still be able to open popups */
visibility: collapse;
:root:not([supress-primary-adjustment='true']) & {
:root:not([supress-primary-adjustment="true"]) & {
transition:
opacity 0.15s,
visibility 0.15s;
}
#navigator-toolbox[zen-has-implicit-hover='true'] &,
#navigator-toolbox[zen-has-implicit-hover="true"] &,
&[open],
#urlbar[has-popup-open='true'] &,
:root[zen-has-empty-tab='true'] & {
#urlbar[has-popup-open="true"] &,
:root[zen-has-empty-tab="true"] & {
opacity: 1;
visibility: visible;
}
}
}
:root:not([zen-single-toolbar='true']):not([zen-has-empty-tab='true'])
#urlbar:not([breakout-extend='true'])
.urlbar-input-container {
:root:not([zen-single-toolbar="true"]):not([zen-has-empty-tab="true"]) #urlbar:not([breakout-extend="true"]) .urlbar-input-container {
padding: 2px 3px;
gap: 2px;
@@ -184,19 +182,19 @@
background: transparent !important;
}
:root:is([zen-single-toolbar='true'], [zen-has-empty-tab='true']) {
:root:is([zen-single-toolbar="true"], [zen-has-empty-tab="true"]) {
#zen-copy-url-button[disabled] {
display: none !important;
}
}
@media -moz-pref('zen.urlbar.single-toolbar-show-copy-url', false) {
:root[zen-single-toolbar='true'] #zen-copy-url-button {
@media -moz-pref("zen.urlbar.single-toolbar-show-copy-url", false) {
:root[zen-single-toolbar="true"] #zen-copy-url-button {
display: none !important;
}
}
@media not -moz-pref('zen.urlbar.show-pip-button') {
@media not -moz-pref("zen.urlbar.show-pip-button") {
#picture-in-picture-button {
display: none !important;
}
@@ -209,7 +207,7 @@
align-items: center !important;
margin: 0;
:root[zen-single-toolbar='true'] & {
:root[zen-single-toolbar="true"] & {
padding: 6px !important;
width: unset !important;
height: unset !important;
@@ -239,11 +237,11 @@
position: fixed;
}
#urlbar[breakout-extend='true'] {
#urlbar[breakout-extend="true"] {
z-index: 2;
:root[zen-single-toolbar='true'] & .urlbar-input-box,
&[zen-floating-urlbar='true'] .urlbar-input-box {
:root[zen-single-toolbar="true"] & .urlbar-input-box,
&[zen-floating-urlbar="true"] .urlbar-input-box {
font-weight: 400;
@media (-moz-platform: windows) {
font-weight: 500;
@@ -254,33 +252,21 @@
height: 100%;
}
:root:not([zen-single-toolbar='true'])
&:not([zen-floating-urlbar='true'])
#identity-box:not([pageproxystate='invalid']) {
:root:not([zen-single-toolbar="true"]) &:not([zen-floating-urlbar="true"]) #identity-box:not([pageproxystate="invalid"]) {
margin-inline-end: 0;
}
& .urlbar-background {
--zen-urlbar-background-base: light-dark(
#fbfbfb,
color-mix(in srgb, hsl(0, 0%, 6.7%), var(--zen-colors-primary) 30%)
);
@media -moz-pref('zen.theme.acrylic-elements') {
--zen-urlbar-background-transparent: color-mix(
in srgb,
var(--zen-urlbar-background-base) 70%,
transparent 30%
);
--zen-urlbar-background-base: light-dark(#fbfbfb, color-mix(in srgb, hsl(0, 0%, 6.7%), var(--zen-colors-primary) 30%));
@media -moz-pref("zen.theme.acrylic-elements") {
--zen-urlbar-background-transparent: color-mix(in srgb, var(--zen-urlbar-background-base) 70%, transparent 30%);
}
background-color: var(
--zen-urlbar-background-transparent,
var(--zen-urlbar-background-base)
) !important;
background-color: var(--zen-urlbar-background-transparent, var(--zen-urlbar-background-base)) !important;
box-shadow: 0px 30px 140px -15px light-dark(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.6)) !important;
backdrop-filter: none !important;
outline: 0.5px solid light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2)) !important;
outline-offset: var(--zen-urlbar-outline-offset) !important;
@media -moz-pref('zen.theme.acrylic-elements') {
@media -moz-pref("zen.theme.acrylic-elements") {
backdrop-filter: blur(42px) saturate(110%) brightness(0.25) contrast(100%) !important;
}
}
@@ -290,9 +276,9 @@
border-radius: 12px !important;
}
&[breakout-extend][animate-searchmode='true']::before {
&[breakout-extend][animate-searchmode="true"]::before {
position: absolute;
content: '';
content: "";
inset: 0;
width: 100%;
height: 100%;
@@ -310,7 +296,7 @@
display: none;
}
:root[zen-single-toolbar='true'] {
:root[zen-single-toolbar="true"] {
--urlbar-icon-border-radius: 8px !important;
--urlbar-inner-border-radius: var(--toolbarbutton-border-radius) !important;
@@ -322,7 +308,7 @@
display: none;
}
&:not([zen-has-empty-tab='true']) #urlbar:not([breakout-extend='true']) #identity-box {
&:not([zen-has-empty-tab="true"]) #urlbar:not([breakout-extend="true"]) #identity-box {
order: 2;
}
@@ -354,7 +340,7 @@
}
}
:root:not([zen-single-toolbar='true']) {
:root:not([zen-single-toolbar="true"]) {
--urlbar-icon-border-radius: 6px !important;
#notification-popup-box {
@@ -372,7 +358,7 @@
}
}
#urlbar[breakout-extend='true'] #notification-popup-box {
#urlbar[breakout-extend="true"] #notification-popup-box {
min-width: calc(var(--urlbar-min-height) - 4 * var(--urlbar-container-padding)) !important;
height: calc(var(--urlbar-min-height) - 4 * var(--urlbar-container-padding)) !important;
}
@@ -411,9 +397,7 @@
/* Border radius on hover */
#urlbar .urlbar-page-action,
#urlbar #tracking-protection-icon-container,
#urlbar:not([breakout-extend='true'])
#identity-box:is(:not(.chromeUI), [pageproxystate='invalid'])
#identity-icon-box {
#urlbar:not([breakout-extend="true"]) #identity-box:is(:not(.chromeUI), [pageproxystate="invalid"]) #identity-icon-box {
border-radius: var(--urlbar-icon-border-radius) !important;
min-width: 28px;
}
@@ -423,7 +407,7 @@
.notificationbox-stack {
background: transparent;
&[notificationside='top'] {
&[notificationside="top"] {
position: fixed;
bottom: calc(var(--zen-element-separation) * 1.5);
right: calc(var(--zen-element-separation) * 1.5);
@@ -453,12 +437,12 @@
align-items: center;
}
:root:not([zen-single-toolbar='true']) {
&[zen-right-side='true']:not([zen-window-buttons-reversed='true']) #nav-bar {
:root:not([zen-single-toolbar="true"]) {
&[zen-right-side="true"]:not([zen-window-buttons-reversed="true"]) #nav-bar {
margin-inline-start: var(--zen-element-separation);
}
&:not([zen-right-side='true'])[zen-window-buttons-reversed='true'] #nav-bar {
&:not([zen-right-side="true"])[zen-window-buttons-reversed="true"] #nav-bar {
margin-inline-end: var(--zen-element-separation);
}
}
@@ -489,17 +473,17 @@
}
}
:root[zen-single-toolbar='true'] {
:root[zen-single-toolbar="true"] {
#urlbar[open] {
min-width: min(90%, 40rem);
}
&[zen-right-side='true'] #urlbar[open]:not([zen-floating-urlbar='true']) {
&[zen-right-side="true"] #urlbar[open]:not([zen-floating-urlbar="true"]) {
right: 0;
}
}
#urlbar[open][zen-floating-urlbar='true'] {
#urlbar[open][zen-floating-urlbar="true"] {
z-index: 1000;
max-width: unset;
--urlbar-container-height: 62px !important;
@@ -520,7 +504,7 @@
background: var(--toolbarbutton-hover-background);
height: var(--urlbar-height) !important;
margin-inline: 0.15rem !important;
:root:not([zen-single-toolbar='true']) & {
:root:not([zen-single-toolbar="true"]) & {
max-height: 32px !important;
min-height: unset !important;
margin-block: -1px !important;
@@ -528,7 +512,7 @@
}
}
@media not -moz-pref('zen.urlbar.show-protections-icon') {
@media not -moz-pref("zen.urlbar.show-protections-icon") {
#tracking-protection-icon-container {
display: none !important;
}
@@ -601,13 +585,13 @@
}
}
.urlbarView-row[has-action]:is([type='switchtab'], [type='remotetab'], [type='clipboard']) {
.urlbarView-row[has-action]:is([type="switchtab"], [type="remotetab"], [type="clipboard"]) {
& .urlbarView-action:last-child {
margin-left: auto !important;
margin-right: 0 !important;
}
&:is([type='switchtab'], [type='remotetab']) .urlbarView-action:last-child {
&:is([type="switchtab"], [type="remotetab"]) .urlbarView-action:last-child {
background: transparent !important;
align-items: center;
display: flex;
@@ -619,13 +603,13 @@
transform-origin: right;
&::after {
content: '';
content: "";
display: inline-block;
width: 28px;
height: 28px;
background-color: currentColor;
mask-image: url('chrome://browser/skin/zen-icons/urlbar-arrow.svg');
mask-image: url("chrome://browser/skin/zen-icons/urlbar-arrow.svg");
mask-size: contain;
mask-repeat: no-repeat;
mask-position: center;
@@ -648,11 +632,7 @@
#urlbar-label-box,
#urlbar-search-mode-indicator {
background-color: color-mix(
in srgb,
var(--zen-primary-color) 50%,
light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.2)) 50%
) !important;
background-color: color-mix(in srgb, var(--zen-primary-color) 50%, light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.2)) 50%) !important;
color: white;
padding: 4px 8px;
border-radius: 50px;
@@ -667,20 +647,12 @@
&:hover {
&,
& .urlbarView-favicon {
background-color: color-mix(
in srgb,
var(--zen-branding-bg-reverse) 5%,
transparent 95%
) !important;
background-color: color-mix(in srgb, var(--zen-branding-bg-reverse) 5%, transparent 95%) !important;
}
}
&[selected] {
--zen-selected-bg: color-mix(
in srgb,
var(--zen-primary-color) 50%,
light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.2)) 50%
);
--zen-selected-bg: color-mix(in srgb, var(--zen-primary-color) 50%, light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.2)) 50%);
--zen-selected-color: color-mix(in srgb, var(--zen-selected-bg), black 30%);
background-color: var(--zen-selected-bg) !important;
@@ -698,7 +670,7 @@
color: var(--zen-selected-color) !important;
}
&:is([type='switchtab'], [type='dynamic']) .urlbarView-favicon,
&:is([type="switchtab"], [type="dynamic"]) .urlbarView-favicon,
& .urlbarView-shortcutContent {
fill: var(--zen-selected-color) !important;
background-color: rgba(255, 255, 255, 0.9) !important;
@@ -723,8 +695,7 @@
}
}
:root:not([zen-single-toolbar='true'])
#urlbar[breakout-extend='true']:not([zen-floating-urlbar='true']) {
:root:not([zen-single-toolbar="true"]) #urlbar[breakout-extend="true"]:not([zen-floating-urlbar="true"]) {
& .urlbar-background {
border-radius: 10px !important;
}
@@ -759,7 +730,7 @@
display: none !important;
}
@media not -moz-pref('zen.urlbar.show-contextual-id') {
@media not -moz-pref("zen.urlbar.show-contextual-id") {
#userContext-icons {
display: none !important;
}

View File

@@ -3,30 +3,30 @@
* 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/.
*/
panel[type='arrow'] {
panel[type="arrow"] {
@media (-moz-platform: macos) and (-moz-panel-animations) {
&[side='bottom'] {
&[side="bottom"] {
/* Animate from the bottom */
-zen-window-transform-origin: 0 100%;
}
:root[zen-right-side='true'] & {
:root[zen-right-side="true"] & {
/* Animate from the right */
-zen-window-transform-origin: 100% 0;
&[side='bottom'] {
&[side="bottom"] {
/* Animate from the bottom right */
-zen-window-transform-origin: 100% 100%;
}
}
-moz-window-opacity: 0;
&[animate='open'] {
&[animate="open"] {
animation: zen-jello-animation-macos 0.2s ease-in-out forwards !important;
}
}
}
menupopup,
panel[type='arrow']:not(#feature-callout) {
panel[type="arrow"]:not(#feature-callout) {
@media (-moz-windows-mica-popups) {
appearance: auto !important;
-moz-default-appearance: menupopup;

View File

@@ -3,15 +3,14 @@
* 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 url('chrome://browser/content/zen-styles/zen-panels/bookmarks.css');
@import url('chrome://browser/content/zen-styles/zen-panels/print.css');
@import url('chrome://browser/content/zen-styles/zen-panels/dialog.css');
@import url("chrome://browser/content/zen-styles/zen-panels/bookmarks.css");
@import url("chrome://browser/content/zen-styles/zen-panels/print.css");
@import url("chrome://browser/content/zen-styles/zen-panels/dialog.css");
:root {
--panel-subview-body-padding: 2px 0;
--arrowpanel-menuitem-border-radius: 5px;
--arrowpanel-menuitem-margin: var(--uc-arrowpanel-menuitem-margin-block)
var(--uc-arrowpanel-menuitem-margin-inline);
--arrowpanel-menuitem-margin: var(--uc-arrowpanel-menuitem-margin-block) var(--uc-arrowpanel-menuitem-margin-inline);
--arrowpanel-menuitem-padding-block: 8px;
--arrowpanel-menuitem-padding-inline: 14px;
--uc-arrowpanel-menuicon-margin-inline: 14px;
@@ -22,9 +21,7 @@
--uc-panel-zoom-button-padding: 8px;
--uc-panel-zoom-button-inline-padding: 9px;
--uc-panel-zoom-padding-block: calc(
var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block)
);
--uc-panel-zoom-padding-block: calc(var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block));
--uc-autocomplete-panel-menuitem-margin: 4px;
--uc-autocomplete-panel-menuicon-padding-inline: 14px;
@@ -71,9 +68,7 @@ panel {
}
.widget-overflow-list .toolbarbutton-1:not(.toolbarbutton-combined) > .toolbarbutton-text,
.subviewbutton:not(#appMenu-zoom-controls > .subviewbutton)
> .toolbarbutton-icon
+ .toolbarbutton-text,
.subviewbutton:not(#appMenu-zoom-controls > .subviewbutton) > .toolbarbutton-icon + .toolbarbutton-text,
#appMenu-fxa-label2 > vbox {
padding-inline-start: var(--uc-arrowpanel-menuicon-margin-inline);
}
@@ -87,7 +82,7 @@ panel {
/* Firefox profile avatar in appmenu */
#appMenu-fxa-label2::before {
content: '';
content: "";
display: -moz-box;
height: 16px;
width: 16px;
@@ -112,10 +107,7 @@ panel {
/* zoom controls */
#appMenu-zoom-controls {
border-top: 1px solid var(--panel-separator-color);
padding-inline: calc(
var(--arrowpanel-menuitem-padding-inline) + var(--uc-arrowpanel-menuitem-margin-inline)
)
var(--uc-arrowpanel-menuitem-margin-inline);
padding-inline: calc(var(--arrowpanel-menuitem-padding-inline) + var(--uc-arrowpanel-menuitem-margin-inline)) var(--uc-arrowpanel-menuitem-margin-inline);
padding-block: var(--uc-panel-zoom-padding-block);
margin: var(--panel-separator-margin-vertical) 0 calc(var(--panel-separator-margin-vertical) * -1);
}
@@ -131,23 +123,18 @@ panel {
/* #appMenu-zoomReduce-button2, */
#appMenu-zoom-controls > #appMenu-fullscreen-button2 {
margin-left: calc(
(var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block)) * 2 + 1px
);
margin-left: calc((var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block)) * 2 + 1px);
}
#appMenu-zoom-controls > #appMenu-fullscreen-button2::before {
content: '';
content: "";
border-inline-start: 1px solid var(--panel-separator-color);
display: block;
position: relative;
height: 32px;
margin-block: calc(var(--uc-panel-zoom-button-padding) * -1);
transform: translateX(
calc(
var(--uc-panel-zoom-button-inline-padding) * -1 -
(var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block)) - 1px
)
calc(var(--uc-panel-zoom-button-inline-padding) * -1 - (var(--panel-separator-margin-vertical) + var(--uc-arrowpanel-menuitem-margin-block)) - 1px)
);
}
@@ -319,7 +306,7 @@ menuseparator {
cursor: pointer;
}
#editBMPanel_workspaceList input[type='checkbox'] {
#editBMPanel_workspaceList input[type="checkbox"] {
margin-right: 8px;
}
@@ -333,16 +320,16 @@ menuseparator {
display: flex;
align-items: end;
:root:not([zen-right-side='true']) & {
:root:not([zen-right-side="true"]) & {
right: var(--zen-toast-spacing);
}
:root[zen-right-side='true'] & {
:root[zen-right-side="true"] & {
left: var(--zen-toast-spacing);
}
& .zen-toast {
:root[zen-right-side='true'] & {
:root[zen-right-side="true"] & {
translate: 100%;
}
@@ -357,11 +344,7 @@ menuseparator {
z-index: 1000;
padding: var(--zen-toast-padding);
border-radius: 10px;
background: linear-gradient(
to bottom,
var(--zen-primary-color) -40%,
color-mix(in srgb, var(--zen-primary-color), #0f0f0f 20%)
);
background: linear-gradient(to bottom, var(--zen-primary-color) -40%, color-mix(in srgb, var(--zen-primary-color), #0f0f0f 20%));
box-shadow: light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.4)) 0px 0px 22px 2px;
border: none;
display: flex;
@@ -408,7 +391,7 @@ menuseparator {
outline: 0.5px solid light-dark(transparent, rgba(255, 255, 255, 0.02));
outline-offset: -0.5px;
:root[zen-right-side='true'] & {
:root[zen-right-side="true"] & {
order: -1;
}

View File

@@ -92,13 +92,7 @@
opacity: 1;
--special-color: color-mix(in srgb, var(--zen-primary-color), currentColor 50%);
--specia-color-2: color-mix(in srgb, var(--zen-primary-color), currentColor 90%);
background: linear-gradient(
135deg,
var(--specia-color-2),
var(--special-color),
var(--specia-color-2),
var(--special-color)
);
background: linear-gradient(135deg, var(--specia-color-2), var(--special-color), var(--specia-color-2), var(--special-color));
background-size: 400%;
filter: saturate(3);
background-clip: text;

View File

@@ -23,7 +23,7 @@
display: none !important;
}
@media -moz-pref('zen.theme.disable-lightweight') {
@media -moz-pref("zen.theme.disable-lightweight") {
#customization-lwtheme-link {
display: none !important;
}
@@ -76,7 +76,7 @@ body > #confetti {
}
}
&[only-svg-icons='true'] {
&[only-svg-icons="true"] {
& #PanelUI-zen-emojis-picker-change-emojis {
display: none;
}
@@ -85,7 +85,7 @@ body > #confetti {
pointer-events: none;
}
& #PanelUI-zen-emojis-picker-pages > vbox[emojis='true'] {
& #PanelUI-zen-emojis-picker-pages > vbox[emojis="true"] {
display: none;
}
}
@@ -186,11 +186,11 @@ body > #confetti {
background-color 0.1s,
transform 0.2s;
&[open='true'] {
&[open="true"] {
transition: background-color 0.1s;
}
&:not([open='true']):active:hover {
&:not([open="true"]):active:hover {
transform: scale(0.95);
}
}
@@ -216,13 +216,7 @@ body > #confetti {
position: fixed;
width: 100%;
height: 100%;
background: linear-gradient(
to bottom,
transparent,
rgba(255, 255, 255, 0.5) 40%,
rgba(255, 255, 255, 0.5) 60%,
transparent 100%
);
background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0.5) 40%, rgba(255, 255, 255, 0.5) 60%, transparent 100%);
left: 0;
z-index: 999;
opacity: 0;
@@ -238,17 +232,13 @@ body > #confetti {
}
#zen-update-animation-border::before {
content: '';
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
padding: 2px; /* thickness of border */
background: radial-gradient(
ellipse 100% 50% at center var(--background-top),
rgba(255, 255, 255, 0.5) 80%,
transparent
);
background: radial-gradient(ellipse 100% 50% at center var(--background-top), rgba(255, 255, 255, 0.5) 80%, transparent);
/* Punch out the inside once (not animated) */
mask:
@@ -264,7 +254,7 @@ body > #confetti {
/* Status panel */
@media (-moz-pref('zen.theme.styled-status-panel')) {
@media (-moz-pref("zen.theme.styled-status-panel")) {
#statuspanel {
padding: 6px;
@@ -310,7 +300,7 @@ body > #confetti {
display: none !important;
}
&[overflowing='true'] {
&[overflowing="true"] {
overflow-x: auto;
max-height: 420px;
mask-image: linear-gradient(to top, transparent, black 5%);
@@ -443,7 +433,7 @@ body > #confetti {
}
&::before {
content: '';
content: "";
position: absolute;
inset: 1px;
border-radius: 99px;
@@ -464,7 +454,7 @@ body > #confetti {
transform: scale(0.95);
}
.permission-popup-permission-item[state='allow'] &::before {
.permission-popup-permission-item[state="allow"] &::before {
opacity: 1;
}
}
@@ -491,13 +481,13 @@ body > #confetti {
}
}
@media -moz-pref('zen.theme.hide-unified-extensions-button') {
@media -moz-pref("zen.theme.hide-unified-extensions-button") {
#unified-extensions-button:not([showing]) {
display: none !important;
}
}
@media not -moz-pref('zen.theme.hide-unified-extensions-button') {
@media not -moz-pref("zen.theme.hide-unified-extensions-button") {
#zen-site-data-section-addons {
display: none;
}
@@ -509,7 +499,7 @@ body > #confetti {
padding: 10px 9px;
padding-bottom: 8px;
:root[zen-single-toolbar='true']:not([zen-right-side='true']) & {
:root[zen-single-toolbar="true"]:not([zen-right-side="true"]) & {
flex-direction: row-reverse;
}
@@ -539,16 +529,12 @@ body > #confetti {
}
&::before {
content: '';
content: "";
position: absolute;
width: 100%;
height: 100%;
@media (-moz-platform: macos) {
background: linear-gradient(
to bottom,
light-dark(rgb(255, 255, 255), rgb(34, 34, 34)),
light-dark(rgb(246, 246, 246), rgb(21, 21, 21))
);
background: linear-gradient(to bottom, light-dark(rgb(255, 255, 255), rgb(34, 34, 34)), light-dark(rgb(246, 246, 246), rgb(21, 21, 21)));
box-shadow:
0px 2px 4px rgba(0, 0, 0, 0.1),
@@ -624,6 +610,6 @@ body > #confetti {
}
/* Sidebar notification */
:root:not([zen-sidebar-expanded='true']) zen-sidebar-notification {
:root:not([zen-sidebar-expanded="true"]) zen-sidebar-notification {
display: none;
}

View File

@@ -8,6 +8,6 @@
background: transparent;
}
:root[inDOMFullscreen='true'] #zen-appcontent-navbar-wrapper {
:root[inDOMFullscreen="true"] #zen-appcontent-navbar-wrapper {
visibility: collapse;
}

View File

@@ -3,7 +3,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Utility to register JSWindowActors
import { ActorManagerParent } from 'resource://gre/modules/ActorManagerParent.sys.mjs';
import { ActorManagerParent } from "resource://gre/modules/ActorManagerParent.sys.mjs";
/**
* Fission-compatible JSProcess implementations.
@@ -21,25 +21,25 @@ let JSPROCESSACTORS = {};
let JSWINDOWACTORS = {
ZenModsMarketplace: {
parent: {
esModuleURI: 'resource:///actors/ZenModsMarketplaceParent.sys.mjs',
esModuleURI: "resource:///actors/ZenModsMarketplaceParent.sys.mjs",
},
child: {
esModuleURI: 'resource:///actors/ZenModsMarketplaceChild.sys.mjs',
esModuleURI: "resource:///actors/ZenModsMarketplaceChild.sys.mjs",
events: {
DOMContentLoaded: {},
},
},
matches: [
...Services.prefs.getStringPref('zen.injections.match-urls').split(','),
'about:preferences',
...Services.prefs.getStringPref("zen.injections.match-urls").split(","),
"about:preferences",
],
},
ZenGlance: {
parent: {
esModuleURI: 'resource:///actors/ZenGlanceParent.sys.mjs',
esModuleURI: "resource:///actors/ZenGlanceParent.sys.mjs",
},
child: {
esModuleURI: 'resource:///actors/ZenGlanceChild.sys.mjs',
esModuleURI: "resource:///actors/ZenGlanceChild.sys.mjs",
events: {
DOMContentLoaded: {},
mousedown: {
@@ -54,8 +54,8 @@ let JSWINDOWACTORS = {
},
},
allFrames: true,
matches: ['*://*/*'],
enablePreference: 'zen.glance.enabled',
matches: ["*://*/*"],
enablePreference: "zen.glance.enabled",
},
};

View File

@@ -2,27 +2,27 @@
// 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 { AppConstants } from 'resource://gre/modules/AppConstants.sys.mjs';
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
export const ZenCustomizableUI = new (class {
constructor() {}
TYPE_TOOLBAR = 'toolbar';
defaultSidebarIcons = ['downloads-button', 'zen-workspaces-button', 'zen-create-new-button'];
TYPE_TOOLBAR = "toolbar";
defaultSidebarIcons = ["downloads-button", "zen-workspaces-button", "zen-create-new-button"];
startup(CustomizableUIInternal) {
CustomizableUIInternal.registerArea(
'zen-sidebar-top-buttons',
"zen-sidebar-top-buttons",
{
type: this.TYPE_TOOLBAR,
defaultPlacements: ['zen-toggle-compact-mode'],
defaultPlacements: ["zen-toggle-compact-mode"],
defaultCollapsed: null,
overflowable: true,
},
true
);
CustomizableUIInternal.registerArea(
'zen-sidebar-foot-buttons',
"zen-sidebar-foot-buttons",
{
type: this.TYPE_TOOLBAR,
defaultPlacements: this.defaultSidebarIcons,
@@ -39,16 +39,16 @@ export const ZenCustomizableUI = new (class {
}
#addSidebarButtons(window) {
const kDefaultSidebarWidth = AppConstants.platform === 'macosx' ? '230px' : '186px';
const kDefaultSidebarWidth = AppConstants.platform === "macosx" ? "230px" : "186px";
const toolbox = window.gNavToolbox;
// Set a splitter to navigator-toolbox
const splitter = window.document.createXULElement('splitter');
splitter.setAttribute('id', 'zen-sidebar-splitter');
splitter.setAttribute('orient', 'horizontal');
splitter.setAttribute('resizebefore', 'sibling');
splitter.setAttribute('resizeafter', 'none');
toolbox.insertAdjacentElement('afterend', splitter);
const splitter = window.document.createXULElement("splitter");
splitter.setAttribute("id", "zen-sidebar-splitter");
splitter.setAttribute("orient", "horizontal");
splitter.setAttribute("resizebefore", "sibling");
splitter.setAttribute("resizeafter", "none");
toolbox.insertAdjacentElement("afterend", splitter);
const sidebarBox = window.MozXULElement.parseXULToFragment(`
<toolbar id="zen-sidebar-top-buttons"
@@ -82,7 +82,9 @@ export const ZenCustomizableUI = new (class {
`);
toolbox.prepend(sidebarBox);
new window.MutationObserver((e) => {
if (e[0].type !== 'attributes' || e[0].attributeName !== 'width') return;
if (e[0].type !== "attributes" || e[0].attributeName !== "width") {
return;
}
this._dispatchResizeEvent(window);
}).observe(toolbox, {
attributes: true, //configure it to listen to attribute changes
@@ -90,23 +92,27 @@ export const ZenCustomizableUI = new (class {
// remove all styles except for the width, since we are xulstoring the complet style list
const width = toolbox.style.width || kDefaultSidebarWidth;
toolbox.removeAttribute('style');
toolbox.removeAttribute("style");
toolbox.style.width = width;
toolbox.setAttribute('width', width);
toolbox.setAttribute("width", width);
splitter.addEventListener('dblclick', (e) => {
if (e.button !== 0) return;
splitter.addEventListener("dblclick", (e) => {
if (e.button !== 0) {
return;
}
toolbox.style.width = kDefaultSidebarWidth;
toolbox.setAttribute('width', kDefaultSidebarWidth);
toolbox.setAttribute("width", kDefaultSidebarWidth);
});
const newTab = window.document.getElementById('vertical-tabs-newtab-button');
newTab.classList.add('zen-sidebar-action-button');
const newTab = window.document.getElementById("vertical-tabs-newtab-button");
newTab.classList.add("zen-sidebar-action-button");
for (let id of this.defaultSidebarIcons) {
const elem = window.document.getElementById(id);
if (!elem || elem.id === 'zen-workspaces-button') continue;
elem.setAttribute('removable', 'true');
if (!elem || elem.id === "zen-workspaces-button") {
continue;
}
elem.setAttribute("removable", "true");
}
this.#initCreateNewButton(window);
@@ -114,18 +120,19 @@ export const ZenCustomizableUI = new (class {
}
#initCreateNewButton(window) {
const button = window.document.getElementById('zen-create-new-button');
button.addEventListener('command', (event) => {
const button = window.document.getElementById("zen-create-new-button");
button.addEventListener("command", (event) => {
if (window.gZenWorkspaces.privateWindowOrDisabled) {
return window.document.getElementById('cmd_newNavigatorTab').doCommand();
}
if (button.hasAttribute('open')) {
window.document.getElementById("cmd_newNavigatorTab").doCommand();
return;
}
const popup = window.document.getElementById('zenCreateNewPopup');
if (button.hasAttribute("open")) {
return;
}
const popup = window.document.getElementById("zenCreateNewPopup");
popup.openPopup(
button,
'before_start',
"before_start",
0,
0,
true /* isContextMenu */,
@@ -136,13 +143,13 @@ export const ZenCustomizableUI = new (class {
}
#moveWindowButtons(window) {
const windowControls = window.document.getElementsByClassName('titlebar-buttonbox-container');
const windowControls = window.document.getElementsByClassName("titlebar-buttonbox-container");
const toolboxIcons = window.document.getElementById(
'zen-sidebar-top-buttons-customization-target'
"zen-sidebar-top-buttons-customization-target"
);
if (
window.AppConstants.platform === 'macosx' ||
window.matchMedia('(-moz-gtk-csd-reversed-placement)').matches
window.AppConstants.platform === "macosx" ||
window.matchMedia("(-moz-gtk-csd-reversed-placement)").matches
) {
for (let i = 0; i < windowControls.length; i++) {
if (i === 0) {
@@ -155,27 +162,27 @@ export const ZenCustomizableUI = new (class {
}
#modifyToolbarButtons(window) {
const wrapper = window.document.getElementById('zen-sidebar-foot-buttons');
const elementsToHide = ['new-tab-button'];
const wrapper = window.document.getElementById("zen-sidebar-foot-buttons");
const elementsToHide = ["new-tab-button"];
for (let id of elementsToHide) {
const elem = window.document.getElementById(id);
if (elem) {
wrapper.prepend(elem);
}
}
window.document.getElementById('stop-reload-button').removeAttribute('overflows');
window.document.getElementById("stop-reload-button").removeAttribute("overflows");
}
_dispatchResizeEvent(window) {
window.dispatchEvent(new window.Event('resize'));
window.dispatchEvent(new window.Event("resize"));
}
registerToolbarNodes(window) {
window.CustomizableUI.registerToolbarNode(
window.document.getElementById('zen-sidebar-top-buttons')
window.document.getElementById("zen-sidebar-top-buttons")
);
window.CustomizableUI.registerToolbarNode(
window.document.getElementById('zen-sidebar-foot-buttons')
window.document.getElementById("zen-sidebar-foot-buttons")
);
}
})();

View File

@@ -2,10 +2,10 @@
* 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 { AppConstants } from 'resource://gre/modules/AppConstants.sys.mjs';
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
class nsZenUIMigration {
PREF_NAME = 'zen.ui.migration.version';
PREF_NAME = "zen.ui.migration.version";
MIGRATION_VERSION = 5;
init(isNewProfile) {
@@ -13,7 +13,7 @@ class nsZenUIMigration {
try {
this._migrate();
} catch (e) {
console.error('ZenUIMigration: Error during migration', e);
console.error("ZenUIMigration: Error during migration", e);
}
}
this.clearVariables();
@@ -46,48 +46,48 @@ class nsZenUIMigration {
// If there's an userChrome.css or userContent.css existing, we set
// 'toolkit.legacyUserProfileCustomizations.stylesheets' back to true
// We do this to avoid existing user stylesheets to be ignored
const profileDir = Services.dirsvc.get('ProfD', Ci.nsIFile);
const profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
const userChromeFile = profileDir.clone();
userChromeFile.append('chrome');
userChromeFile.append('userChrome.css');
userChromeFile.append("chrome");
userChromeFile.append("userChrome.css");
const userContentFile = profileDir.clone();
userContentFile.append('chrome');
userContentFile.append('userContent.css');
userContentFile.append("chrome");
userContentFile.append("userContent.css");
Services.prefs.setBoolPref(
'zen.workspaces.separate-essentials',
Services.prefs.getBoolPref('zen.workspaces.container-specific-essentials-enabled', false)
"zen.workspaces.separate-essentials",
Services.prefs.getBoolPref("zen.workspaces.container-specific-essentials-enabled", false)
);
const theme = Services.prefs.getIntPref('layout.css.prefers-color-scheme.content-override', 0);
Services.prefs.setIntPref('zen.view.window.scheme', theme);
const theme = Services.prefs.getIntPref("layout.css.prefers-color-scheme.content-override", 0);
Services.prefs.setIntPref("zen.view.window.scheme", theme);
if (userChromeFile.exists() || userContentFile.exists()) {
Services.prefs.setBoolPref('toolkit.legacyUserProfileCustomizations.stylesheets', true);
console.log('ZenUIMigration: User stylesheets detected, enabling legacy stylesheets.');
Services.prefs.setBoolPref("toolkit.legacyUserProfileCustomizations.stylesheets", true);
console.warn("ZenUIMigration: User stylesheets detected, enabling legacy stylesheets.");
this.shouldRestart = true;
}
}
_migrateV2() {
if (AppConstants.platform !== 'linux') {
Services.prefs.setIntPref('zen.theme.gradient-legacy-version', 0);
if (AppConstants.platform !== "linux") {
Services.prefs.setIntPref("zen.theme.gradient-legacy-version", 0);
}
}
_migrateV3() {
if (Services.prefs.getStringPref('zen.theme.accent-color', '').startsWith('system')) {
Services.prefs.setStringPref('zen.theme.accent-color', 'AccentColor');
if (Services.prefs.getStringPref("zen.theme.accent-color", "").startsWith("system")) {
Services.prefs.setStringPref("zen.theme.accent-color", "AccentColor");
}
}
_migrateV4() {
// Fix spelling mistake in preference name
Services.prefs.setBoolPref(
'zen.theme.use-system-colors',
Services.prefs.getBoolPref('zen.theme.use-sysyem-colors', false)
"zen.theme.use-system-colors",
Services.prefs.getBoolPref("zen.theme.use-sysyem-colors", false)
);
}
_migrateV5() {
Services.prefs.setBoolPref('zen.site-data-panel.show-callout', true);
Services.prefs.setBoolPref("zen.site-data-panel.show-callout", true);
}
}

View File

@@ -3,114 +3,115 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
document.addEventListener(
'MozBeforeInitialXULLayout',
"MozBeforeInitialXULLayout",
() => {
// <commandset id="mainCommandSet"> defined in browser-sets.inc
document.getElementById('zenCommandSet').addEventListener('command', (event) => {
// eslint-disable-next-line complexity
document.getElementById("zenCommandSet").addEventListener("command", (event) => {
switch (event.target.id) {
case 'cmd_zenCompactModeToggle':
case "cmd_zenCompactModeToggle":
gZenCompactModeManager.toggle();
break;
case 'cmd_zenCompactModeShowSidebar':
case "cmd_zenCompactModeShowSidebar":
gZenCompactModeManager.toggleSidebar();
break;
case 'cmd_toggleCompactModeIgnoreHover':
case "cmd_toggleCompactModeIgnoreHover":
gZenCompactModeManager.toggle(true);
break;
case 'cmd_zenWorkspaceForward':
case "cmd_zenWorkspaceForward":
gZenWorkspaces.changeWorkspaceShortcut();
break;
case 'cmd_zenWorkspaceBackward':
case "cmd_zenWorkspaceBackward":
gZenWorkspaces.changeWorkspaceShortcut(-1);
break;
case 'cmd_zenSplitViewGrid':
gZenViewSplitter.toggleShortcut('grid');
case "cmd_zenSplitViewGrid":
gZenViewSplitter.toggleShortcut("grid");
break;
case 'cmd_zenSplitViewVertical':
gZenViewSplitter.toggleShortcut('vsep');
case "cmd_zenSplitViewVertical":
gZenViewSplitter.toggleShortcut("vsep");
break;
case 'cmd_zenSplitViewHorizontal':
gZenViewSplitter.toggleShortcut('hsep');
case "cmd_zenSplitViewHorizontal":
gZenViewSplitter.toggleShortcut("hsep");
break;
case 'cmd_zenSplitViewUnsplit':
gZenViewSplitter.toggleShortcut('unsplit');
case "cmd_zenSplitViewUnsplit":
gZenViewSplitter.toggleShortcut("unsplit");
break;
case 'cmd_zenSplitViewContextMenu':
case "cmd_zenSplitViewContextMenu":
gZenViewSplitter.contextSplitTabs();
break;
case 'cmd_zenCopyCurrentURLMarkdown':
case "cmd_zenCopyCurrentURLMarkdown":
gZenCommonActions.copyCurrentURLAsMarkdownToClipboard();
break;
case 'cmd_zenCopyCurrentURL':
case "cmd_zenCopyCurrentURL":
gZenCommonActions.copyCurrentURLToClipboard();
break;
case 'cmd_zenPinnedTabReset':
case "cmd_zenPinnedTabReset":
gZenPinnedTabManager.resetPinnedTab(gBrowser.selectedTab);
break;
case 'cmd_zenPinnedTabResetNoTab':
case "cmd_zenPinnedTabResetNoTab":
gZenPinnedTabManager.resetPinnedTab();
break;
case 'cmd_zenToggleSidebar':
case "cmd_zenToggleSidebar":
gZenVerticalTabsManager.toggleExpand();
break;
case 'cmd_zenOpenZenThemePicker':
case "cmd_zenOpenZenThemePicker":
gZenThemePicker.openThemePicker(event);
break;
case 'cmd_zenChangeWorkspaceTab':
case "cmd_zenChangeWorkspaceTab":
gZenWorkspaces.changeTabWorkspace(
event.sourceEvent.target.getAttribute('zen-workspace-id')
event.sourceEvent.target.getAttribute("zen-workspace-id")
);
break;
case 'cmd_zenToggleTabsOnRight':
case "cmd_zenToggleTabsOnRight":
gZenVerticalTabsManager.toggleTabsOnRight();
break;
case 'cmd_zenSplitViewLinkInNewTab':
case "cmd_zenSplitViewLinkInNewTab":
gZenViewSplitter.splitLinkInNewTab();
break;
case 'cmd_zenNewEmptySplit':
case "cmd_zenNewEmptySplit":
setTimeout(() => {
gZenViewSplitter.createEmptySplit();
}, 0);
break;
case 'cmd_zenReplacePinnedUrlWithCurrent':
case "cmd_zenReplacePinnedUrlWithCurrent":
gZenPinnedTabManager.replacePinnedUrlWithCurrent();
break;
case 'cmd_contextZenAddToEssentials':
case "cmd_contextZenAddToEssentials":
gZenPinnedTabManager.addToEssentials();
break;
case 'cmd_contextZenRemoveFromEssentials':
case "cmd_contextZenRemoveFromEssentials":
gZenPinnedTabManager.removeEssentials();
break;
case 'cmd_zenCtxDeleteWorkspace':
case "cmd_zenCtxDeleteWorkspace":
gZenWorkspaces.contextDeleteWorkspace(event);
break;
case 'cmd_zenChangeWorkspaceName':
case "cmd_zenChangeWorkspaceName":
gZenVerticalTabsManager.renameTabStart({
target: gZenWorkspaces.activeWorkspaceIndicator.querySelector(
'.zen-current-workspace-indicator-name'
".zen-current-workspace-indicator-name"
),
});
break;
case 'cmd_zenChangeWorkspaceIcon':
case "cmd_zenChangeWorkspaceIcon":
gZenWorkspaces.changeWorkspaceIcon();
break;
case 'cmd_zenReorderWorkspaces':
gZenUIManager.showToast('zen-workspaces-how-to-reorder-title', {
case "cmd_zenReorderWorkspaces":
gZenUIManager.showToast("zen-workspaces-how-to-reorder-title", {
timeout: 9000,
descriptionId: 'zen-workspaces-how-to-reorder-desc',
descriptionId: "zen-workspaces-how-to-reorder-desc",
});
break;
case 'cmd_zenOpenWorkspaceCreation':
case "cmd_zenOpenWorkspaceCreation":
gZenWorkspaces.openWorkspaceCreation(event);
break;
case 'cmd_zenOpenFolderCreation':
case "cmd_zenOpenFolderCreation":
gZenFolders.createFolder([], {
renameFolder: true,
});
break;
case 'cmd_zenTogglePinTab': {
case "cmd_zenTogglePinTab": {
const currentTab = gBrowser.selectedTab;
if (currentTab && !currentTab.hasAttribute('zen-empty-tab')) {
if (currentTab && !currentTab.hasAttribute("zen-empty-tab")) {
if (currentTab.pinned) {
gBrowser.unpinTab(currentTab);
} else {
@@ -119,20 +120,20 @@ document.addEventListener(
}
break;
}
case 'cmd_zenCloseUnpinnedTabs':
case "cmd_zenCloseUnpinnedTabs":
gZenWorkspaces.closeAllUnpinnedTabs();
break;
case 'cmd_zenUnloadWorkspace': {
case "cmd_zenUnloadWorkspace": {
gZenWorkspaces.unloadWorkspace();
break;
}
case 'cmd_zenNewNavigatorUnsynced':
case "cmd_zenNewNavigatorUnsynced":
OpenBrowserWindow({ zenSyncedWindow: false });
break;
default:
gZenGlanceManager.handleMainCommandSet(event);
if (event.target.id.startsWith('cmd_zenWorkspaceSwitch')) {
const index = parseInt(event.target.id.replace('cmd_zenWorkspaceSwitch', ''), 10) - 1;
if (event.target.id.startsWith("cmd_zenWorkspaceSwitch")) {
const index = parseInt(event.target.id.replace("cmd_zenWorkspaceSwitch", ""), 10) - 1;
gZenWorkspaces.shortcutSwitchTo(index);
}
break;

View File

@@ -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/. */
'use strict';
"use strict";
/* INCLUDE THIS FILE AS:
* <script src="chrome://browser/content/zenThemeModifier.js"></script>
@@ -11,13 +11,13 @@
*/
{
const { AppConstants } = ChromeUtils.importESModule(
'resource://gre/modules/AppConstants.sys.mjs'
"resource://gre/modules/AppConstants.sys.mjs"
);
const kZenThemePrefsList = [
'zen.theme.accent-color',
'zen.theme.border-radius',
'zen.theme.content-element-separation',
"zen.theme.accent-color",
"zen.theme.border-radius",
"zen.theme.content-element-separation",
];
const kZenMaxElementSeparation = 12;
@@ -38,7 +38,7 @@
* begin listening to changes in preferred color scheme.
*/
init() {
this._inMainBrowserWindow = window.location.href == 'chrome://browser/content/browser.xhtml';
this._inMainBrowserWindow = window.location.href == "chrome://browser/content/browser.xhtml";
this.listenForEvents();
this.updateAllThemeBasics();
},
@@ -52,10 +52,10 @@
// Add fullscreen listener to update the theme when going in and out of fullscreen
const eventsForSeparation = [
'ZenViewSplitter:SplitViewDeactivated',
'ZenViewSplitter:SplitViewActivated',
'fullscreen',
'ZenCompactMode:Toggled',
"ZenViewSplitter:SplitViewDeactivated",
"ZenViewSplitter:SplitViewActivated",
"fullscreen",
"ZenCompactMode:Toggled",
];
const separationHandler = this.updateElementSeparation.bind(this);
for (let eventName of eventsForSeparation) {
@@ -63,7 +63,7 @@
}
window.addEventListener(
'unload',
"unload",
() => {
for (let pref of kZenThemePrefsList) {
Services.prefs.removeObserver(pref, handleEvent);
@@ -91,27 +91,27 @@
},
updateBorderRadius() {
const borderRadius = Services.prefs.getIntPref('zen.theme.border-radius', -1);
const borderRadius = Services.prefs.getIntPref("zen.theme.border-radius", -1);
// -1 is the default value, will use platform-native values
// otherwise, use the custom value
if (borderRadius == -1) {
if (AppConstants.platform == 'macosx') {
const targetRadius = window.matchMedia('(-moz-mac-tahoe-theme)').matches ? 15 : 10;
document.documentElement.style.setProperty('--zen-border-radius', targetRadius + 'px');
} else if (AppConstants.platform == 'linux') {
if (AppConstants.platform == "macosx") {
const targetRadius = window.matchMedia("(-moz-mac-tahoe-theme)").matches ? 15 : 10;
document.documentElement.style.setProperty("--zen-border-radius", targetRadius + "px");
} else if (AppConstants.platform == "linux") {
// Linux uses GTK CSD titlebar radius, default to 8px
document.documentElement.style.setProperty(
'--zen-border-radius',
'env(-moz-gtk-csd-titlebar-radius, 8px)'
"--zen-border-radius",
"env(-moz-gtk-csd-titlebar-radius, 8px)"
);
} else {
// Windows defaults to 8px
document.documentElement.style.setProperty('--zen-border-radius', '8px');
document.documentElement.style.setProperty("--zen-border-radius", "8px");
}
} else {
// Use the overridden value
document.documentElement.style.setProperty('--zen-border-radius', borderRadius + 'px');
document.documentElement.style.setProperty("--zen-border-radius", borderRadius + "px");
}
},
@@ -119,26 +119,26 @@
const kMinElementSeparation = 0.1; // in px
let separation = this.elementSeparation;
if (
document.documentElement.hasAttribute('inFullscreen') &&
document.documentElement.hasAttribute("inFullscreen") &&
window.gZenCompactModeManager?.preference &&
!document.getElementById('tabbrowser-tabbox')?.hasAttribute('zen-split-view') &&
Services.prefs.getBoolPref('zen.view.borderless-fullscreen', true)
!document.getElementById("tabbrowser-tabbox")?.hasAttribute("zen-split-view") &&
Services.prefs.getBoolPref("zen.view.borderless-fullscreen", true)
) {
separation = 0;
}
// In order to still use it on fullscreen, even if it's 0px, add .1px (almost invisible)
separation = Math.max(kMinElementSeparation, separation);
document.documentElement.style.setProperty('--zen-element-separation', separation + 'px');
document.documentElement.style.setProperty("--zen-element-separation", separation + "px");
if (separation == kMinElementSeparation) {
document.documentElement.setAttribute('zen-no-padding', true);
document.documentElement.setAttribute("zen-no-padding", true);
} else {
document.documentElement.removeAttribute('zen-no-padding');
document.documentElement.removeAttribute("zen-no-padding");
}
},
get elementSeparation() {
return Math.min(
Services.prefs.getIntPref('zen.theme.content-element-separation'),
Services.prefs.getIntPref("zen.theme.content-element-separation"),
kZenMaxElementSeparation
);
},
@@ -147,10 +147,12 @@
* Update the accent color.
*/
updateAccentColor() {
const accentColor = Services.prefs.getStringPref('zen.theme.accent-color');
document.documentElement.style.setProperty('--zen-primary-color', accentColor);
const accentColor = Services.prefs.getStringPref("zen.theme.accent-color");
document.documentElement.style.setProperty("--zen-primary-color", accentColor);
},
};
if (typeof Services !== 'undefined') ZenThemeModifier.init();
if (typeof Services !== "undefined") {
ZenThemeModifier.init();
}
}

View File

@@ -6,34 +6,34 @@ const lazy = {};
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'COMPACT_MODE_FLASH_DURATION',
'zen.view.compact.toolbar-flash-popup.duration',
"COMPACT_MODE_FLASH_DURATION",
"zen.view.compact.toolbar-flash-popup.duration",
800
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'COMPACT_MODE_FLASH_ENABLED',
'zen.view.compact.toolbar-flash-popup',
"COMPACT_MODE_FLASH_ENABLED",
"zen.view.compact.toolbar-flash-popup",
true
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'COMPACT_MODE_CAN_ANIMATE_SIDEBAR',
'zen.view.compact.animate-sidebar',
"COMPACT_MODE_CAN_ANIMATE_SIDEBAR",
"zen.view.compact.animate-sidebar",
true
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'COMPACT_MODE_SHOW_SIDEBAR_AND_TOOLBAR_ON_HOVER',
'zen.view.compact.show-sidebar-and-toolbar-on-hover',
"COMPACT_MODE_SHOW_SIDEBAR_AND_TOOLBAR_ON_HOVER",
"zen.view.compact.show-sidebar-and-toolbar-on-hover",
true
);
ChromeUtils.defineLazyGetter(lazy, 'mainAppWrapper', () =>
document.getElementById('zen-main-app-wrapper')
ChromeUtils.defineLazyGetter(lazy, "mainAppWrapper", () =>
document.getElementById("zen-main-app-wrapper")
);
window.gZenCompactModeManager = {
@@ -42,14 +42,14 @@ window.gZenCompactModeManager = {
_removeHoverFrames: {},
// Delay to avoid flickering when hovering over the sidebar
HOVER_HACK_DELAY: Services.prefs.getIntPref('zen.view.compact.hover-hack-delay', 0),
HOVER_HACK_DELAY: Services.prefs.getIntPref("zen.view.compact.hover-hack-delay", 0),
preInit() {
this._wasInCompactMode = Services.prefs.getBoolPref(
'zen.view.compact.enable-at-startup',
"zen.view.compact.enable-at-startup",
false
);
this._canDebugLog = Services.prefs.getBoolPref('zen.view.compact.debug', false);
this._canDebugLog = Services.prefs.getBoolPref("zen.view.compact.debug", false);
this.addContextMenu();
},
@@ -58,35 +58,37 @@ window.gZenCompactModeManager = {
this.addMouseActions();
const tabIsRightObserver = this._updateSidebarIsOnRight.bind(this);
Services.prefs.addObserver('zen.tabs.vertical.right-side', tabIsRightObserver);
Services.prefs.addObserver("zen.tabs.vertical.right-side", tabIsRightObserver);
window.addEventListener(
'unload',
"unload",
() => {
Services.prefs.removeObserver('zen.tabs.vertical.right-side', tabIsRightObserver);
Services.prefs.removeObserver("zen.tabs.vertical.right-side", tabIsRightObserver);
},
{ once: true }
);
gZenUIManager.addPopupTrackingAttribute(this.sidebar);
gZenUIManager.addPopupTrackingAttribute(
document.getElementById('zen-appcontent-navbar-wrapper')
document.getElementById("zen-appcontent-navbar-wrapper")
);
this.addHasPolyfillObserver();
// Clear hover states when window state changes (minimize, maximize, etc.)
window.addEventListener('sizemodechange', () => this._clearAllHoverStates());
window.addEventListener("sizemodechange", () => this._clearAllHoverStates());
this._canShowBackgroundTabToast = Services.prefs.getBoolPref(
'zen.view.compact.show-background-tab-toast',
"zen.view.compact.show-background-tab-toast",
true
);
if (AppConstants.platform == 'macosx') {
window.addEventListener('mouseover', (event) => {
if (AppConstants.platform == "macosx") {
window.addEventListener("mouseover", (event) => {
const buttons = gZenVerticalTabsManager.actualWindowButtons;
if (event.target.closest('.titlebar-buttonbox-container') === buttons) return;
if (event.target.closest(".titlebar-buttonbox-container") === buttons) {
return;
}
this._setElementExpandAttribute(buttons, false);
});
}
@@ -98,28 +100,29 @@ window.gZenCompactModeManager = {
log(...args) {
if (this._canDebugLog) {
console.log('[Zen Compact Mode]', ...args);
// eslint-disable-next-line no-console
console.debug("[Zen Compact Mode]", ...args);
}
},
get preference() {
return document.documentElement.getAttribute('zen-compact-mode') === 'true';
return document.documentElement.getAttribute("zen-compact-mode") === "true";
},
get shouldBeCompact() {
return !document.documentElement.getAttribute('chromehidden')?.includes('toolbar');
return !document.documentElement.getAttribute("chromehidden")?.includes("toolbar");
},
set preference(value) {
if (!this.shouldBeCompact) {
value = false;
}
this.log('Setting compact mode preference to', value);
this.log("Setting compact mode preference to", value);
if (
this.preference === value ||
document.documentElement.hasAttribute('zen-compact-animating')
document.documentElement.hasAttribute("zen-compact-animating")
) {
if (typeof this._wasInCompactMode !== 'undefined') {
if (typeof this._wasInCompactMode !== "undefined") {
// We wont do anything with it anyway, so we remove it
delete this._wasInCompactMode;
}
@@ -127,22 +130,22 @@ window.gZenCompactModeManager = {
// We dont want the user to be able to spam the button
return;
}
this.sidebar.removeAttribute('zen-user-show');
this.sidebar.removeAttribute("zen-user-show");
// We use this element in order to make it persis across restarts, by using the XULStore.
// main-window can't store attributes other than window sizes, so we use this instead
lazy.mainAppWrapper.setAttribute('zen-compact-mode', value);
document.documentElement.setAttribute('zen-compact-mode', value);
if (typeof this._wasInCompactMode === 'undefined') {
Services.prefs.setBoolPref('zen.view.compact.enable-at-startup', value);
lazy.mainAppWrapper.setAttribute("zen-compact-mode", value);
document.documentElement.setAttribute("zen-compact-mode", value);
if (typeof this._wasInCompactMode === "undefined") {
Services.prefs.setBoolPref("zen.view.compact.enable-at-startup", value);
}
this._updateEvent();
},
get sidebarIsOnRight() {
if (typeof this._sidebarIsOnRight !== 'undefined') {
if (typeof this._sidebarIsOnRight !== "undefined") {
return this._sidebarIsOnRight;
}
this._sidebarIsOnRight = Services.prefs.getBoolPref('zen.tabs.vertical.right-side');
this._sidebarIsOnRight = Services.prefs.getBoolPref("zen.tabs.vertical.right-side");
return this._sidebarIsOnRight;
},
@@ -151,7 +154,7 @@ window.gZenCompactModeManager = {
},
addHasPolyfillObserver() {
const attributes = ['panelopen', 'open', 'breakout-extend', 'zen-floating-urlbar'];
const attributes = ["panelopen", "open", "breakout-extend", "zen-floating-urlbar"];
this.sidebarObserverId = ZenHasPolyfill.observeSelectorExistence(
this.sidebar,
[
@@ -160,18 +163,18 @@ window.gZenCompactModeManager = {
":is([panelopen='true'], [open='true'], [breakout-extend='true']):not(#urlbar[zen-floating-urlbar='true']):not(tab):not(.zen-compact-mode-ignore)",
},
],
'zen-compact-mode-active',
"zen-compact-mode-active",
attributes
);
this.toolbarObserverId = ZenHasPolyfill.observeSelectorExistence(
document.getElementById('zen-appcontent-navbar-wrapper'),
document.getElementById("zen-appcontent-navbar-wrapper"),
[
{
selector:
":is([panelopen='true'], [open='true'], #urlbar:focus-within, [breakout-extend='true']):not(.zen-compact-mode-ignore)",
},
],
'zen-compact-mode-active',
"zen-compact-mode-active",
attributes
);
// Always connect this observer, we need it even if compact mode is disabled
@@ -208,64 +211,66 @@ window.gZenCompactModeManager = {
`);
const idToAction = {
'zen-context-menu-compact-mode-hide-sidebar': this.hideSidebar.bind(this),
'zen-context-menu-compact-mode-hide-toolbar': this.hideToolbar.bind(this),
'zen-context-menu-compact-mode-hide-both': this.hideBoth.bind(this),
"zen-context-menu-compact-mode-hide-sidebar": this.hideSidebar.bind(this),
"zen-context-menu-compact-mode-hide-toolbar": this.hideToolbar.bind(this),
"zen-context-menu-compact-mode-hide-both": this.hideBoth.bind(this),
};
for (let menuitem of fragment.querySelectorAll('menuitem')) {
for (let menuitem of fragment.querySelectorAll("menuitem")) {
if (menuitem.id in idToAction) {
menuitem.addEventListener('command', idToAction[menuitem.id]);
menuitem.addEventListener("command", idToAction[menuitem.id]);
}
}
document.getElementById('viewToolbarsMenuSeparator').before(fragment);
document.getElementById("viewToolbarsMenuSeparator").before(fragment);
this.updateContextMenu();
},
updateCompactModeContext(isSingleToolbar) {
const isIllegalState = this.checkIfIllegalState();
const menuitem = document.getElementById('zen-context-menu-compact-mode-toggle');
const menu = document.getElementById('zen-context-menu-compact-mode');
const menuitem = document.getElementById("zen-context-menu-compact-mode-toggle");
const menu = document.getElementById("zen-context-menu-compact-mode");
if (!menu) {
return;
}
if (isSingleToolbar) {
menu.setAttribute('hidden', 'true');
menu.setAttribute("hidden", "true");
menu.before(menuitem);
} else {
menu.removeAttribute('hidden');
menu.querySelector('menupopup').prepend(menuitem);
menu.removeAttribute("hidden");
menu.querySelector("menupopup").prepend(menuitem);
}
const hideToolbarMenuItem = document.getElementById(
'zen-context-menu-compact-mode-hide-toolbar'
"zen-context-menu-compact-mode-hide-toolbar"
);
if (isIllegalState) {
hideToolbarMenuItem.setAttribute('disabled', 'true');
hideToolbarMenuItem.setAttribute("disabled", "true");
} else {
hideToolbarMenuItem.removeAttribute('disabled');
hideToolbarMenuItem.removeAttribute("disabled");
}
},
hideSidebar() {
Services.prefs.setBoolPref('zen.view.compact.hide-tabbar', true);
Services.prefs.setBoolPref('zen.view.compact.hide-toolbar', false);
Services.prefs.setBoolPref("zen.view.compact.hide-tabbar", true);
Services.prefs.setBoolPref("zen.view.compact.hide-toolbar", false);
this.callAllEventListeners();
},
hideToolbar() {
Services.prefs.setBoolPref('zen.view.compact.hide-toolbar', true);
Services.prefs.setBoolPref('zen.view.compact.hide-tabbar', false);
Services.prefs.setBoolPref("zen.view.compact.hide-toolbar", true);
Services.prefs.setBoolPref("zen.view.compact.hide-tabbar", false);
this.callAllEventListeners();
},
hideBoth() {
Services.prefs.setBoolPref('zen.view.compact.hide-tabbar', true);
Services.prefs.setBoolPref('zen.view.compact.hide-toolbar', true);
Services.prefs.setBoolPref("zen.view.compact.hide-tabbar", true);
Services.prefs.setBoolPref("zen.view.compact.hide-toolbar", true);
this.callAllEventListeners();
},
/* Check for illegal states and fix them
/**
* Check for illegal states and fix them
*
* @returns {boolean} If the context menu should just show the "toggle" item
* instead of a submenu with hide options
*/
@@ -288,8 +293,8 @@ window.gZenCompactModeManager = {
(isLeftSideButtons && !isRightSidebar) || (!isLeftSideButtons && isRightSidebar);
if (closelyIllegalState && canHideToolbar && !canHideSidebar) {
// This state is illegal
Services.prefs.setBoolPref('zen.view.compact.hide-tabbar', true);
Services.prefs.setBoolPref('zen.view.compact.hide-toolbar', false);
Services.prefs.setBoolPref("zen.view.compact.hide-tabbar", true);
Services.prefs.setBoolPref("zen.view.compact.hide-toolbar", false);
this.callAllEventListeners();
return true;
}
@@ -332,7 +337,7 @@ window.gZenCompactModeManager = {
} else {
ZenHasPolyfill.disconnectObserver(this.sidebarObserverId);
}
window.dispatchEvent(new CustomEvent('ZenCompactMode:Toggled', { detail: this.preference }));
window.dispatchEvent(new CustomEvent("ZenCompactMode:Toggled", { detail: this.preference }));
},
// NOTE: Dont actually use event, it's just so we make sure
@@ -344,15 +349,15 @@ window.gZenCompactModeManager = {
}
let sidebarWidth = this.sidebar.getBoundingClientRect().width;
const shouldRecalculate =
this.preference || document.documentElement.hasAttribute('zen-creating-workspace');
const sidebarExpanded = document.documentElement.hasAttribute('zen-sidebar-expanded');
this.preference || document.documentElement.hasAttribute("zen-creating-workspace");
const sidebarExpanded = document.documentElement.hasAttribute("zen-sidebar-expanded");
if (sidebarWidth > 1) {
if (shouldRecalculate && sidebarExpanded) {
sidebarWidth = Math.max(sidebarWidth, 150);
}
// Second variable to get the genuine width of the sidebar
this.sidebar.style.setProperty('--actual-zen-sidebar-width', `${sidebarWidth}px`);
window.dispatchEvent(new window.Event('resize')); // To recalculate the layout
this.sidebar.style.setProperty("--actual-zen-sidebar-width", `${sidebarWidth}px`);
window.dispatchEvent(new window.Event("resize")); // To recalculate the layout
if (
event &&
shouldRecalculate &&
@@ -362,57 +367,56 @@ window.gZenCompactModeManager = {
return;
}
delete gZenVerticalTabsManager._hadSidebarCollapse;
this.sidebar.style.setProperty('--zen-sidebar-width', `${sidebarWidth}px`);
this.sidebar.style.setProperty("--zen-sidebar-width", `${sidebarWidth}px`);
}
return sidebarWidth;
},
get canHideSidebar() {
return (
Services.prefs.getBoolPref('zen.view.compact.hide-tabbar') ||
Services.prefs.getBoolPref("zen.view.compact.hide-tabbar") ||
gZenVerticalTabsManager._hasSetSingleToolbar
);
},
get canHideToolbar() {
return (
Services.prefs.getBoolPref('zen.view.compact.hide-toolbar') &&
Services.prefs.getBoolPref("zen.view.compact.hide-toolbar") &&
!gZenVerticalTabsManager._hasSetSingleToolbar
);
},
animateCompactMode() {
// Get the splitter width before hiding it (we need to hide it before animating on right)
document.documentElement.setAttribute('zen-compact-animating', 'true');
document.documentElement.setAttribute("zen-compact-animating", "true");
return new Promise((resolve) => {
// We need to set the splitter width before hiding it
let splitterWidth = document
.getElementById('zen-sidebar-splitter')
.getElementById("zen-sidebar-splitter")
.getBoundingClientRect().width;
const isCompactMode = this.preference;
const canHideSidebar = this.canHideSidebar;
let canAnimate = lazy.COMPACT_MODE_CAN_ANIMATE_SIDEBAR && !this.isSidebarPotentiallyOpen();
if (typeof this._wasInCompactMode !== 'undefined') {
if (typeof this._wasInCompactMode !== "undefined") {
canAnimate = false;
delete this._wasInCompactMode;
}
// Do this so we can get the correct width ONCE compact mode styled have been applied
if (canAnimate) {
this.sidebar.setAttribute('animate', 'true');
this.sidebar.setAttribute("animate", "true");
}
if (this._ignoreNextHover) {
this._setElementExpandAttribute(this.sidebar, false);
}
this.sidebar.style.removeProperty('margin-right');
this.sidebar.style.removeProperty('margin-left');
this.sidebar.style.removeProperty('transform');
this.sidebar.style.removeProperty("margin-right");
this.sidebar.style.removeProperty("margin-left");
this.sidebar.style.removeProperty("transform");
window.requestAnimationFrame(() => {
delete this._ignoreNextResize;
let sidebarWidth = this.getAndApplySidebarWidth();
const elementSeparation = ZenThemeModifier.elementSeparation;
if (!canAnimate) {
this.sidebar.removeAttribute('animate');
document.documentElement.removeAttribute('zen-compact-animating');
this.sidebar.removeAttribute("animate");
document.documentElement.removeAttribute("zen-compact-animating");
this.getAndApplySidebarWidth({});
this._ignoreNextResize = true;
@@ -422,7 +426,7 @@ window.gZenCompactModeManager = {
resolve();
return;
}
if (document.documentElement.hasAttribute('zen-sidebar-expanded')) {
if (document.documentElement.hasAttribute("zen-sidebar-expanded")) {
sidebarWidth -= 0.5 * splitterWidth;
if (elementSeparation < splitterWidth) {
// Subtract from the splitter width to end up with the correct element separation
@@ -441,20 +445,20 @@ window.gZenCompactModeManager = {
marginLeft: [0, this.sidebarIsOnRight ? 0 : `-${sidebarWidth}px`],
},
{
ease: 'easeIn',
type: 'spring',
ease: "easeIn",
type: "spring",
bounce: 0,
duration: 0.12,
}
)
.then(() => {
this.sidebar.style.transition = 'none';
this.sidebar.style.pointEvents = 'none';
const titlebar = document.getElementById('titlebar');
titlebar.style.visibility = 'hidden';
titlebar.style.transition = 'none';
this.sidebar.removeAttribute('animate');
document.documentElement.removeAttribute('zen-compact-animating');
this.sidebar.style.transition = "none";
this.sidebar.style.pointEvents = "none";
const titlebar = document.getElementById("titlebar");
titlebar.style.visibility = "hidden";
titlebar.style.transition = "none";
this.sidebar.removeAttribute("animate");
document.documentElement.removeAttribute("zen-compact-animating");
setTimeout(() => {
this.getAndApplySidebarWidth({});
@@ -467,16 +471,16 @@ window.gZenCompactModeManager = {
});
}
this.sidebar.style.removeProperty('margin-right');
this.sidebar.style.removeProperty('margin-left');
this.sidebar.style.removeProperty('transition');
this.sidebar.style.removeProperty('transform');
this.sidebar.style.removeProperty('point-events');
this.sidebar.style.removeProperty("margin-right");
this.sidebar.style.removeProperty("margin-left");
this.sidebar.style.removeProperty("transition");
this.sidebar.style.removeProperty("transform");
this.sidebar.style.removeProperty("point-events");
titlebar.style.removeProperty('visibility');
titlebar.style.removeProperty('transition');
titlebar.style.removeProperty("visibility");
titlebar.style.removeProperty("transition");
gURLBar.style.removeProperty('visibility');
gURLBar.style.removeProperty("visibility");
resolve();
});
@@ -485,7 +489,7 @@ window.gZenCompactModeManager = {
} else if (canHideSidebar && !isCompactMode) {
// Shouldn't be ever true, but just in case
delete this._ignoreNextHover;
document.getElementById('browser').style.overflow = 'clip';
document.getElementById("browser").style.overflow = "clip";
if (this.sidebarIsOnRight) {
this.sidebar.style.marginRight = `-${sidebarWidth}px`;
} else {
@@ -497,32 +501,32 @@ window.gZenCompactModeManager = {
this.sidebarIsOnRight
? {
marginRight: [`-${sidebarWidth}px`, 0],
transform: ['translateX(100%)', 'translateX(0)'],
transform: ["translateX(100%)", "translateX(0)"],
}
: { marginLeft: 0 },
{
ease: 'easeOut',
type: 'spring',
ease: "easeOut",
type: "spring",
bounce: 0,
duration: 0.12,
}
)
.then(() => {
this.sidebar.removeAttribute('animate');
document.getElementById('browser').style.removeProperty('overflow');
this.sidebar.style.transition = 'none';
this.sidebar.style.removeProperty('margin-right');
this.sidebar.style.removeProperty('margin-left');
this.sidebar.style.removeProperty('transform');
document.documentElement.removeAttribute('zen-compact-animating');
this.sidebar.removeAttribute("animate");
document.getElementById("browser").style.removeProperty("overflow");
this.sidebar.style.transition = "none";
this.sidebar.style.removeProperty("margin-right");
this.sidebar.style.removeProperty("margin-left");
this.sidebar.style.removeProperty("transform");
document.documentElement.removeAttribute("zen-compact-animating");
setTimeout(() => {
this.sidebar.style.removeProperty('transition');
this.sidebar.style.removeProperty("transition");
resolve();
});
});
} else {
this.sidebar.removeAttribute('animate'); // remove the attribute if we are not animating
document.documentElement.removeAttribute('zen-compact-animating');
this.sidebar.removeAttribute("animate"); // remove the attribute if we are not animating
document.documentElement.removeAttribute("zen-compact-animating");
delete this._ignoreNextHover;
resolve();
}
@@ -531,32 +535,32 @@ window.gZenCompactModeManager = {
},
updateContextMenu() {
const toggle = document.getElementById('zen-context-menu-compact-mode-toggle');
const toggle = document.getElementById("zen-context-menu-compact-mode-toggle");
if (!toggle) {
return;
}
toggle.setAttribute('checked', this.preference);
toggle.setAttribute("checked", this.preference);
const hideTabBar = this.canHideSidebar;
const hideToolbar = this.canHideToolbar;
const hideBoth = hideTabBar && hideToolbar;
const idName = 'zen-context-menu-compact-mode-hide-';
const sidebarItem = document.getElementById(idName + 'sidebar');
const toolbarItem = document.getElementById(idName + 'toolbar');
const bothItem = document.getElementById(idName + 'both');
sidebarItem.setAttribute('checked', !hideBoth && hideTabBar);
toolbarItem.setAttribute('checked', !hideBoth && hideToolbar);
bothItem.setAttribute('checked', hideBoth);
const idName = "zen-context-menu-compact-mode-hide-";
const sidebarItem = document.getElementById(idName + "sidebar");
const toolbarItem = document.getElementById(idName + "toolbar");
const bothItem = document.getElementById(idName + "both");
sidebarItem.setAttribute("checked", !hideBoth && hideTabBar);
toolbarItem.setAttribute("checked", !hideBoth && hideToolbar);
bothItem.setAttribute("checked", hideBoth);
},
_removeOpenStateOnUnifiedExtensions() {
// Fix for bug https://github.com/zen-browser/desktop/issues/1925
const buttons = document.querySelectorAll(
'toolbarbutton:is(#unified-extensions-button, .webextension-browser-action)'
"toolbarbutton:is(#unified-extensions-button, .webextension-browser-action)"
);
for (let button of buttons) {
button.removeAttribute('open');
button.removeAttribute("open");
}
},
@@ -567,30 +571,30 @@ window.gZenCompactModeManager = {
},
_updateSidebarIsOnRight() {
this._sidebarIsOnRight = Services.prefs.getBoolPref('zen.tabs.vertical.right-side');
this._sidebarIsOnRight = Services.prefs.getBoolPref("zen.tabs.vertical.right-side");
},
toggleSidebar() {
this.sidebar.toggleAttribute('zen-user-show');
this.sidebar.toggleAttribute("zen-user-show");
},
get hideAfterHoverDuration() {
if (this._hideAfterHoverDuration) {
return this._hideAfterHoverDuration;
}
return Services.prefs.getIntPref('zen.view.compact.toolbar-hide-after-hover.duration');
return Services.prefs.getIntPref("zen.view.compact.toolbar-hide-after-hover.duration");
},
get hoverableElements() {
return [
{
element: this.sidebar,
screenEdge: this.sidebarIsOnRight ? 'right' : 'left',
screenEdge: this.sidebarIsOnRight ? "right" : "left",
keepHoverDuration: 100,
},
{
element: document.getElementById('zen-appcontent-navbar-wrapper'),
screenEdge: 'top',
element: document.getElementById("zen-appcontent-navbar-wrapper"),
screenEdge: "top",
},
{
element: gZenVerticalTabsManager.actualWindowButtons,
@@ -599,13 +603,13 @@ window.gZenCompactModeManager = {
},
flashSidebar(duration = lazy.COMPACT_MODE_FLASH_DURATION) {
let tabPanels = document.getElementById('tabbrowser-tabpanels');
let tabPanels = document.getElementById("tabbrowser-tabpanels");
if (!tabPanels.matches("[zen-split-view='true']")) {
this.flashElement(this.sidebar, duration, this.sidebar.id);
}
},
flashElement(element, duration, id, attrName = 'flash-popup') {
flashElement(element, duration, id, attrName = "flash-popup") {
if (this._flashTimeouts[id]) {
clearTimeout(this._flashTimeouts[id]);
} else {
@@ -624,48 +628,50 @@ window.gZenCompactModeManager = {
this._flashTimeouts[id] = null;
},
_setElementExpandAttribute(element, value, attr = 'zen-has-hover') {
const kVerifiedAttributes = ['zen-has-hover', 'has-popup-menu', 'zen-compact-mode-active'];
const isToolbar = element.id === 'zen-appcontent-navbar-wrapper';
_setElementExpandAttribute(element, value, attr = "zen-has-hover") {
const kVerifiedAttributes = ["zen-has-hover", "has-popup-menu", "zen-compact-mode-active"];
const isToolbar = element.id === "zen-appcontent-navbar-wrapper";
if (value) {
if (attr === 'zen-has-hover' && element !== gZenVerticalTabsManager.actualWindowButtons) {
element.setAttribute('zen-has-implicit-hover', 'true');
if (attr === "zen-has-hover" && element !== gZenVerticalTabsManager.actualWindowButtons) {
element.setAttribute("zen-has-implicit-hover", "true");
if (!lazy.COMPACT_MODE_SHOW_SIDEBAR_AND_TOOLBAR_ON_HOVER) {
return;
}
}
element.setAttribute(attr, 'true');
element.setAttribute(attr, "true");
if (
isToolbar &&
((gZenVerticalTabsManager._hasSetSingleToolbar &&
(element.hasAttribute('should-hide') ||
document.documentElement.hasAttribute('zen-has-bookmarks'))) ||
(element.hasAttribute("should-hide") ||
document.documentElement.hasAttribute("zen-has-bookmarks"))) ||
(this.preference &&
Services.prefs.getBoolPref('zen.view.compact.hide-toolbar') &&
Services.prefs.getBoolPref("zen.view.compact.hide-toolbar") &&
!gZenVerticalTabsManager._hasSetSingleToolbar))
) {
gBrowser.tabpanels.setAttribute('has-toolbar-hovered', 'true');
gBrowser.tabpanels.setAttribute("has-toolbar-hovered", "true");
}
} else {
if (attr === 'zen-has-hover') {
element.removeAttribute('zen-has-implicit-hover');
if (attr === "zen-has-hover") {
element.removeAttribute("zen-has-implicit-hover");
}
element.removeAttribute(attr);
// Only remove if none of the verified attributes are present
if (isToolbar && !kVerifiedAttributes.some((attr) => element.hasAttribute(attr))) {
gBrowser.tabpanels.removeAttribute('has-toolbar-hovered');
if (
isToolbar &&
!kVerifiedAttributes.some((verifiedAttr) => element.hasAttribute(verifiedAttr))
) {
gBrowser.tabpanels.removeAttribute("has-toolbar-hovered");
}
}
},
addMouseActions() {
gURLBar.addEventListener('mouseenter', (event) => {
if (event.target.closest('#urlbar[zen-floating-urlbar]')) {
gURLBar.addEventListener("mouseenter", (event) => {
if (event.target.closest("#urlbar[zen-floating-urlbar]")) {
window.requestAnimationFrame(() => {
this._setElementExpandAttribute(gZenVerticalTabsManager.actualWindowButtons, false);
});
this._hasHoveredUrlbar = true;
return;
}
});
@@ -673,22 +679,26 @@ window.gZenCompactModeManager = {
let target = this.hoverableElements[i].element;
// Add the attribute on startup if the mouse is already over the element
if (target.matches(':hover')) {
if (target.matches(":hover")) {
this._setElementExpandAttribute(target, true);
}
const onEnter = (event) => {
setTimeout(() => {
if (event.type === 'mouseenter' && !event.target.matches(':hover')) return;
if (event.target.closest('panel')) return;
if (event.type === "mouseenter" && !event.target.matches(":hover")) {
return;
}
if (event.target.closest("panel")) {
return;
}
// Dont register the hover if the urlbar is floating and we are hovering over it
this.clearFlashTimeout('has-hover' + target.id);
this.clearFlashTimeout("has-hover" + target.id);
window.requestAnimationFrame(() => {
if (
document.documentElement.getAttribute('supress-primary-adjustment') === 'true' ||
document.documentElement.getAttribute("supress-primary-adjustment") === "true" ||
this._hasHoveredUrlbar ||
this._ignoreNextHover ||
target.hasAttribute('zen-has-hover')
target.hasAttribute("zen-has-hover")
) {
return;
}
@@ -698,7 +708,7 @@ window.gZenCompactModeManager = {
};
const onLeave = (event) => {
if (AppConstants.platform == 'macosx') {
if (AppConstants.platform == "macosx") {
const buttonRect = gZenVerticalTabsManager.actualWindowButtons.getBoundingClientRect();
const MAC_WINDOW_BUTTONS_X_BORDER = buttonRect.width + buttonRect.x;
const MAC_WINDOW_BUTTONS_Y_BORDER = buttonRect.height + buttonRect.y;
@@ -717,17 +727,17 @@ window.gZenCompactModeManager = {
// This is because the mouse is left to be handled natively so firefox thinks the mouse left the window for a split second.
setTimeout(() => {
// Let's double check if the mouse is still hovering over the element, see the bug above.
if (event.target.matches(':hover')) {
if (event.target.matches(":hover")) {
return;
}
if (
event.explicitOriginalTarget?.closest?.('#urlbar[zen-floating-urlbar]') ||
(document.documentElement.getAttribute('supress-primary-adjustment') === 'true' &&
event.explicitOriginalTarget?.closest?.("#urlbar[zen-floating-urlbar]") ||
(document.documentElement.getAttribute("supress-primary-adjustment") === "true" &&
gZenVerticalTabsManager._hasSetSingleToolbar) ||
this._hasHoveredUrlbar ||
this._ignoreNextHover ||
(event.type === 'dragleave' &&
(event.type === "dragleave" &&
event.explicitOriginalTarget !== target &&
target.contains?.(event.explicitOriginalTarget))
) {
@@ -738,8 +748,8 @@ window.gZenCompactModeManager = {
this.flashElement(
target,
this.hoverableElements[i].keepHoverDuration,
'has-hover' + target.id,
'zen-has-hover'
"has-hover" + target.id,
"zen-has-hover"
);
} else {
this._removeHoverFrames[target.id] = window.requestAnimationFrame(() =>
@@ -749,21 +759,25 @@ window.gZenCompactModeManager = {
}, this.HOVER_HACK_DELAY);
};
target.addEventListener('mouseover', onEnter);
target.addEventListener('dragover', onEnter);
target.addEventListener("mouseover", onEnter);
target.addEventListener("dragover", onEnter);
target.addEventListener('mouseleave', onLeave);
target.addEventListener('dragleave', onLeave);
target.addEventListener("mouseleave", onLeave);
target.addEventListener("dragleave", onLeave);
}
document.documentElement.addEventListener('mouseleave', (event) => {
document.documentElement.addEventListener("mouseleave", (event) => {
setTimeout(() => {
const screenEdgeCrossed = this._getCrossedEdge(event.pageX, event.pageY);
if (!screenEdgeCrossed) return;
if (!screenEdgeCrossed) {
return;
}
for (let entry of this.hoverableElements) {
if (screenEdgeCrossed !== entry.screenEdge) continue;
if (screenEdgeCrossed !== entry.screenEdge) {
continue;
}
const target = entry.element;
const boundAxis = entry.screenEdge === 'right' || entry.screenEdge === 'left' ? 'y' : 'x';
const boundAxis = entry.screenEdge === "right" || entry.screenEdge === "left" ? "y" : "x";
if (!this._positionInBounds(boundAxis, target, event.pageX, event.pageY, 7)) {
continue;
}
@@ -772,15 +786,17 @@ window.gZenCompactModeManager = {
this.flashElement(
target,
this.hideAfterHoverDuration,
'has-hover' + target.id,
'zen-has-hover'
"has-hover" + target.id,
"zen-has-hover"
);
document.addEventListener(
'mousemove',
"mousemove",
() => {
if (target.matches(':hover')) return;
if (target.matches(":hover")) {
return;
}
this._setElementExpandAttribute(target, false);
this.clearFlashTimeout('has-hover' + target.id);
this.clearFlashTimeout("has-hover" + target.id);
},
{ once: true }
);
@@ -788,7 +804,7 @@ window.gZenCompactModeManager = {
}, this.HOVER_HACK_DELAY);
});
gURLBar.addEventListener('mouseleave', () => {
gURLBar.addEventListener("mouseleave", () => {
setTimeout(() => {
setTimeout(() => {
requestAnimationFrame(() => {
@@ -803,25 +819,27 @@ window.gZenCompactModeManager = {
const targetBox = element.getBoundingClientRect();
posX = Math.max(targetBox.left, Math.min(posX, targetBox.right));
posY = Math.max(targetBox.top, Math.min(posY, targetBox.bottom));
return ['top', 'bottom', 'left', 'right'].find((edge, i) => {
return ["top", "bottom", "left", "right"].find((edge, i) => {
const distance = Math.abs((i < 2 ? posY : posX) - targetBox[edge]);
return distance <= maxDistance;
});
},
_positionInBounds(axis = 'x', element, x, y, error = 0) {
_positionInBounds(axis = "x", element, x, y, error = 0) {
const bBox = element.getBoundingClientRect();
if (axis === 'y') return bBox.top - error < y && y < bBox.bottom + error;
else return bBox.left - error < x && x < bBox.right + error;
if (axis === "y") {
return bBox.top - error < y && y < bBox.bottom + error;
}
return bBox.left - error < x && x < bBox.right + error;
},
_clearAllHoverStates() {
// Clear hover attributes from all hoverable elements
for (let entry of this.hoverableElements) {
const target = entry.element;
if (target && !target.matches(':hover') && target.hasAttribute('zen-has-hover')) {
if (target && !target.matches(":hover") && target.hasAttribute("zen-has-hover")) {
this._setElementExpandAttribute(target, false);
this.clearFlashTimeout('has-hover' + target.id);
this.clearFlashTimeout("has-hover" + target.id);
}
}
},
@@ -831,9 +849,9 @@ window.gZenCompactModeManager = {
this._setElementExpandAttribute(this.sidebar, false);
}
return (
this.sidebar.hasAttribute('zen-user-show') ||
this.sidebar.hasAttribute('zen-has-hover') ||
this.sidebar.hasAttribute('zen-has-empty-tab')
this.sidebar.hasAttribute("zen-user-show") ||
this.sidebar.hasAttribute("zen-has-hover") ||
this.sidebar.hasAttribute("zen-has-empty-tab")
);
},
@@ -846,9 +864,9 @@ window.gZenCompactModeManager = {
!gZenGlanceManager._animating &&
!this._nextTimeWillBeActive
) {
gZenUIManager.showToast('zen-background-tab-opened-toast', {
gZenUIManager.showToast("zen-background-tab-opened-toast", {
button: {
id: 'zen-open-background-tab-button',
id: "zen-open-background-tab-button",
command: () => {
const targetWindow = window.ownerGlobal.parent || window;
targetWindow.gBrowser.selectedTab = tab;
@@ -861,7 +879,7 @@ window.gZenCompactModeManager = {
};
document.addEventListener(
'MozBeforeInitialXULLayout',
"MozBeforeInitialXULLayout",
() => {
gZenCompactModeManager.preInit();
},

View File

@@ -5,7 +5,7 @@
import {
nsZenDOMOperatedFeature,
nsZenMultiWindowFeature,
} from 'chrome://browser/content/zen-components/ZenCommonUtils.mjs';
} from "chrome://browser/content/zen-components/ZenCommonUtils.mjs";
const CONFIG = Object.freeze({
ANIMATION: {
@@ -37,7 +37,7 @@ class nsZenDownloadAnimation extends nsZenDOMOperatedFeature {
#handleNewDownload() {
if (
!Services.prefs.getBoolPref('zen.downloads.download-animation') ||
!Services.prefs.getBoolPref("zen.downloads.download-animation") ||
!nsZenMultiWindowFeature.isActiveWindow
) {
return;
@@ -54,10 +54,10 @@ class nsZenDownloadAnimation extends nsZenDOMOperatedFeature {
}
#animateDownload(startPosition) {
let animationElement = document.querySelector('zen-download-animation');
let animationElement = document.querySelector("zen-download-animation");
if (!animationElement) {
animationElement = document.createElement('zen-download-animation');
animationElement = document.createElement("zen-download-animation");
document.body.appendChild(animationElement);
}
@@ -72,17 +72,17 @@ class nsZenDownloadAnimationElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.attachShadow({ mode: "open" });
this.#loadArcStyles();
}
#loadArcStyles() {
try {
const link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
const link = document.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute(
'href',
'chrome://browser/content/zen-styles/zen-download-arc-animation.css'
"href",
"chrome://browser/content/zen-styles/zen-download-arc-animation.css"
);
this.shadowRoot.appendChild(link);
} catch (error) {
@@ -131,14 +131,18 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
#areTabsOnRightSide() {
const position = Services.prefs.getIntPref('zen.downloads.icon-popup-position', 0);
if (position === 1) return false;
if (position === 2) return true;
return Services.prefs.getBoolPref('zen.tabs.vertical.right-side');
const position = Services.prefs.getIntPref("zen.downloads.icon-popup-position", 0);
if (position === 1) {
return false;
}
if (position === 2) {
return true;
}
return Services.prefs.getBoolPref("zen.tabs.vertical.right-side");
}
#determineEndPosition() {
const downloadsButton = document.getElementById('downloads-button');
const downloadsButton = document.getElementById("downloads-button");
const isDownloadButtonVisible = downloadsButton && this.#isElementVisible(downloadsButton);
let endPosition = { clientX: 0, clientY: 0 };
@@ -153,7 +157,7 @@ class nsZenDownloadAnimationElement extends HTMLElement {
} else {
// Use alternative position at bottom of wrapper
const areTabsPositionedRight = this.#areTabsOnRightSide();
const wrapper = document.getElementById('zen-main-app-wrapper');
const wrapper = document.getElementById("zen-main-app-wrapper");
const wrapperRect = wrapper.getBoundingClientRect();
endPosition = {
@@ -175,12 +179,12 @@ class nsZenDownloadAnimationElement extends HTMLElement {
`;
const fragment = window.MozXULElement.parseXULToFragment(arcAnimationHTML);
const animationElement = fragment.querySelector('.zen-download-arc-animation');
const animationElement = fragment.querySelector(".zen-download-arc-animation");
Object.assign(animationElement.style, {
left: `${startPosition.clientX}px`,
top: `${startPosition.clientY}px`,
transform: 'translate(-50%, -50%)',
transform: "translate(-50%, -50%)",
});
this.shadowRoot.appendChild(animationElement);
@@ -229,14 +233,14 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
await gZenUIManager.motion.animate(arcAnimationElement, sequence, {
duration: Services.prefs.getIntPref('zen.downloads.download-animation-duration') / 1000,
easing: 'cubic-bezier(0.37, 0, 0.63, 1)',
fill: 'forwards',
duration: Services.prefs.getIntPref("zen.downloads.download-animation-duration") / 1000,
easing: "cubic-bezier(0.37, 0, 0.63, 1)",
fill: "forwards",
});
this.#cleanArcAnimation(arcAnimationElement);
} catch (error) {
console.error('[nsZenDownloadAnimationElement] Error in animation sequence:', error);
console.error("[nsZenDownloadAnimationElement] Error in animation sequence:", error);
this.#cleanArcAnimation(arcAnimationElement);
}
}
@@ -330,7 +334,7 @@ class nsZenDownloadAnimationElement extends HTMLElement {
return;
}
const wrapper = document.getElementById('zen-main-app-wrapper');
const wrapper = document.getElementById("zen-main-app-wrapper");
if (!wrapper) {
console.warn(
`[${nsZenDownloadAnimationElement.name}] Cannot start box animation, Wrapper element not found`
@@ -347,15 +351,15 @@ class nsZenDownloadAnimationElement extends HTMLElement {
</box>
`;
const sideProp = areTabsPositionedRight ? 'right' : 'left';
const sideProp = areTabsPositionedRight ? "right" : "left";
const fragment = window.MozXULElement.parseXULToFragment(boxAnimationHTML);
this.#boxAnimationElement = fragment.querySelector('.zen-download-box-animation');
this.#boxAnimationElement = fragment.querySelector(".zen-download-box-animation");
Object.assign(this.#boxAnimationElement.style, {
bottom: '24px',
transform: 'scale(0.8)',
[sideProp]: '-50px',
bottom: "24px",
transform: "scale(0.8)",
[sideProp]: "-50px",
});
wrapper.appendChild(this.#boxAnimationElement);
@@ -363,25 +367,25 @@ class nsZenDownloadAnimationElement extends HTMLElement {
await gZenUIManager.motion.animate(
this.#boxAnimationElement,
{
[sideProp]: '34px',
[sideProp]: "34px",
opacity: 1,
transform: 'scale(1.1)',
transform: "scale(1.1)",
},
{
duration: 0.35,
easing: 'ease-out',
easing: "ease-out",
}
).finished;
await gZenUIManager.motion.animate(
this.#boxAnimationElement,
{
[sideProp]: '24px',
transform: 'scale(1)',
[sideProp]: "24px",
transform: "scale(1)",
},
{
duration: 0.2,
easing: 'ease-in-out',
easing: "ease-in-out",
}
).finished;
@@ -401,7 +405,7 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
#getBoxAnimationDurationMs() {
return Services.prefs.getIntPref('zen.downloads.download-animation-duration') + 200;
return Services.prefs.getIntPref("zen.downloads.download-animation-duration") + 200;
}
async #finishBoxAnimation(areTabsPositionedRight) {
@@ -409,36 +413,38 @@ class nsZenDownloadAnimationElement extends HTMLElement {
this.#boxAnimationTimeoutId = null;
if (!this.#boxAnimationElement || this.#isBoxAnimationRunning) {
if (!this.#boxAnimationElement) this.#cleanBoxAnimationState();
if (!this.#boxAnimationElement) {
this.#cleanBoxAnimationState();
}
return;
}
this.#isBoxAnimationRunning = true;
try {
const sideProp = areTabsPositionedRight ? 'right' : 'left';
const sideProp = areTabsPositionedRight ? "right" : "left";
await gZenUIManager.motion.animate(
this.#boxAnimationElement,
{
transform: 'scale(0.9)',
transform: "scale(0.9)",
},
{
duration: 0.15,
easing: 'ease-in',
easing: "ease-in",
}
).finished;
await gZenUIManager.motion.animate(
this.#boxAnimationElement,
{
[sideProp]: '-50px',
[sideProp]: "-50px",
opacity: 0,
transform: 'scale(0.8)',
transform: "scale(0.8)",
},
{
duration: 0.3,
easing: 'cubic-bezier(0.5, 0, 0.75, 0)',
easing: "cubic-bezier(0.5, 0, 0.75, 0)",
}
).finished;
} catch (error) {
@@ -474,7 +480,9 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
#isElementVisible(element) {
if (!element) return false;
if (!element) {
return false;
}
const rect = element.getBoundingClientRect();
@@ -495,6 +503,6 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
}
customElements.define('zen-download-animation', nsZenDownloadAnimationElement);
customElements.define("zen-download-animation", nsZenDownloadAnimationElement);
new nsZenDownloadAnimation();

View File

@@ -41,6 +41,6 @@
width: 100%;
height: 100%;
background-color: var(--zen-primary-color);
mask: url('chrome://browser/content/zen-images/downloads/download.svg') no-repeat center;
mask: url("chrome://browser/content/zen-images/downloads/download.svg") no-repeat center;
mask-size: 70%;
}

View File

@@ -21,7 +21,7 @@
width: 50%;
height: 50%;
background-color: var(--zen-primary-color);
mask: url('chrome://browser/content/zen-images/downloads/archive.svg') no-repeat center;
mask: url("chrome://browser/content/zen-images/downloads/archive.svg") no-repeat center;
mask-size: contain;
display: block;
}

View File

@@ -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/. */
'use strict';
"use strict";
// Wrap in a block to prevent leaking to window scope.
{
@@ -33,19 +33,19 @@
*/
const elementToMove = (element) => {
if (
element.closest('.zen-current-workspace-indicator') ||
element.hasAttribute('split-view-group')
element.closest(".zen-current-workspace-indicator") ||
element.hasAttribute("split-view-group")
) {
return element;
}
if (element.group?.hasAttribute('split-view-group')) {
if (element.group?.hasAttribute("split-view-group")) {
return element.group;
}
if (isTab(element)) {
return element;
}
if (isTabGroupLabel(element)) {
return element.closest('.tab-group-label-container');
return element.closest(".tab-group-label-container");
}
throw new Error(`Element "${element.tagName}" is not expected to move`);
};
@@ -64,15 +64,15 @@
XPCOMUtils.defineLazyServiceGetter(
this,
'ZenDragAndDropService',
'@mozilla.org/zen/drag-and-drop;1',
"ZenDragAndDropService",
"@mozilla.org/zen/drag-and-drop;1",
Ci.nsIZenDragAndDrop
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
'_dndSwitchSpaceDelay',
'zen.tabs.dnd-switch-space-delay',
"_dndSwitchSpaceDelay",
"zen.tabs.dnd-switch-space-delay",
1000
);
}
@@ -80,7 +80,7 @@
init() {
super.init();
this.handle_windowDragEnter = this.handle_windowDragEnter.bind(this);
window.addEventListener('dragleave', this.handle_windowDragLeave.bind(this), {
window.addEventListener("dragleave", this.handle_windowDragLeave.bind(this), {
capture: true,
});
}
@@ -102,28 +102,28 @@
#createDragImageForTabs(draggedTab, movingTabs) {
const periphery = gZenWorkspaces.activeWorkspaceElement.querySelector(
'#tabbrowser-arrowscrollbox-periphery'
"#tabbrowser-arrowscrollbox-periphery"
);
const dragData = draggedTab._dragData;
const tabRect = window.windowUtils.getBoundsWithoutFlushing(movingTabs[0]);
const wrapper = document.createElement('div');
wrapper.style.width = tabRect.width + 'px';
wrapper.style.height = tabRect.height * movingTabs.length + 'px';
wrapper.style.overflow = 'clip';
wrapper.style.position = 'fixed';
wrapper.style.top = '-9999px';
const wrapper = document.createElement("div");
wrapper.style.width = tabRect.width + "px";
wrapper.style.height = tabRect.height * movingTabs.length + "px";
wrapper.style.overflow = "clip";
wrapper.style.position = "fixed";
wrapper.style.top = "-9999px";
periphery.appendChild(wrapper);
for (let i = 0; i < movingTabs.length; i++) {
const tab = movingTabs[i];
const tabClone = tab.cloneNode(true);
if (tabClone.hasAttribute('zen-essential')) {
if (tabClone.hasAttribute("zen-essential")) {
const rect = tab.getBoundingClientRect();
tabClone.style.minWidth = tabClone.style.maxWidth = `${rect.width}px`;
tabClone.style.minHeight = tabClone.style.maxHeight = `${rect.height}px`;
}
if (i > 0) {
tabClone.style.transform = `translate(${i * 4}px, -${i * (tabRect.height - 4)}px)`;
tabClone.style.opacity = '0.2';
tabClone.style.opacity = "0.2";
tabClone.style.zIndex = `${-i}`;
}
// Apply a transform translate to the tab in order to center it within the drag image
@@ -131,9 +131,9 @@
if (!movingTabs.length > 1) {
tabClone.style.transform = `translate(${(tabRect.width - dragData.offsetX) / 2}px, ${(tabRect.height - dragData.offsetY) / 2}px)`;
}
tabClone.setAttribute('drag-image', 'true');
tabClone.setAttribute("drag-image", "true");
wrapper.appendChild(tabClone);
if (isTab(tabClone) && !tabClone.hasAttribute('zen-essential')) {
if (isTab(tabClone) && !tabClone.hasAttribute("zen-essential")) {
// We need to limit the label content so the drag image doesn't grow too big.
const label = tabClone.textLabel;
const tabLabelParentWidth = label.parentElement.getBoundingClientRect().width;
@@ -147,32 +147,34 @@
#maybeCreateDragImageDot(movingTabs, wrapper) {
if (movingTabs.length > 1) {
const dot = document.createElement('div');
const dot = document.createElement("div");
dot.textContent = movingTabs.length;
dot.style.position = 'absolute';
dot.style.top = '-10px';
dot.style.left = '-16px';
dot.style.background = 'red';
dot.style.borderRadius = '50%';
dot.style.fontWeight = 'bold';
dot.style.fontSize = '10px';
dot.style.lineHeight = '16px';
dot.style.justifyContent = dot.style.alignItems = 'center';
dot.style.height = dot.style.minWidth = '16px';
dot.style.textAlign = 'center';
dot.style.color = 'white';
dot.style.position = "absolute";
dot.style.top = "-10px";
dot.style.left = "-16px";
dot.style.background = "red";
dot.style.borderRadius = "50%";
dot.style.fontWeight = "bold";
dot.style.fontSize = "10px";
dot.style.lineHeight = "16px";
dot.style.justifyContent = dot.style.alignItems = "center";
dot.style.height = dot.style.minWidth = "16px";
dot.style.textAlign = "center";
dot.style.color = "white";
wrapper.appendChild(dot);
}
}
// eslint-disable-next-line complexity
_animateTabMove(event) {
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
if (event.target.closest('#zen-essentials')) {
if (event.target.closest("#zen-essentials")) {
if (!isTab(draggedTab)) {
this.clearDragOverVisuals();
return;
}
return this.#animateVerticalPinnedGridDragOver(event);
this.#animateVerticalPinnedGridDragOver(event);
return;
} else if (this._fakeEssentialTab) {
this.#makeDragImageNonEssential(event);
}
@@ -185,7 +187,7 @@
: dragData.screenX;
let allTabs = this._tabbrowserTabs.ariaFocusableItems;
let numEssentials = gBrowser._numZenEssentials;
let isEssential = draggedTab.hasAttribute('zen-essential');
let isEssential = draggedTab.hasAttribute("zen-essential");
let tabs = allTabs.slice(
isEssential ? 0 : numEssentials,
isEssential ? numEssentials : undefined
@@ -206,8 +208,8 @@
let bounds = (ele) => window.windowUtils.getBoundsWithoutFlushing(ele);
let logicalForward = screenForward != this._rtlMode;
let screenAxis = this._tabbrowserTabs.verticalMode ? 'screenY' : 'screenX';
let size = this._tabbrowserTabs.verticalMode ? 'height' : 'width';
let screenAxis = this._tabbrowserTabs.verticalMode ? "screenY" : "screenX";
let size = this._tabbrowserTabs.verticalMode ? "height" : "width";
let { width: tabWidth, height: tabHeight } = bounds(draggedTab);
let tabSize = this._tabbrowserTabs.verticalMode ? tabHeight : tabWidth;
let translateX = event.screenX - dragData.screenX;
@@ -219,7 +221,7 @@
dragData.translateY = translateY;
// Move the dragged tab based on the mouse position.
let periphery = document.getElementById('tabbrowser-arrowscrollbox-periphery');
let periphery = document.getElementById("tabbrowser-arrowscrollbox-periphery");
let lastMovingTab = movingTabs.at(-1);
let firstMovingTab = movingTabs[0];
let endEdge = (ele) => ele[screenAxis] + bounds(ele)[size];
@@ -485,7 +487,7 @@
);
moveOverThreshold = gBrowser._tabGroupsEnabled
? Services.prefs.getIntPref('browser.tabs.dragDrop.moveOverThresholdPercent') / 100
? Services.prefs.getIntPref("browser.tabs.dragDrop.moveOverThresholdPercent") / 100
: 0.5;
moveOverThreshold = Math.min(1, Math.max(0, moveOverThreshold));
let shouldMoveOver = overlapPercent > moveOverThreshold;
@@ -516,8 +518,8 @@
}
}
this._tabbrowserTabs.removeAttribute('movingtab-group');
this._resetGroupTarget(document.querySelector('[dragover-groupTarget]'));
this._tabbrowserTabs.removeAttribute("movingtab-group");
this._resetGroupTarget(document.querySelector("[dragover-groupTarget]"));
delete dragData.shouldDropIntoCollapsedTabGroup;
@@ -538,8 +540,8 @@
dropBefore = true;
}
this._setDragOverGroupColor(colorCode);
this._tabbrowserTabs.toggleAttribute('movingtab-addToGroup', colorCode);
this._tabbrowserTabs.toggleAttribute('movingtab-ungroup', !colorCode);
this._tabbrowserTabs.toggleAttribute("movingtab-addToGroup", colorCode);
this._tabbrowserTabs.toggleAttribute("movingtab-ungroup", !colorCode);
if (
newDropElementIndex == oldDropElementIndex &&
@@ -555,15 +557,15 @@
}
#isMovingTab() {
return this._tabbrowserTabs.hasAttribute('movingtab');
return this._tabbrowserTabs.hasAttribute("movingtab");
}
get #dragShiftableItems() {
const separator = gZenWorkspaces.pinnedTabsContainer.querySelector(
'.pinned-tabs-container-separator'
".pinned-tabs-container-separator"
);
// Make sure to always return the separator at the start of the array
return Services.prefs.getBoolPref('zen.view.show-newtab-button-top')
return Services.prefs.getBoolPref("zen.view.show-newtab-button-top")
? [separator, gZenWorkspaces.activeWorkspaceElement.newTabButton]
: [separator];
}
@@ -577,10 +579,10 @@
}
#shouldSwitchSpace(event) {
const padding = Services.prefs.getIntPref('zen.workspaces.dnd-switch-padding');
const padding = Services.prefs.getIntPref("zen.workspaces.dnd-switch-padding");
// If we are hovering over the edges of the gNavToolbox or the splitter, we
// can change the workspace after a short delay.
const splitter = document.getElementById('zen-sidebar-splitter');
const splitter = document.getElementById("zen-sidebar-splitter");
let rect = window.windowUtils.getBoundsWithoutFlushing(gNavToolbox);
if (!(gZenCompactModeManager.preference && gZenCompactModeManager.canHideSidebar)) {
rect.width += window.windowUtils.getBoundsWithoutFlushing(splitter).width;
@@ -601,7 +603,7 @@
#handle_sidebarDragOver(event) {
const dt = event.dataTransfer;
const draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
if (draggedTab.hasAttribute('zen-essential')) {
if (draggedTab.hasAttribute("zen-essential")) {
this.clearSpaceSwitchTimer();
return;
}
@@ -655,12 +657,12 @@
let dragData = draggedTab._dragData;
let movingTabs = dragData.movingTabs;
if (!this._browserDragImageWrapper) {
const wrappingDiv = document.createXULElement('vbox');
canvas.style.borderRadius = '8px';
canvas.style.border = '2px solid white';
wrappingDiv.style.width = 200 + 'px';
wrappingDiv.style.height = 130 + 'px';
wrappingDiv.style.position = 'relative';
const wrappingDiv = document.createXULElement("vbox");
canvas.style.borderRadius = "8px";
canvas.style.border = "2px solid white";
wrappingDiv.style.width = 200 + "px";
wrappingDiv.style.height = 130 + "px";
wrappingDiv.style.position = "relative";
this.#maybeCreateDragImageDot(movingTabs, wrappingDiv);
wrappingDiv.appendChild(canvas);
this._browserDragImageWrapper = wrappingDiv;
@@ -671,7 +673,7 @@
this.originalDragImageArgs[1],
this.originalDragImageArgs[2]
);
window.addEventListener('dragover', this.handle_windowDragEnter, {
window.addEventListener("dragover", this.handle_windowDragEnter, {
once: true,
capture: true,
});
@@ -686,12 +688,12 @@
let draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
if (
isTab(draggedTab) &&
!draggedTab.hasAttribute('zen-essential') &&
draggedTab.getAttribute('zen-workspace-id') != activeWorkspace
!draggedTab.hasAttribute("zen-essential") &&
draggedTab.getAttribute("zen-workspace-id") != activeWorkspace
) {
const movingTabs = draggedTab._dragData?.movingTabs || [draggedTab];
for (let tab of movingTabs) {
tab.setAttribute('zen-workspace-id', activeWorkspace);
tab.setAttribute("zen-workspace-id", activeWorkspace);
}
gBrowser.selectedTab = draggedTab;
}
@@ -716,9 +718,9 @@
!gZenStartup.isReady ||
gReduceMotion ||
!dropElement ||
dropElement.hasAttribute('zen-essential') ||
draggedTab.hasAttribute('zen-essential') ||
draggedTab.getAttribute('zen-workspace-id') != gZenWorkspaces.activeWorkspace ||
dropElement.hasAttribute("zen-essential") ||
draggedTab.hasAttribute("zen-essential") ||
draggedTab.getAttribute("zen-workspace-id") != gZenWorkspaces.activeWorkspace ||
!dropElement.visible ||
!draggedTab.visible
) {
@@ -727,16 +729,16 @@
this.#isAnimatingTabMove = true;
for (let item of this._tabbrowserTabs.ariaFocusableItems) {
item = elementToMove(item);
item.style.transform = '';
item.style.transform = "";
}
const animateElement = (ele, translateY) => {
ele.style.transform = `translateY(${translateY}px)`;
let animateInternal = (resolve) => {
gZenUIManager
.elementAnimate(ele, { y: [translateY, 0] }, { duration: 100, easing: 'ease-out' })
.elementAnimate(ele, { y: [translateY, 0] }, { duration: 100, easing: "ease-out" })
.then(() => {
ele.style.transform = '';
ele.style.zIndex = '';
ele.style.transform = "";
ele.style.zIndex = "";
})
.finally(resolve);
};
@@ -785,7 +787,7 @@
: -rect.height * tabsInBetween.length;
draggedTabTranslateY +=
extraTranslate * (draggedTab.elementIndex > dropElement.elementIndex ? 1 : -1);
draggedTab.style.zIndex = '9';
draggedTab.style.zIndex = "9";
animateElement(draggedTab, draggedTabTranslateY);
} catch (e) {
console.error(e);
@@ -802,7 +804,7 @@
gZenPinnedTabManager.removeTabContainersDragoverClass();
this.#maybeClearVerticalPinnedGridDragOver();
this.originalDragImageArgs = [];
window.removeEventListener('dragover', this.handle_windowDragEnter, { capture: true });
window.removeEventListener("dragover", this.handle_windowDragEnter, { capture: true });
this.#isOutOfWindow = false;
if (this._browserDragImageWrapper) {
this._browserDragImageWrapper.remove();
@@ -820,8 +822,8 @@
}
const margin = 2;
const rect = window.windowUtils.getBoundsWithoutFlushing(element);
this.#dragOverBackground = document.createElement('div');
this.#dragOverBackground.id = 'zen-dragover-background';
this.#dragOverBackground = document.createElement("div");
this.#dragOverBackground.id = "zen-dragover-background";
this.#dragOverBackground.style.height = `${rect.height - margin * 2}px`;
this.#dragOverBackground.style.top = `${rect.top + margin}px`;
gNavToolbox.appendChild(this.#dragOverBackground);
@@ -842,16 +844,16 @@
gZenPinnedTabManager.removeTabContainersDragoverClass();
}
// eslint-disable-next-line complexity
#applyDragoverIndicator(event, tabs, movingTabs, draggedTab) {
const separation = 4;
const dropZoneSelector =
':is(.tabbrowser-tab, .zen-drop-target, .tab-group-label, tab-group[split-view-group])';
":is(.tabbrowser-tab, .zen-drop-target, .tab-group-label, tab-group[split-view-group])";
let shouldPlayHapticFeedback = false;
let showIndicatorUnderNewTabButton = false;
let dropBefore = false;
let dropElement = event.target.closest(dropZoneSelector);
if (!dropElement) {
if (event.target.classList.contains('zen-workspace-empty-space')) {
if (event.target.classList.contains("zen-workspace-empty-space")) {
dropElement = this._tabbrowserTabs.ariaFocusableItems.at(-1);
// Only if there are no normal tabs to drop after
showIndicatorUnderNewTabButton = !tabs.some((tab) => !(tab.group || tab).pinned);
@@ -884,14 +886,14 @@
const overlapPercent = (event.clientY - rect.top) / rect.height;
// We wan't to leave a small threshold (20% for example) so we can drag tabs below and above
// a folder label without dragging into the folder.
let threshold = Services.prefs.getIntPref('zen.tabs.folder-dragover-threshold-percent') / 100;
let threshold = Services.prefs.getIntPref("zen.tabs.folder-dragover-threshold-percent") / 100;
let dropIntoFolder =
isZenFolder && (overlapPercent < threshold || overlapPercent > 1 - threshold);
if (
isTabGroupLabel(draggedTab) &&
draggedTab.group?.isZenFolder &&
(isTab(dropElement) || dropElement.hasAttribute('split-view-group')) &&
(!dropElement.pinned || dropElement.hasAttribute('zen-essential'))
(isTab(dropElement) || dropElement.hasAttribute("split-view-group")) &&
(!dropElement.pinned || dropElement.hasAttribute("zen-essential"))
) {
this.clearDragOverVisuals();
return;
@@ -900,7 +902,7 @@
isTab(dropElement) ||
dropIntoFolder ||
showIndicatorUnderNewTabButton ||
dropElement.hasAttribute('split-view-group')
dropElement.hasAttribute("split-view-group")
) {
if (showIndicatorUnderNewTabButton) {
rect = window.windowUtils.getBoundsWithoutFlushing(this.#dragShiftableItems.at(-1));
@@ -908,42 +910,39 @@
const indicator = gZenPinnedTabManager.dragIndicator;
let top = 0;
threshold =
Services.prefs.getIntPref('browser.tabs.dragDrop.moveOverThresholdPercent') / 100;
Services.prefs.getIntPref("browser.tabs.dragDrop.moveOverThresholdPercent") / 100;
if (overlapPercent > threshold) {
top = Math.round(rect.top + rect.height) + 'px';
dropBefore = false;
top = Math.round(rect.top + rect.height) + "px";
} else {
top = Math.round(rect.top) + 'px';
dropBefore = true;
top = Math.round(rect.top) + "px";
}
if (indicator.style.top !== top) {
shouldPlayHapticFeedback = true;
}
indicator.setAttribute('orientation', 'horizontal');
indicator.style.setProperty('--indicator-left', rect.left + separation / 2 + 'px');
indicator.style.setProperty('--indicator-width', rect.width - separation + 'px');
indicator.setAttribute("orientation", "horizontal");
indicator.style.setProperty("--indicator-left", rect.left + separation / 2 + "px");
indicator.style.setProperty("--indicator-width", rect.width - separation + "px");
indicator.style.top = top;
indicator.style.removeProperty('left');
indicator.style.removeProperty("left");
this.#removeDragOverBackground();
if (!isTab(dropElement) && dropElement?.parentElement?.isZenFolder) {
dropElement = dropElement.parentElement;
}
} else if (dropElement.classList.contains('zen-drop-target') && canHightlightGroup) {
} else if (dropElement.classList.contains("zen-drop-target") && canHightlightGroup) {
shouldPlayHapticFeedback =
this.#applyDragOverBackground(dropElement) && !gZenPinnedTabManager._dragIndicator;
gZenPinnedTabManager.removeTabContainersDragoverClass();
dropElement = dropElement.parentElement?.labelElement || dropElement;
if (dropElement.classList.contains('zen-current-workspace-indicator')) {
if (dropElement.classList.contains("zen-current-workspace-indicator")) {
dropElement =
elementToMove(this._tabbrowserTabs.ariaFocusableItems.at(gBrowser._numZenEssentials)) ||
dropElement;
dropBefore = true;
}
}
if (shouldPlayHapticFeedback) {
// eslint-disable-next-line mozilla/valid-services
Services.zen.playHapticFeedback();
}
return [dropBefore, dropElement];
}
#getDragImageOffset(event, tab, draggingTabs) {
@@ -960,13 +959,14 @@
};
}
// eslint-disable-next-line complexity
#animateVerticalPinnedGridDragOver(event) {
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
let dragData = draggedTab._dragData;
let movingTabs = dragData.movingTabs;
this.clearDragOverVisuals();
if (
!draggedTab.hasAttribute('zen-essential') &&
!draggedTab.hasAttribute("zen-essential") &&
gBrowser._numZenEssentials >= gZenPinnedTabManager.maxEssentialTabs
) {
return;
@@ -975,11 +975,11 @@
if (!this._fakeEssentialTab) {
const numEssentials = gBrowser._numZenEssentials;
let pinnedTabs = this._tabbrowserTabs.ariaFocusableItems.slice(0, numEssentials);
this._fakeEssentialTab = document.createXULElement('vbox');
this._fakeEssentialTab = document.createXULElement("vbox");
this._fakeEssentialTab.elementIndex = numEssentials;
delete dragData.animDropElementIndex;
if (!draggedTab.hasAttribute('zen-essential')) {
event.target.closest('.zen-essentials-container').appendChild(this._fakeEssentialTab);
if (!draggedTab.hasAttribute("zen-essential")) {
event.target.closest(".zen-essentials-container").appendChild(this._fakeEssentialTab);
gZenWorkspaces.updateTabsContainers();
pinnedTabs.push(this._fakeEssentialTab);
}
@@ -1180,7 +1180,7 @@
for (let tab of tabs) {
if (tab != draggedTab) {
let [shiftX, shiftY] = getTabShift(tab, newIndex);
tab.style.transform = shiftX || shiftY ? `translate(${shiftX}px, ${shiftY}px)` : '';
tab.style.transform = shiftX || shiftY ? `translate(${shiftX}px, ${shiftY}px)` : "";
}
}
}
@@ -1190,7 +1190,7 @@
this._fakeEssentialTab.remove();
delete this._fakeEssentialTab;
for (let tab of this._tabbrowserTabs.visibleTabs.slice(0, gBrowser._numZenEssentials)) {
tab.style.transform = '';
tab.style.transform = "";
}
gZenWorkspaces.updateTabsContainers();
}
@@ -1202,15 +1202,15 @@
const dragData = draggedTab._dragData;
const [wrapper] = this.originalDragImageArgs;
const tab = wrapper.firstElementChild;
tab.setAttribute('zen-essential', 'true');
tab.setAttribute('pinned', 'true');
tab.setAttribute('selected', 'true');
tab.setAttribute("zen-essential", "true");
tab.setAttribute("pinned", "true");
tab.setAttribute("selected", "true");
const draggedTabRect = window.windowUtils.getBoundsWithoutFlushing(this._fakeEssentialTab);
tab.style.minWidth = tab.style.maxWidth = wrapper.style.width = draggedTabRect.width + 'px';
tab.style.minWidth = tab.style.maxWidth = wrapper.style.width = draggedTabRect.width + "px";
tab.style.minHeight =
tab.style.maxHeight =
wrapper.style.height =
draggedTabRect.height + 'px';
draggedTabRect.height + "px";
const offsetY = dragData.offsetY;
const offsetX = dragData.offsetX;
// Apply a transform translate to the tab in order to center it within the drag image
@@ -1224,17 +1224,17 @@
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
const wrapper = this.originalDragImageArgs[0];
const tab = wrapper.firstElementChild;
tab.style.setProperty('transition', 'none', 'important');
tab.removeAttribute('zen-essential');
tab.removeAttribute('pinned');
tab.style.minWidth = tab.style.maxWidth = '';
tab.style.minHeight = tab.style.maxHeight = '';
tab.style.transform = '';
tab.style.setProperty("transition", "none", "important");
tab.removeAttribute("zen-essential");
tab.removeAttribute("pinned");
tab.style.minWidth = tab.style.maxWidth = "";
tab.style.minHeight = tab.style.maxHeight = "";
tab.style.transform = "";
const rect = window.windowUtils.getBoundsWithoutFlushing(draggedTab);
wrapper.style.width = rect.width + 'px';
wrapper.style.height = rect.height + 'px';
wrapper.style.width = rect.width + "px";
wrapper.style.height = rect.height + "px";
setTimeout(() => {
tab.style.transition = '';
tab.style.transition = "";
dt.updateDragImage(...this.originalDragImageArgs);
}, 50);
}

View File

@@ -53,7 +53,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
<ellipse cx="18" cy="16" rx="1.25" ry="1.25"/>
</g>
</svg>`,
'image/svg+xml'
"image/svg+xml"
).documentElement;
constructor() {
@@ -70,29 +70,30 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
this._activeTabs = [];
this.icon.appendChild(nsZenFolder.rawIcon.cloneNode(true));
this.labelElement.parentElement.setAttribute('context', 'zenFolderActions');
this.labelElement.parentElement.setAttribute("context", "zenFolderActions");
this.labelElement.onRenameFinished = (newLabel) => {
this.name = newLabel.trim() || 'Folder';
const event = new CustomEvent('ZenFolderRenamed', {
this.name = newLabel.trim() || "Folder";
const event = new CustomEvent("ZenFolderRenamed", {
bubbles: true,
});
this.dispatchEvent(event);
};
if (this.collapsed) {
this.groupContainer.setAttribute('hidden', true);
this.groupContainer.setAttribute("hidden", true);
}
}
get icon() {
return this.querySelector('.tab-group-folder-icon');
return this.querySelector(".tab-group-folder-icon");
}
/**
* Returns the group this folder belongs to.
*
* @returns {MozTabbrowserTabGroup|null} The group this folder belongs to, or null if it is not part of a group.
**/
*/
get group() {
if (gBrowser.isTabGroup(this.parentElement?.parentElement)) {
return this.parentElement.parentElement;
@@ -107,10 +108,12 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
get activeGroups() {
let activeGroups = [];
let currentGroup = this;
if (currentGroup?.hasAttribute('has-active')) activeGroups.push(currentGroup);
if (currentGroup?.hasAttribute("has-active")) {
activeGroups.push(currentGroup);
}
while (currentGroup?.group) {
currentGroup = currentGroup?.group;
if (currentGroup?.hasAttribute('has-active')) {
if (currentGroup?.hasAttribute("has-active")) {
activeGroups.push(currentGroup);
}
}
@@ -118,14 +121,14 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
}
get childActiveGroups() {
if (this.tagName === 'zen-workspace-collapsible-pins') {
return Array.from(this.parentElement.querySelectorAll('zen-folder[has-active]'));
if (this.tagName === "zen-workspace-collapsible-pins") {
return Array.from(this.parentElement.querySelectorAll("zen-folder[has-active]"));
}
return Array.from(this.querySelectorAll('zen-folder[has-active]'));
return Array.from(this.querySelectorAll("zen-folder[has-active]"));
}
rename() {
if (!document.documentElement.hasAttribute('zen-sidebar-expanded')) {
if (!document.documentElement.hasAttribute("zen-sidebar-expanded")) {
return;
}
gZenVerticalTabsManager.renameTabStart({
@@ -143,7 +146,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
} while (currentFolder);
gZenFolders.createFolder([], {
renameFolder: !gZenUIManager.testingEnabled,
label: 'Subfolder',
label: "Subfolder",
insertAfter: this.groupContainer.lastElementChild,
});
}
@@ -151,8 +154,8 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
async unpackTabs() {
this.collapsed = false;
for (let tab of this.allItems.reverse()) {
tab = tab.group.hasAttribute('split-view-group') ? tab.group : tab;
if (tab.hasAttribute('zen-empty-tab')) {
tab = tab.group.hasAttribute("split-view-group") ? tab.group : tab;
if (tab.hasAttribute("zen-empty-tab")) {
gBrowser.removeTab(tab);
} else {
gBrowser.ungroupTab(tab);
@@ -162,7 +165,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
async delete() {
for (const tab of this.allItemsRecursive) {
if (tab.hasAttribute('zen-empty-tab')) {
if (tab.hasAttribute("zen-empty-tab")) {
// Manually remove the empty tabs as removeTabs() inside removeTabGroup
// does ignore them.
gBrowser.removeTab(tab);
@@ -187,8 +190,8 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
return [...this.groupContainer.children].filter(
(child) =>
!(
child.classList.contains('zen-tab-group-start') ||
child.classList.contains('pinned-tabs-container-separator')
child.classList.contains("zen-tab-group-start") ||
child.classList.contains("pinned-tabs-container-separator")
)
);
}
@@ -207,26 +210,26 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
set pinned(value) {}
get iconURL() {
return this.icon.querySelector('image')?.getAttribute('href') || '';
return this.icon.querySelector("image")?.getAttribute("href") || "";
}
set activeTabs(tabs) {
if (tabs.length) {
this._activeTabs = tabs;
for (let tab of tabs) {
tab.setAttribute('folder-active', 'true');
tab.setAttribute("folder-active", "true");
}
} else {
const folders = new Map();
for (let tab of this._activeTabs) {
const group = tab?.group?.hasAttribute('split-view-group') ? tab?.group?.group : tab?.group;
const group = tab?.group?.hasAttribute("split-view-group") ? tab?.group?.group : tab?.group;
if (!folders.has(group?.id)) {
folders.set(group?.id, group?.activeGroups?.at(-1));
}
let activeGroup = folders.get(group?.id);
if (!activeGroup) {
tab.removeAttribute('folder-active');
tab.style.removeProperty('--zen-folder-indent');
tab.removeAttribute("folder-active");
tab.style.removeProperty("--zen-folder-indent");
}
}
this._activeTabs = [];
@@ -239,7 +242,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
}
get resetButton() {
return this.labelElement.parentElement.querySelector('.tab-reset-button');
return this.labelElement.parentElement.querySelector(".tab-reset-button");
}
unloadAllTabs(event) {
@@ -266,6 +269,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
/**
* Get the root most collapsed folder in the tree.
*
* @returns {ZenFolder|null} The root most collapsed folder, or null if none are collapsed.
*/
get rootMostCollapsedFolder() {
@@ -281,4 +285,4 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
}
}
customElements.define('zen-folder', nsZenFolder);
customElements.define("zen-folder", nsZenFolder);

File diff suppressed because it is too large Load Diff

View File

@@ -13,23 +13,14 @@ zen-folder {
flex-direction: column;
visibility: visible;
--zen-folder-behind-bgcolor: light-dark(
color-mix(in srgb, var(--zen-primary-color) 60%, gray),
color-mix(in srgb, var(--zen-primary-color) 60%, #c1c1c1)
);
--zen-folder-front-bgcolor: light-dark(
color-mix(in srgb, var(--zen-primary-color), white 70%),
color-mix(in srgb, var(--zen-primary-color), black 40%)
);
--zen-folder-stroke: light-dark(
color-mix(in srgb, var(--zen-primary-color) 50%, black),
color-mix(in srgb, var(--zen-colors-primary) 15%, #ebebeb)
);
--zen-folder-behind-bgcolor: light-dark(color-mix(in srgb, var(--zen-primary-color) 60%, gray), color-mix(in srgb, var(--zen-primary-color) 60%, #c1c1c1));
--zen-folder-front-bgcolor: light-dark(color-mix(in srgb, var(--zen-primary-color), white 70%), color-mix(in srgb, var(--zen-primary-color), black 40%));
--zen-folder-stroke: light-dark(color-mix(in srgb, var(--zen-primary-color) 50%, black), color-mix(in srgb, var(--zen-colors-primary) 15%, #ebebeb));
-moz-window-dragging: no-drag;
transition: var(--zen-tabbox-element-indent-transition);
:root[zen-sidebar-expanded='true'] & {
:root[zen-sidebar-expanded="true"] & {
margin-inline-start: var(--zen-folder-indent) !important;
}
@@ -82,7 +73,7 @@ zen-folder {
height: calc(var(--tab-block-margin) * 2 + var(--tab-min-height));
padding-inline: var(--tab-group-label-padding);
:root[zen-sidebar-expanded='true'] & {
:root[zen-sidebar-expanded="true"] & {
padding-inline-end: calc(var(--tab-group-label-padding) * 2);
}
@@ -111,7 +102,7 @@ zen-folder {
:root:not([zen-sidebar-expanded]) & {
transition: transform 0.1s ease;
&[state='open'] {
&[state="open"] {
transform: translate(-2px);
}
}
@@ -131,11 +122,11 @@ zen-folder {
opacity 0.3s cubic-bezier(0.42, 0, 0, 1);
}
&[state='open'] .back {
&[state="open"] .back {
transform: skewX(16deg) translate(-2px, 3.4px) scale(0.85);
}
&[state='open'] :is(.front, .dots, .icon) {
&[state="open"] :is(.front, .dots, .icon) {
transform: skewX(-16deg) translate(11.1px, 3.4px) scale(0.85);
}
@@ -147,18 +138,18 @@ zen-folder {
opacity: 0;
}
&[active='true'] .icon {
&[active="true"] .icon {
opacity: 0;
}
&[active='true'] .dots {
&[active="true"] .dots {
opacity: 1;
}
}
}
&::before {
content: '';
content: "";
position: absolute;
top: 2px;
left: 2px;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
// 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/.
export class ZenGlanceChild extends JSWindowActorChild {
#activationMethod;
@@ -10,13 +11,13 @@ export class ZenGlanceChild extends JSWindowActorChild {
async handleEvent(event) {
const handler = this[`on_${event.type}`];
if (typeof handler === 'function') {
if (typeof handler === "function") {
await handler.call(this, event);
}
}
async #initActivationMethod() {
this.#activationMethod = await this.sendQuery('ZenGlance:GetActivationMethod');
this.#activationMethod = await this.sendQuery("ZenGlance:GetActivationMethod");
}
#ensureOnlyKeyModifiers(event) {
@@ -29,7 +30,7 @@ export class ZenGlanceChild extends JSWindowActorChild {
if (!url.match(/^(?:[a-z]+:)?\/\//i)) {
url = this.contentWindow.location.origin + url;
}
this.sendAsyncMessage('ZenGlance:OpenGlance', {
this.sendAsyncMessage("ZenGlance:OpenGlance", {
url,
});
}
@@ -49,7 +50,7 @@ export class ZenGlanceChild extends JSWindowActorChild {
if (anchorRect.width * anchorRect.height > rect.width * rect.height) {
rect = anchorRect;
}
this.sendAsyncMessage('ZenGlance:RecordLinkClickData', {
this.sendAsyncMessage("ZenGlance:RecordLinkClickData", {
clientX: rect.left,
clientY: rect.top,
width: rect.width,
@@ -60,10 +61,12 @@ export class ZenGlanceChild extends JSWindowActorChild {
/**
* Returns the closest A element from the event target
* and the element to record (originalTarget or target)
*
* @param {Event} event
*/
#getTargetFromEvent(event) {
// get closest A element
const target = event.target.closest('A');
const target = event.target.closest("A");
const elementToRecord = event.originalTarget || event.target;
return {
target,
@@ -87,13 +90,13 @@ export class ZenGlanceChild extends JSWindowActorChild {
return;
}
const activationMethod = this.#activationMethod;
if (activationMethod === 'ctrl' && !event.ctrlKey) {
if (activationMethod === "ctrl" && !event.ctrlKey) {
return;
} else if (activationMethod === 'alt' && !event.altKey) {
} else if (activationMethod === "alt" && !event.altKey) {
return;
} else if (activationMethod === 'shift' && !event.shiftKey) {
} else if (activationMethod === "shift" && !event.shiftKey) {
return;
} else if (activationMethod === 'meta' && !event.metaKey) {
} else if (activationMethod === "meta" && !event.metaKey) {
return;
}
event.preventDefault();
@@ -102,10 +105,10 @@ export class ZenGlanceChild extends JSWindowActorChild {
}
on_keydown(event) {
if (event.defaultPrevented || event.key !== 'Escape') {
if (event.defaultPrevented || event.key !== "Escape") {
return;
}
this.sendAsyncMessage('ZenGlance:CloseGlance', {
this.sendAsyncMessage("ZenGlance:CloseGlance", {
hasFocused: this.contentWindow.document.activeElement !== this.contentWindow.document.body,
});
}

View File

@@ -1,6 +1,9 @@
// 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/.
/* eslint-disable consistent-return */
export class ZenGlanceParent extends JSWindowActorParent {
constructor() {
super();
@@ -8,14 +11,14 @@ export class ZenGlanceParent extends JSWindowActorParent {
async receiveMessage(message) {
switch (message.name) {
case 'ZenGlance:GetActivationMethod': {
return Services.prefs.getStringPref('zen.glance.activation-method', 'ctrl');
case "ZenGlance:GetActivationMethod": {
return Services.prefs.getStringPref("zen.glance.activation-method", "ctrl");
}
case 'ZenGlance:OpenGlance': {
case "ZenGlance:OpenGlance": {
this.openGlance(this.browsingContext.topChromeWindow, message.data);
break;
}
case 'ZenGlance:CloseGlance': {
case "ZenGlance:CloseGlance": {
const params = {
onTabClose: true,
...message.data,
@@ -23,7 +26,7 @@ export class ZenGlanceParent extends JSWindowActorParent {
this.browsingContext.topChromeWindow.gZenGlanceManager.closeGlance(params);
break;
}
case 'ZenGlance:RecordLinkClickData': {
case "ZenGlance:RecordLinkClickData": {
this.browsingContext.topChromeWindow.gZenGlanceManager.lastLinkClickData = message.data;
break;
}

View File

@@ -3,10 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
export function openGlanceOnTab(window, callback, close = true) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
window.gZenGlanceManager
.openGlance({
url: 'https://example.com',
url: "https://example.com",
clientX: 0,
clientY: 0,
width: 0,

View File

@@ -14,22 +14,18 @@
gap: 12px;
max-width: 56px;
:root:not([zen-right-side='true']) & {
:root:not([zen-right-side="true"]) & {
left: 100%;
}
:root[zen-right-side='true'] & {
:root[zen-right-side="true"] & {
right: 100%;
}
& toolbarbutton {
width: 32px;
height: 32px;
background: color-mix(
in srgb,
light-dark(rgb(24, 24, 24), rgb(231, 231, 231)) 96%,
var(--zen-primary-color)
);
background: color-mix(in srgb, light-dark(rgb(24, 24, 24), rgb(231, 231, 231)) 96%, var(--zen-primary-color));
transition:
background 0.05s ease,
scale 0.05s ease;
@@ -57,7 +53,7 @@
}
}
&[disabled='true'] {
&[disabled="true"] {
scale: 1 !important;
& image {
opacity: 0.5;
@@ -93,7 +89,7 @@
}
}
:root[zen-no-padding='true'] .browserSidebarContainer.zen-glance-background {
:root[zen-no-padding="true"] .browserSidebarContainer.zen-glance-background {
--zen-native-inner-radius: 6px;
--zen-element-separation: 6px;
}
@@ -103,7 +99,7 @@
}
.browserSidebarContainer.zen-glance-background,
.browserSidebarContainer.zen-glance-overlay .browserContainer:not([fade-out='true']) {
.browserSidebarContainer.zen-glance-overlay .browserContainer:not([fade-out="true"]) {
border-radius: var(--zen-native-inner-radius);
}
@@ -114,7 +110,7 @@
/* Hint compositor to optimize animations and scrolling */
will-change: transform, opacity, filter;
:root[zen-no-padding='true'] & {
:root[zen-no-padding="true"] & {
--zen-native-inner-radius: 0px;
}
@@ -129,11 +125,11 @@
width: 85%;
height: 100%;
&:not([has-finished-animation='true']) #statuspanel {
&:not([has-finished-animation="true"]) #statuspanel {
display: none;
}
&[has-finished-animation='true'] {
&[has-finished-animation="true"] {
position: relative !important;
transition: 0s !important;
transform: none !important;
@@ -154,12 +150,12 @@
height: 100%;
}
&[animate='true'] {
&[animate="true"] {
position: absolute;
}
}
&[fade-out='true'] {
&[fade-out="true"] {
& .browserStack {
transition: opacity 0.15s ease-in-out;
opacity: 0;

File diff suppressed because it is too large Load Diff

View File

@@ -5,11 +5,15 @@
const lazy = {};
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'RESPECT_PIP_DISABLED',
'media.videocontrols.picture-in-picture.respect-disablePictureInPicture',
"RESPECT_PIP_DISABLED",
"media.videocontrols.picture-in-picture.respect-disablePictureInPicture",
true
);
/**
* Zen Media Controller, handles the small media control bar UI and interactions
* located at the bottom of the sidebar.
*/
class nsZenMediaController {
_currentMediaController = null;
_currentBrowser = null;
@@ -24,7 +28,7 @@ class nsZenMediaController {
mediaFocusButton = null;
mediaProgressBarContainer = null;
supportedKeys = ['playpause', 'previoustrack', 'nexttrack'];
supportedKeys = ["playpause", "previoustrack", "nexttrack"];
mediaControllersMap = new Map();
_tabTimeout = null;
@@ -33,16 +37,18 @@ class nsZenMediaController {
#isSeeking = false;
init() {
if (!Services.prefs.getBoolPref('zen.mediacontrols.enabled', true)) return;
if (!Services.prefs.getBoolPref("zen.mediacontrols.enabled", true)) {
return;
}
this.mediaTitle = document.querySelector('#zen-media-title');
this.mediaArtist = document.querySelector('#zen-media-artist');
this.mediaControlBar = document.querySelector('#zen-media-controls-toolbar');
this.mediaProgressBar = document.querySelector('#zen-media-progress-bar');
this.mediaCurrentTime = document.querySelector('#zen-media-current-time');
this.mediaDuration = document.querySelector('#zen-media-duration');
this.mediaFocusButton = document.querySelector('#zen-media-focus-button');
this.mediaProgressBarContainer = document.querySelector('#zen-media-progress-hbox');
this.mediaTitle = document.querySelector("#zen-media-title");
this.mediaArtist = document.querySelector("#zen-media-artist");
this.mediaControlBar = document.querySelector("#zen-media-controls-toolbar");
this.mediaProgressBar = document.querySelector("#zen-media-progress-bar");
this.mediaCurrentTime = document.querySelector("#zen-media-current-time");
this.mediaDuration = document.querySelector("#zen-media-duration");
this.mediaFocusButton = document.querySelector("#zen-media-focus-button");
this.mediaProgressBarContainer = document.querySelector("#zen-media-progress-hbox");
this.onPositionstateChange = this._onPositionstateChange.bind(this);
this.onPlaybackstateChange = this._onPlaybackstateChange.bind(this);
@@ -55,50 +61,56 @@ class nsZenMediaController {
}
#initEventListeners() {
this.mediaControlBar.addEventListener('mousedown', (event) => {
if (event.target.closest(':is(toolbarbutton,#zen-media-progress-hbox)')) return;
else this.onMediaFocus();
this.mediaControlBar.addEventListener("mousedown", (event) => {
if (event.target.closest(":is(toolbarbutton,#zen-media-progress-hbox)")) {
return;
}
this.onMediaFocus();
});
this.mediaControlBar.addEventListener('command', (event) => {
const button = event.target.closest('toolbarbutton');
if (!button) return;
this.mediaControlBar.addEventListener("command", (event) => {
const button = event.target.closest("toolbarbutton");
if (!button) {
return;
}
switch (button.id) {
case 'zen-media-pip-button':
case "zen-media-pip-button":
this.onMediaPip();
break;
case 'zen-media-close-button':
case "zen-media-close-button":
this.onControllerClose();
break;
case 'zen-media-focus-button':
case "zen-media-focus-button":
this.onMediaFocus();
break;
case 'zen-media-mute-button':
case "zen-media-mute-button":
this.onMediaMute();
break;
case 'zen-media-previoustrack-button':
case "zen-media-previoustrack-button":
this.onMediaPlayPrev();
break;
case 'zen-media-nexttrack-button':
case "zen-media-nexttrack-button":
this.onMediaPlayNext();
break;
case 'zen-media-playpause-button':
case "zen-media-playpause-button":
this.onMediaToggle();
break;
case 'zen-media-mute-mic-button':
case "zen-media-mute-mic-button":
this.onMicrophoneMuteToggle();
break;
case 'zen-media-mute-camera-button':
case "zen-media-mute-camera-button":
this.onCameraMuteToggle();
break;
}
});
this.mediaProgressBar.addEventListener('input', this.onMediaSeekDrag.bind(this));
this.mediaProgressBar.addEventListener('change', this.onMediaSeekComplete.bind(this));
this.mediaProgressBar.addEventListener("input", this.onMediaSeekDrag.bind(this));
this.mediaProgressBar.addEventListener("change", this.onMediaSeekComplete.bind(this));
window.addEventListener('TabSelect', (event) => {
if (this.isSharing) return;
window.addEventListener("TabSelect", (event) => {
if (this.isSharing) {
return;
}
const linkedBrowser = event.target.linkedBrowser;
this.switchController();
@@ -113,8 +125,11 @@ class nsZenMediaController {
this.hideMediaControls();
} else {
this._tabTimeout = setTimeout(() => {
if (!this.mediaControlBar.hasAttribute('pip')) this.showMediaControls();
else this._tabTimeout = null;
if (!this.mediaControlBar.hasAttribute("pip")) {
this.showMediaControls();
} else {
this._tabTimeout = null;
}
}, 500);
}
}
@@ -122,15 +137,15 @@ class nsZenMediaController {
const onTabDiscardedOrClosed = this.onTabDiscardedOrClosed.bind(this);
window.addEventListener('TabClose', onTabDiscardedOrClosed);
window.addEventListener('TabBrowserDiscarded', onTabDiscardedOrClosed);
window.addEventListener("TabClose", onTabDiscardedOrClosed);
window.addEventListener("TabBrowserDiscarded", onTabDiscardedOrClosed);
window.addEventListener('DOMAudioPlaybackStarted', (event) => {
window.addEventListener("DOMAudioPlaybackStarted", (event) => {
setTimeout(() => {
if (
this._currentMediaController?.isPlaying &&
this.mediaControlBar.hasAttribute('hidden') &&
!this.mediaControlBar.hasAttribute('pip')
this.mediaControlBar.hasAttribute("hidden") &&
!this.mediaControlBar.hasAttribute("pip")
) {
const { selectedBrowser } = gBrowser;
if (selectedBrowser.browserId !== this._currentBrowser.browserId) {
@@ -142,7 +157,7 @@ class nsZenMediaController {
this.activateMediaControls(event.target.browsingContext.mediaController, event.target);
});
window.addEventListener('DOMAudioPlaybackStopped', () => this.updateMuteState());
window.addEventListener("DOMAudioPlaybackStopped", () => this.updateMuteState());
}
onTabDiscardedOrClosed(event) {
@@ -171,12 +186,12 @@ class nsZenMediaController {
shouldHide = true
) {
if (shouldForget && mediaController) {
mediaController.removeEventListener('pictureinpicturemodechange', this.onPipModeChange);
mediaController.removeEventListener('positionstatechange', this.onPositionstateChange);
mediaController.removeEventListener('playbackstatechange', this.onPlaybackstateChange);
mediaController.removeEventListener('supportedkeyschange', this.onSupportedKeysChange);
mediaController.removeEventListener('metadatachange', this.onMetadataChange);
mediaController.removeEventListener('deactivated', this.onDeactivated);
mediaController.removeEventListener("pictureinpicturemodechange", this.onPipModeChange);
mediaController.removeEventListener("positionstatechange", this.onPositionstateChange);
mediaController.removeEventListener("playbackstatechange", this.onPlaybackstateChange);
mediaController.removeEventListener("supportedkeyschange", this.onSupportedKeysChange);
mediaController.removeEventListener("metadatachange", this.onMetadataChange);
mediaController.removeEventListener("deactivated", this.onDeactivated);
this.mediaControllersMap.delete(mediaController.id);
}
@@ -190,36 +205,40 @@ class nsZenMediaController {
this._mediaUpdateInterval = null;
}
if (shouldHide) await this.hideMediaControls();
this.mediaControlBar.removeAttribute('muted');
this.mediaControlBar.classList.remove('playing');
if (shouldHide) {
await this.hideMediaControls();
}
this.mediaControlBar.removeAttribute("muted");
this.mediaControlBar.classList.remove("playing");
}
}
get isSharing() {
return this.mediaControlBar.hasAttribute('media-sharing');
return this.mediaControlBar.hasAttribute("media-sharing");
}
set isSharing(value) {
if (this._currentBrowser?.browsingContext && !value) {
const webRTC = this._currentBrowser.browsingContext.currentWindowGlobal.getActor('WebRTC');
webRTC.sendAsyncMessage('webrtc:UnmuteMicrophone');
webRTC.sendAsyncMessage('webrtc:UnmuteCamera');
const webRTC = this._currentBrowser.browsingContext.currentWindowGlobal.getActor("WebRTC");
webRTC.sendAsyncMessage("webrtc:UnmuteMicrophone");
webRTC.sendAsyncMessage("webrtc:UnmuteCamera");
}
if (!value) {
this.mediaControlBar.removeAttribute('mic-muted');
this.mediaControlBar.removeAttribute('camera-muted');
this.mediaControlBar.removeAttribute("mic-muted");
this.mediaControlBar.removeAttribute("camera-muted");
} else {
this.mediaControlBar.setAttribute('media-position-hidden', '');
this.mediaControlBar.setAttribute('media-sharing', '');
this.mediaControlBar.setAttribute("media-position-hidden", "");
this.mediaControlBar.setAttribute("media-sharing", "");
}
}
hideMediaControls() {
if (this.mediaControlBar.hasAttribute('hidden')) return;
if (this.mediaControlBar.hasAttribute("hidden")) {
return;
}
return gZenUIManager.motion
gZenUIManager.motion
.animate(
this.mediaControlBar,
{
@@ -231,32 +250,38 @@ class nsZenMediaController {
}
)
.then(() => {
this.mediaControlBar.setAttribute('hidden', 'true');
this.mediaControlBar.removeAttribute('media-sharing');
this.mediaControlBar.setAttribute("hidden", "true");
this.mediaControlBar.removeAttribute("media-sharing");
gZenUIManager.updateTabsToolbar();
});
}
showMediaControls() {
if (!this.mediaControlBar.hasAttribute('hidden')) return;
if (!this.mediaControlBar.hasAttribute("hidden")) {
return;
}
if (!this.isSharing) {
if (!this._currentMediaController) return;
if (this._currentMediaController.isBeingUsedInPIPModeOrFullscreen)
return this.hideMediaControls();
if (!this._currentMediaController) {
return;
}
if (this._currentMediaController.isBeingUsedInPIPModeOrFullscreen) {
this.hideMediaControls();
return;
}
this.updatePipButton();
}
const mediaInfoElements = [this.mediaTitle, this.mediaArtist];
for (const element of mediaInfoElements) {
element.removeAttribute('overflow'); // So we can properly recalculate the overflow
element.removeAttribute("overflow"); // So we can properly recalculate the overflow
}
this.mediaControlBar.removeAttribute('hidden');
this.mediaControlBar.removeAttribute("hidden");
window.requestAnimationFrame(() => {
this.mediaControlBar.style.height =
this.mediaControlBar.querySelector('toolbaritem').getBoundingClientRect().height + 'px';
this.mediaControlBar.querySelector("toolbaritem").getBoundingClientRect().height + "px";
this.mediaControlBar.style.opacity = 0;
gZenUIManager.updateTabsToolbar();
gZenUIManager.motion.animate(
@@ -273,11 +298,12 @@ class nsZenMediaController {
addLabelOverflows(elements) {
for (const element of elements) {
// eslint-disable-next-line no-shadow
const parent = element.parentElement;
if (element.scrollWidth > parent.clientWidth) {
element.setAttribute('overflow', '');
element.setAttribute("overflow", "");
} else {
element.removeAttribute('overflow');
element.removeAttribute("overflow");
}
}
}
@@ -293,18 +319,18 @@ class nsZenMediaController {
this.updatePipButton();
if (
!this.mediaControlBar.classList.contains('playing') &&
!this.mediaControlBar.classList.contains("playing") &&
this._currentMediaController.isPlaying
) {
this.mediaControlBar.classList.add('playing');
this.mediaControlBar.classList.add("playing");
}
const iconURL =
this._currentBrowser.mIconURL || `page-icon:${this._currentBrowser.currentURI.spec}`;
this.mediaFocusButton.style.listStyleImage = `url(${iconURL})`;
this.mediaTitle.textContent = metadata.title || '';
this.mediaArtist.textContent = metadata.artist || '';
this.mediaTitle.textContent = metadata.title || "";
this.mediaArtist.textContent = metadata.artist || "";
gZenUIManager.updateTabsToolbar();
@@ -324,7 +350,9 @@ class nsZenMediaController {
this.updateMuteState();
this.switchController();
if (!mediaController.isActive || this._currentBrowser?.browserId === browser.browserId) return;
if (!mediaController.isActive || this._currentBrowser?.browserId === browser.browserId) {
return;
}
const metadata = mediaController.getMetadata();
const positionState = mediaController.getPositionState();
@@ -342,17 +370,17 @@ class nsZenMediaController {
this.setupMediaControlUI(metadata, positionState);
}
mediaController.addEventListener('pictureinpicturemodechange', this.onPipModeChange);
mediaController.addEventListener('positionstatechange', this.onPositionstateChange);
mediaController.addEventListener('playbackstatechange', this.onPlaybackstateChange);
mediaController.addEventListener('supportedkeyschange', this.onSupportedKeysChange);
mediaController.addEventListener('metadatachange', this.onMetadataChange);
mediaController.addEventListener('deactivated', this.onDeactivated);
mediaController.addEventListener("pictureinpicturemodechange", this.onPipModeChange);
mediaController.addEventListener("positionstatechange", this.onPositionstateChange);
mediaController.addEventListener("playbackstatechange", this.onPlaybackstateChange);
mediaController.addEventListener("supportedkeyschange", this.onSupportedKeysChange);
mediaController.addEventListener("metadatachange", this.onMetadataChange);
mediaController.addEventListener("deactivated", this.onDeactivated);
}
activateMediaDeviceControls(browser) {
if (browser?.browsingContext.currentWindowGlobal.hasActivePeerConnections()) {
this.mediaControlBar.removeAttribute('can-pip');
this.mediaControlBar.removeAttribute("can-pip");
this._currentBrowser = browser;
const tab = window.gBrowser.getTabForBrowser(browser);
@@ -362,7 +390,7 @@ class nsZenMediaController {
this.mediaFocusButton.style.listStyleImage = `url(${iconURL})`;
this.mediaTitle.textContent = tab.label;
this.mediaArtist.textContent = '';
this.mediaArtist.textContent = "";
this.showMediaControls();
}
@@ -376,19 +404,25 @@ class nsZenMediaController {
const isCurrentBrowser = this._currentBrowser?.browserId === browser.browserId;
const shouldShow = showCameraIndicator || showMicrophoneIndicator;
if (!isMatch) continue;
if (!isMatch) {
continue;
}
if (shouldShow && !(isCurrentBrowser && this.isSharing)) {
const webRTC = browser.browsingContext.currentWindowGlobal.getActor('WebRTC');
webRTC.sendAsyncMessage('webrtc:UnmuteMicrophone');
webRTC.sendAsyncMessage('webrtc:UnmuteCamera');
const webRTC = browser.browsingContext.currentWindowGlobal.getActor("WebRTC");
webRTC.sendAsyncMessage("webrtc:UnmuteMicrophone");
webRTC.sendAsyncMessage("webrtc:UnmuteCamera");
if (this._currentBrowser) this.isSharing = false;
if (this._currentBrowser) {
this.isSharing = false;
}
if (this._currentMediaController) {
this._currentMediaController.pause();
this.deinitMediaController(this._currentMediaController, true, true).then(() =>
this.activateMediaDeviceControls(browser)
);
} else this.activateMediaDeviceControls(browser);
} else {
this.activateMediaDeviceControls(browser);
}
} else if (!shouldShow && isCurrentBrowser && this.isSharing) {
this.isSharing = false;
this._currentBrowser = null;
@@ -411,15 +445,17 @@ class nsZenMediaController {
_onPlaybackstateChange() {
if (this._currentMediaController?.isPlaying) {
this.mediaControlBar.classList.add('playing');
this.mediaControlBar.classList.add("playing");
} else {
this.switchController();
this.mediaControlBar.classList.remove('playing');
this.mediaControlBar.classList.remove("playing");
}
}
_onSupportedKeysChange(event) {
if (event.target.id !== this._currentMediaController?.id) return;
if (event.target.id !== this._currentMediaController?.id) {
return;
}
for (const key of this.supportedKeys) {
const button = this.mediaControlBar.querySelector(`#zen-media-${key}-button`);
button.disabled = !event.target.supportedKeys.includes(key);
@@ -436,7 +472,9 @@ class nsZenMediaController {
lastUpdated: Date.now(),
});
if (event.target.id !== this._currentMediaController?.id) return;
if (event.target.id !== this._currentMediaController?.id) {
return;
}
this._currentPosition = event.position;
this._currentDuration = event.duration;
@@ -448,15 +486,21 @@ class nsZenMediaController {
switchController(force = false) {
let timeout = 3000;
if (this.isSharing) return;
if (this.#isSeeking) return;
if (this.isSharing) {
return;
}
if (this.#isSeeking) {
return;
}
if (this._controllerSwitchTimeout) {
clearTimeout(this._controllerSwitchTimeout);
this._controllerSwitchTimeout = null;
}
if (this.mediaControllersMap.size === 1) timeout = 0;
if (this.mediaControllersMap.size === 1) {
timeout = 0;
}
this._controllerSwitchTimeout = setTimeout(() => {
if (!this._currentMediaController?.isPlaying || force) {
const nextController = Array.from(this.mediaControllersMap.values())
@@ -496,11 +540,15 @@ class nsZenMediaController {
this._mediaUpdateInterval = null;
}
if (this._currentDuration >= 900_000)
return this.mediaControlBar.setAttribute('media-position-hidden', 'true');
else this.mediaControlBar.removeAttribute('media-position-hidden');
if (this._currentDuration >= 900_000) {
this.mediaControlBar.setAttribute("media-position-hidden", "true");
return;
}
this.mediaControlBar.removeAttribute("media-position-hidden");
if (!this._currentDuration) return;
if (!this._currentDuration) {
return;
}
this.mediaCurrentTime.textContent = this.formatSecondsToTime(this._currentPosition);
this.mediaDuration.textContent = this.formatSecondsToTime(this._currentDuration);
@@ -522,7 +570,9 @@ class nsZenMediaController {
}
formatSecondsToTime(seconds) {
if (!seconds || isNaN(seconds)) return '0:00';
if (!seconds || isNaN(seconds)) {
return "0:00";
}
const totalSeconds = Math.max(0, Math.ceil(seconds));
const hours = Math.floor(totalSeconds / 3600);
@@ -530,51 +580,55 @@ class nsZenMediaController {
const secs = (totalSeconds % 60).toString();
if (hours > 0) {
return `${hours}:${minutes.padStart(2, '0')}:${secs.padStart(2, '0')}`;
return `${hours}:${minutes.padStart(2, "0")}:${secs.padStart(2, "0")}`;
}
return `${minutes}:${secs.padStart(2, '0')}`;
return `${minutes}:${secs.padStart(2, "0")}`;
}
_onMetadataChange(event) {
if (event.target.id !== this._currentMediaController?.id) return;
if (event.target.id !== this._currentMediaController?.id) {
return;
}
this.updatePipButton();
const metadata = event.target.getMetadata();
this.mediaTitle.textContent = metadata.title || '';
this.mediaArtist.textContent = metadata.artist || '';
this.mediaTitle.textContent = metadata.title || "";
this.mediaArtist.textContent = metadata.artist || "";
const mediaInfoElements = [this.mediaTitle, this.mediaArtist];
for (const element of mediaInfoElements) {
element.removeAttribute('overflow');
element.removeAttribute("overflow");
}
this.addLabelOverflows(mediaInfoElements);
}
_onPictureInPictureModeChange(event) {
if (event.target.id !== this._currentMediaController?.id) return;
if (event.target.id !== this._currentMediaController?.id) {
return;
}
if (event.target.isBeingUsedInPIPModeOrFullscreen) {
this.hideMediaControls();
this.mediaControlBar.setAttribute('pip', '');
this.mediaControlBar.setAttribute("pip", "");
} else {
const { selectedBrowser } = gBrowser;
if (selectedBrowser.browserId !== this._currentBrowser.browserId) {
this.showMediaControls();
}
this.mediaControlBar.removeAttribute('pip');
this.mediaControlBar.removeAttribute("pip");
}
}
onMediaPlayPrev() {
if (this._currentMediaController?.supportedKeys.includes('previoustrack')) {
if (this._currentMediaController?.supportedKeys.includes("previoustrack")) {
this._currentMediaController.prevTrack();
}
}
onMediaPlayNext() {
if (this._currentMediaController?.supportedKeys.includes('nexttrack')) {
if (this._currentMediaController?.supportedKeys.includes("nexttrack")) {
this._currentMediaController.nextTrack();
}
}
@@ -589,7 +643,7 @@ class nsZenMediaController {
onMediaSeekComplete(event) {
const newPosition = (event.target.value / 100) * this._currentDuration;
if (this._currentMediaController?.supportedKeys.includes('seekto')) {
if (this._currentMediaController?.supportedKeys.includes("seekto")) {
this._currentMediaController.seekTo(newPosition);
this._currentMediaController.play();
}
@@ -598,12 +652,17 @@ class nsZenMediaController {
}
onMediaFocus() {
if (!this._currentBrowser) return;
if (!this._currentBrowser) {
return;
}
if (this._currentMediaController) this._currentMediaController.focus();
else if (this._currentBrowser) {
if (this._currentMediaController) {
this._currentMediaController.focus();
} else if (this._currentBrowser) {
const tab = window.gBrowser.getTabForBrowser(this._currentBrowser);
if (tab) window.gZenWorkspaces.switchTabIfNeeded(tab);
if (tab) {
window.gZenWorkspaces.switchTabIfNeeded(tab);
}
}
}
@@ -616,7 +675,7 @@ class nsZenMediaController {
}
onMediaToggle() {
if (this.mediaControlBar.classList.contains('playing')) {
if (this.mediaControlBar.classList.contains("playing")) {
this._currentMediaController?.pause();
} else {
this._currentMediaController?.play();
@@ -627,7 +686,9 @@ class nsZenMediaController {
if (this._currentMediaController) {
this._currentMediaController.pause();
this.deinitMediaController(this._currentMediaController);
} else if (this.isSharing) this.isSharing = false;
} else if (this.isSharing) {
this.isSharing = false;
}
this.hideMediaControls();
this.switchController(true);
@@ -635,51 +696,57 @@ class nsZenMediaController {
onMediaPip() {
this._currentBrowser.browsingContext.currentWindowGlobal
.getActor('PictureInPictureLauncher')
.sendAsyncMessage('PictureInPicture:KeyToggle');
.getActor("PictureInPictureLauncher")
.sendAsyncMessage("PictureInPicture:KeyToggle");
}
onMicrophoneMuteToggle() {
if (this._currentBrowser) {
const shouldMute = this.mediaControlBar.hasAttribute('mic-muted')
? 'webrtc:UnmuteMicrophone'
: 'webrtc:MuteMicrophone';
const shouldMute = this.mediaControlBar.hasAttribute("mic-muted")
? "webrtc:UnmuteMicrophone"
: "webrtc:MuteMicrophone";
this._currentBrowser.browsingContext.currentWindowGlobal
.getActor('WebRTC')
.getActor("WebRTC")
.sendAsyncMessage(shouldMute);
this.mediaControlBar.toggleAttribute('mic-muted');
this.mediaControlBar.toggleAttribute("mic-muted");
}
}
onCameraMuteToggle() {
if (this._currentBrowser) {
const shouldMute = this.mediaControlBar.hasAttribute('camera-muted')
? 'webrtc:UnmuteCamera'
: 'webrtc:MuteCamera';
const shouldMute = this.mediaControlBar.hasAttribute("camera-muted")
? "webrtc:UnmuteCamera"
: "webrtc:MuteCamera";
this._currentBrowser.browsingContext.currentWindowGlobal
.getActor('WebRTC')
.getActor("WebRTC")
.sendAsyncMessage(shouldMute);
this.mediaControlBar.toggleAttribute('camera-muted');
this.mediaControlBar.toggleAttribute("camera-muted");
}
}
updateMuteState() {
if (!this._currentBrowser) return;
this.mediaControlBar.toggleAttribute('muted', this._currentBrowser.audioMuted);
if (!this._currentBrowser) {
return;
}
this.mediaControlBar.toggleAttribute("muted", this._currentBrowser.audioMuted);
}
updatePipButton() {
if (!this._currentBrowser) return;
if (this.isSharing) return;
if (!this._currentBrowser) {
return;
}
if (this.isSharing) {
return;
}
const { totalPipCount, totalPipDisabled } = PictureInPicture.getEligiblePipVideoCount(
this._currentBrowser
);
const canPip = totalPipCount === 1 || (totalPipDisabled > 0 && lazy.RESPECT_PIP_DISABLED);
this.mediaControlBar.toggleAttribute('can-pip', canPip);
this.mediaControlBar.toggleAttribute("can-pip", canPip);
}
}

View File

@@ -115,13 +115,13 @@
}
& #zen-media-focus-button::after {
content: '';
content: "";
position: absolute;
width: 110%;
height: 110%;
background-repeat: no-repeat;
opacity: 1;
background: url('chrome://browser/content/zen-images/note-indicator.svg') no-repeat;
background: url("chrome://browser/content/zen-images/note-indicator.svg") no-repeat;
top: -70%;
left: 50%;
transform: translateX(-50%);
@@ -238,7 +238,7 @@
min-width: 1px;
&::before {
content: '';
content: "";
position: absolute;
width: 0.6em;
background: linear-gradient(to right, var(--zen-sidebar-notification-bg) 0%, transparent 100%);
@@ -309,7 +309,7 @@
}
}
:root:not([zen-sidebar-expanded='true']) {
:root:not([zen-sidebar-expanded="true"]) {
#zen-media-controls-toolbar {
display: none;
}

View File

@@ -5,11 +5,16 @@
import {
nsZenPreloadedFeature,
nsZenMultiWindowFeature,
} from 'chrome://browser/content/zen-components/ZenCommonUtils.mjs';
} from "chrome://browser/content/zen-components/ZenCommonUtils.mjs";
/**
* Zen Mods Manager, handles downloading, updating and applying Zen Mods.
*
* @augments nsZenPreloadedFeature
*/
class nsZenMods extends nsZenPreloadedFeature {
// private properties start
#kZenStylesheetModHeader = '/* Zen Mods - Generated by ZenMods.';
#kZenStylesheetModHeader = "/* Zen Mods - Generated by ZenMods.";
#kZenStylesheetModHeaderBody = `* DO NOT EDIT THIS FILE DIRECTLY!
* Your changes will be overwritten.
* Instead, go to the preferences and edit the mods there.
@@ -19,9 +24,9 @@ class nsZenMods extends nsZenPreloadedFeature {
/* End of Zen Mods */
`;
#getCurrentDateTime = () =>
new Intl.DateTimeFormat('en-US', {
dateStyle: 'full',
timeStyle: 'full',
new Intl.DateTimeFormat("en-US", {
dateStyle: "full",
timeStyle: "full",
}).format(new Date().getTime());
constructor() {
@@ -33,13 +38,13 @@ class nsZenMods extends nsZenPreloadedFeature {
get #modsBackend() {
if (!this.#_modsBackend) {
this.#_modsBackend = Cc['@mozilla.org/zen/mods-backend;1'].getService(Ci.nsIZenModsBackend);
this.#_modsBackend = Cc["@mozilla.org/zen/mods-backend;1"].getService(Ci.nsIZenModsBackend);
}
return this.#_modsBackend;
}
get #styleSheetPath() {
return PathUtils.join(PathUtils.profileDir, 'chrome', 'zen-themes.css');
return PathUtils.join(PathUtils.profileDir, "chrome", "zen-themes.css");
}
async #handleDisableMods() {
@@ -47,13 +52,13 @@ class nsZenMods extends nsZenPreloadedFeature {
}
#getStylesheetPathForMod(mod) {
return PathUtils.join(this.getModFolder(mod.id), 'chrome.css');
return PathUtils.join(this.getModFolder(mod.id), "chrome.css");
}
async #readStylesheet() {
const path = this.modsRootPath;
if (!(await IOUtils.exists(path))) {
return '';
return "";
}
return await IOUtils.readUTF8(this.#styleSheetPath);
}
@@ -63,7 +68,7 @@ class nsZenMods extends nsZenPreloadedFeature {
const content = await this.#readStylesheet();
this.#modsBackend.rebuildModsStyles(content);
} catch (e) {
console.warn('[ZenMods]: Error rebuilding mods styles:', e);
console.warn("[ZenMods]: Error rebuilding mods styles:", e);
}
}
@@ -91,8 +96,9 @@ class nsZenMods extends nsZenPreloadedFeature {
}
async #getEnabledMods() {
if (Services.prefs.getBoolPref('zen.themes.disable-all', false)) {
console.log('[ZenMods]: Mods are disabled by user preference.');
if (Services.prefs.getBoolPref("zen.themes.disable-all", false)) {
// eslint-disable-next-line no-console
console.info("[ZenMods]: Mods are disabled by user preference.");
return [];
}
const modsObject = await this.getMods();
@@ -100,14 +106,15 @@ class nsZenMods extends nsZenPreloadedFeature {
(mod) => mod.enabled === undefined || mod.enabled
);
const modList = mods.map(({ name }) => name).join(', ');
// eslint-disable-next-line no-shadow
const modList = mods.map(({ name }) => name).join(", ");
const message =
modList !== ''
modList !== ""
? `[ZenMods]: Loading enabled Zen mods: ${modList}.`
: '[ZenMods]: No enabled Zen mods.';
: "[ZenMods]: No enabled Zen mods.";
console.log(message);
console.warn(message);
return mods;
}
@@ -124,21 +131,21 @@ class nsZenMods extends nsZenPreloadedFeature {
}
const getProperty =
type === 'checkbox' ? Services.prefs.getBoolPref : Services.prefs.getStringPref;
type === "checkbox" ? Services.prefs.getBoolPref : Services.prefs.getStringPref;
const setProperty =
type === 'checkbox' ? Services.prefs.setBoolPref : Services.prefs.setStringPref;
type === "checkbox" ? Services.prefs.setBoolPref : Services.prefs.setStringPref;
try {
getProperty(property);
} catch {
console.debug(
console.warn(
`[ZenMods]: Setting default value for ${property} to ${defaultValue} (${typeof defaultValue})`
);
if (
typeof defaultValue !== 'boolean' &&
typeof defaultValue !== 'string' &&
typeof defaultValue !== 'number'
typeof defaultValue !== "boolean" &&
typeof defaultValue !== "string" &&
typeof defaultValue !== "number"
) {
console.warn(
`[ZenMods]: Warning, invalid data type received (${typeof defaultValue}), skipping.`
@@ -148,7 +155,7 @@ class nsZenMods extends nsZenPreloadedFeature {
setProperty(
property,
typeof defaultValue === 'boolean' ? defaultValue : defaultValue.toString()
typeof defaultValue === "boolean" ? defaultValue : defaultValue.toString()
);
}
}
@@ -157,6 +164,7 @@ class nsZenMods extends nsZenPreloadedFeature {
#writeToDom(modsWithPreferences) {
for (const browser of nsZenMultiWindowFeature.browsers) {
// eslint-disable-next-line no-shadow
for (const { enabled, preferences, name } of modsWithPreferences) {
const sanitizedName = this.sanitizeModName(name);
@@ -167,29 +175,29 @@ class nsZenMods extends nsZenPreloadedFeature {
element.remove();
}
for (const { property } of preferences.filter(({ type }) => type !== 'checkbox')) {
const sanitizedProperty = property?.replaceAll(/\./g, '-');
for (const { property } of preferences.filter(({ type }) => type !== "checkbox")) {
const sanitizedProperty = property?.replaceAll(/\./g, "-");
browser.document.querySelector(':root').style.removeProperty(`--${sanitizedProperty}`);
browser.document.querySelector(":root").style.removeProperty(`--${sanitizedProperty}`);
}
continue;
}
for (const { property, type } of preferences) {
const value = Services.prefs.getStringPref(property, '');
const sanitizedProperty = property?.replaceAll(/\./g, '-');
const value = Services.prefs.getStringPref(property, "");
const sanitizedProperty = property?.replaceAll(/\./g, "-");
switch (type) {
case 'dropdown': {
if (value !== '') {
case "dropdown": {
if (value !== "") {
let element = browser.document.getElementById(sanitizedName);
if (!element) {
element = browser.document.createElement('div');
element = browser.document.createElement("div");
element.style.display = 'none';
element.setAttribute('id', sanitizedName);
element.style.display = "none";
element.setAttribute("id", sanitizedName);
browser.document.body.appendChild(element);
}
@@ -199,14 +207,14 @@ class nsZenMods extends nsZenPreloadedFeature {
break;
}
case 'string': {
if (value === '') {
case "string": {
if (value === "") {
browser.document
.querySelector(':root')
.querySelector(":root")
.style.removeProperty(`--${sanitizedProperty}`);
} else {
browser.document
.querySelector(':root')
.querySelector(":root")
.style.setProperty(`--${sanitizedProperty}`, value);
}
break;
@@ -256,12 +264,12 @@ class nsZenMods extends nsZenPreloadedFeature {
#compareVersions(version1, version2) {
let result = false;
if (typeof version1 !== 'object') {
version1 = version1.toString().split('.');
if (typeof version1 !== "object") {
version1 = version1.toString().split(".");
}
if (typeof version2 !== 'object') {
version2 = version2.toString().split('.');
if (typeof version2 !== "object") {
version2 = version2.toString().split(".");
}
for (let i = 0; i < Math.max(version1.length, version2.length); i++) {
@@ -287,7 +295,6 @@ class nsZenMods extends nsZenPreloadedFeature {
return `https://zen-browser.github.io/theme-store/themes/${modId}/theme.json`;
}
/* eslint-disable no-unused-vars */
async #downloadUrlToFile(url, path, isStyleSheet = false, maxRetries = 3, retryDelayMs = 500) {
let attempt = 0;
@@ -309,7 +316,7 @@ class nsZenMods extends nsZenPreloadedFeature {
} catch (e) {
attempt++;
if (attempt >= maxRetries) {
console.error('[ZenMods]: Error downloading file after retries', url, e);
console.error("[ZenMods]: Error downloading file after retries", url, e);
} else {
console.warn(
`[ZenMods]: Download failed (attempt ${attempt} of ${maxRetries}), retrying in ${retryDelayMs}ms...`,
@@ -350,21 +357,22 @@ class nsZenMods extends nsZenPreloadedFeature {
};
}
sanitizeModName(name) {
sanitizeModName(aName) {
// Do not change to "mod-" for backwards compatibility
return `theme-${name?.replaceAll(/\s/g, '-')?.replaceAll(/[^A-Za-z_-]+/g, '')}`;
// eslint-disable-next-line no-shadow
return `theme-${aName?.replaceAll(/\s/g, "-")?.replaceAll(/[^A-Za-z_-]+/g, "")}`;
}
get updatePref() {
return 'zen.mods.updated-value-observer';
return "zen.mods.updated-value-observer";
}
get modsRootPath() {
return PathUtils.join(PathUtils.profileDir, 'chrome', 'zen-themes');
return PathUtils.join(PathUtils.profileDir, "chrome", "zen-themes");
}
get modsDataFile() {
return PathUtils.join(PathUtils.profileDir, 'zen-themes.json');
return PathUtils.join(PathUtils.profileDir, "zen-themes.json");
}
getModFolder(modId) {
@@ -383,16 +391,16 @@ class nsZenMods extends nsZenPreloadedFeature {
try {
mods = await IOUtils.readJSON(this.modsDataFile);
if (mods === null || typeof mods !== 'object') {
throw new Error('Mods data file is invalid');
if (mods === null || typeof mods !== "object") {
throw new Error("Mods data file is invalid");
}
} catch {
// If we have a corrupted file, reset it
await IOUtils.writeJSON(this.modsDataFile, {});
Services.wm
.getMostRecentWindow('navigator:browser')
.gZenUIManager.showToast('zen-themes-corrupted', {
.getMostRecentWindow("navigator:browser")
.gZenUIManager.showToast("zen-themes-corrupted", {
timeout: 8000,
});
}
@@ -401,7 +409,7 @@ class nsZenMods extends nsZenPreloadedFeature {
}
async getModPreferences(mod) {
const modPath = PathUtils.join(this.modsRootPath, mod.id, 'preferences.json');
const modPath = PathUtils.join(this.modsRootPath, mod.id, "preferences.json");
if (!(await IOUtils.exists(modPath)) || !mod.preferences) {
return [];
@@ -424,10 +432,10 @@ class nsZenMods extends nsZenPreloadedFeature {
await SessionStore.promiseInitialized;
if (
Services.prefs.getBoolPref('zen.themes.disable-all', false) ||
Services.prefs.getBoolPref("zen.themes.disable-all", false) ||
Services.appinfo.inSafeMode
) {
console.log('[ZenMods]: Mods disabled by user or in safe mode.');
console.warn("[ZenMods]: Mods disabled by user or in safe mode.");
return;
}
@@ -464,29 +472,29 @@ class nsZenMods extends nsZenPreloadedFeature {
);
}
} catch (e) {
console.error('[ZenMods]: Error loading Zen Mods:', e);
console.error("[ZenMods]: Error loading Zen Mods:", e);
}
Services.prefs.addObserver(this.updatePref, this.#rebuildModsStylesheet.bind(this), false);
Services.prefs.addObserver('zen.themes.disable-all', this.#handleDisableMods.bind(this), false);
Services.prefs.addObserver(this.updatePref, this.#rebuildModsStylesheet.bind(this));
Services.prefs.addObserver("zen.themes.disable-all", this.#handleDisableMods.bind(this));
}
#setNewMilestoneIfNeeded() {
const previousMilestone = Services.prefs.getStringPref('zen.mods.milestone', '');
const previousMilestone = Services.prefs.getStringPref("zen.mods.milestone", "");
if (previousMilestone != Services.appinfo.version) {
Services.prefs.setStringPref('zen.mods.milestone', Services.appinfo.version);
Services.prefs.clearUserPref('zen.mods.last-update');
Services.prefs.setStringPref("zen.mods.milestone", Services.appinfo.version);
Services.prefs.clearUserPref("zen.mods.last-update");
}
}
#shouldAutoUpdate() {
const daysBeforeUpdate = Services.prefs.getIntPref('zen.mods.auto-update-days');
const lastUpdatedSec = Services.prefs.getIntPref('zen.mods.last-update', -1);
const daysBeforeUpdate = Services.prefs.getIntPref("zen.mods.auto-update-days");
const lastUpdatedSec = Services.prefs.getIntPref("zen.mods.last-update", -1);
const nowSec = Math.floor(Date.now() / 1000);
const daysSinceUpdate = (nowSec - lastUpdatedSec) / (60 * 60 * 24);
return (
(Services.prefs.getBoolPref('zen.mods.auto-update', true) &&
(Services.prefs.getBoolPref("zen.mods.auto-update", true) &&
daysSinceUpdate >= daysBeforeUpdate) ||
lastUpdatedSec < 0
);
@@ -505,10 +513,10 @@ class nsZenMods extends nsZenPreloadedFeature {
}
if (
!this.#compareVersions(possibleNewModVersion.version, currentMod.version ?? '0.0.0') &&
!this.#compareVersions(possibleNewModVersion.version, currentMod.version ?? "0.0.0") &&
possibleNewModVersion.version != currentMod.version
) {
console.log(
console.warn(
`[ZenMods]: Mod update found for mod ${currentMod.name} (${currentMod.id}), current: ${currentMod.version}, new: ${possibleNewModVersion.version}`
);
@@ -523,7 +531,7 @@ class nsZenMods extends nsZenPreloadedFeature {
return null;
} catch (e) {
console.error('[ZenMods]: Error checking for mod updates', e);
console.error("[ZenMods]: Error checking for mod updates", e);
return null;
}
@@ -531,7 +539,7 @@ class nsZenMods extends nsZenPreloadedFeature {
);
await this.updateMods(mods);
Services.prefs.setIntPref('zen.mods.last-update', Math.floor(Date.now() / 1000));
Services.prefs.setIntPref("zen.mods.last-update", Math.floor(Date.now() / 1000));
return updates.filter((update) => {
return update !== null;
});
@@ -540,7 +548,7 @@ class nsZenMods extends nsZenPreloadedFeature {
async removeMod(modId, triggerUpdate = true) {
const modPath = this.getModFolder(modId);
console.log(`[ZenMods]: Removing mod ${modPath}`);
console.warn(`[ZenMods]: Removing mod ${modPath}`);
await IOUtils.remove(modPath, { recursive: true, ignoreAbsent: true });
@@ -559,7 +567,7 @@ class nsZenMods extends nsZenPreloadedFeature {
const mods = await this.getMods();
const mod = mods[modId];
console.log(`[ZenMods]: Enabling mod ${mod.name}`);
console.warn(`[ZenMods]: Enabling mod ${mod.name}`);
mod.enabled = true;
@@ -570,7 +578,7 @@ class nsZenMods extends nsZenPreloadedFeature {
const mods = await this.getMods();
const mod = mods[modId];
console.log(`[ZenMods]: Disabling mod ${mod.name}`);
console.warn(`[ZenMods]: Disabling mod ${mod.name}`);
mod.enabled = false;
@@ -595,14 +603,14 @@ class nsZenMods extends nsZenPreloadedFeature {
const modPath = PathUtils.join(this.modsRootPath, mod.id);
await IOUtils.makeDirectory(modPath, { ignoreExisting: true });
await this.#downloadUrlToFile(mod.style, PathUtils.join(modPath, 'chrome.css'), true);
await this.#downloadUrlToFile(mod.readme, PathUtils.join(modPath, 'readme.md'));
await this.#downloadUrlToFile(mod.style, PathUtils.join(modPath, "chrome.css"), true);
await this.#downloadUrlToFile(mod.readme, PathUtils.join(modPath, "readme.md"));
if (mod.preferences) {
await this.#downloadUrlToFile(mod.preferences, PathUtils.join(modPath, 'preferences.json'));
await this.#downloadUrlToFile(mod.preferences, PathUtils.join(modPath, "preferences.json"));
}
} catch (e) {
console.error('[ZenMods]: Error installing mod', mod.id, e);
console.error("[ZenMods]: Error installing mod", mod.id, e);
}
}
@@ -619,7 +627,7 @@ class nsZenMods extends nsZenPreloadedFeature {
await this.installMod(mod);
}
} catch (e) {
console.error('[ZenMods]: Error checking for mod changes', e);
console.error("[ZenMods]: Error checking for mod changes", e);
}
}
@@ -629,10 +637,10 @@ class nsZenMods extends nsZenPreloadedFeature {
async requestMod(modId) {
const url = this.#composeModApiUrl(modId);
console.debug(`[ZenMods]: Fetching mod ${modId} info from ${url}`);
console.warn(`[ZenMods]: Fetching mod ${modId} info from ${url}`);
const data = await fetch(url, {
mode: 'no-cors',
mode: "no-cors",
});
if (data.ok) {

View File

@@ -8,19 +8,19 @@ export class ZenModsMarketplaceChild extends JSWindowActorChild {
}
handleEvent(event) {
if (event.type === 'DOMContentLoaded') {
if (event.type === "DOMContentLoaded") {
const verifier = this.contentWindow.document.querySelector(
'meta[name="zen-content-verified"]'
);
if (verifier) {
verifier.setAttribute('content', 'verified');
verifier.setAttribute("content", "verified");
}
this.initiateModsMarketplace();
this.contentWindow.document.addEventListener(
'ZenCheckForModUpdates',
"ZenCheckForModUpdates",
this.checkForModUpdates.bind(this)
);
}
@@ -30,7 +30,7 @@ export class ZenModsMarketplaceChild extends JSWindowActorChild {
checkForModUpdates(event) {
event.preventDefault();
this.sendAsyncMessage('ZenModsMarketplace:CheckForUpdates');
this.sendAsyncMessage("ZenModsMarketplace:CheckForUpdates");
}
initiateModsMarketplace() {
@@ -41,20 +41,20 @@ export class ZenModsMarketplaceChild extends JSWindowActorChild {
}
get actionButton() {
return this.contentWindow.document.getElementById('install-theme');
return this.contentWindow.document.getElementById("install-theme");
}
get actionButtonUninstall() {
return this.contentWindow.document.getElementById('install-theme-uninstall');
return this.contentWindow.document.getElementById("install-theme-uninstall");
}
async isThemeInstalled(themeId) {
return await this.sendQuery('ZenModsMarketplace:IsModInstalled', { themeId });
return await this.sendQuery("ZenModsMarketplace:IsModInstalled", { themeId });
}
async receiveMessage(message) {
switch (message.name) {
case 'ZenModsMarketplace:ModChanged': {
case "ZenModsMarketplace:ModChanged": {
const modId = message.data.modId;
const actionButton = this.actionButton;
const actionButtonInstalled = this.actionButtonUninstall;
@@ -64,22 +64,22 @@ export class ZenModsMarketplaceChild extends JSWindowActorChild {
actionButtonInstalled.disabled = false;
if (await this.isThemeInstalled(modId)) {
actionButton.classList.add('hidden');
actionButtonInstalled.classList.remove('hidden');
actionButton.classList.add("hidden");
actionButtonInstalled.classList.remove("hidden");
} else {
actionButton.classList.remove('hidden');
actionButtonInstalled.classList.add('hidden');
actionButton.classList.remove("hidden");
actionButtonInstalled.classList.add("hidden");
}
}
break;
}
case 'ZenModsMarketplace:CheckForUpdatesFinished': {
case "ZenModsMarketplace:CheckForUpdatesFinished": {
const updates = message.data.updates;
this.contentWindow.document.dispatchEvent(
new CustomEvent('ZenModsMarketplace:CheckForUpdatesFinished', { detail: { updates } })
new CustomEvent("ZenModsMarketplace:CheckForUpdatesFinished", { detail: { updates } })
);
break;
@@ -89,38 +89,38 @@ export class ZenModsMarketplaceChild extends JSWindowActorChild {
injectMarketplaceAPI() {
Cu.exportFunction(this.handleModInstallationEvent.bind(this), this.contentWindow, {
defineAs: 'ZenInstallMod',
defineAs: "ZenInstallMod",
});
}
async addButtons() {
const actionButton = this.actionButton;
const actionButtonUninstall = this.actionButtonUninstall;
const errorMessage = this.contentWindow.document.getElementById('install-theme-error');
const errorMessage = this.contentWindow.document.getElementById("install-theme-error");
if (!actionButton || !actionButtonUninstall) {
return;
}
errorMessage.classList.add('hidden');
errorMessage.classList.add("hidden");
const themeId = actionButton.getAttribute('zen-theme-id');
const themeId = actionButton.getAttribute("zen-theme-id");
if (await this.isThemeInstalled(themeId)) {
actionButtonUninstall.classList.remove('hidden');
actionButtonUninstall.classList.remove("hidden");
} else {
actionButton.classList.remove('hidden');
actionButton.classList.remove("hidden");
}
actionButton.addEventListener('click', this.handleModInstallationEvent.bind(this));
actionButtonUninstall.addEventListener('click', this.handleModUninstallEvent.bind(this));
actionButton.addEventListener("click", this.handleModInstallationEvent.bind(this));
actionButtonUninstall.addEventListener("click", this.handleModUninstallEvent.bind(this));
}
async handleModUninstallEvent(event) {
const button = event.target;
button.disabled = true;
const modId = button.getAttribute('zen-theme-id');
const modId = button.getAttribute("zen-theme-id");
this.sendAsyncMessage('ZenModsMarketplace:UninstallMod', { modId });
this.sendAsyncMessage("ZenModsMarketplace:UninstallMod", { modId });
}
async handleModInstallationEvent(event) {
@@ -131,12 +131,12 @@ export class ZenModsMarketplaceChild extends JSWindowActorChild {
const button = event.target;
button.disabled = true;
modId = button.getAttribute('zen-theme-id');
modId = button.getAttribute("zen-theme-id");
} else {
// Backwards compatibility is... Interesting
modId = event.themeId ?? event.modId ?? event.id;
}
this.sendAsyncMessage('ZenModsMarketplace:InstallMod', { modId });
this.sendAsyncMessage("ZenModsMarketplace:InstallMod", { modId });
}
}

View File

@@ -13,11 +13,11 @@ export class ZenModsMarketplaceParent extends JSWindowActorParent {
async receiveMessage(message) {
switch (message.name) {
case 'ZenModsMarketplace:InstallMod': {
case "ZenModsMarketplace:InstallMod": {
const modId = message.data.modId;
const mod = await this.modsManager.requestMod(modId);
console.log(`[ZenModsMarketplaceParent]: Installing mod ${mod.id}`);
console.warn(`[ZenModsMarketplaceParent]: Installing mod ${mod.id}`);
mod.enabled = true;
@@ -29,9 +29,9 @@ export class ZenModsMarketplaceParent extends JSWindowActorParent {
break;
}
case 'ZenModsMarketplace:UninstallMod': {
case "ZenModsMarketplace:UninstallMod": {
const modId = message.data.modId;
console.log(`[ZenModsMarketplaceParent]: Uninstalling mod ${modId}`);
console.warn(`[ZenModsMarketplaceParent]: Uninstalling mod ${modId}`);
const mods = await this.modsManager.getMods();
@@ -44,22 +44,23 @@ export class ZenModsMarketplaceParent extends JSWindowActorParent {
break;
}
case 'ZenModsMarketplace:CheckForUpdates': {
case "ZenModsMarketplace:CheckForUpdates": {
const updates = await this.modsManager.checkForModsUpdates();
this.sendAsyncMessage('ZenModsMarketplace:CheckForUpdatesFinished', { updates });
this.sendAsyncMessage("ZenModsMarketplace:CheckForUpdatesFinished", { updates });
break;
}
case 'ZenModsMarketplace:IsModInstalled': {
case "ZenModsMarketplace:IsModInstalled": {
const themeId = message.data.themeId;
const themes = await this.modsManager.getMods();
return Boolean(themes?.[themeId]);
}
}
return undefined;
}
async updateChildProcesses(modId) {
this.sendAsyncMessage('ZenModsMarketplace:ModChanged', { modId });
this.sendAsyncMessage("ZenModsMarketplace:ModChanged", { modId });
}
}

View File

@@ -2,37 +2,41 @@
* 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 { JSONFile } from 'resource://gre/modules/JSONFile.sys.mjs';
import { XPCOMUtils } from 'resource://gre/modules/XPCOMUtils.sys.mjs';
import { JSONFile } from "resource://gre/modules/JSONFile.sys.mjs";
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
PrivateBrowsingUtils: 'resource://gre/modules/PrivateBrowsingUtils.sys.mjs',
BrowserWindowTracker: 'resource:///modules/BrowserWindowTracker.sys.mjs',
TabGroupState: 'resource:///modules/sessionstore/TabGroupState.sys.mjs',
SessionStore: 'resource:///modules/sessionstore/SessionStore.sys.mjs',
SessionSaver: 'resource:///modules/sessionstore/SessionSaver.sys.mjs',
setTimeout: 'resource://gre/modules/Timer.sys.mjs',
gWindowSyncEnabled: 'resource:///modules/zen/ZenWindowSync.sys.mjs',
DeferredTask: 'resource://gre/modules/DeferredTask.sys.mjs',
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
// eslint-disable-next-line mozilla/valid-lazy
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
// eslint-disable-next-line mozilla/valid-lazy
TabGroupState: "resource:///modules/sessionstore/TabGroupState.sys.mjs",
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
// eslint-disable-next-line mozilla/valid-lazy
SessionSaver: "resource:///modules/sessionstore/SessionSaver.sys.mjs",
// eslint-disable-next-line mozilla/valid-lazy
setTimeout: "resource://gre/modules/Timer.sys.mjs",
gWindowSyncEnabled: "resource:///modules/zen/ZenWindowSync.sys.mjs",
DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs",
});
XPCOMUtils.defineLazyPreferenceGetter(lazy, 'gShouldLog', 'zen.session-store.log', true);
XPCOMUtils.defineLazyPreferenceGetter(lazy, "gShouldLog", "zen.session-store.log", true);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'gMaxSessionBackups',
'zen.session-store.max-backups',
"gMaxSessionBackups",
"zen.session-store.max-backups",
10
);
// Note that changing this hidden pref will make the previous session file
// unused, causing a new session file to be created on next write.
const SHOULD_COMPRESS_FILE = Services.prefs.getBoolPref('zen.session-store.compress-file', true);
const SHOULD_BACKUP_FILE = Services.prefs.getBoolPref('zen.session-store.backup-file', true);
const SHOULD_COMPRESS_FILE = Services.prefs.getBoolPref("zen.session-store.compress-file", true);
const SHOULD_BACKUP_FILE = Services.prefs.getBoolPref("zen.session-store.backup-file", true);
const FILE_NAME = SHOULD_COMPRESS_FILE ? 'zen-sessions.jsonlz4' : 'zen-sessions.json';
const MIGRATION_PREF = 'zen.ui.migration.session-manager-restore';
const FILE_NAME = SHOULD_COMPRESS_FILE ? "zen-sessions.jsonlz4" : "zen-sessions.json";
const MIGRATION_PREF = "zen.ui.migration.session-manager-restore";
// 'browser.startup.page' preference value to resume the previous session.
const BROWSER_STARTUP_RESUME_SESSION = 3;
@@ -61,11 +65,13 @@ class nsZenSidebarObject {
export class nsZenSessionManager {
/**
* The JSON file instance used to read/write session data.
*
* @type {JSONFile}
*/
#file = null;
/**
* The sidebar object holding tabs, groups, folders and split view data.
*
* @type {nsZenSidebarObject}
*/
#sidebarObject = new nsZenSidebarObject();
@@ -76,8 +82,8 @@ export class nsZenSessionManager {
// Called from SessionComponents.manifest on app-startup
init() {
this.log('Initializing session manager');
let profileDir = Services.dirsvc.get('ProfD', Ci.nsIFile).path;
this.log("Initializing session manager");
let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
let backupFile = null;
if (SHOULD_BACKUP_FILE) {
backupFile = PathUtils.join(this.#backupFolderPath, FILE_NAME);
@@ -85,7 +91,7 @@ export class nsZenSessionManager {
let filePath = PathUtils.join(profileDir, FILE_NAME);
this.#file = new JSONFile({
path: filePath,
compression: SHOULD_COMPRESS_FILE ? 'lz4' : undefined,
compression: SHOULD_COMPRESS_FILE ? "lz4" : undefined,
backupFile,
});
this.#deferredBackupTask = new lazy.DeferredTask(async () => {
@@ -95,13 +101,13 @@ export class nsZenSessionManager {
log(...args) {
if (lazy.gShouldLog) {
console.info('ZenSessionManager:', ...args);
console.warn("ZenSessionManager:", ...args);
}
}
get #backupFolderPath() {
let profileDir = Services.dirsvc.get('ProfD', Ci.nsIFile).path;
return PathUtils.join(profileDir, 'zen-sessions-backup');
let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
return PathUtils.join(profileDir, "zen-sessions-backup");
}
/**
@@ -112,24 +118,24 @@ export class nsZenSessionManager {
async #getDataFromDBForMigration() {
try {
const { PlacesUtils } = ChromeUtils.importESModule(
'resource://gre/modules/PlacesUtils.sys.mjs'
"resource://gre/modules/PlacesUtils.sys.mjs"
);
const db = await PlacesUtils.promiseDBConnection();
let data = {};
let rows = await db.execute('SELECT * FROM zen_workspaces ORDER BY created_at ASC');
let rows = await db.execute("SELECT * FROM zen_workspaces ORDER BY created_at ASC");
data.spaces = rows.map((row) => ({
uuid: row.getResultByName('uuid'),
name: row.getResultByName('name'),
icon: row.getResultByName('icon'),
containerTabId: row.getResultByName('container_id') ?? 0,
position: row.getResultByName('position'),
theme: row.getResultByName('theme_type')
uuid: row.getResultByName("uuid"),
name: row.getResultByName("name"),
icon: row.getResultByName("icon"),
containerTabId: row.getResultByName("container_id") ?? 0,
position: row.getResultByName("position"),
theme: row.getResultByName("theme_type")
? {
type: row.getResultByName('theme_type'),
gradientColors: JSON.parse(row.getResultByName('theme_colors')),
opacity: row.getResultByName('theme_opacity'),
rotation: row.getResultByName('theme_rotation'),
texture: row.getResultByName('theme_texture'),
type: row.getResultByName("theme_type"),
gradientColors: JSON.parse(row.getResultByName("theme_colors")),
opacity: row.getResultByName("theme_opacity"),
rotation: row.getResultByName("theme_rotation"),
texture: row.getResultByName("theme_texture"),
}
: null,
}));
@@ -142,11 +148,12 @@ export class nsZenSessionManager {
/**
* Reads the session file and populates the sidebar object.
* This should be only called once at startup.
*
* @see SessionFileInternal.read
*/
async readFile() {
try {
this.log('Reading Zen session file from disk');
this.log("Reading Zen session file from disk");
let promises = [];
promises.push(this.#file.load());
if (!Services.prefs.getBoolPref(MIGRATION_PREF, false)) {
@@ -154,7 +161,7 @@ export class nsZenSessionManager {
}
await Promise.all(promises);
} catch (e) {
console.error('ZenSessionManager: Failed to read session file', e);
console.error("ZenSessionManager: Failed to read session file", e);
}
this.#sidebar = this.#file.data || {};
}
@@ -163,18 +170,20 @@ export class nsZenSessionManager {
* Called when the session file is read. Restores the sidebar data
* into all windows.
*
* @param initialState
* @param {object} initialState
* The initial session state read from the session file.
*/
onFileRead(initialState) {
if (!lazy.gWindowSyncEnabled) return;
if (!lazy.gWindowSyncEnabled) {
return;
}
// For the first time after migration, we restore the tabs
// That where going to be restored by SessionStore. The sidebar
// object will always be empty after migration because we haven't
// gotten the opportunity to save the session yet.
if (!Services.prefs.getBoolPref(MIGRATION_PREF, false)) {
Services.prefs.setBoolPref(MIGRATION_PREF, true);
this.log('Restoring tabs from Places DB after migration');
this.log("Restoring tabs from Places DB after migration");
this.#sidebar = {
...this.#sidebar,
spaces: this._migrationData?.spaces || [],
@@ -189,7 +198,7 @@ export class nsZenSessionManager {
);
if (normalClosedWindow) {
initialState.windows = [Cu.cloneInto(normalClosedWindow, {})];
this.log('Restoring tabs from last closed normal window');
this.log("Restoring tabs from last closed normal window");
}
}
for (const winData of initialState?.windows || []) {
@@ -207,17 +216,17 @@ export class nsZenSessionManager {
// This would happen on first run after having a single private window
// open when quitting the app, for example.
if (!initialState?.windows?.length) {
this.log('No windows found in initial state, creating an empty one');
this.log("No windows found in initial state, creating an empty one");
initialState ||= {};
initialState.windows = [{}];
}
// When we don't have browser.startup.page set to resume session,
// we only want to restore the pinned tabs into the new windows.
const shouldRestoreOnlyPinned =
Services.prefs.getIntPref('browser.startup.page', 1) !== BROWSER_STARTUP_RESUME_SESSION ||
Services.prefs.getIntPref("browser.startup.page", 1) !== BROWSER_STARTUP_RESUME_SESSION ||
lazy.PrivateBrowsingUtils.permanentPrivateBrowsing;
if (shouldRestoreOnlyPinned && this.#sidebar?.tabs) {
this.log('Restoring only pinned tabs into windows');
this.log("Restoring only pinned tabs into windows");
const sidebar = this.#sidebar;
sidebar.tabs = (sidebar.tabs || []).filter((tab) => tab.pinned);
this.#sidebar = sidebar;
@@ -226,7 +235,7 @@ export class nsZenSessionManager {
// guarantee that all tabs, groups, folders and split view data
// are properly synced across all windows.
const allowRestoreUnsynced = Services.prefs.getBoolPref(
'zen.session-store.restore-unsynced-windows',
"zen.session-store.restore-unsynced-windows",
true
);
this.log(`Restoring Zen session data into ${initialState.windows?.length || 0} windows`);
@@ -235,7 +244,7 @@ export class nsZenSessionManager {
if (winData.isZenUnsynced) {
if (!allowRestoreUnsynced) {
// We don't wan't to restore any unsynced windows with the sidebar data.
this.log('Skipping restore of unsynced window');
this.log("Skipping restore of unsynced window");
delete initialState.windows[i];
}
continue;
@@ -255,7 +264,7 @@ export class nsZenSessionManager {
/**
* Saves the current session state. Collects data and writes to disk.
*
* @param state The current session state.
* @param {object} state The current session state.
*/
saveState(state) {
if (!state?.windows?.length || !lazy.gWindowSyncEnabled) {
@@ -306,8 +315,8 @@ export class nsZenSessionManager {
});
const todayFileName = `zen-sessions-${today.getFullYear()}-${(today.getMonth() + 1)
.toString()
.padStart(2, '0')}-${today.getDate().toString().padStart(2, '0')}.json${
SHOULD_COMPRESS_FILE ? 'lz4' : ''
.padStart(2, "0")}-${today.getDate().toString().padStart(2, "0")}.json${
SHOULD_COMPRESS_FILE ? "lz4" : ""
}`;
const todayFilePath = PathUtils.join(backupFolder, todayFileName);
const sessionFilePath = this.#file.path;
@@ -317,14 +326,14 @@ export class nsZenSessionManager {
// number of backups allowed, and delete the oldest ones
// if needed.
let files = await IOUtils.getChildren(backupFolder);
files = files.filter((file) => file.startsWith('zen-sessions-')).sort();
files = files.filter((file) => file.startsWith("zen-sessions-")).sort();
for (let i = 0; i < files.length - lazy.gMaxSessionBackups; i++) {
const fileToDelete = PathUtils.join(backupFolder, files[i].name);
this.log(`Deleting old backup file ${files[i].name}`);
await IOUtils.remove(fileToDelete);
}
} catch (e) {
console.error('ZenSessionManager: Failed to create session file backups', e);
console.error("ZenSessionManager: Failed to create session file backups", e);
}
}
@@ -332,8 +341,8 @@ export class nsZenSessionManager {
* Saves the session data for a closed window if it meets the criteria.
* See SessionStoreInternal.maybeSaveClosedWindow for more details.
*
* @param aWinData - The window data object to save.
* @param isLastWindow - Whether this is the last saveable window.
* @param {object} aWinData - The window data object to save.
* @param {boolean} isLastWindow - Whether this is the last saveable window.
*/
maybeSaveClosedWindow(aWinData, isLastWindow) {
// We only want to save the *last* normal window that is closed.
@@ -342,14 +351,14 @@ export class nsZenSessionManager {
if (aWinData.isPopup || aWinData.isTaskbarTab || aWinData.isZenUnsynced || !isLastWindow) {
return;
}
this.log('Saving closed window session data into Zen session store');
this.log("Saving closed window session data into Zen session store");
this.saveState({ windows: [aWinData] });
}
/**
* Collects session data for a given window.
*
* @param state
* @param {object} state
* The current session state.
*/
#collectWindowData(state) {
@@ -374,8 +383,8 @@ export class nsZenSessionManager {
/**
* Collects session data for all tabs in a given window.
*
* @param sidebarData The sidebar data object to populate.
* @param state The current session state.
* @param {object} sidebarData The sidebar data object to populate.
* @param {object} state The current session state.
*/
#collectTabsData(sidebarData, state) {
const tabIdRelationMap = new Map();
@@ -404,7 +413,7 @@ export class nsZenSessionManager {
* We do this in order to make sure all new window objects
* have the same sidebar data.
*
* @param aWindowData The window data object to restore into.
* @param {object} aWindowData The window data object to restore into.
*/
#restoreWindowData(aWindowData) {
const sidebar = this.#sidebar;
@@ -422,18 +431,18 @@ export class nsZenSessionManager {
* Restores a new window with Zen session data. This should be called
* not at startup, but when a new window is opened by the user.
*
* @param aWindow
* @param {Window} aWindow
* The window to restore.
* @param SessionStoreInternal
* @param {object} SessionStoreInternal
* The SessionStore module instance.
* @param fromClosedWindow
* @param {boolean} fromClosedWindow
* Whether this new window is being restored from a closed window.
*/
restoreNewWindow(aWindow, SessionStoreInternal, fromClosedWindow = false) {
if (aWindow.gZenWorkspaces?.privateWindowOrDisabled || !lazy.gWindowSyncEnabled) {
return;
}
this.log('Restoring new window with Zen session data');
this.log("Restoring new window with Zen session data");
const state = lazy.SessionStore.getCurrentState(true);
const windows = (state.windows || []).filter(
(win) => !win.isPrivate && !win.isPopup && !win.isTaskbarTab && !win.isZenUnsynced
@@ -444,7 +453,7 @@ export class nsZenSessionManager {
// We only want to restore the sidebar object if we found
// only one normal window to clone from (which is the one
// we are opening).
this.log('Restoring sidebar data into new window');
this.log("Restoring sidebar data into new window");
this.#restoreWindowData(newWindow);
}
newWindow.tabs = this.#filterUnusedTabs(newWindow.tabs || []);
@@ -477,11 +486,11 @@ export class nsZenSessionManager {
* Called when a new empty session is created. For example,
* when creating a new profile or when the user installed it for
* the first time.
* @param {*} aWindow
* @returns
*
* @param {Window} aWindow
*/
onNewEmptySession(aWindow) {
this.log('Restoring empty session with Zen session data');
this.log("Restoring empty session with Zen session data");
aWindow.gZenWorkspaces.restoreWorkspacesFromSessionStore({
spaces: this.#sidebar.spaces || [],
});

View File

@@ -2,47 +2,48 @@
* 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 { XPCOMUtils } from 'resource://gre/modules/XPCOMUtils.sys.mjs';
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
BrowserWindowTracker: 'resource:///modules/BrowserWindowTracker.sys.mjs',
SessionStore: 'resource:///modules/sessionstore/SessionStore.sys.mjs',
TabStateFlusher: 'resource:///modules/sessionstore/TabStateFlusher.sys.mjs',
ZenSessionStore: 'resource:///modules/zen/ZenSessionManager.sys.mjs',
TabStateCache: 'resource:///modules/sessionstore/TabStateCache.sys.mjs',
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
// eslint-disable-next-line mozilla/valid-lazy
ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
});
XPCOMUtils.defineLazyPreferenceGetter(lazy, 'gWindowSyncEnabled', 'zen.window-sync.enabled');
XPCOMUtils.defineLazyPreferenceGetter(lazy, 'gShouldLog', 'zen.window-sync.log', true);
XPCOMUtils.defineLazyPreferenceGetter(lazy, "gWindowSyncEnabled", "zen.window-sync.enabled");
XPCOMUtils.defineLazyPreferenceGetter(lazy, "gShouldLog", "zen.window-sync.log", true);
const OBSERVING = ['browser-window-before-show'];
const INSTANT_EVENTS = ['SSWindowClosing'];
const OBSERVING = ["browser-window-before-show"];
const INSTANT_EVENTS = ["SSWindowClosing"];
const EVENTS = [
'TabOpen',
'TabClose',
"TabOpen",
"TabClose",
'ZenTabIconChanged',
'ZenTabLabelChanged',
"ZenTabIconChanged",
"ZenTabLabelChanged",
'TabMove',
'TabPinned',
'TabUnpinned',
'TabAddedToEssentials',
'TabRemovedFromEssentials',
"TabMove",
"TabPinned",
"TabUnpinned",
"TabAddedToEssentials",
"TabRemovedFromEssentials",
'TabGroupUpdate',
'TabGroupCreate',
'TabGroupRemoved',
'TabGroupMoved',
"TabGroupUpdate",
"TabGroupCreate",
"TabGroupRemoved",
"TabGroupMoved",
'ZenTabRemovedFromSplit',
'ZenSplitViewTabsSplit',
"ZenTabRemovedFromSplit",
"ZenSplitViewTabsSplit",
'TabSelect',
"TabSelect",
'focus',
"focus",
...INSTANT_EVENTS,
];
@@ -124,7 +125,7 @@ class nsZenWindowSync {
log(...args) {
if (lazy.gShouldLog) {
console.info('ZenWindowSync:', ...args);
console.warn("ZenWindowSync:", ...args);
}
}
@@ -144,21 +145,21 @@ class nsZenWindowSync {
// to avoid confusing the old private window behavior.
let forcedSync = !aWindow.gZenWorkspaces?.privateWindowOrDisabled;
let hasUnsyncedArg = false;
if (aWindow._zenStartupSyncFlag === 'synced') {
if (aWindow._zenStartupSyncFlag === "synced") {
forcedSync = true;
} else if (aWindow._zenStartupSyncFlag === 'unsynced') {
} else if (aWindow._zenStartupSyncFlag === "unsynced") {
hasUnsyncedArg = true;
}
delete aWindow._zenStartupSyncFlag;
if (
!forcedSync &&
(hasUnsyncedArg ||
(typeof aWindow.arguments[0] === 'string' &&
(typeof aWindow.arguments[0] === "string" &&
aWindow.arguments.length > 1 &&
[...this.#browserWindows].length > 0))
!![...this.#browserWindows].length))
) {
this.log('Not syncing new window due to unsynced argument or existing synced windows');
aWindow.document.documentElement.setAttribute('zen-unsynced-window', 'true');
this.log("Not syncing new window due to unsynced argument or existing synced windows");
aWindow.document.documentElement.setAttribute("zen-unsynced-window", "true");
return;
}
aWindow.gZenWindowSync = this;
@@ -169,8 +170,6 @@ class nsZenWindowSync {
/**
* Called when the session store has finished initializing for a window.
*
* @param {Window} aWindow - The browser window that has initialized session store.
*/
async #onSessionStoreInitialized() {
// For every tab we have in where there's no sync ID, we need to
@@ -226,6 +225,7 @@ class nsZenWindowSync {
/**
* Runs a callback function on all browser windows except the specified one.
* This version supports asynchronous callbacks.
*
* @see #runOnAllWindows - Make sure functionality is the same.
* @param {Window} aWindow - The browser window to exclude.
* @param {Function} aCallback - The asynchronous callback function to run on each window.
@@ -240,7 +240,7 @@ class nsZenWindowSync {
observe(aSubject, aTopic) {
switch (aTopic) {
case 'browser-window-before-show': {
case "browser-window-before-show": {
this.#onWindowBeforeShow(aSubject);
break;
}
@@ -257,7 +257,8 @@ class nsZenWindowSync {
return;
}
if (INSTANT_EVENTS.includes(aEvent.type)) {
return this.#handleNextEvent(aEvent);
this.#handleNextEvent(aEvent);
return;
}
if (this.#eventHandlingContext.window && this.#eventHandlingContext.window !== window) {
// We're already handling an event for another window.
@@ -284,6 +285,7 @@ class nsZenWindowSync {
/**
* Adds a sync handler for a specific event type.
*
* @param {Function} aHandler - The sync handler function to add.
*/
addSyncHandler(aHandler) {
@@ -295,6 +297,7 @@ class nsZenWindowSync {
/**
* Removes a sync handler for a specific event type.
*
* @param {Function} aHandler - The sync handler function to remove.
*/
removeSyncHandler(aHandler) {
@@ -309,7 +312,7 @@ class nsZenWindowSync {
#handleNextEvent(aEvent) {
const handler = `on_${aEvent.type}`;
try {
if (typeof this[handler] === 'function') {
if (typeof this[handler] === "function") {
let promise = this[handler](aEvent) || Promise.resolve();
promise.then(() => {
for (let syncHandler of this.#syncHandlers) {
@@ -321,9 +324,8 @@ class nsZenWindowSync {
}
});
return promise;
} else {
throw new Error(`No handler for event type: ${aEvent.type}`);
}
throw new Error(`No handler for event type: ${aEvent.type}`);
} catch (e) {
return Promise.reject(e);
}
@@ -345,6 +347,7 @@ class nsZenWindowSync {
/**
* Synchronizes a specific attribute from the original item to the target item.
*
* @param {MozTabbrowserTab|MozTabbrowserTabGroup} aOriginalItem - The original item to copy from.
* @param {MozTabbrowserTab|MozTabbrowserTabGroup} aTargetItem - The target item to copy to.
* @param {string} aAttributeName - The name of the attribute to synchronize.
@@ -360,8 +363,8 @@ class nsZenWindowSync {
/**
* Synchronizes the icon and label of the target tab with the original tab.
*
* @param {Object} aOriginalTab - The original tab to copy from.
* @param {Object} aTargetTab - The target tab to copy to.
* @param {object} aOriginalItem - The original item to copy from.
* @param {object} aTargetItem - The target item to copy to.
* @param {Window} aWindow - The window containing the tabs.
* @param {number} flags - The sync flags indicating what to synchronize.
*/
@@ -375,7 +378,7 @@ class nsZenWindowSync {
if (gBrowser.isTab(aOriginalItem)) {
gBrowser.setIcon(
aTargetItem,
aOriginalItem.getAttribute('image') || gBrowser.getIcon(aOriginalItem)
aOriginalItem.getAttribute("image") || gBrowser.getIcon(aOriginalItem)
);
} else if (aOriginalItem.isZenFolder) {
// Icons are a zen-only feature for tab groups.
@@ -392,8 +395,8 @@ class nsZenWindowSync {
aTargetItem.label = aOriginalItem.label;
}
}
if (flags & SYNC_FLAG_MOVE && !aTargetItem.hasAttribute('zen-empty-tab')) {
this.#maybeSyncAttributeChange(aOriginalItem, aTargetItem, 'zen-workspace-id');
if (flags & SYNC_FLAG_MOVE && !aTargetItem.hasAttribute("zen-empty-tab")) {
this.#maybeSyncAttributeChange(aOriginalItem, aTargetItem, "zen-workspace-id");
this.#syncItemPosition(aOriginalItem, aTargetItem, aWindow);
}
if (gBrowser.isTab(aTargetItem)) {
@@ -410,8 +413,8 @@ class nsZenWindowSync {
*/
#syncItemPosition(aOriginalItem, aTargetItem, aWindow) {
const { gBrowser, gZenPinnedTabManager } = aWindow;
const originalIsEssential = aOriginalItem.hasAttribute('zen-essential');
const targetIsEssential = aTargetItem.hasAttribute('zen-essential');
const originalIsEssential = aOriginalItem.hasAttribute("zen-essential");
const targetIsEssential = aTargetItem.hasAttribute("zen-essential");
const originalIsPinned = aOriginalItem.pinned;
const targetIsPinned = aTargetItem.pinned;
@@ -448,7 +451,7 @@ class nsZenWindowSync {
* @param {MozTabbrowserTab|MozTabbrowserTabGroup} aOriginalItem - The original item to match.
* @param {MozTabbrowserTab|MozTabbrowserTabGroup} aTargetItem - The target item to move.
* @param {Window} aWindow - The window containing the items.
* @param {Object} options - Additional options for moving the item.
* @param {object} options - Additional options for moving the item.
* @param {boolean} options.isEssential - Indicates if the item is essential.
* @param {boolean} options.isPinned - Indicates if the item is pinned.
*/
@@ -458,15 +461,15 @@ class nsZenWindowSync {
let isFirstTab = true;
if (gBrowser.isTabGroup(originalSibling) || gBrowser.isTab(originalSibling)) {
isFirstTab =
!originalSibling.hasAttribute('id') || originalSibling.hasAttribute('zen-empty-tab');
!originalSibling.hasAttribute("id") || originalSibling.hasAttribute("zen-empty-tab");
}
gBrowser.zenHandleTabMove(aTargetItem, () => {
if (isFirstTab) {
let container;
const parentGroup = aOriginalItem.group;
if (parentGroup?.hasAttribute('id')) {
container = this.getItemFromWindow(aWindow, parentGroup.getAttribute('id'));
if (parentGroup?.hasAttribute("id")) {
container = this.getItemFromWindow(aWindow, parentGroup.getAttribute("id"));
if (container) {
if (container?.tabs?.length) {
// First tab in folders is the empty tab placeholder.
@@ -481,7 +484,7 @@ class nsZenWindowSync {
container = gZenWorkspaces.getEssentialsSection(aTargetItem);
} else {
const workspaceId =
aTargetItem.getAttribute('zen-workspace-id') ||
aTargetItem.getAttribute("zen-workspace-id") ||
aOriginalItem.ownerGlobal.gZenWorkspaces.activeWorkspace;
const workspaceElement = gZenWorkspaces.workspaceElement(workspaceId);
container = isPinned
@@ -522,8 +525,8 @@ class nsZenWindowSync {
/**
* Swaps the browser docshells between two tabs.
*
* @param {Object} aOurTab - The tab in the current window.
* @param {Object} aOtherTab - The tab in the other window.
* @param {object} aOurTab - The tab in the current window.
* @param {object} aOtherTab - The tab in the other window.
*/
async #swapBrowserDocShellsAsync(aOurTab, aOtherTab) {
lazy.TabStateFlusher.flush(aOtherTab.linkedBrowser);
@@ -535,7 +538,7 @@ class nsZenWindowSync {
/**
* Restores the tab progress listener for a given tab.
*
* @param {Object} aTab - The tab to restore the progress listener for.
* @param {object} aTab - The tab to restore the progress listener for.
* @param {Function} callback - The callback function to execute while the listener is removed.
* @param {boolean} onClose - Indicates if the swap is done during a tab close operation.
*/
@@ -573,8 +576,9 @@ class nsZenWindowSync {
/**
* Swaps the browser docshells between two tabs.
*
* @param {Object} aOurTab - The tab in the current window.
* @param {Object} aOtherTab - The tab in the other window.
* @param {object} aOurTab - The tab in the current window.
* @param {object} aOtherTab - The tab in the other window.
* @param {object} options - Options object.
* @param {boolean} options.focus - Indicates if the tab should be focused after the swap.
* @param {boolean} options.onClose - Indicates if the swap is done during a tab close operation.
*/
@@ -601,8 +605,8 @@ class nsZenWindowSync {
// and will stay in a 'busy' state forever.
// To avoid this, we manually check if the other tab is still busy after the swap,
// and if not, we remove the busy attribute from our tab.
if (!aOtherTab.hasAttribute('busy')) {
aOurTab.removeAttribute('busy');
if (!aOtherTab.hasAttribute("busy")) {
aOurTab.removeAttribute("busy");
}
// Load about:blank if by any chance we loaded the previous tab's URL.
// TODO: We should maybe start using a singular about:blank preloaded view
@@ -612,11 +616,11 @@ class nsZenWindowSync {
// around this limitation somehow.
if (
!onClose &&
(aOtherTab.linkedBrowser?.currentURI.spec !== 'about:blank' ||
aOtherTab.hasAttribute('busy'))
(aOtherTab.linkedBrowser?.currentURI.spec !== "about:blank" ||
aOtherTab.hasAttribute("busy"))
) {
this.log(`Loading about:blank in our tab ${aOtherTab.id} before swap`);
aOtherTab.linkedBrowser.loadURI(Services.io.newURI('about:blank'), {
aOtherTab.linkedBrowser.loadURI(Services.io.newURI("about:blank"), {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
loadFlags: Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY,
});
@@ -624,7 +628,7 @@ class nsZenWindowSync {
},
onClose
);
const kAttributesToRemove = ['muted', 'soundplaying', 'sharing', 'pictureinpicture', 'busy'];
const kAttributesToRemove = ["muted", "soundplaying", "sharing", "pictureinpicture", "busy"];
// swapBrowsersAndCloseOther already takes care of transferring attributes like 'muted',
// but we need to manually remove some attributes from the other tab.
for (let attr of kAttributesToRemove) {
@@ -656,8 +660,8 @@ class nsZenWindowSync {
/**
* Styles the swapped browsers to ensure proper visibility and layout.
*
* @param {Object} aOurTab - The tab in the current window.
* @param {Object} aOtherTab - The tab in the other window.
* @param {object} aOurTab - The tab in the current window.
* @param {object} aOtherTab - The tab in the other window.
* @param {Function|undefined} callback - The callback function to execute after styling.
*/
async #styleSwapedBrowsers(aOurTab, aOtherTab, callback = undefined) {
@@ -681,7 +685,7 @@ class nsZenWindowSync {
resolve(reader.result);
};
reader.onerror = function () {
reject(new Error('Failed to read blob as data URL'));
reject(new Error("Failed to read blob as data URL"));
};
});
@@ -689,25 +693,25 @@ class nsZenWindowSync {
// Run a reflow to ensure the image is rendered before hiding the browser.
void img.getBoundingClientRect();
await loadPromise;
otherBrowser.setAttribute('zen-pseudo-hidden', 'true');
otherBrowser.setAttribute("zen-pseudo-hidden", "true");
callback();
}
this.#maybeRemovePseudoImageForBrowser(ourBrowser);
ourBrowser.removeAttribute('zen-pseudo-hidden');
ourBrowser.removeAttribute("zen-pseudo-hidden");
}
/**
* Create and insert a new pseudo image for a browser element.
*
* @param {Object} aBrowser - The browser element to create the pseudo image for.
* @param {object} aBrowser - The browser element to create the pseudo image for.
* @param {string} aSrc - The source URL of the image.
* @returns {Object} The created pseudo image element.
* @returns {object} The created pseudo image element.
*/
#createPseudoImageForBrowser(aBrowser, aSrc) {
const doc = aBrowser.ownerDocument;
const img = doc.createElement('img');
img.className = 'zen-pseudo-browser-image';
const img = doc.createElement("img");
img.className = "zen-pseudo-browser-image";
aBrowser.after(img);
const loadPromise = new Promise((resolve) => {
img.onload = () => resolve();
@@ -719,10 +723,10 @@ class nsZenWindowSync {
/**
* Removes the pseudo image element for a browser if it exists.
*
* @param {Object} aBrowser - The browser element to remove the pseudo image for.
* @param {object} aBrowser - The browser element to remove the pseudo image for.
*/
#maybeRemovePseudoImageForBrowser(aBrowser) {
const elements = aBrowser.parentNode?.querySelectorAll('.zen-pseudo-browser-image');
const elements = aBrowser.parentNode?.querySelectorAll(".zen-pseudo-browser-image");
if (elements) {
elements.forEach((element) => element.remove());
}
@@ -735,7 +739,7 @@ class nsZenWindowSync {
* @param {Window} aWindow - The window to exclude.
* @param {string} aTabId - The ID of the tab to retrieve.
* @param {Function} filter - A function to filter the tabs.
* @returns {Object|null} The active tab from other windows if found, otherwise null.
* @returns {object | null} The active tab from other windows if found, otherwise null.
*/
#getActiveTabFromOtherWindows(aWindow, aTabId, filter = (tab) => tab?._zenContentsVisible) {
return this.#runOnAllWindows(aWindow, (win) => {
@@ -743,6 +747,7 @@ class nsZenWindowSync {
if (filter(tab)) {
return tab;
}
return undefined;
});
}
@@ -781,7 +786,7 @@ class nsZenWindowSync {
* Handles tab switch or window focus events to synchronize tab contents visibility.
*
* @param {Window} aWindow - The window that triggered the event.
* @param {Object} aPreviousTab - The previously selected tab.
* @param {object} aPreviousTab - The previously selected tab.
* @param {boolean} ignoreSameTab - Indicates if the same tab should be ignored.
*/
async #onTabSwitchOrWindowFocus(aWindow, aPreviousTab = null, ignoreSameTab = false) {
@@ -805,7 +810,7 @@ class nsZenWindowSync {
let promises = [];
for (const browserView of aWindow.gBrowser.selectedBrowsers) {
const selectedTab = aWindow.gBrowser.getTabForBrowser(browserView);
if (selectedTab._zenContentsVisible || selectedTab.hasAttribute('zen-empty-tab')) {
if (selectedTab._zenContentsVisible || selectedTab.hasAttribute("zen-empty-tab")) {
continue;
}
const otherSelectedTab = this.#getActiveTabFromOtherWindows(aWindow, selectedTab.id);
@@ -832,8 +837,8 @@ class nsZenWindowSync {
/**
* Retrieves the tab state for a given tab.
*
* @param {Object} tab - The tab to retrieve the state for.
* @returns {Object} The tab state.
* @param {object} tab - The tab to retrieve the state for.
* @returns {object} The tab state.
*/
#getTabState(tab) {
return JSON.parse(lazy.SessionStore.getTabState(tab));
@@ -844,14 +849,14 @@ class nsZenWindowSync {
/**
* Sets the initial pinned state for a tab across all windows.
*
* @param {Object} aTab - The tab to set the pinned state for.
* @param {object} aTab - The tab to set the pinned state for.
* @returns {Promise} A promise that resolves when the operation is complete.
*/
setPinnedTabState(aTab) {
return lazy.TabStateFlusher.flush(aTab.linkedBrowser).finally(() => {
this.log(`Setting pinned initial state for tab ${aTab.id}`);
const state = this.#getTabState(aTab);
let activeIndex = 'index' in state ? state.index : state.entries.length - 1;
let activeIndex = "index" in state ? state.index : state.entries.length - 1;
activeIndex = Math.min(activeIndex, state.entries.length - 1);
activeIndex = Math.max(activeIndex, 0);
const initialState = {
@@ -869,6 +874,7 @@ class nsZenWindowSync {
/**
* Propagates the workspaces to all windows.
*
* @param {Array} aWorkspaces - The workspaces to propagate.
*/
propagateWorkspacesToAllWindows(aWorkspaces) {
@@ -886,7 +892,7 @@ class nsZenWindowSync {
*/
moveTabsToSyncedWorkspace(aWindow, aWorkspaceId) {
const tabsToMove = aWindow.gZenWorkspaces.allStoredTabs.filter(
(tab) => !tab.hasAttribute('zen-empty-tab')
(tab) => !tab.hasAttribute("zen-empty-tab")
);
const selectedTab = aWindow.gBrowser.selectedTab;
let win = [...this.#browserWindows][0];
@@ -899,7 +905,7 @@ class nsZenWindowSync {
const newTab = gBrowser.adoptTab(tab, { tabIndex: Infinity });
if (!newTab) {
// The adoption failed. Restore "fadein" and don't increase the index.
tab.setAttribute('fadein', 'true');
tab.setAttribute("fadein", "true");
success = false;
continue;
}
@@ -913,7 +919,7 @@ class nsZenWindowSync {
}
};
if (!win) {
this.log('No synced window found, creating a new one');
this.log("No synced window found, creating a new one");
win = aWindow.gBrowser.replaceTabWithWindow(selectedTab, {}, /* zenForceSync = */ true);
win.gZenWorkspaces.promiseInitialized.then(() => {
moveAllTabsToWindow();
@@ -935,11 +941,11 @@ class nsZenWindowSync {
tab._zenContentsVisible = true;
tab.id = this.#newTabSyncId;
this.#runOnAllWindows(window, (win) => {
const newTab = win.gBrowser.addTrustedTab('about:blank', {
const newTab = win.gBrowser.addTrustedTab("about:blank", {
animate: true,
createLazyBrowser: true,
zenWorkspaceId: tab.getAttribute('zen-workspace-id') || '',
_forZenEmptyTab: tab.hasAttribute('zen-empty-tab'),
zenWorkspaceId: tab.getAttribute("zen-workspace-id") || "",
_forZenEmptyTab: tab.hasAttribute("zen-empty-tab"),
});
newTab.id = tab.id;
this.#syncItemWithOriginal(
@@ -957,7 +963,7 @@ class nsZenWindowSync {
// No need to sync icon changes for tabs that aren't active in this window.
return;
}
return this.#delegateGenericSyncEvent(aEvent, SYNC_FLAG_ICON);
this.#delegateGenericSyncEvent(aEvent, SYNC_FLAG_ICON);
}
on_ZenTabLabelChanged(aEvent) {
@@ -965,7 +971,7 @@ class nsZenWindowSync {
// No need to sync label changes for tabs that aren't active in this window.
return;
}
return this.#delegateGenericSyncEvent(aEvent, SYNC_FLAG_LABEL);
this.#delegateGenericSyncEvent(aEvent, SYNC_FLAG_LABEL);
}
on_TabMove(aEvent) {
@@ -1025,7 +1031,7 @@ class nsZenWindowSync {
}
this.#lastFocusedWindow = new WeakRef(window);
this.#lastSelectedTab = new WeakRef(window.gBrowser.selectedTab);
return this.#onTabSwitchOrWindowFocus(window);
this.#onTabSwitchOrWindowFocus(window);
}
on_TabSelect(aEvent) {
@@ -1035,7 +1041,7 @@ class nsZenWindowSync {
}
this.#lastSelectedTab = new WeakRef(tab);
const previousTab = aEvent.detail.previousTab;
return this.#onTabSwitchOrWindowFocus(aEvent.target.ownerGlobal, previousTab);
this.#onTabSwitchOrWindowFocus(aEvent.target.ownerGlobal, previousTab);
}
on_SSWindowClosing(aEvent) {
@@ -1056,7 +1062,7 @@ class nsZenWindowSync {
}
const window = tabGroup.ownerGlobal;
const isFolder = tabGroup.isZenFolder;
const isSplitView = tabGroup.hasAttribute('split-view-group');
const isSplitView = tabGroup.hasAttribute("split-view-group");
if (isSplitView) {
return; // Split view groups are synced via ZenSplitViewTabsSplit event.
}
@@ -1066,7 +1072,7 @@ class nsZenWindowSync {
const existingGroup = this.getItemFromWindow(win, tabGroup.id);
if (existingGroup) {
this.log(
`Attempted to create group ${tabGroup.id} in window ${win}, ` + `but it already exists.`
`Attempted to create group ${tabGroup.id} in window ${win}, but it already exists.`
);
return; // Do not proceed with creation.
}
@@ -1127,8 +1133,8 @@ class nsZenWindowSync {
const otherWindowTabs = tabs
.map((tab) => this.getItemFromWindow(win, tab.id))
.filter(Boolean);
if (otherWindowTabs.length > 0 && win.gZenViewSplitter) {
const group = win.gZenViewSplitter.splitTabs(otherWindowTabs, 'grid', -1);
if (otherWindowTabs.length && win.gZenViewSplitter) {
const group = win.gZenViewSplitter.splitTabs(otherWindowTabs, "grid", -1);
if (group) {
let otherTabGroup = group.tabs[0].group;
otherTabGroup.id = tabGroup.id;
@@ -1141,5 +1147,6 @@ class nsZenWindowSync {
}
}
// eslint-disable-next-line mozilla/valid-lazy
export const gWindowSyncEnabled = lazy.gWindowSyncEnabled;
export const ZenWindowSync = new nsZenWindowSync();

File diff suppressed because it is too large Load Diff

View File

@@ -2,37 +2,39 @@
// 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 { nsZenDOMOperatedFeature } from 'chrome://browser/content/zen-components/ZenCommonUtils.mjs';
import { nsZenDOMOperatedFeature } from "chrome://browser/content/zen-components/ZenCommonUtils.mjs";
const lazy = {};
class ZenPinnedTabsObserver {
static ALL_EVENTS = ['TabPinned', 'TabUnpinned'];
static ALL_EVENTS = ["TabPinned", "TabUnpinned"];
#listeners = [];
constructor() {
// eslint-disable-next-line mozilla/valid-lazy
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'zenPinnedTabRestorePinnedTabsToPinnedUrl',
'zen.pinned-tab-manager.restore-pinned-tabs-to-pinned-url',
"zenPinnedTabRestorePinnedTabsToPinnedUrl",
"zen.pinned-tab-manager.restore-pinned-tabs-to-pinned-url",
false
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'zenPinnedTabCloseShortcutBehavior',
'zen.pinned-tab-manager.close-shortcut-behavior',
'switch'
"zenPinnedTabCloseShortcutBehavior",
"zen.pinned-tab-manager.close-shortcut-behavior",
"switch"
);
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
'zenTabsEssentialsMax',
'zen.tabs.essentials.max',
"zenTabsEssentialsMax",
"zen.tabs.essentials.max",
12
);
ChromeUtils.defineESModuleGetters(lazy, {
E10SUtils: 'resource://gre/modules/E10SUtils.sys.mjs',
TabStateCache: 'resource:///modules/sessionstore/TabStateCache.sys.mjs',
// eslint-disable-next-line mozilla/valid-lazy
E10SUtils: "resource://gre/modules/E10SUtils.sys.mjs",
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
});
this.#listenPinnedTabEvents();
}
@@ -42,7 +44,7 @@ class ZenPinnedTabsObserver {
for (const event of ZenPinnedTabsObserver.ALL_EVENTS) {
window.addEventListener(event, eventListener);
}
window.addEventListener('unload', () => {
window.addEventListener("unload", () => {
for (const event of ZenPinnedTabsObserver.ALL_EVENTS) {
window.removeEventListener(event, eventListener);
}
@@ -65,7 +67,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
if (!this.enabled) {
return;
}
this._canLog = Services.prefs.getBoolPref('zen.pinned-tab-manager.debug', false);
this._canLog = Services.prefs.getBoolPref("zen.pinned-tab-manager.debug", false);
this.observer = new ZenPinnedTabsObserver();
this._initClosePinnedTabShortcut();
this._insertItemsIntoTabContextMenu();
@@ -78,20 +80,21 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
log(message) {
if (this._canLog) {
/* eslint-disable-next-line no-console */
console.log(`[ZenPinnedTabManager] ${message}`);
}
}
onTabIconChanged(tab, url = null) {
tab.dispatchEvent(new CustomEvent('ZenTabIconChanged', { bubbles: true, detail: { tab } }));
if (tab.hasAttribute('zen-essential')) {
tab.dispatchEvent(new CustomEvent("ZenTabIconChanged", { bubbles: true, detail: { tab } }));
if (tab.hasAttribute("zen-essential")) {
this.setEssentialTabIcon(tab, url);
}
}
setEssentialTabIcon(tab, url = null) {
const iconUrl = url ?? tab.getAttribute('image') ?? '';
tab.style.setProperty('--zen-essential-tab-icon', `url(${iconUrl})`);
const iconUrl = url ?? tab.getAttribute("image") ?? "";
tab.style.setProperty("--zen-essential-tab-icon", `url(${iconUrl})`);
}
_onTabResetPinButton(event, tab) {
@@ -108,26 +111,28 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
_onPinnedTabEvent(action, event) {
if (!this.enabled) return;
if (!this.enabled) {
return;
}
const tab = event.target;
if (this._ignoreNextTabPinnedEvent) {
delete this._ignoreNextTabPinnedEvent;
return;
}
switch (action) {
case 'TabPinned':
case "TabPinned":
tab._zenClickEventListener = this._zenClickEventListener;
tab.addEventListener('click', tab._zenClickEventListener);
tab.addEventListener("click", tab._zenClickEventListener);
break;
// [Fall through]
case 'TabUnpinned':
case "TabUnpinned":
if (tab._zenClickEventListener) {
tab.removeEventListener('click', tab._zenClickEventListener);
tab.removeEventListener("click", tab._zenClickEventListener);
delete tab._zenClickEventListener;
}
break;
default:
console.warn('ZenPinnedTabManager: Unhandled tab event', action);
console.warn("ZenPinnedTabManager: Unhandled tab event", action);
break;
}
}
@@ -137,10 +142,10 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
async _onTabClick(e) {
const tab = e.target?.closest('tab');
const tab = e.target?.closest("tab");
if (e.button === 1 && tab) {
await this.onCloseTabShortcut(e, tab, {
closeIfPending: Services.prefs.getBoolPref('zen.pinned-tab-manager.wheel-close-if-pending'),
closeIfPending: Services.prefs.getBoolPref("zen.pinned-tab-manager.wheel-close-if-pending"),
});
}
}
@@ -165,17 +170,18 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
window.gZenWindowSync.setPinnedTabState(tab);
this.resetPinChangedUrl(tab);
gZenUIManager.showToast('zen-pinned-tab-replaced');
gZenUIManager.showToast("zen-pinned-tab-replaced");
}
_initClosePinnedTabShortcut() {
let cmdClose = document.getElementById('cmd_close');
let cmdClose = document.getElementById("cmd_close");
if (cmdClose) {
cmdClose.addEventListener('command', this.onCloseTabShortcut.bind(this));
cmdClose.addEventListener("command", this.onCloseTabShortcut.bind(this));
}
}
// eslint-disable-next-line complexity
async onCloseTabShortcut(
event,
selectedTab = gBrowser.selectedTab,
@@ -193,7 +199,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
...new Set(
tabs
.flatMap((tab) => {
if (tab.group?.hasAttribute('split-view-group')) {
if (tab.group?.hasAttribute("split-view-group")) {
return tab.group.tabs;
}
return tab;
@@ -211,28 +217,28 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
event.stopPropagation();
event.preventDefault();
if (noClose && behavior === 'close') {
behavior = 'unload-switch';
if (noClose && behavior === "close") {
behavior = "unload-switch";
}
if (alwaysUnload && ['close', 'reset', 'switch', 'reset-switch'].includes(behavior)) {
behavior = behavior.contains('reset') ? 'reset-unload-switch' : 'unload-switch';
if (alwaysUnload && ["close", "reset", "switch", "reset-switch"].includes(behavior)) {
behavior = behavior.contains("reset") ? "reset-unload-switch" : "unload-switch";
}
switch (behavior) {
case 'close': {
case "close": {
for (const tab of pinnedTabs) {
gBrowser.removeTab(tab, { animate: true });
}
break;
}
case 'reset-unload-switch':
case 'unload-switch':
case 'reset-switch':
case 'switch':
if (behavior.includes('unload')) {
case "reset-unload-switch":
case "unload-switch":
case "reset-switch":
case "switch":
if (behavior.includes("unload")) {
for (const tab of pinnedTabs) {
if (tab.hasAttribute('glance-id')) {
if (tab.hasAttribute("glance-id")) {
// We have a glance tab inside the tab we are trying to unload,
// before we used to just ignore it but now we need to fully close
// it as well.
@@ -243,22 +249,22 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
hasRan = true;
resolve();
};
window.addEventListener('GlanceClose', onGlanceClose, { once: true });
window.addEventListener("GlanceClose", onGlanceClose, { once: true });
// Set a timeout to resolve the promise if the event doesn't fire.
// We do this to prevent any future issues where glance woudnt close such as
// glance requering to ask for permit unload.
setTimeout(() => {
if (!hasRan) {
console.warn('GlanceClose event did not fire within 3 seconds');
console.warn("GlanceClose event did not fire within 3 seconds");
resolve();
}
}, 3000);
});
return;
}
const isSpltView = tab.group?.hasAttribute('split-view-group');
const isSpltView = tab.group?.hasAttribute("split-view-group");
const group = isSpltView ? tab.group.group : tab.group;
if (!folderToUnload && tab.hasAttribute('folder-active')) {
if (!folderToUnload && tab.hasAttribute("folder-active")) {
await gZenFolders.animateUnload(group, tab);
}
}
@@ -266,37 +272,37 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
await gZenFolders.animateUnloadAll(folderToUnload);
}
const allAreUnloaded = pinnedTabs.every(
(tab) => tab.hasAttribute('pending') && !tab.hasAttribute('zen-essential')
(tab) => tab.hasAttribute("pending") && !tab.hasAttribute("zen-essential")
);
for (const tab of pinnedTabs) {
for (const tabItem of pinnedTabs) {
if (allAreUnloaded && closeIfPending) {
return await this.onCloseTabShortcut(event, tab, { behavior: 'close' });
await this.onCloseTabShortcut(event, tabItem, { behavior: "close" });
return;
}
}
await gBrowser.explicitUnloadTabs(pinnedTabs);
for (const tab of pinnedTabs) {
tab.removeAttribute('discarded');
tab.removeAttribute("discarded");
}
}
if (selectedTabs.length) {
this._handleTabSwitch(selectedTabs[0]);
}
if (behavior.includes('reset')) {
if (behavior.includes("reset")) {
for (const tab of pinnedTabs) {
this._resetTabToStoredState(tab);
}
}
break;
case 'reset':
case "reset":
for (const tab of pinnedTabs) {
this._resetTabToStoredState(tab);
}
break;
default:
return;
}
} catch (ex) {
console.error('Error handling close tab shortcut for pinned tab:', ex);
console.error("Error handling close tab shortcut for pinned tab:", ex);
}
}
@@ -349,12 +355,13 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
return faviconData.dataURI;
} catch (ex) {
console.error('Failed to get favicon:', ex);
console.error("Failed to get favicon:", ex);
return null;
}
}
addToEssentials(tab) {
// eslint-disable-next-line no-nested-ternary
const tabs = tab
? // if it's already an array, dont make it [tab]
tab?.length
@@ -365,18 +372,19 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
: [TabContextMenu.contextTab];
let movedAll = true;
for (let i = 0; i < tabs.length; i++) {
// eslint-disable-next-line no-shadow
let tab = tabs[i];
const section = gZenWorkspaces.getEssentialsSection(tab);
if (!this.canEssentialBeAdded(tab)) {
movedAll = false;
continue;
}
if (tab.hasAttribute('zen-essential')) {
if (tab.hasAttribute("zen-essential")) {
continue;
}
tab.setAttribute('zen-essential', 'true');
if (tab.hasAttribute('zen-workspace-id')) {
tab.removeAttribute('zen-workspace-id');
tab.setAttribute("zen-essential", "true");
if (tab.hasAttribute("zen-workspace-id")) {
tab.removeAttribute("zen-workspace-id");
}
if (tab.pinned) {
gBrowser.zenHandleTabMove(tab, () => {
@@ -384,7 +392,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
tab = gBrowser.adoptTab(tab, {
selectTab: tab.selected,
});
tab.setAttribute('zen-essential', 'true');
tab.setAttribute("zen-essential", "true");
}
section.appendChild(tab);
});
@@ -392,13 +400,13 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
gBrowser.pinTab(tab);
this._ignoreNextTabPinnedEvent = true;
}
tab.setAttribute('zenDefaultUserContextId', true);
tab.setAttribute("zenDefaultUserContextId", true);
if (tab.selected) {
gZenWorkspaces.switchTabIfNeeded(tab);
}
this.onTabIconChanged(tab);
// Dispatch the event to update the UI
const event = new CustomEvent('TabAddedToEssentials', {
const event = new CustomEvent("TabAddedToEssentials", {
detail: { tab },
bubbles: true,
cancelable: false,
@@ -410,16 +418,18 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
removeEssentials(tab, unpin = true) {
// eslint-disable-next-line no-nested-ternary
const tabs = tab
? [tab]
: TabContextMenu.contextTab.multiselected
? gBrowser.selectedTabs
: [TabContextMenu.contextTab];
for (let i = 0; i < tabs.length; i++) {
// eslint-disable-next-line no-shadow
const tab = tabs[i];
tab.removeAttribute('zen-essential');
tab.removeAttribute("zen-essential");
if (gZenWorkspaces.workspaceEnabled && gZenWorkspaces.getActiveWorkspaceFromCache().uuid) {
tab.setAttribute('zen-workspace-id', gZenWorkspaces.getActiveWorkspaceFromCache().uuid);
tab.setAttribute("zen-workspace-id", gZenWorkspaces.getActiveWorkspaceFromCache().uuid);
}
if (unpin) {
gBrowser.unpinTab(tab);
@@ -430,7 +440,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
});
}
// Dispatch the event to update the UI
const event = new CustomEvent('TabRemovedFromEssentials', {
const event = new CustomEvent("TabRemovedFromEssentials", {
detail: { tab },
bubbles: true,
cancelable: false,
@@ -455,7 +465,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
hidden="true"
command="cmd_zenPinnedTabResetNoTab"/>
`);
document.getElementById('tabContextMenu').appendChild(elements);
document.getElementById("tabContextMenu").appendChild(elements);
const element = window.MozXULElement.parseXULToFragment(`
<menuitem id="context_zen-add-essential"
@@ -476,11 +486,11 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
<menuseparator/>
`);
document.getElementById('context_pinTab')?.before(element);
document.getElementById('context_zen-edit-tab-title').addEventListener('command', (event) => {
document.getElementById("context_pinTab")?.before(element);
document.getElementById("context_zen-edit-tab-title").addEventListener("command", (event) => {
gZenVerticalTabsManager.renameTabStart(event);
});
document.getElementById('context_zen-edit-tab-icon').addEventListener('command', () => {
document.getElementById("context_zen-edit-tab-icon").addEventListener("command", () => {
const tab = TabContextMenu.contextTab;
gZenEmojiPicker
.open(tab.iconImage, { emojiAsSVG: true })
@@ -497,46 +507,46 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
})
.catch((err) => {
console.error(err);
return;
});
});
}
updatePinnedTabContextMenu(contextTab) {
if (!this.enabled) {
document.getElementById('context_pinTab').hidden = true;
document.getElementById("context_pinTab").hidden = true;
return;
}
const isVisible = contextTab.pinned && !contextTab.multiselected;
const isEssential = contextTab.getAttribute('zen-essential');
const zenAddEssential = document.getElementById('context_zen-add-essential');
document.getElementById('context_zen-reset-pinned-tab').hidden = !isVisible;
document.getElementById('context_zen-replace-pinned-url-with-current').hidden = !isVisible;
const isEssential = contextTab.getAttribute("zen-essential");
const zenAddEssential = document.getElementById("context_zen-add-essential");
document.getElementById("context_zen-reset-pinned-tab").hidden = !isVisible;
document.getElementById("context_zen-replace-pinned-url-with-current").hidden = !isVisible;
zenAddEssential.hidden = isEssential || !!contextTab.group;
document.l10n
.formatValue('tab-context-zen-add-essential-badge', {
.formatValue("tab-context-zen-add-essential-badge", {
num: gBrowser._numZenEssentials,
max: this.maxEssentialTabs,
})
.then((badgeText) => {
zenAddEssential.setAttribute('badge', badgeText);
zenAddEssential.setAttribute("badge", badgeText);
});
document
.getElementById('cmd_contextZenAddToEssentials')
.setAttribute('disabled', !this.canEssentialBeAdded(contextTab));
document.getElementById('context_closeTab').hidden = contextTab.hasAttribute('zen-essential');
document.getElementById('context_zen-remove-essential').hidden = !isEssential;
document.getElementById('context_unpinTab').hidden =
document.getElementById('context_unpinTab').hidden || isEssential;
document.getElementById('context_unpinSelectedTabs').hidden =
document.getElementById('context_unpinSelectedTabs').hidden || isEssential;
document.getElementById('context_zen-pinned-tab-separator').hidden = !isVisible;
document.getElementById('context_zen-edit-tab-title').hidden =
.getElementById("cmd_contextZenAddToEssentials")
.setAttribute("disabled", !this.canEssentialBeAdded(contextTab));
document.getElementById("context_closeTab").hidden = contextTab.hasAttribute("zen-essential");
document.getElementById("context_zen-remove-essential").hidden = !isEssential;
document.getElementById("context_unpinTab").hidden =
document.getElementById("context_unpinTab").hidden || isEssential;
document.getElementById("context_unpinSelectedTabs").hidden =
document.getElementById("context_unpinSelectedTabs").hidden || isEssential;
document.getElementById("context_zen-pinned-tab-separator").hidden = !isVisible;
document.getElementById("context_zen-edit-tab-title").hidden =
isEssential ||
!Services.prefs.getBoolPref('zen.tabs.rename-tabs') ||
!Services.prefs.getBoolPref("zen.tabs.rename-tabs") ||
!gZenVerticalTabsManager._prefsSidebarExpanded;
}
// eslint-disable-next-line complexity
moveToAnotherTabContainerIfNecessary(event, movingTabs) {
movingTabs = [...movingTabs];
if (!this.enabled) {
@@ -544,9 +554,9 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
try {
const pinnedTabsTarget = event.target.closest(
':is(.zen-current-workspace-indicator, .zen-workspace-pinned-tabs-section)'
":is(.zen-current-workspace-indicator, .zen-workspace-pinned-tabs-section)"
);
const essentialTabsTarget = event.target.closest('.zen-essentials-container');
const essentialTabsTarget = event.target.closest(".zen-essentials-container");
const tabsTarget = !pinnedTabsTarget;
// TODO: Solve the issue of adding a tab between two groups
@@ -570,7 +580,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
let isRegularTabs = false;
// Check for essentials container
if (essentialTabsTarget) {
if (!draggedTab.hasAttribute('zen-essential') && !draggedTab?.group) {
if (!draggedTab.hasAttribute("zen-essential") && !draggedTab?.group) {
moved = true;
isVertical = false;
hasActuallyMoved = this.addToEssentials(draggedTab);
@@ -580,31 +590,31 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
else if (pinnedTabsTarget) {
if (!draggedTab.pinned) {
gBrowser.pinTab(draggedTab);
} else if (draggedTab.hasAttribute('zen-essential')) {
} else if (draggedTab.hasAttribute("zen-essential")) {
this.removeEssentials(draggedTab, false);
moved = true;
}
}
// Check for normal tabs container
else if (tabsTarget || event.target.id === 'zen-tabs-wrapper') {
if (draggedTab.pinned && !draggedTab.hasAttribute('zen-essential')) {
else if (tabsTarget || event.target.id === "zen-tabs-wrapper") {
if (draggedTab.pinned && !draggedTab.hasAttribute("zen-essential")) {
gBrowser.unpinTab(draggedTab);
isRegularTabs = true;
} else if (draggedTab.hasAttribute('zen-essential')) {
} else if (draggedTab.hasAttribute("zen-essential")) {
this.removeEssentials(draggedTab);
moved = true;
isRegularTabs = true;
}
}
if (typeof hasActuallyMoved === 'undefined') {
if (typeof hasActuallyMoved === "undefined") {
hasActuallyMoved = moved;
}
// If the tab was moved, adjust its position relative to the target tab
if (hasActuallyMoved) {
const targetTab = event.target.closest('.tabbrowser-tab');
const targetFolder = event.target.closest('zen-folder');
const targetTab = event.target.closest(".tabbrowser-tab");
const targetFolder = event.target.closest("zen-folder");
let targetElem = targetTab || targetFolder?.labelElement;
if (targetElem?.group?.activeGroups?.length > 0) {
const activeGroup = targetElem.group.activeGroups.at(-1);
@@ -642,7 +652,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
return moved;
} catch (ex) {
console.error('Error moving tabs:', ex);
console.error("Error moving tabs:", ex);
return false;
}
}
@@ -652,14 +662,14 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
if (
!tab ||
!tab.pinned ||
tab.hasAttribute('zen-essential') ||
tab.hasAttribute("zen-essential") ||
!tab._zenPinnedInitialState?.entry
) {
return;
}
// Remove # and ? from the URL
const pinUrl = tab._zenPinnedInitialState.entry.url.split('#')[0];
const currentUrl = browser.currentURI.spec.split('#')[0];
const pinUrl = tab._zenPinnedInitialState.entry.url.split("#")[0];
const currentUrl = browser.currentURI.spec.split("#")[0];
// Add an indicator that the pin has been changed
if (pinUrl === currentUrl) {
this.resetPinChangedUrl(tab);
@@ -669,57 +679,58 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
resetPinChangedUrl(tab) {
if (!tab.hasAttribute('zen-pinned-changed')) {
if (!tab.hasAttribute("zen-pinned-changed")) {
return;
}
tab.removeAttribute('zen-pinned-changed');
tab.removeAttribute('had-zen-pinned-changed');
tab.style.removeProperty('--zen-original-tab-icon');
tab.removeAttribute("zen-pinned-changed");
tab.removeAttribute("had-zen-pinned-changed");
tab.style.removeProperty("--zen-original-tab-icon");
}
pinHasChangedUrl(tab) {
if (tab.hasAttribute('zen-pinned-changed')) {
if (tab.hasAttribute("zen-pinned-changed")) {
return;
}
if (tab.group?.hasAttribute('split-view-group')) {
tab.setAttribute('had-zen-pinned-changed', 'true');
if (tab.group?.hasAttribute("split-view-group")) {
tab.setAttribute("had-zen-pinned-changed", "true");
} else {
tab.setAttribute('zen-pinned-changed', 'true');
tab.setAttribute("zen-pinned-changed", "true");
}
tab.style.setProperty('--zen-original-tab-icon', `url(${tab._zenPinnedInitialState.image})`);
tab.style.setProperty("--zen-original-tab-icon", `url(${tab._zenPinnedInitialState.image})`);
}
removeTabContainersDragoverClass(hideIndicator = true) {
this.dragIndicator.remove();
this._dragIndicator = null;
if (hideIndicator) {
gZenWorkspaces.activeWorkspaceIndicator?.removeAttribute('open');
gZenWorkspaces.activeWorkspaceIndicator?.removeAttribute("open");
}
}
get dragIndicator() {
if (!this._dragIndicator) {
this._dragIndicator = document.createElement('div');
this._dragIndicator.id = 'zen-drag-indicator';
this._dragIndicator = document.createElement("div");
this._dragIndicator.id = "zen-drag-indicator";
gNavToolbox.appendChild(this._dragIndicator);
}
return this._dragIndicator;
}
get expandedSidebarMode() {
return document.documentElement.getAttribute('zen-sidebar-expanded') === 'true';
return document.documentElement.getAttribute("zen-sidebar-expanded") === "true";
}
canEssentialBeAdded(tab) {
return (
!(
(tab.getAttribute('usercontextid') || 0) !=
(tab.getAttribute("usercontextid") || 0) !=
gZenWorkspaces.getActiveWorkspaceFromCache().containerTabId &&
gZenWorkspaces.containerSpecificEssentials
) && gBrowser._numZenEssentials < this.maxEssentialTabs
);
}
// eslint-disable-next-line complexity
applyDragoverClass(event, draggedTab) {
if (!this.enabled) {
return;
@@ -727,27 +738,27 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
let isVertical = this.expandedSidebarMode;
if (
gBrowser.isTabGroupLabel(draggedTab) &&
!draggedTab?.group?.hasAttribute('split-view-group')
!draggedTab?.group?.hasAttribute("split-view-group")
) {
// If the target is a tab group label, we don't want to apply the dragover class
this.removeTabContainersDragoverClass();
return;
}
const pinnedTabsTarget = event.target.closest('.zen-workspace-pinned-tabs-section');
const essentialTabsTarget = event.target.closest('.zen-essentials-container');
const tabsTarget = event.target.closest('.zen-workspace-normal-tabs-section');
const folderTarget = event.target.closest('zen-folder');
let targetTab = event.target.closest('.tabbrowser-tab');
const pinnedTabsTarget = event.target.closest(".zen-workspace-pinned-tabs-section");
const essentialTabsTarget = event.target.closest(".zen-essentials-container");
const tabsTarget = event.target.closest(".zen-workspace-normal-tabs-section");
const folderTarget = event.target.closest("zen-folder");
let targetTab = event.target.closest(".tabbrowser-tab");
targetTab = targetTab?.group || targetTab;
draggedTab = draggedTab?.group?.hasAttribute('split-view-group')
draggedTab = draggedTab?.group?.hasAttribute("split-view-group")
? draggedTab.group
: draggedTab;
const isHoveringIndicator = !!event.target.closest('.zen-current-workspace-indicator');
const isHoveringIndicator = !!event.target.closest(".zen-current-workspace-indicator");
if (isHoveringIndicator) {
this.removeTabContainersDragoverClass(false);
gZenWorkspaces.activeWorkspaceIndicator?.setAttribute('open', true);
gZenWorkspaces.activeWorkspaceIndicator?.setAttribute("open", true);
} else {
gZenWorkspaces.activeWorkspaceIndicator?.removeAttribute('open');
gZenWorkspaces.activeWorkspaceIndicator?.removeAttribute("open");
}
if (draggedTab?._dragData?.movingTabs) {
@@ -758,16 +769,16 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
// Decide whether we should show a dragover class for the given target
if (essentialTabsTarget) {
if (!draggedTab.hasAttribute('zen-essential') && this.canEssentialBeAdded(draggedTab)) {
if (!draggedTab.hasAttribute("zen-essential") && this.canEssentialBeAdded(draggedTab)) {
shouldAddDragOverElement = true;
isVertical = false;
}
} else if (pinnedTabsTarget) {
if (draggedTab.hasAttribute('zen-essential')) {
if (draggedTab.hasAttribute("zen-essential")) {
shouldAddDragOverElement = true;
}
} else if (tabsTarget) {
if (draggedTab.hasAttribute('zen-essential')) {
if (draggedTab.hasAttribute("zen-essential")) {
shouldAddDragOverElement = true;
}
}
@@ -784,46 +795,48 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
const separation = 8;
const middleY = targetTab.screenY + rect.height / 2;
const indicator = this.dragIndicator;
// eslint-disable-next-line no-shadow
let top = 0;
if (event.screenY > middleY) {
top = Math.round(rect.top + rect.height) + 'px';
top = Math.round(rect.top + rect.height) + "px";
} else {
top = Math.round(rect.top) + 'px';
top = Math.round(rect.top) + "px";
}
if (indicator.style.top !== top) {
shouldPlayHapticFeedback = true;
}
indicator.setAttribute('orientation', 'horizontal');
indicator.style.setProperty('--indicator-left', rect.left + separation / 2 + 'px');
indicator.style.setProperty('--indicator-width', rect.width - separation + 'px');
indicator.setAttribute("orientation", "horizontal");
indicator.style.setProperty("--indicator-left", rect.left + separation / 2 + "px");
indicator.style.setProperty("--indicator-width", rect.width - separation + "px");
indicator.style.top = top;
indicator.style.removeProperty('left');
indicator.style.removeProperty("left");
} else {
const separation = 8;
const middleX = targetTab.screenX + rect.width / 2;
const indicator = this.dragIndicator;
let left = 0;
if (event.screenX > middleX) {
left = Math.round(rect.left + rect.width + 1) + 'px';
left = Math.round(rect.left + rect.width + 1) + "px";
} else {
left = Math.round(rect.left - 2) + 'px';
left = Math.round(rect.left - 2) + "px";
}
if (indicator.style.left !== left) {
shouldPlayHapticFeedback = true;
}
indicator.setAttribute('orientation', 'vertical');
indicator.style.setProperty('--indicator-top', rect.top + separation / 2 + 'px');
indicator.style.setProperty('--indicator-height', rect.height - separation + 'px');
indicator.setAttribute("orientation", "vertical");
indicator.style.setProperty("--indicator-top", rect.top + separation / 2 + "px");
indicator.style.setProperty("--indicator-height", rect.height - separation + "px");
indicator.style.left = left;
indicator.style.removeProperty('top');
indicator.style.removeProperty("top");
}
if (shouldPlayHapticFeedback) {
// eslint-disable-next-line mozilla/valid-services
Services.zen.playHapticFeedback();
}
}
onTabLabelChanged(tab) {
tab.dispatchEvent(new CustomEvent('ZenTabLabelChanged', { bubbles: true, detail: { tab } }));
tab.dispatchEvent(new CustomEvent("ZenTabLabelChanged", { bubbles: true, detail: { tab } }));
}
}

View File

@@ -5,12 +5,7 @@
*/
&:not([zen-compact-animating])
#zen-sidebar-top-buttons:not(
:has(
#zen-sidebar-top-buttons-customization-target > *:not(#zen-sidebar-top-buttons-separator),
.titlebar-buttonbox-container
)
) {
#zen-sidebar-top-buttons:not(:has(#zen-sidebar-top-buttons-customization-target > *:not(#zen-sidebar-top-buttons-separator), .titlebar-buttonbox-container)) {
max-height: 0 !important;
min-height: 0 !important;
opacity: 0;

View File

@@ -29,8 +29,8 @@
/* ==========================================================================
Single Toolbar Mode Specific Styles (`zen-single-toolbar='true'`)
========================================================================== */
:root[zen-single-toolbar='true'] {
@media (-moz-platform: macos) and (not -moz-pref('zen.view.mac.show-three-dot-menu')) {
:root[zen-single-toolbar="true"] {
@media (-moz-platform: macos) and (not -moz-pref("zen.view.mac.show-three-dot-menu")) {
&:not([customizing]) #PanelUI-button:not([open]):not([panelopen]) {
position: absolute;
opacity: 0;
@@ -51,20 +51,20 @@
/* ==========================================================================
Vertical Tabs Mode Specific Styles (`zen.tabs.vertical` pref)
========================================================================== */
@media -moz-pref('zen.tabs.vertical') {
:root:not([zen-window-buttons-reversed='true']) {
@media -moz-pref("zen.tabs.vertical") {
:root:not([zen-window-buttons-reversed="true"]) {
& .titlebar-buttonbox-container {
margin-left: auto;
width: fit-content;
}
&:root[zen-right-side='true'] #zen-sidebar-top-buttons .titlebar-buttonbox-container {
&:root[zen-right-side="true"] #zen-sidebar-top-buttons .titlebar-buttonbox-container {
margin-right: calc(-1 * var(--zen-toolbox-padding));
}
}
}
:root[zen-window-buttons-reversed='true'] .titlebar-buttonbox-container {
:root[zen-window-buttons-reversed="true"] .titlebar-buttonbox-container {
margin-right: auto;
width: fit-content;
}
@@ -89,21 +89,18 @@
--zen-min-toolbox-padding: 0.35rem;
}
--zen-toolbox-padding: max(
var(--zen-min-toolbox-padding),
calc(var(--zen-element-separation) / 1.5)
);
--zen-toolbox-padding: max(var(--zen-min-toolbox-padding), calc(var(--zen-element-separation) / 1.5));
}
/* ==========================================================================
Single Toolbar Mode - Further Layout Adjustments
========================================================================== */
:root[zen-single-toolbar='true'] {
:root[zen-single-toolbar="true"] {
#urlbar-container {
width: -moz-available !important;
}
& #urlbar-container[breakout='true']:has(#urlbar[zen-floating-urlbar='true']) {
& #urlbar-container[breakout="true"]:has(#urlbar[zen-floating-urlbar="true"]) {
--urlbar-container-height: 36px !important;
--urlbar-height: 38px !important;
}
@@ -116,7 +113,7 @@
& #zen-sidebar-top-buttons {
margin: calc(var(--zen-toolbox-padding) / 2) 0;
:root[zen-right-side='true']:not([zen-window-buttons-reversed='true']) & {
:root[zen-right-side="true"]:not([zen-window-buttons-reversed="true"]) & {
margin-top: 0;
}
}
@@ -182,7 +179,7 @@
font-weight: 500;
gap: 2px;
#navigator-toolbox[zen-has-implicit-hover='true'] & {
#navigator-toolbox[zen-has-implicit-hover="true"] & {
visibility: visible;
opacity: 0.5;
}
@@ -191,7 +188,7 @@
opacity: 1 !important;
}
:root:not([zen-sidebar-expanded='true']) & {
:root:not([zen-sidebar-expanded="true"]) & {
display: none;
}
@@ -214,7 +211,7 @@
}
}
:root[zen-unsynced-window='true'] & {
:root[zen-unsynced-window="true"] & {
transform: translateY(-4px);
}
}
@@ -246,8 +243,8 @@
}
/* Hide default titlebar spacers */
.titlebar-spacer[type='pre-tabs'],
.titlebar-spacer[type='post-tabs'] {
.titlebar-spacer[type="pre-tabs"],
.titlebar-spacer[type="post-tabs"] {
display: none;
}
@@ -260,7 +257,7 @@
gap: 0;
&::after {
content: '';
content: "";
display: block;
height: 1px;
margin: 0 auto;
@@ -320,7 +317,7 @@
var(--zen-tabbox-element-indent-transition);
}
:root[zen-sidebar-expanded='true'] &:not([zen-glance-tab]) {
:root[zen-sidebar-expanded="true"] &:not([zen-glance-tab]) {
margin-inline-start: var(--zen-folder-indent) !important;
}
@@ -344,11 +341,7 @@
&:not([src]),
&:-moz-broken {
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3C/svg%3E") !important;
background: color-mix(
in srgb,
var(--zen-primary-color) 80%,
light-dark(rgb(0, 0, 0), rgb(255, 255, 255))
);
background: color-mix(in srgb, var(--zen-primary-color) 80%, light-dark(rgb(0, 0, 0), rgb(255, 255, 255)));
}
}
@@ -408,13 +401,13 @@
}
&[soundplaying]:not([muted]) .tab-icon-stack::after {
content: '';
content: "";
position: absolute;
width: 110%;
height: 110%;
background-repeat: no-repeat;
opacity: 1;
background: url('chrome://browser/content/zen-images/note-indicator.svg') no-repeat;
background: url("chrome://browser/content/zen-images/note-indicator.svg") no-repeat;
top: -70%;
left: 50%;
transform: translateX(-50%);
@@ -427,7 +420,7 @@
/* --- Essentials Glance Tab Specifics (Floating) --- */
/* Additional styles for glance tabs in "essential" mode */
&[zen-essential='true'] .tabbrowser-tab {
&[zen-essential="true"] .tabbrowser-tab {
position: absolute;
top: 0px;
right: 0px;
@@ -472,7 +465,7 @@
overflow-y: auto;
height: 100%;
:root[zen-workspace-id][zen-sidebar-expanded='true'] & {
:root[zen-workspace-id][zen-sidebar-expanded="true"] & {
margin-left: calc(-1 * var(--zen-toolbox-padding));
width: calc(100% + var(--zen-toolbox-padding) * 2);
}
@@ -495,7 +488,7 @@
margin: 0;
}
#navigator-toolbox[zen-sidebar-expanded='true'] {
#navigator-toolbox[zen-sidebar-expanded="true"] {
--zen-toolbox-min-width: fit-content;
padding: var(--zen-toolbox-padding);
@@ -523,8 +516,8 @@
& #nav-bar {
padding-right: 0;
:root[zen-single-toolbar='true']:not([zen-has-empty-tab='true']) & {
& #urlbar:not([breakout-extend='true']) .urlbar-input-container {
:root[zen-single-toolbar="true"]:not([zen-has-empty-tab="true"]) & {
& #urlbar:not([breakout-extend="true"]) .urlbar-input-container {
padding-left: 8px;
padding-right: 4px;
}
@@ -535,12 +528,12 @@
margin-top: 0;
}
& .zen-current-workspace-indicator-icon[no-icon='true'] {
& .zen-current-workspace-indicator-icon[no-icon="true"] {
display: none;
}
& #zen-workspaces-button {
& .zen-workspace-sidebar-icon[no-icon='true'] {
& .zen-workspace-sidebar-icon[no-icon="true"] {
display: none;
}
}
@@ -557,10 +550,10 @@
--tab-min-height: 44px;
}
&[zen-right-side='true'] {
&[zen-right-side="true"] {
padding-left: 0;
}
&:not([zen-right-side='true']) {
&:not([zen-right-side="true"]) {
padding-right: 0;
padding-left: var(--zen-toolbox-padding);
}
@@ -624,10 +617,7 @@
/* --- Pinned Tab Icon Repositioning & Reset Button --- */
/* Reposition icon stack absolutely when tab is pinned (and not essential) */
&[zen-pinned-changed='true']:not([zen-essential])
> .tab-stack
> .tab-content
> .tab-icon-stack {
&[zen-pinned-changed="true"]:not([zen-essential]) > .tab-stack > .tab-content > .tab-icon-stack {
position: absolute;
top: 50%;
transform: translateY(-50%);
@@ -640,11 +630,11 @@
}
}
&[zen-pinned-changed='true']:not([zen-essential]) .tab-reset-pin-button image {
&[zen-pinned-changed="true"]:not([zen-essential]) .tab-reset-pin-button image {
opacity: 0;
}
&[zen-pinned-changed='true']:not([zen-essential]) .tab-reset-pin-button:hover {
&[zen-pinned-changed="true"]:not([zen-essential]) .tab-reset-pin-button:hover {
& ~ .tab-label-container .tab-reset-pin-label {
max-height: 10px;
opacity: 0.6;
@@ -684,13 +674,13 @@
}
}
:root:not([zen-sidebar-expanded='true']) {
:root:not([zen-sidebar-expanded="true"]) {
--tab-min-width: 48px !important;
--zen-toolbox-padding: 6px !important;
--zen-toolbox-max-width: calc(var(--tab-min-width) + var(--zen-toolbox-padding) * 2);
}
#navigator-toolbox:not([zen-sidebar-expanded='true']) {
#navigator-toolbox:not([zen-sidebar-expanded="true"]) {
max-width: var(--zen-toolbox-max-width) !important;
min-width: var(--zen-toolbox-max-width) !important;
padding-bottom: var(--zen-toolbox-padding);
@@ -713,7 +703,7 @@
height: 100%;
}
&:is([open='true'], :hover) .zen-current-workspace-indicator-icon {
&:is([open="true"], :hover) .zen-current-workspace-indicator-icon {
display: none;
}
}
@@ -857,7 +847,7 @@
}
}
:root:not([zen-sidebar-expanded='true']) #zen-sidebar-splitter {
:root:not([zen-sidebar-expanded="true"]) #zen-sidebar-splitter {
display: none !important;
}
@@ -873,7 +863,7 @@
order: 0;
}
:root[zen-right-side='true'] {
:root[zen-right-side="true"] {
& #navigator-toolbox {
order: 10 !important;
}
@@ -885,18 +875,18 @@
#tabbrowser-tabs {
& .tabbrowser-tab {
&[pinned]:not([pending='true']) .tab-close-button {
&[pinned]:not([pending="true"]) .tab-close-button {
display: none !important;
}
&[pinned]:not([pending='true']):not([zen-essential]) {
&[pinned]:not([pending="true"]):not([zen-essential]) {
&:hover .tab-reset-button,
&[visuallyselected] .tab-reset-button {
display: block;
}
}
&:not([zen-pinned-changed='true']) .tab-reset-pin-button {
&:not([zen-pinned-changed="true"]) .tab-reset-pin-button {
display: none;
}
@@ -942,8 +932,7 @@
height: calc(100% - var(--tab-block-margin) * 2);
margin-left: calc(-1 * var(--tab-inline-padding) + var(--tab-block-margin));
margin-right: 8px;
padding: 0 calc(var(--toolbarbutton-inner-padding) - 2px) 0
calc(var(--toolbarbutton-inner-padding) / 4 + var(--tab-inline-padding) - 2px);
padding: 0 calc(var(--toolbarbutton-inner-padding) - 2px) 0 calc(var(--toolbarbutton-inner-padding) / 4 + var(--tab-inline-padding) - 2px);
border-radius: 0;
border-top-left-radius: var(--border-radius-medium);
width: unset;
@@ -960,7 +949,7 @@
}
&::after {
content: '';
content: "";
display: block;
width: 2.5px;
height: 16px;
@@ -1019,11 +1008,11 @@
order: -1;
min-width: unset !important;
:root[zen-sidebar-expanded='true'] & {
:root[zen-sidebar-expanded="true"] & {
--toolbarbutton-inner-padding: var(--zen-toolbar-button-inner-padding) !important;
}
:root[zen-single-toolbar='true'] & {
:root[zen-single-toolbar="true"] & {
--zen-toolbar-height: 36px;
@media (-moz-platform: macos) {
--zen-toolbar-height: 38px;
@@ -1042,7 +1031,7 @@
padding-inline-end: var(--toolbarbutton-outer-padding);
}
:root:not([zen-sidebar-expanded='true']) & toolbarspring {
:root:not([zen-sidebar-expanded="true"]) & toolbarspring {
display: none;
}
}
@@ -1061,7 +1050,7 @@
-moz-user-focus: ignore !important;
}
@media -moz-pref('zen.tabs.show-newtab-vertical') {
@media -moz-pref("zen.tabs.show-newtab-vertical") {
#tabs-newtab-button {
max-height: var(--tab-min-height);
display: flex !important;
@@ -1091,7 +1080,7 @@
--zen-colors-border: var(--zen-colors-tertiary);
}
@media -moz-pref('zen.view.show-newtab-button-top') {
@media -moz-pref("zen.view.show-newtab-button-top") {
order: -1;
}
}
@@ -1119,24 +1108,14 @@
grid-template-columns 0.3s ease-out;
opacity: 1;
--min-essentials-width-wrap: calc(var(--tab-min-height) + 4px);
grid-template-columns: repeat(
auto-fit,
minmax(max(23.7%, var(--min-essentials-width-wrap)), 1fr)
);
&[data-hack-type='1'] {
grid-template-columns: repeat(
auto-fit,
minmax(max(30%, var(--min-essentials-width-wrap)), auto)
);
grid-template-columns: repeat(auto-fit, minmax(max(23.7%, var(--min-essentials-width-wrap)), 1fr));
&[data-hack-type="1"] {
grid-template-columns: repeat(auto-fit, minmax(max(30%, var(--min-essentials-width-wrap)), auto));
}
&[data-hack-type='2'] {
grid-template-columns: repeat(
auto-fit,
minmax(max(23%, var(--min-essentials-width-wrap)), 1fr)
minmax(max(23%, var(--min-essentials-width-wrap)), 1fr)
);
&[data-hack-type="2"] {
grid-template-columns: repeat(auto-fit, minmax(max(23%, var(--min-essentials-width-wrap)), 1fr) minmax(max(23%, var(--min-essentials-width-wrap)), 1fr));
}
&[data-hack-type='3'] {
&[data-hack-type="3"] {
grid-template-columns: repeat(auto-fit, minmax(max(25%, 48px), 1fr));
}
scrollbar-width: thin;
@@ -1147,15 +1126,13 @@
position: absolute;
:root[zen-single-toolbar='true'] &:not(:empty) {
:root[zen-single-toolbar="true"] &:not(:empty) {
padding-top: 6px;
}
&[hidden='true'] {
&[hidden="true"] {
--hidden-essentials-width: calc(var(--zen-sidebar-width) + var(--zen-toolbox-padding));
max-width: var(
--hidden-essentials-width
) !important; /* To still allow essentials to grid the tabs */
max-width: var(--hidden-essentials-width) !important; /* To still allow essentials to grid the tabs */
min-width: var(--hidden-essentials-width) !important;
visibility: hidden;
@@ -1168,7 +1145,7 @@
}
}
.tabbrowser-tab[zen-essential='true'],
.tabbrowser-tab[zen-essential="true"],
#zen-welcome-initial-essentials-browser-sidebar-essentials .tabbrowser-tab {
--toolbarbutton-inner-padding: 0;
max-width: unset;
@@ -1180,7 +1157,7 @@
--tab-selected-bgcolor: light-dark(rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.2));
&:not([visuallyselected], [multiselected='true']) .tab-background {
&:not([visuallyselected], [multiselected="true"]) .tab-background {
background: var(--zen-toolbar-element-bg);
border: none;
}
@@ -1204,10 +1181,10 @@
background: light-dark(rgba(0, 0, 0, 0.1), var(--tab-selected-bgcolor));
}
@media -moz-pref('zen.theme.essentials-favicon-bg') {
@media -moz-pref("zen.theme.essentials-favicon-bg") {
&[visuallyselected] > .tab-stack > .tab-background {
&::after {
content: '';
content: "";
inset: -50%;
filter: blur(20px);
position: absolute;
@@ -1225,24 +1202,12 @@
position: relative;
--zen-essential-bg-margin: 2px;
--zen-essential-tab-selected-bg: light-dark(
rgba(255, 255, 255, 0.85),
color-mix(in srgb, var(--zen-primary-color), rgba(132, 132, 132, 0.85) 40%)
);
--zen-essential-tab-selected-bg-hover: light-dark(
rgba(255, 255, 255, 0.8),
color-mix(in srgb, var(--zen-primary-color), rgba(132, 132, 132, 0.85) 30%)
);
--zen-essential-tab-selected-bg: light-dark(rgba(255, 255, 255, 0.85), color-mix(in srgb, var(--zen-primary-color), rgba(132, 132, 132, 0.85) 40%));
--zen-essential-tab-selected-bg-hover: light-dark(rgba(255, 255, 255, 0.8), color-mix(in srgb, var(--zen-primary-color), rgba(132, 132, 132, 0.85) 30%));
:root[zen-default-theme='true'] & {
--zen-essential-tab-selected-bg: light-dark(
rgba(255, 255, 255, 0.85),
rgba(68, 64, 64, 0.85)
);
--zen-essential-tab-selected-bg-hover: light-dark(
rgba(255, 255, 255, 0.8),
rgba(68, 64, 64, 0.75)
);
:root[zen-default-theme="true"] & {
--zen-essential-tab-selected-bg: light-dark(rgba(255, 255, 255, 0.85), rgba(68, 64, 64, 0.85));
--zen-essential-tab-selected-bg-hover: light-dark(rgba(255, 255, 255, 0.8), rgba(68, 64, 64, 0.75));
}
&::before {
@@ -1252,7 +1217,7 @@
position: absolute;
inset: 0;
z-index: 0;
content: '';
content: "";
transition: background 0.1s ease-in-out;
}
}
@@ -1265,11 +1230,7 @@
#zen-drag-indicator {
--zen-drag-indicator-height: 2px;
--zen-drag-indicator-bg: color-mix(
in srgb,
var(--zen-primary-color) 50%,
light-dark(rgba(0, 0, 0, 0.85), rgba(255, 255, 255, 0.95)) 50%
);
--zen-drag-indicator-bg: color-mix(in srgb, var(--zen-primary-color) 50%, light-dark(rgba(0, 0, 0, 0.85), rgba(255, 255, 255, 0.95)) 50%);
position: fixed;
z-index: 1000;
@@ -1278,7 +1239,7 @@
border-radius: 5px;
&::before {
content: '';
content: "";
position: absolute;
height: calc(2 * var(--zen-drag-indicator-height));
width: calc(2 * var(--zen-drag-indicator-height));
@@ -1287,7 +1248,7 @@
background: transparent;
}
&[orientation='horizontal'] {
&[orientation="horizontal"] {
left: calc(var(--indicator-left) + 2 * var(--zen-drag-indicator-height) + 4px);
width: calc(var(--indicator-width) - 2 * var(--zen-drag-indicator-height) - 4px);
height: var(--zen-drag-indicator-height);
@@ -1303,7 +1264,7 @@
}
}
&[orientation='vertical'] {
&[orientation="vertical"] {
top: calc(var(--indicator-top) + 2 * var(--zen-drag-indicator-height) + 4px);
height: calc(var(--indicator-height) - 2 * var(--zen-drag-indicator-height) - 4px);
width: var(--zen-drag-indicator-height);
@@ -1347,11 +1308,11 @@
&:not(.zen-essentials-container) {
display: flex;
:root[zen-sidebar-expanded='true'] & {
:root[zen-sidebar-expanded="true"] & {
min-width: calc(100% - var(--zen-toolbox-padding) * 2);
}
:root:not([zen-sidebar-expanded='true']) & {
:root:not([zen-sidebar-expanded="true"]) & {
max-width: var(--zen-sidebar-width);
align-items: center;
}
@@ -1363,12 +1324,12 @@
}
}
#tabs-newtab-button:not([in-urlbar='true']) label,
#tabs-newtab-button:not([in-urlbar="true"]) label,
.zen-current-workspace-indicator-name {
opacity: 0.7;
}
@media (-moz-pref('zen.theme.hide-tab-throbber')) {
@media (-moz-pref("zen.theme.hide-tab-throbber")) {
.tab-throbber {
display: none !important;
}

View File

@@ -1,16 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
function goToRightSideTabs(callback) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
await SpecialPowers.pushPrefEnv({
set: [['zen.tabs.vertical.right-side', true]],
set: [["zen.tabs.vertical.right-side", true]],
});
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(async () => {
await callback();
await SpecialPowers.popPrefEnv();
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(() => {
resolve();
}, 1000); // Wait for new layout
@@ -26,20 +29,22 @@ async function testSidebarWidth() {
let hasRan = false;
const ogSize = gNavToolbox.getBoundingClientRect().width;
const onCompactChanged = (event) => {
const onCompactChanged = (_event) => {
if (hasRan) {
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(() => {
gZenCompactModeManager.removeEventListener(onCompactChanged);
resolvePromise();
}, 500);
return;
}
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(() => {
const newSize = gNavToolbox.style.getPropertyValue('--zen-sidebar-width').replace('px', '');
const newSize = gNavToolbox.style.getPropertyValue("--zen-sidebar-width").replace("px", "");
Assert.equal(
newSize,
ogSize,
'The size of the titlebar should be the same as the original size'
"The size of the titlebar should be the same as the original size"
);
hasRan = true;
gZenCompactModeManager.preference = false;
@@ -61,7 +66,7 @@ add_task(async function test_Compact_Mode_Width_Right_Side() {
});
add_task(async function test_Compact_Mode_Hover() {
gNavToolbox.setAttribute('zen-has-hover', true);
gNavToolbox.setAttribute("zen-has-hover", true);
await testSidebarWidth();
gNavToolbox.removeAttribute('zen-has-hover');
gNavToolbox.removeAttribute("zen-has-hover");
});

View File

@@ -1,34 +1,34 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Container_Essentials_Auto_Swithc() {
await gZenWorkspaces.createAndSaveWorkspace('Container Profile 1', undefined, false, 1);
await gZenWorkspaces.createAndSaveWorkspace("Container Profile 1", undefined, false, 1);
const workspaces = await gZenWorkspaces._workspaces();
ok(workspaces.length === 2, 'Two workspaces should exist.');
Assert.strictEqual(workspaces.length, 2, "Two workspaces should exist.");
let newTab = BrowserTestUtils.addTab(gBrowser, 'about:blank', {
let newTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
skipAnimation: true,
userContextId: 1,
});
ok(newTab, 'New tab should be opened.');
ok(newTab, "New tab should be opened.");
gZenPinnedTabManager.addToEssentials(newTab);
ok(
newTab.hasAttribute('zen-essential') && newTab.parentNode.getAttribute('container') == '1',
'New tab should be marked as essential.'
newTab.hasAttribute("zen-essential") && newTab.parentNode.getAttribute("container") == "1",
"New tab should be marked as essential."
);
ok(
gBrowser.tabs.find(
(t) => t.hasAttribute('zen-essential') && t.getAttribute('usercontextid') == 1
(t) => t.hasAttribute("zen-essential") && t.getAttribute("usercontextid") == 1
),
'New tab should be marked as essential.'
"New tab should be marked as essential."
);
const newWorkspaceUUID = gZenWorkspaces.activeWorkspace;
Assert.equal(
gZenWorkspaces.activeWorkspace,
workspaces[1].uuid,
'The new workspace should be active.'
"The new workspace should be active."
);
// Change to the original workspace, there should be no essential tabs

View File

@@ -1,29 +1,29 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Check_Creation() {
await gZenWorkspaces.createAndSaveWorkspace('Container Profile 1', undefined, false, 1);
await gZenWorkspaces.createAndSaveWorkspace("Container Profile 1", undefined, false, 1);
const workspaces = await gZenWorkspaces._workspaces();
ok(workspaces.length === 2, 'Two workspaces should exist.');
Assert.strictEqual(workspaces.length, 2, "Two workspaces should exist.");
await gZenWorkspaces.changeWorkspace(workspaces[1]);
let newTab = BrowserTestUtils.addTab(gBrowser, 'about:blank', {
let newTab = BrowserTestUtils.addTab(gBrowser, "about:blank", {
skipAnimation: true,
userContextId: 1,
});
ok(newTab, 'New tab should be opened.');
ok(newTab, "New tab should be opened.");
gZenPinnedTabManager.addToEssentials(newTab);
ok(
newTab.hasAttribute('zen-essential') && newTab.parentNode.getAttribute('container') == '1',
'New tab should be marked as essential.'
newTab.hasAttribute("zen-essential") && newTab.parentNode.getAttribute("container") == "1",
"New tab should be marked as essential."
);
ok(
gBrowser.tabs.find(
(t) => t.hasAttribute('zen-essential') && t.getAttribute('usercontextid') == 1
(t) => t.hasAttribute("zen-essential") && t.getAttribute("usercontextid") == 1
),
'New tab should be marked as essential.'
"New tab should be marked as essential."
);
const newWorkspaceUUID = gZenWorkspaces.activeWorkspace;
@@ -31,9 +31,9 @@ add_task(async function test_Check_Creation() {
await gZenWorkspaces.changeWorkspace(workspaces[0]);
ok(
!gBrowser.tabs.find(
(t) => t.hasAttribute('zen-essential') && t.getAttribute('usercontextid') == 1
(t) => t.hasAttribute("zen-essential") && t.getAttribute("usercontextid") == 1
),
'No essential tabs should be found in the original workspace.'
"No essential tabs should be found in the original workspace."
);
await gZenWorkspaces.removeWorkspace(newWorkspaceUUID);

View File

@@ -1,21 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Basic_Toggle() {
const folder = await gZenFolders.createFolder([], {
renameFolder: false,
label: 'subfolder',
label: "subfolder",
});
ok(!folder.collapsed, 'Folder should not be collapsed by default');
ok(!folder.collapsed, "Folder should not be collapsed by default");
folder.labelElement.click();
ok(folder.collapsed, 'Folder should be collapsed after clicking on it');
ok(folder.collapsed, "Folder should be collapsed after clicking on it");
folder.labelElement.click();
ok(!folder.collapsed, 'Folder should be expanded after clicking on it again');
ok(!folder.collapsed, "Folder should be expanded after clicking on it again");
await removeFolder(folder);
});

View File

@@ -1,25 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Create_Folder() {
const tab = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab = BrowserTestUtils.addTab(gBrowser, "about:blank");
const folder = await gZenFolders.createFolder([tab], {
renameFolder: false,
label: 'test',
label: "test",
});
ok(folder, 'Folder created successfully');
ok(folder, "Folder created successfully");
Assert.equal(
folder.tabs.length,
2,
'Folder contains the tab and the empty tab created by Zen Folders'
"Folder contains the tab and the empty tab created by Zen Folders"
);
ok(tab.pinned, 'Tab is pinned after folder creation');
Assert.equal(folder.label, 'test', 'Folder label is set correctly');
ok(!folder.collapsed, 'Folder is expanded after creation');
ok(tab.pinned, "Tab is pinned after folder creation");
Assert.equal(folder.label, "test", "Folder label is set correctly");
ok(!folder.collapsed, "Folder is expanded after creation");
await removeFolder(folder);
Assert.equal(folder.tabs.length, 0, 'Folder is empty after deletion');
ok(!folder.parentElement, 'Folder is removed from the DOM');
ok(tab.closing, 'Tab is closing after folder deletion');
Assert.equal(folder.tabs.length, 0, "Folder is empty after deletion");
ok(!folder.parentElement, "Folder is removed from the DOM");
ok(tab.closing, "Tab is closing after folder deletion");
});

View File

@@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Folder_Density() {
const tab = gBrowser.selectedTab;
@@ -11,15 +11,15 @@ add_task(async function test_Folder_Density() {
let tabRect = tab.getBoundingClientRect();
let folderRect = folder.labelElement.parentElement.getBoundingClientRect();
Assert.equal(tabRect.height, folderRect.height, 'Folder height matches tab height');
Assert.equal(tabRect.width, folderRect.width, 'Folder width matches tab width');
Assert.equal(tabRect.height, folderRect.height, "Folder height matches tab height");
Assert.equal(tabRect.width, folderRect.width, "Folder width matches tab width");
gUIDensity.update(gUIDensity.MODE_TOUCH);
tabRect = tab.getBoundingClientRect();
folderRect = folder.getBoundingClientRect();
Assert.equal(tabRect.height, folderRect.height, 'Folder height matches tab height');
Assert.equal(tabRect.width, folderRect.width, 'Folder width matches tab width');
Assert.equal(tabRect.height, folderRect.height, "Folder height matches tab height");
Assert.equal(tabRect.width, folderRect.width, "Folder width matches tab width");
gUIDensity.update();
await removeFolder(folder);

View File

@@ -1,22 +1,20 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Empty_Tab_First() {
const tab = gBrowser.selectedTab;
const [tab1, tab2] = await Promise.all([addTabTo(gBrowser), addTabTo(gBrowser)]);
const folder = await gZenFolders.createFolder([tab1], {
renameFolder: false,
});
Assert.equal(folder.tabs.length, 2, 'Folder should contain the original tab');
ok(folder.tabs[0].hasAttribute('zen-empty-tab'), 'First tab should be an empty tab');
Assert.equal(folder.tabs.length, 2, "Folder should contain the original tab");
ok(folder.tabs[0].hasAttribute("zen-empty-tab"), "First tab should be an empty tab");
folder.appendChild(tab2);
Assert.equal(folder.tabs.length, 3, 'Folder should contain the second tab');
ok(folder.tabs[0].hasAttribute('zen-empty-tab'), 'First tab should be an empty tab');
Assert.equal(folder.tabs.length, 3, "Folder should contain the second tab");
ok(folder.tabs[0].hasAttribute("zen-empty-tab"), "First tab should be an empty tab");
await removeFolder(folder);
});

View File

@@ -1,27 +1,27 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Issue_9885() {
const subfolder = await gZenFolders.createFolder([], {
renameFolder: false,
label: 'subfolder',
label: "subfolder",
});
const parent = await gZenFolders.createFolder([], {
renameFolder: false,
label: 'parent',
label: "parent",
});
parent.tabs[0].after(subfolder);
Assert.equal(parent, subfolder.group, 'Parent folder is set correctly');
Assert.equal(parent, subfolder.group, "Parent folder is set correctly");
ok(!subfolder.collapsed, 'Subfolder should not be collapsed by default');
ok(!parent.collapsed, 'Parent folder should not be collapsed by default');
ok(!subfolder.collapsed, "Subfolder should not be collapsed by default");
ok(!parent.collapsed, "Parent folder should not be collapsed by default");
subfolder.labelElement.click();
ok(subfolder.collapsed, 'Subfolder should be collapsed after clicking on it');
ok(!parent.collapsed, 'Parent folder should be collapsed after clicking on subfolder');
ok(subfolder.collapsed, "Subfolder should be collapsed after clicking on it");
ok(!parent.collapsed, "Parent folder should be collapsed after clicking on subfolder");
await removeFolder(subfolder);
await removeFolder(parent);

View File

@@ -1,40 +1,40 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Issue_9981() {
const selectedTab = gBrowser.selectedTab;
const tab1 = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab2 = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab1 = BrowserTestUtils.addTab(gBrowser, "about:blank");
const tab2 = BrowserTestUtils.addTab(gBrowser, "about:blank");
const folder = await gZenFolders.createFolder([tab1, tab2], {});
gBrowser.selectedTab = tab2;
gBrowser.addRangeToMultiSelectedTabs(tab1, tab2);
ok(tab1.multiselected, 'Tab 1 should be multiselected');
ok(tab2.multiselected, 'Tab 2 should be multiselected');
Assert.equal(gBrowser.multiSelectedTabsCount, 2, 'There should be 2 multiselected tabs');
ok(tab1.multiselected, "Tab 1 should be multiselected");
ok(tab2.multiselected, "Tab 2 should be multiselected");
Assert.equal(gBrowser.multiSelectedTabsCount, 2, "There should be 2 multiselected tabs");
await new Promise((resolve) => setTimeout(resolve, 0));
const collapseEvent = BrowserTestUtils.waitForEvent(window, 'TabGroupCollapse');
const collapseEvent = BrowserTestUtils.waitForEvent(window, "TabGroupCollapse");
EventUtils.synthesizeMouseAtCenter(folder.labelElement, {});
await collapseEvent;
gBrowser.clearMultiSelectedTabs();
gBrowser.selectedTab = selectedTab;
Assert.equal(folder.activeTabs.length, 2, 'Folder should have 2 active tabs');
Assert.equal(folder.activeTabs.length, 2, "Folder should have 2 active tabs");
ok(tab1.hasAttribute('folder-active'), 'Tab 1 should be in the active folder');
ok(tab2.hasAttribute('folder-active'), 'Tab 2 should be in the active folder');
ok(tab1.hasAttribute("folder-active"), "Tab 1 should be in the active folder");
ok(tab2.hasAttribute("folder-active"), "Tab 2 should be in the active folder");
const tab2ResetButton = tab2.querySelector('.tab-reset-button');
tab2ResetButton.style.display = 'flex';
const tab2ResetButton = tab2.querySelector(".tab-reset-button");
tab2ResetButton.style.display = "flex";
EventUtils.synthesizeMouseAtCenter(tab2ResetButton, {});
ok(tab1.hasAttribute('folder-active'), 'Tab 1 should be in the active folder');
ok(!tab2.hasAttribute('folder-active'), 'Tab 2 should not be in the active folder');
ok(tab1.hasAttribute("folder-active"), "Tab 1 should be in the active folder");
ok(!tab2.hasAttribute("folder-active"), "Tab 2 should not be in the active folder");
await removeFolder(folder);
});

View File

@@ -1,21 +1,21 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Issue_9885() {
const subfolder = await gZenFolders.createFolder([], {
renameFolder: false,
label: 'subfolder',
label: "subfolder",
});
const parent = await gZenFolders.createFolder([], {
renameFolder: false,
label: 'parent',
label: "parent",
});
parent.tabs[0].after(subfolder);
Assert.equal(parent.level, 0, 'Parent folder should be at level 0');
Assert.equal(subfolder.level, 1, 'Subfolder should be at level 1');
Assert.equal(parent.level, 0, "Parent folder should be at level 0");
Assert.equal(subfolder.level, 1, "Subfolder should be at level 1");
await removeFolder(parent);
});

View File

@@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
// Keep in sync with the default value for `zen.folders.max-subfolders`
const TEST_MAX_FOLDERS = 5;
@@ -11,13 +11,16 @@ add_task(async function test_Max_Subfolders() {
renameFolder: false,
});
const subfolderItem = document.getElementById('context_zenFolderNewSubfolder');
debugger;
const subfolderItem = document.getElementById("context_zenFolderNewSubfolder");
let currentFolder = folder;
for (let i = 1; i < TEST_MAX_FOLDERS; i++) {
await openFolderContextMenu(currentFolder);
ok(subfolderItem.getAttribute('disabled') !== 'true', `Subfolder item should be enabled`);
const folderCreateEvent = BrowserTestUtils.waitForEvent(window, 'TabGroupCreate');
Assert.notStrictEqual(
subfolderItem.getAttribute("disabled"),
"true",
`Subfolder item should be enabled`
);
const folderCreateEvent = BrowserTestUtils.waitForEvent(window, "TabGroupCreate");
EventUtils.synthesizeMouseAtCenter(subfolderItem, {});
await folderCreateEvent;
const items = currentFolder.allItems;
@@ -28,12 +31,12 @@ add_task(async function test_Max_Subfolders() {
await openFolderContextMenu(currentFolder);
Assert.equal(
subfolderItem.getAttribute('disabled'),
'true',
subfolderItem.getAttribute("disabled"),
"true",
`Subfolder item should be disabled after reaching max subfolders`
);
document.getElementById('zenFolderActions').hidePopup();
document.getElementById("zenFolderActions").hidePopup();
await removeFolder(folder);
});

View File

@@ -1,25 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Folder_Multiselected_Tabs() {
const selectedTab = gBrowser.selectedTab;
const tab1 = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab2 = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab1 = BrowserTestUtils.addTab(gBrowser, "about:blank");
const tab2 = BrowserTestUtils.addTab(gBrowser, "about:blank");
const folder = await gZenFolders.createFolder([tab1], {});
gBrowser.addRangeToMultiSelectedTabs(tab1, tab2);
ok(tab1.multiselected, 'Tab 1 should be multiselected');
ok(tab2.multiselected, 'Tab 2 should be multiselected');
Assert.greater(gBrowser.multiSelectedTabsCount, 1, 'There should be 2 multiselected tabs');
ok(tab1.multiselected, "Tab 1 should be multiselected");
ok(tab2.multiselected, "Tab 2 should be multiselected");
Assert.greater(gBrowser.multiSelectedTabsCount, 1, "There should be 2 multiselected tabs");
const collapseEvent = BrowserTestUtils.waitForEvent(window, 'TabGroupCollapse');
const collapseEvent = BrowserTestUtils.waitForEvent(window, "TabGroupCollapse");
folder.collapsed = true;
await collapseEvent;
ok(tab2.multiselected, 'Tab 2 should not be multiselected');
Assert.equal(gBrowser.multiSelectedTabsCount, 3, 'There should be 3 multiselected tabs');
ok(tab2.multiselected, "Tab 2 should not be multiselected");
Assert.equal(gBrowser.multiSelectedTabsCount, 3, "There should be 3 multiselected tabs");
for (const t of [tab1, tab2]) {
BrowserTestUtils.removeTab(t);

View File

@@ -1,20 +1,20 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Duplicate_Tab_Inside_Folder() {
await SpecialPowers.pushPrefEnv({
set: [['zen.folders.owned-tabs-in-folder', true]],
set: [["zen.folders.owned-tabs-in-folder", true]],
});
const selectedTab = gBrowser.selectedTab;
const tab = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab = BrowserTestUtils.addTab(gBrowser, "about:blank");
const folder = await gZenFolders.createFolder([tab], {
renameFolder: false,
});
gBrowser.selectedTab = tab;
const triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
gBrowser.addTab('https://example.com', {
gBrowser.addTab("https://example.com", {
tabIndex: undefined,
relatedToCurrent: true,
ownerTab: tab,
@@ -24,13 +24,14 @@ add_task(async function test_Duplicate_Tab_Inside_Folder() {
Assert.equal(
folder.tabs.length,
3,
'Folder contains the original tab and the two duplicated tabs'
"Folder contains the original tab and the two duplicated tabs"
);
/* eslint-disable mozilla/no-arbitrary-setTimeout */
await new Promise((resolve) => setTimeout(resolve, 100));
for (const t of folder.tabs) {
ok(t.pinned, 'All tabs in the folder should be pinned');
ok(t.pinned, "All tabs in the folder should be pinned");
}
gBrowser.selectedTab = selectedTab;
@@ -40,16 +41,16 @@ add_task(async function test_Duplicate_Tab_Inside_Folder() {
add_task(async function test_Duplicate_Tab_Inside_Folder_Unpinned() {
await SpecialPowers.pushPrefEnv({
set: [['zen.folders.owned-tabs-in-folder', false]],
set: [["zen.folders.owned-tabs-in-folder", false]],
});
const selectedTab = gBrowser.selectedTab;
const tab = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab = BrowserTestUtils.addTab(gBrowser, "about:blank");
const folder = await gZenFolders.createFolder([tab], {
renameFolder: false,
});
gBrowser.selectedTab = tab;
const triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
let newTab = gBrowser.addTab('https://example.com', {
let newTab = gBrowser.addTab("https://example.com", {
tabIndex: undefined,
relatedToCurrent: true,
ownerTab: tab,
@@ -59,10 +60,10 @@ add_task(async function test_Duplicate_Tab_Inside_Folder_Unpinned() {
Assert.equal(
folder.tabs.length,
2,
'Folder contains the original tab and the two duplicated tabs'
"Folder contains the original tab and the two duplicated tabs"
);
ok(!newTab.group, 'New tab should not be grouped');
ok(!newTab.group, "New tab should not be grouped");
gBrowser.selectedTab = selectedTab;
BrowserTestUtils.removeTab(newTab);

View File

@@ -1,40 +1,41 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Issue_() {
const selectedTab = gBrowser.selectedTab;
const tab1 = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab2 = BrowserTestUtils.addTab(gBrowser, 'about:blank');
const tab1 = BrowserTestUtils.addTab(gBrowser, "about:blank");
const tab2 = BrowserTestUtils.addTab(gBrowser, "about:blank");
const folder = await gZenFolders.createFolder([tab1, tab2], {});
gBrowser.selectedTab = tab2;
gBrowser.addRangeToMultiSelectedTabs(tab1, tab2);
ok(tab1.multiselected, 'Tab 1 should be multiselected');
ok(tab2.multiselected, 'Tab 2 should be multiselected');
Assert.equal(gBrowser.multiSelectedTabsCount, 2, 'There should be 2 multiselected tabs');
ok(tab1.multiselected, "Tab 1 should be multiselected");
ok(tab2.multiselected, "Tab 2 should be multiselected");
Assert.equal(gBrowser.multiSelectedTabsCount, 2, "There should be 2 multiselected tabs");
await new Promise((resolve) => setTimeout(resolve, 0));
const collapseEvent = BrowserTestUtils.waitForEvent(window, 'TabGroupCollapse');
const collapseEvent = BrowserTestUtils.waitForEvent(window, "TabGroupCollapse");
EventUtils.synthesizeMouseAtCenter(folder.labelElement, {});
await collapseEvent;
gBrowser.clearMultiSelectedTabs();
gBrowser.selectedTab = selectedTab;
Assert.equal(folder.activeTabs.length, 2, 'Folder should have 2 active tabs');
Assert.equal(folder.activeTabs.length, 2, "Folder should have 2 active tabs");
ok(tab1.hasAttribute('folder-active'), 'Tab 1 should be in the active folder');
ok(tab2.hasAttribute('folder-active'), 'Tab 2 should be in the active folder');
ok(tab1.hasAttribute("folder-active"), "Tab 1 should be in the active folder");
ok(tab2.hasAttribute("folder-active"), "Tab 2 should be in the active folder");
EventUtils.synthesizeMouseAtCenter(folder.resetButton, {});
await new Promise((resolve) =>
/* eslint-disable mozilla/no-arbitrary-setTimeout */
setTimeout(() => {
ok(!tab1.hasAttribute('folder-active'), 'Tab 1 should not be in the active folder');
ok(!tab2.hasAttribute('folder-active'), 'Tab 2 should not be in the active folder');
ok(!tab1.hasAttribute("folder-active"), "Tab 1 should not be in the active folder");
ok(!tab2.hasAttribute("folder-active"), "Tab 2 should not be in the active folder");
resolve();
}, 500)
);

View File

@@ -1,28 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Create_Folder() {
const tab = BrowserTestUtils.addTab(gBrowser, 'data:text/html,tab1');
const tab2 = BrowserTestUtils.addTab(gBrowser, 'data:text/html,tab2');
const tab = BrowserTestUtils.addTab(gBrowser, "data:text/html,tab1");
const tab2 = BrowserTestUtils.addTab(gBrowser, "data:text/html,tab2");
const subfolder = await gZenFolders.createFolder([tab], {
renameFolder: false,
label: 'subfolder',
label: "subfolder",
});
const parent = await gZenFolders.createFolder([tab2], {
renameFolder: false,
label: 'parent',
label: "parent",
});
parent.tabs[0].after(subfolder);
Assert.equal(parent, subfolder.group, 'Parent folder is set correctly');
Assert.equal(parent, subfolder.group, "Parent folder is set correctly");
Assert.equal(
subfolder.tabs.length,
2,
'Subfolder contains the tab and the empty tab created by Zen Folders'
"Subfolder contains the tab and the empty tab created by Zen Folders"
);
Assert.equal(parent.tabs.length, 4, 'Parent folder contains the subfolder');
Assert.equal(parent.tabs.length, 4, "Parent folder contains the subfolder");
await removeFolder(subfolder);
await removeFolder(parent);
});

View File

@@ -1,47 +1,47 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Not_Visible_Collapsed() {
const tab = BrowserTestUtils.addTab(gBrowser, 'data:text/html,tab1');
const tab = BrowserTestUtils.addTab(gBrowser, "data:text/html,tab1");
const folder = await gZenFolders.createFolder([tab]);
Assert.equal(
folder.tabs.length,
2,
'Subfolder contains the tab and the empty tab created by Zen Folders'
"Subfolder contains the tab and the empty tab created by Zen Folders"
);
ok(tab.visible, 'Tab is visible in the folder');
ok(tab.visible, "Tab is visible in the folder");
folder.collapsed = true;
ok(!tab.visible, 'Tab is not visible in the folder when collapsed');
ok(!tab.visible, "Tab is not visible in the folder when collapsed");
await removeFolder(folder);
});
add_task(async function test_Visible_Selected() {
const originalTab = gBrowser.selectedTab;
const tab = BrowserTestUtils.addTab(gBrowser, 'data:text/html,tab1');
const tab = BrowserTestUtils.addTab(gBrowser, "data:text/html,tab1");
const folder = await gZenFolders.createFolder([tab]);
Assert.equal(
folder.tabs.length,
2,
'Subfolder contains the tab and the empty tab created by Zen Folders'
"Subfolder contains the tab and the empty tab created by Zen Folders"
);
ok(tab.visible, 'Tab is visible in the folder');
ok(tab.visible, "Tab is visible in the folder");
gBrowser.selectedTab = tab;
folder.collapsed = true;
ok(tab.visible, 'Tab is visible in the folder when collapsed');
ok(tab.hasAttribute('folder-active'), 'Tab is marked as active in the folder when selected');
ok(tab.visible, "Tab is visible in the folder when collapsed");
ok(tab.hasAttribute("folder-active"), "Tab is marked as active in the folder when selected");
ok(
tab.group.hasAttribute('has-active'),
'Tab group is marked as active when the tab is selected'
tab.group.hasAttribute("has-active"),
"Tab group is marked as active when the tab is selected"
);
Assert.deepEqual(
tab.group.activeTabs,
[tab],
'Tab is included in the active tabs of the group when selected'
"Tab is included in the active tabs of the group when selected"
);
gBrowser.selectedTab = originalTab;
@@ -50,28 +50,28 @@ add_task(async function test_Visible_Selected() {
add_task(async function test_Visible_Not_Selected() {
const originalTab = gBrowser.selectedTab;
const tab = BrowserTestUtils.addTab(gBrowser, 'data:text/html,tab1');
const tab = BrowserTestUtils.addTab(gBrowser, "data:text/html,tab1");
const folder = await gZenFolders.createFolder([tab]);
Assert.equal(
folder.tabs.length,
2,
'Subfolder contains the tab and the empty tab created by Zen Folders'
"Subfolder contains the tab and the empty tab created by Zen Folders"
);
ok(tab.visible, 'Tab is visible in the folder');
ok(tab.visible, "Tab is visible in the folder");
gBrowser.selectedTab = tab;
folder.collapsed = true;
gBrowser.selectedTab = originalTab;
ok(tab.visible, 'Tab is visible in the folder when collapsed');
ok(tab.hasAttribute('folder-active'), 'Tab is marked as active in the folder when selected');
ok(tab.visible, "Tab is visible in the folder when collapsed");
ok(tab.hasAttribute("folder-active"), "Tab is marked as active in the folder when selected");
ok(
tab.group.hasAttribute('has-active'),
'Tab group is marked as active when the tab is selected'
tab.group.hasAttribute("has-active"),
"Tab group is marked as active when the tab is selected"
);
Assert.deepEqual(
tab.group.activeTabs,
[tab],
'Tab is included in the active tabs of the group when selected'
"Tab is included in the active tabs of the group when selected"
);
await removeFolder(folder);

View File

@@ -1,25 +1,27 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
async function removeFolder(folder) {
if (!folder) return;
const removeEvent = BrowserTestUtils.waitForEvent(folder, 'TabGroupRemoved');
if (!folder) {
return;
}
const removeEvent = BrowserTestUtils.waitForEvent(folder, "TabGroupRemoved");
folder.delete();
await removeEvent;
}
async function openFolderContextMenu(folder) {
const popup = document.getElementById('zenFolderActions');
let menuEvent = BrowserTestUtils.waitForEvent(popup, 'popupshown');
const popup = document.getElementById("zenFolderActions");
let menuEvent = BrowserTestUtils.waitForEvent(popup, "popupshown");
EventUtils.synthesizeMouseAtCenter(folder.labelElement, {
type: 'contextmenu',
type: "contextmenu",
});
await menuEvent;
}
async function addTabTo(targetBrowser, url = 'http://mochi.test:8888/', params = {}) {
async function addTabTo(targetBrowser, url = "http://mochi.test:8888/", params = {}) {
params.skipAnimation = true;
const tab = BrowserTestUtils.addTab(targetBrowser, url, params);
const browser = targetBrowser.getBrowserForTab(tab);

View File

@@ -1,13 +1,13 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Glance_Basic_Open() {
await openGlanceOnTab(async (glanceTab) => {
ok(
glanceTab.hasAttribute('zen-glance-tab'),
'The glance tab should have the zen-glance-tab attribute'
glanceTab.hasAttribute("zen-glance-tab"),
"The glance tab should have the zen-glance-tab attribute"
);
});
});

View File

@@ -1,24 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Glance_Basic_Close() {
const currentTab = gBrowser.selectedTab;
await openGlanceOnTab(async (glanceTab) => {
ok(
currentTab.hasAttribute('glance-id'),
'The glance tab should have the zen-glance-tab attribute'
currentTab.hasAttribute("glance-id"),
"The glance tab should have the zen-glance-tab attribute"
);
await BrowserTestUtils.removeTab(glanceTab);
await new Promise((resolve) => {
/* eslint-disable mozilla/no-arbitrary-setTimeout */
setTimeout(() => {
resolve();
}, 1000);
});
ok(
!currentTab.hasAttribute('glance-id'),
'The glance tab should not have the zen-glance-tab attribute'
!currentTab.hasAttribute("glance-id"),
"The glance tab should not have the zen-glance-tab attribute"
);
await BrowserTestUtils.removeTab(glanceTab);
}, false);

View File

@@ -1,13 +1,13 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
async function openAndCloseGlance() {
await openGlanceOnTab(async (glanceTab) => {
ok(
glanceTab.hasAttribute('zen-glance-tab'),
'The glance tab should have the zen-glance-tab attribute'
glanceTab.hasAttribute("zen-glance-tab"),
"The glance tab should have the zen-glance-tab attribute"
);
});
}
@@ -15,20 +15,20 @@ async function openAndCloseGlance() {
add_task(async function test_Glance_Close_No_Tabs() {
const currentTab = gBrowser.selectedTab;
await openAndCloseGlance();
Assert.equal(gBrowser.selectedTab, currentTab, 'The original tab should be selected');
ok(currentTab.selected, 'The original tab should be visually selected');
Assert.equal(gBrowser.selectedTab, currentTab, "The original tab should be selected");
ok(currentTab.selected, "The original tab should be visually selected");
});
add_task(async function test_Glance_Close_With_Next_Tab() {
const originalTab = gBrowser.selectedTab;
await BrowserTestUtils.withNewTab(
{ url: 'http://example.com', gBrowser, waitForLoad: false },
{ url: "https://example.com", gBrowser, waitForLoad: false },
async function () {
const selectedTab = gBrowser.selectedTab;
Assert.notEqual(selectedTab, originalTab, 'A new tab should be selected');
Assert.notEqual(selectedTab, originalTab, "A new tab should be selected");
await openAndCloseGlance();
Assert.equal(gBrowser.selectedTab, selectedTab, 'The new tab should still be selected');
ok(selectedTab.selected, 'The new tab should be visually selected');
Assert.equal(gBrowser.selectedTab, selectedTab, "The new tab should still be selected");
ok(selectedTab.selected, "The new tab should be visually selected");
gBrowser.selectedTab = originalTab;
}

View File

@@ -1,24 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Glance_Basic_Open() {
const selectedTab = gBrowser.selectedTab;
await openGlanceOnTab(async (glanceTab) => {
await gZenGlanceManager.fullyOpenGlance();
ok(
!glanceTab.hasAttribute('zen-glance-tab'),
'The glance tab should not have the zen-glance-tab attribute'
!glanceTab.hasAttribute("zen-glance-tab"),
"The glance tab should not have the zen-glance-tab attribute"
);
ok(
gBrowser.tabs.filter((tab) => tab.hasAttribute('zen-glance-tab')).length === 0,
'There should be no zen-glance-tab attribute on any tab'
Assert.strictEqual(
gBrowser.tabs.filter((tab) => tab.hasAttribute("zen-glance-tab")).length,
0,
"There should be no zen-glance-tab attribute on any tab"
);
Assert.greater(
glanceTab._tPos,
selectedTab._tPos,
'The glance tab should be on the right of the selected tab'
"The glance tab should be on the right of the selected tab"
);
BrowserTestUtils.removeTab(glanceTab);
}, false);
@@ -27,7 +28,7 @@ add_task(async function test_Glance_Basic_Open() {
add_task(async function test_Glance_Open_Sibling() {
const tabsToRemove = [];
for (let i = 0; i < 5; i++) {
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, 'https://example.com/', true);
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "https://example.com/", true);
tabsToRemove.push(gBrowser.selectedTab);
}
@@ -39,7 +40,7 @@ add_task(async function test_Glance_Open_Sibling() {
Assert.equal(
glanceTab._tPos,
selectedTab._tPos + 1,
'The glance tab should be on the right of the selected tab'
"The glance tab should be on the right of the selected tab"
);
BrowserTestUtils.removeTab(glanceTab);
}, false);
@@ -52,7 +53,7 @@ add_task(async function test_Glance_Open_Sibling() {
add_task(async function test_Glance_Basic_Open() {
const tabsToRemove = [];
for (let i = 0; i < 3; i++) {
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, 'https://example.com/', true);
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "https://example.com/", true);
gBrowser.pinTab(gBrowser.selectedTab);
tabsToRemove.push(gBrowser.selectedTab);
}
@@ -64,7 +65,7 @@ add_task(async function test_Glance_Basic_Open() {
Assert.equal(
glanceTab,
gBrowser.visibleTabs.find((tab) => !tab.pinned),
'The glance tab should be the first normal tab (Ignoring empty tabs)'
"The glance tab should be the first normal tab (Ignoring empty tabs)"
);
BrowserTestUtils.removeTab(glanceTab);
}, false);
@@ -75,17 +76,18 @@ add_task(async function test_Glance_Basic_Open() {
});
add_task(async function test_Glance_New_From_essential() {
ok(true, 'todo:');
ok(true, "todo:");
return; // TODO: Fix this test, it currently fails
await BrowserTestUtils.withNewTab({ gBrowser, url: 'https://example.com/' }, async (browser) => {
/* eslint-disable no-unreachable, no-unused-vars */
await BrowserTestUtils.withNewTab({ gBrowser, url: "https://example.com/" }, async (browser) => {
const selectedTab = gBrowser.selectedTab;
gZenPinnedTabManager.addToEssentials(selectedTab);
await openGlanceOnTab(async (glanceTab) => {
await gZenGlanceManager.fullyOpenGlance();
ok(!glanceTab.pinned, 'The glance tab should not be pinned');
ok(!glanceTab.pinned, "The glance tab should not be pinned");
ok(
!glanceTab.parentNode.hasAttribute('container'),
'The glance tab should not be in an essentials container'
!glanceTab.parentNode.hasAttribute("container"),
"The glance tab should not be in an essentials container"
);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await BrowserTestUtils.removeTab(glanceTab);

View File

@@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Glance_Next_Tab() {
const tabToCheck = gBrowser.selectedTab;
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, 'https://example.com/', true, {
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "https://example.com/", true, {
skipAnimation: true,
});
await openGlanceOnTab(async (glanceTab) => {
@@ -14,7 +14,7 @@ add_task(async function test_Glance_Next_Tab() {
gBrowser.selectedTab = glanceTab;
await new Promise((resolve) => {
setTimeout(() => {
Assert.equal(nextTab, tabToCheck, 'Next glance tab should equal');
Assert.equal(nextTab, tabToCheck, "Next glance tab should equal");
resolve();
});
});

View File

@@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Glance_Prev_Tab() {
await openGlanceOnTab(async (glanceTab) => {
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, 'https://example.com/', true, {
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "https://example.com/", true, {
skipAnimation: true,
});
const tabToCheck = gBrowser.selectedTab;
@@ -15,7 +15,7 @@ add_task(async function test_Glance_Prev_Tab() {
gBrowser.selectedTab = glanceTab;
await new Promise((resolve) => {
setTimeout(() => {
Assert.equal(prevTab, tabToCheck, 'Previous glance tab should equal');
Assert.equal(prevTab, tabToCheck, "Previous glance tab should equal");
resolve();
});
});

View File

@@ -1,15 +1,15 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Glance_Select_Parent() {
await openGlanceOnTab(async (glanceTab) => {
ok(
glanceTab.hasAttribute('zen-glance-tab'),
'The glance tab should have the zen-glance-tab attribute'
glanceTab.hasAttribute("zen-glance-tab"),
"The glance tab should have the zen-glance-tab attribute"
);
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, 'https://example.com/', true, {
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "https://example.com/", true, {
skipAnimation: true,
});
const tabToRemove = gBrowser.selectedTab;
@@ -17,7 +17,7 @@ add_task(async function test_Glance_Select_Parent() {
await BrowserTestUtils.waitForCondition(() => {
return glanceTab.selected;
});
ok(true, 'The glance tab should be selected');
ok(true, "The glance tab should be selected");
await BrowserTestUtils.removeTab(tabToRemove);
});
});

View File

@@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { openGlanceOnTab: internalGlanceHandle } = ChromeUtils.importESModule(
'resource://testing-common/GlanceTestUtils.sys.mjs'
"resource://testing-common/GlanceTestUtils.sys.mjs"
);
function openGlanceOnTab(callback, close = true) {

View File

@@ -601,6 +601,7 @@ class ReportBrokenSiteHelper {
}
}
class MenuHelper {
menuDescription = undefined;
@@ -696,6 +697,7 @@ class MenuHelper {
}
}
class AppMenuHelper extends MenuHelper {
menuDescription = "AppMenu";
@@ -718,6 +720,7 @@ class AppMenuHelper extends MenuHelper {
}
}
class HelpMenuHelper extends MenuHelper {
menuDescription = "Help Menu";
@@ -786,6 +789,7 @@ class HelpMenuHelper extends MenuHelper {
}
}
class ProtectionsPanelHelper extends MenuHelper {
menuDescription = "Protections Panel";

View File

@@ -15,6 +15,7 @@ Services.scriptloader.loadSubScript(
this
);
// eslint-disable-next-line complexity
async function reformatExpectedWebCompatInfo(tab, overrides) {
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
const snapshot = await Troubleshoot.snapshot();

View File

@@ -11,7 +11,7 @@ add_task(async function testMalware() {
await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
const url = "http://www.itisatrap.org/firefox/its-an-attack.html";
const url = "https://www.itisatrap.org/firefox/its-an-attack.html";
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url);
await BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
@@ -28,7 +28,7 @@ add_task(async function testUnwanted() {
Services.prefs.setBoolPref("browser.safebrowsing.allowOverride", false);
// Now launch the unwanted software test
const url = "http://www.itisatrap.org/firefox/unwanted.html";
const url = "https://www.itisatrap.org/firefox/unwanted.html";
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url);
await BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
@@ -49,7 +49,7 @@ add_task(async function testPhishing() {
Services.prefs.setBoolPref("browser.safebrowsing.allowOverride", true);
// Now launch the phishing test
const url = "http://www.itisatrap.org/firefox/its-a-trap.html";
const url = "https://www.itisatrap.org/firefox/its-a-trap.html";
BrowserTestUtils.startLoadingURIString(gBrowser.selectedBrowser, url);
await BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,

View File

@@ -4,8 +4,8 @@ menu items.
Mac makes this astonishingly painful to test since their help menu is special magic,
but we can at least test it on the other platforms.*/
const NORMAL_PAGE = "http://example.com";
const PHISH_PAGE = "http://www.itisatrap.org/firefox/its-a-trap.html";
const NORMAL_PAGE = "https://example.com";
const PHISH_PAGE = "https://www.itisatrap.org/firefox/its-a-trap.html";
/**
* Opens a new tab and browses to some URL, tests for the existence
@@ -13,14 +13,13 @@ const PHISH_PAGE = "http://www.itisatrap.org/firefox/its-a-trap.html";
* the state of the menu once opened. This function will take care of
* opening and closing the menu.
*
* @param url (string)
* The URL to browse the tab to.
* @param testFn (function)
* @param {string} url The URL to browse the tab to.
* @param {Function} testFn
* The function to run once the menu has been opened. This
* function will be passed the "reportMenu" and "errorMenu"
* DOM nodes as arguments, in that order. This function
* should not yield anything.
* @returns Promise
* @returns {Promise} Promise that resolves when the test is complete
*/
function check_menu_at_page(url, testFn) {
return BrowserTestUtils.withNewTab(

View File

@@ -1,7 +1,7 @@
/* Ensure that hostnames in the whitelisted pref are not blocked. */
const PREF_WHITELISTED_HOSTNAMES = "urlclassifier.skipHostnames";
const TEST_PAGE = "http://www.itisatrap.org/firefox/its-an-attack.html";
const TEST_PAGE = "https://www.itisatrap.org/firefox/its-an-attack.html";
var tabbrowser = null;
registerCleanupFunction(function () {

View File

@@ -6,15 +6,10 @@ const PHISH_URL = "https://www.itisatrap.org/firefox/its-a-trap.html";
* Waits for a load (or custom) event to finish in a given tab. If provided
* load an uri into the tab.
*
* @param tab
* The tab to load into.
* @param [optional] url
* The url to load, or the current url.
* @param [optional] event
* The load event type to wait for. Defaults to "load".
* @return {Promise} resolved when the event is handled.
* @resolves to the received event
* @rejects if a valid load event is not received within a meaningful interval
* @param {MozTabbrowserTab} tab The tab to load into.
* @param {string} [url] The url to load, or the current url.
* @param {string} [eventType] The load event type to wait for. Defaults to "load".
* @returns {Promise<Event>} Promise resolved when the event is handled.
*/
function promiseTabLoadEvent(tab, url, eventType = "load") {
info(`Wait tab event: ${eventType}`);

View File

@@ -36,5 +36,6 @@ add_task(async function test_prefsOpen() {
);
shellSvc.showSecurityPreferences("Privacy_AllFiles");
// eslint-disable-next-line no-undef
equal(killSystemPreferences(), 0, "Ensure System Preferences was started");
});

View File

@@ -2,6 +2,7 @@ function check(aBrowser, aElementName, aBarred, aType) {
return SpecialPowers.spawn(
aBrowser,
[[aElementName, aBarred, aType]],
// eslint-disable-next-line no-shadow
async function ([aElementName, aBarred, aType]) {
let e = content.document.createElement(aElementName);
let contentElement = content.document.getElementById("content");
@@ -55,6 +56,7 @@ function todo_check(aBrowser, aElementName, aBarred) {
return SpecialPowers.spawn(
aBrowser,
[[aElementName, aBarred]],
// eslint-disable-next-line no-shadow
async function ([aElementName]) {
let e = content.document.createElement(aElementName);
let contentElement = content.document.getElementById("content");
@@ -63,6 +65,7 @@ function todo_check(aBrowser, aElementName, aBarred) {
let caught = false;
try {
e.setCustomValidity("foo");
// eslint-disable-next-line no-shadow
} catch (e) {
caught = true;
}

View File

@@ -42,6 +42,7 @@ async function do_test(test) {
);
info("creating input field");
// eslint-disable-next-line no-shadow
await SpecialPowers.spawn(tab.linkedBrowser, [test], async function (test) {
let doc = content.document;
let input = doc.createElement("input");

View File

@@ -1,14 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
const { TabStateFlusher } = ChromeUtils.importESModule(
'resource:///modules/sessionstore/TabStateFlusher.sys.mjs'
"resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
);
async function makeNewEmptyTab() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, 'about:blank');
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
gBrowser.selectedTab = tab;
return tab;
}
@@ -17,20 +17,20 @@ add_task(async function test_Restore_Pinned_Tab() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: 'https://example.com/',
url: "https://example.com/",
},
async function (browser) {
let tab = gBrowser.getTabForBrowser(browser);
gBrowser.pinTab(tab);
ok(tab.pinned, 'The tab should be pinned after being created');
ok(tab.pinned, "The tab should be pinned after being created");
await BrowserTestUtils.removeTab(tab);
await TabStateFlusher.flushWindow(window);
SessionWindowUI.restoreLastClosedTabOrWindowOrSession(window);
tab = gBrowser.selectedTab;
ok(tab.pinned, 'The tab should be pinned after restore');
ok(tab.pinned, "The tab should be pinned after restore");
ok(
tab.parentElement.closest('.zen-workspace-pinned-tabs-section'),
'The tab should be in the pinned tabs section after restore'
tab.parentElement.closest(".zen-workspace-pinned-tabs-section"),
"The tab should be in the pinned tabs section after restore"
);
await makeNewEmptyTab();
await BrowserTestUtils.removeTab(tab);
@@ -42,23 +42,23 @@ add_task(async function test_Restore_Essential_Tab() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: 'https://example.com/',
url: "https://example.com/",
},
async function (browser) {
let tab = gBrowser.getTabForBrowser(browser);
gZenPinnedTabManager.addToEssentials(tab);
ok(
tab.hasAttribute('zen-essential'),
'The tab should be marked as essential after being created'
tab.hasAttribute("zen-essential"),
"The tab should be marked as essential after being created"
);
await BrowserTestUtils.removeTab(tab);
await TabStateFlusher.flushWindow(window);
SessionWindowUI.restoreLastClosedTabOrWindowOrSession(window);
tab = gBrowser.selectedTab;
ok(tab.hasAttribute('zen-essential'), 'The tab should be marked as essential after restore');
ok(tab.hasAttribute("zen-essential"), "The tab should be marked as essential after restore");
ok(
tab.parentElement.closest('.zen-essentials-container'),
'The tab should be in the essentials tabs section after restore'
tab.parentElement.closest(".zen-essentials-container"),
"The tab should be in the essentials tabs section after restore"
);
await BrowserTestUtils.removeTab(tab);
}

View File

@@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Changed_Pinned() {
let resolvePromise;
@@ -9,18 +9,18 @@ add_task(async function test_Changed_Pinned() {
resolvePromise = resolve;
});
await BrowserTestUtils.withNewTab({ gBrowser, url: 'https://example.com/1' }, async (browser) => {
await BrowserTestUtils.withNewTab({ gBrowser, url: "https://example.com/1" }, async (browser) => {
const tab = gBrowser.getTabForBrowser(browser);
gBrowser.pinTab(tab);
ok(tab.pinned, 'The tab should be pinned after calling gBrowser.pinTab()');
ok(tab.pinned, "The tab should be pinned after calling gBrowser.pinTab()");
BrowserTestUtils.startLoadingURIString(browser, 'https://example.com/2');
await BrowserTestUtils.browserLoaded(browser, false, 'https://example.com/2');
BrowserTestUtils.startLoadingURIString(browser, "https://example.com/2");
await BrowserTestUtils.browserLoaded(browser, false, "https://example.com/2");
setTimeout(() => {
ok(
tab.hasAttribute('zen-pinned-changed'),
'The tab should have a zen-pinned-changed attribute after being pinned'
tab.hasAttribute("zen-pinned-changed"),
"The tab should have a zen-pinned-changed attribute after being pinned"
);
resolvePromise();
}, 0);

View File

@@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Unload_NoReset_Pinned() {
await SpecialPowers.pushPrefEnv({
set: [['zen.pinned-tab-manager.close-shortcut-behavior', 'close']],
set: [["zen.pinned-tab-manager.close-shortcut-behavior", "close"]],
});
let resolvePromise;
@@ -13,13 +13,14 @@ add_task(async function test_Unload_NoReset_Pinned() {
resolvePromise = resolve;
});
await BrowserTestUtils.withNewTab({ gBrowser, url: 'https://example.com/1' }, async (browser) => {
await BrowserTestUtils.withNewTab({ gBrowser, url: "https://example.com/1" }, async (browser) => {
const tab = gBrowser.getTabForBrowser(browser);
gBrowser.pinTab(tab);
document.getElementById('cmd_close').doCommand();
document.getElementById("cmd_close").doCommand();
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(() => {
ok(tab.closing, 'The tab should be closing after being closed');
ok(tab.closing, "The tab should be closing after being closed");
resolvePromise();
}, 100);
await promise;

View File

@@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_Create_Pinned() {
let resolvePromise;
@@ -9,24 +9,20 @@ add_task(async function test_Create_Pinned() {
resolvePromise = resolve;
});
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, 'https://example.com/', true);
await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "https://example.com/", true);
const newTab = gBrowser.selectedTab;
gBrowser.pinTab(newTab);
ok(newTab.pinned, 'The tab should be pinned after calling gBrowser.pinTab()');
ok(newTab.pinned, "The tab should be pinned after calling gBrowser.pinTab()");
try {
const pinObject = newTab.__zenPinnedInitialState;
ok(pinObject, 'The pin object should exist in the ZenPinnedTabsStorage');
Assert.equal(
pinObject.entry.url,
'https://example.com/',
'The pin object should have the correct URL'
);
} catch (error) {
ok(false, 'Error while checking the pin object in ZenPinnedTabsStorage: ' + error);
}
const pinObject = newTab._zenPinnedInitialState;
ok(pinObject, "The pin object should be created in the tab's _zenPinnedInitialState");
Assert.equal(
pinObject.entry.url,
"https://example.com/",
"The pin object should have the correct URL"
);
resolvePromise();

View File

@@ -1,11 +1,11 @@
/* Any copyright is dedicated to the Public Domain.
https://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
"use strict";
add_task(async function test_NoUnload_Changed_Pinned() {
await SpecialPowers.pushPrefEnv({
set: [['zen.pinned-tab-manager.close-shortcut-behavior', 'reset-switch']],
set: [["zen.pinned-tab-manager.close-shortcut-behavior", "reset-switch"]],
});
let resolvePromise;
@@ -13,25 +13,30 @@ add_task(async function test_NoUnload_Changed_Pinned() {
resolvePromise = resolve;
});
await BrowserTestUtils.withNewTab({ gBrowser, url: 'https://example.com/1' }, async (browser) => {
await BrowserTestUtils.withNewTab({ gBrowser, url: "https://example.com/1" }, async (browser) => {
const tab = gBrowser.getTabForBrowser(browser);
gBrowser.pinTab(tab);
BrowserTestUtils.startLoadingURIString(browser, 'https://example.com/2');
await BrowserTestUtils.browserLoaded(browser, false, 'https://example.com/2');
BrowserTestUtils.startLoadingURIString(browser, "https://example.com/2");
await BrowserTestUtils.browserLoaded(browser, false, "https://example.com/2");
setTimeout(() => {
ok(
tab.hasAttribute('zen-pinned-changed'),
'The tab should have a zen-pinned-changed attribute after being pinned'
tab.hasAttribute("zen-pinned-changed"),
"The tab should have a zen-pinned-changed attribute after being pinned"
);
document.getElementById('cmd_close').doCommand();
document.getElementById("cmd_close").doCommand();
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
setTimeout(() => {
ok(
!tab.hasAttribute('zen-pinned-changed'),
'The tab should not have a zen-pinned-changed attribute after being closed'
!tab.hasAttribute("zen-pinned-changed"),
"The tab should not have a zen-pinned-changed attribute after being closed"
);
ok(!tab.hasAttribute("discarded"), "The tab should not be discarded after being closed");
Assert.notEqual(
tab,
gBrowser.selectedTab,
"The tab should not be selected after being closed"
);
ok(!tab.hasAttribute('discarded'), 'The tab should not be discarded after being closed');
ok(tab != gBrowser.selectedTab, 'The tab should not be selected after being closed');
resolvePromise();
}, 100);
}, 0);

Some files were not shown because too many files have changed in this diff Show More