mirror of
https://github.com/zen-browser/desktop.git
synced 2026-01-18 02:47:10 +00:00
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:
98
.github/advanced-issue-labeler.yml
vendored
98
.github/advanced-issue-labeler.yml
vendored
@@ -3,56 +3,56 @@ policy:
|
||||
- id: [component]
|
||||
label:
|
||||
# Make sure it's in sync with the dropdown in the issue template
|
||||
- name: 'component: sync'
|
||||
keys: ['Sync']
|
||||
- name: 'component: compact-mode'
|
||||
keys: ['Compact Mode']
|
||||
- name: 'component: workspaces'
|
||||
keys: ['Workspaces']
|
||||
- name: 'component: mods-themes'
|
||||
keys: ['Mods / Themes']
|
||||
- name: 'component: bookmarks'
|
||||
keys: ['Bookmarks']
|
||||
- name: 'component: glance'
|
||||
keys: ['Glance']
|
||||
- name: 'component: url-bar'
|
||||
keys: ['URL Bar']
|
||||
- name: 'component: tabs'
|
||||
keys: ['Tabs']
|
||||
- name: 'component: settings'
|
||||
keys: ['Settings']
|
||||
- name: 'component: privacy'
|
||||
keys: ['Privacy']
|
||||
- name: 'component: split-view'
|
||||
keys: ['Split View']
|
||||
- name: 'component: performance'
|
||||
keys: ['Performance']
|
||||
- name: 'component: media-controller'
|
||||
keys: ['Media Controler']
|
||||
- name: 'component: tab-unloading'
|
||||
keys: ['Tab unloading']
|
||||
- name: 'component: tab-folders'
|
||||
keys: ['Tab Folders']
|
||||
- name: 'component: keyboard-shortcuts'
|
||||
keys: ['Keyboard Shortcuts']
|
||||
- name: 'component: security'
|
||||
keys: ['Security']
|
||||
- name: 'component: extensions'
|
||||
keys: ['Extensions']
|
||||
- name: 'component: customizable-ui-toolbars'
|
||||
keys: ['Customizable UI / Toolbars']
|
||||
- name: 'component: localization'
|
||||
keys: ['Localization']
|
||||
- name: 'component: other'
|
||||
keys: ['Other']
|
||||
- name: "component: sync"
|
||||
keys: ["Sync"]
|
||||
- name: "component: compact-mode"
|
||||
keys: ["Compact Mode"]
|
||||
- name: "component: workspaces"
|
||||
keys: ["Workspaces"]
|
||||
- name: "component: mods-themes"
|
||||
keys: ["Mods / Themes"]
|
||||
- name: "component: bookmarks"
|
||||
keys: ["Bookmarks"]
|
||||
- name: "component: glance"
|
||||
keys: ["Glance"]
|
||||
- name: "component: url-bar"
|
||||
keys: ["URL Bar"]
|
||||
- name: "component: tabs"
|
||||
keys: ["Tabs"]
|
||||
- name: "component: settings"
|
||||
keys: ["Settings"]
|
||||
- name: "component: privacy"
|
||||
keys: ["Privacy"]
|
||||
- name: "component: split-view"
|
||||
keys: ["Split View"]
|
||||
- name: "component: performance"
|
||||
keys: ["Performance"]
|
||||
- name: "component: media-controller"
|
||||
keys: ["Media Controler"]
|
||||
- name: "component: tab-unloading"
|
||||
keys: ["Tab unloading"]
|
||||
- name: "component: tab-folders"
|
||||
keys: ["Tab Folders"]
|
||||
- name: "component: keyboard-shortcuts"
|
||||
keys: ["Keyboard Shortcuts"]
|
||||
- name: "component: security"
|
||||
keys: ["Security"]
|
||||
- name: "component: extensions"
|
||||
keys: ["Extensions"]
|
||||
- name: "component: customizable-ui-toolbars"
|
||||
keys: ["Customizable UI / Toolbars"]
|
||||
- name: "component: localization"
|
||||
keys: ["Localization"]
|
||||
- name: "component: other"
|
||||
keys: ["Other"]
|
||||
|
||||
- id: [platform]
|
||||
block-list: ['Other']
|
||||
block-list: ["Other"]
|
||||
label:
|
||||
# Make sure it's in sync with the dropdown in the issue template
|
||||
- name: 'platform: linux'
|
||||
keys: ['Linux (AppImage)', 'Linux (Flatpak)', 'Linux (Tarball)']
|
||||
- name: 'platform: macOS'
|
||||
keys: ['macOS - aarch64', 'macOS - Intel']
|
||||
- name: 'platform: windows'
|
||||
keys: ['Windows - x64', 'Windows - aarch64']
|
||||
- name: "platform: linux"
|
||||
keys: ["Linux (AppImage)", "Linux (Flatpak)", "Linux (Tarball)"]
|
||||
- name: "platform: macOS"
|
||||
keys: ["macOS - aarch64", "macOS - Intel"]
|
||||
- name: "platform: windows"
|
||||
keys: ["Windows - x64", "Windows - aarch64"]
|
||||
|
||||
56
.github/workflows/build.yml
vendored
56
.github/workflows/build.yml
vendored
@@ -4,49 +4,49 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
create_release:
|
||||
description: 'Create a new release for this build'
|
||||
description: "Create a new release for this build"
|
||||
required: false
|
||||
default: false
|
||||
type: 'boolean'
|
||||
type: "boolean"
|
||||
update_version:
|
||||
description: 'Update the version number'
|
||||
description: "Update the version number"
|
||||
required: false
|
||||
default: false
|
||||
type: 'boolean'
|
||||
type: "boolean"
|
||||
update_branch:
|
||||
description: 'Update branch with new version'
|
||||
description: "Update branch with new version"
|
||||
required: true
|
||||
default: 'release'
|
||||
type: 'choice'
|
||||
default: "release"
|
||||
type: "choice"
|
||||
options:
|
||||
- 'release'
|
||||
- 'twilight'
|
||||
- "release"
|
||||
- "twilight"
|
||||
use-sccache:
|
||||
description: 'Use sccache'
|
||||
description: "Use sccache"
|
||||
required: true
|
||||
type: 'boolean'
|
||||
type: "boolean"
|
||||
default: false
|
||||
workflow_call:
|
||||
inputs:
|
||||
create_release:
|
||||
description: 'Create a new release for this build'
|
||||
description: "Create a new release for this build"
|
||||
required: false
|
||||
default: false
|
||||
type: 'boolean'
|
||||
type: "boolean"
|
||||
update_version:
|
||||
description: 'Update the version number'
|
||||
description: "Update the version number"
|
||||
required: false
|
||||
default: false
|
||||
type: 'boolean'
|
||||
type: "boolean"
|
||||
update_branch:
|
||||
description: 'Update branch with new version'
|
||||
description: "Update branch with new version"
|
||||
required: true
|
||||
default: 'release'
|
||||
type: 'string'
|
||||
default: "release"
|
||||
type: "string"
|
||||
use-sccache:
|
||||
description: 'Use sccache'
|
||||
description: "Use sccache"
|
||||
required: true
|
||||
type: 'boolean'
|
||||
type: "boolean"
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: useblacksmith/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -202,7 +202,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: useblacksmith/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -244,7 +244,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: useblacksmith/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
@@ -379,7 +379,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: useblacksmith/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -565,8 +565,8 @@ jobs:
|
||||
./zen.installer.exe/*
|
||||
./zen.installer-arm64.exe/*
|
||||
./zen.macos-universal.dmg/*
|
||||
tag_name: 'twilight'
|
||||
name: 'Twilight build - ${{ needs.build-data.outputs.version }} (${{ needs.build-data.outputs.build_date }} at ${{ needs.build-data.outputs.build_time }})'
|
||||
tag_name: "twilight"
|
||||
name: "Twilight build - ${{ needs.build-data.outputs.version }} (${{ needs.build-data.outputs.build_date }} at ${{ needs.build-data.outputs.build_time }})"
|
||||
draft: false
|
||||
generate_release_notes: false
|
||||
prerelease: true
|
||||
@@ -584,7 +584,7 @@ jobs:
|
||||
prerelease: false
|
||||
fail_on_unmatched_files: false
|
||||
generate_release_notes: false
|
||||
name: 'Release build - ${{ needs.build-data.outputs.version }} (${{ needs.build-data.outputs.build_date }})'
|
||||
name: "Release build - ${{ needs.build-data.outputs.version }} (${{ needs.build-data.outputs.build_date }})"
|
||||
body_path: release_notes.md
|
||||
files: |
|
||||
./zen.source.tar.zst/*
|
||||
@@ -656,7 +656,7 @@ jobs:
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: '[release]: Update Flatpak manifest'
|
||||
commit_message: "[release]: Update Flatpak manifest"
|
||||
commit_user_name: Zen Browser Robot
|
||||
commit_user_email: zen-browser-auto@users.noreply.github.com
|
||||
repository: ./flatpak
|
||||
|
||||
@@ -2,7 +2,7 @@ name: Check Firefox Candidate Release
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '59 4 * * 2'
|
||||
- cron: "59 4 * * 2"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
||||
11
.github/workflows/code-linter.yml
vendored
11
.github/workflows/code-linter.yml
vendored
@@ -5,9 +5,6 @@ on:
|
||||
branches:
|
||||
- dev
|
||||
workflow_call:
|
||||
pull_request:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -25,7 +22,13 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Download Firefox
|
||||
env:
|
||||
ZEN_DOWNLOAD_DONT_INIT_GIT: "1"
|
||||
run: |
|
||||
npm run download
|
||||
|
||||
- name: Setup and run autopep8
|
||||
if: ${{ contains(join(github.event.commits.*.modified, ' '), '.py') || contains(join(github.event.commits.*.added, ' '), '.py') || contains(join(github.event.commits.*.removed, ' '), '.py') }}
|
||||
|
||||
6
.github/workflows/issue-metrics.yml
vendored
6
.github/workflows/issue-metrics.yml
vendored
@@ -5,7 +5,7 @@ permissions:
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '3 2 1 * *'
|
||||
- cron: "3 2 1 * *"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.DEPLOY_KEY }}
|
||||
HIDE_AUTHOR: true
|
||||
HIDE_TIME_TO_ANSWER: true
|
||||
SEARCH_QUERY: 'repo:zen-browser/desktop is:issue created:${{ env.last_month }}'
|
||||
SEARCH_QUERY: "repo:zen-browser/desktop is:issue created:${{ env.last_month }}"
|
||||
|
||||
- name: Move metrics to docs folder
|
||||
run: |
|
||||
@@ -62,6 +62,6 @@ jobs:
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: 'docs: Update monthly issue metrics, b=(no bug), c={docs}'
|
||||
commit_message: "docs: Update monthly issue metrics, b=(no bug), c={docs}"
|
||||
commit_user_name: Zen Browser Robot
|
||||
commit_user_email: zen-browser-auto@users.noreply.github.com
|
||||
|
||||
10
.github/workflows/linux-release-build.yml
vendored
10
.github/workflows/linux-release-build.yml
vendored
@@ -4,19 +4,19 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build-version:
|
||||
description: 'The version to build'
|
||||
description: "The version to build"
|
||||
required: true
|
||||
type: string
|
||||
release-branch:
|
||||
description: 'The branch to build'
|
||||
description: "The branch to build"
|
||||
required: true
|
||||
type: string
|
||||
MOZ_BUILD_DATE:
|
||||
type: string
|
||||
required: true
|
||||
default: ''
|
||||
default: ""
|
||||
use-sccache:
|
||||
description: 'Use sccache'
|
||||
description: "Use sccache"
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: useblacksmith/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@main
|
||||
|
||||
10
.github/workflows/macos-release-build.yml
vendored
10
.github/workflows/macos-release-build.yml
vendored
@@ -6,19 +6,19 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build-version:
|
||||
description: 'The version to build'
|
||||
description: "The version to build"
|
||||
required: true
|
||||
type: string
|
||||
release-branch:
|
||||
description: 'The branch to build'
|
||||
description: "The branch to build"
|
||||
required: true
|
||||
type: string
|
||||
MOZ_BUILD_DATE:
|
||||
type: string
|
||||
required: true
|
||||
default: ''
|
||||
default: ""
|
||||
use-sccache:
|
||||
description: 'Use sccache'
|
||||
description: "Use sccache"
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@main
|
||||
|
||||
@@ -4,18 +4,18 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build-version:
|
||||
description: 'The version to build'
|
||||
description: "The version to build"
|
||||
required: true
|
||||
type: string
|
||||
release-branch:
|
||||
description: 'The branch to build'
|
||||
description: "The branch to build"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
mac-build:
|
||||
name: Unify macOS (Universal)
|
||||
runs-on: 'macos-26'
|
||||
runs-on: "macos-26"
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
|
||||
7
.github/workflows/pr-test.yml
vendored
7
.github/workflows/pr-test.yml
vendored
@@ -19,13 +19,18 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Download Firefox and dependencies
|
||||
env:
|
||||
ZEN_DOWNLOAD_DONT_INIT_GIT: "1"
|
||||
run: npm run download
|
||||
|
||||
- name: Import patches
|
||||
run: npm run import
|
||||
|
||||
- name: Run linting
|
||||
run: npm run lint
|
||||
|
||||
12
.github/workflows/sync-upstream.yml
vendored
12
.github/workflows/sync-upstream.yml
vendored
@@ -4,14 +4,14 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_candidate:
|
||||
description: 'Set to true to sync release candidates'
|
||||
description: "Set to true to sync release candidates"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
workflow_call:
|
||||
inputs:
|
||||
release_candidate:
|
||||
description: 'Set to true to sync release candidates'
|
||||
description: "Set to true to sync release candidates"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
|
||||
@@ -119,9 +119,9 @@ jobs:
|
||||
GIT_CURL_VERBOSE: 1
|
||||
with:
|
||||
token: ${{ secrets.DEPLOY_KEY }}
|
||||
commit-message: 'chore: Sync upstream to `Firefox ${{ steps.build-data.outputs.version }}`'
|
||||
branch: 'chore/upstream-sync'
|
||||
title: 'Sync upstream Firefox to version ${{ steps.build-data.outputs.version }}'
|
||||
commit-message: "chore: Sync upstream to `Firefox ${{ steps.build-data.outputs.version }}`"
|
||||
branch: "chore/upstream-sync"
|
||||
title: "Sync upstream Firefox to version ${{ steps.build-data.outputs.version }}"
|
||||
body: |
|
||||
This PR syncs the upstream Firefox to version ${{ steps.build-data.outputs.version }}.
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ name: Zen Twilight Scheduled Releases
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 23 * * *'
|
||||
- cron: "0 23 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
create_release:
|
||||
description: 'Whether to do a release'
|
||||
description: "Whether to do a release"
|
||||
required: false
|
||||
type: boolean
|
||||
default: true
|
||||
@@ -34,4 +34,4 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
8
.github/workflows/windows-profile-build.yml
vendored
8
.github/workflows/windows-profile-build.yml
vendored
@@ -7,15 +7,15 @@ on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build-version:
|
||||
description: 'The version to build'
|
||||
description: "The version to build"
|
||||
required: true
|
||||
type: string
|
||||
profile-data-path-archive:
|
||||
description: 'The path to the zip archive containing the profile data'
|
||||
description: "The path to the zip archive containing the profile data"
|
||||
required: false
|
||||
type: string
|
||||
release-branch:
|
||||
description: 'The branch to build'
|
||||
description: "The branch to build"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
|
||||
12
.github/workflows/windows-release-build.yml
vendored
12
.github/workflows/windows-release-build.yml
vendored
@@ -11,22 +11,22 @@ on:
|
||||
type: boolean
|
||||
default: false
|
||||
build-version:
|
||||
description: 'The version to build'
|
||||
description: "The version to build"
|
||||
required: true
|
||||
type: string
|
||||
profile-data-path-archive:
|
||||
description: 'The path to the zip archive containing the profile data'
|
||||
description: "The path to the zip archive containing the profile data"
|
||||
type: string
|
||||
release-branch:
|
||||
description: 'The branch to build'
|
||||
description: "The branch to build"
|
||||
required: true
|
||||
type: string
|
||||
MOZ_BUILD_DATE:
|
||||
type: string
|
||||
required: true
|
||||
default: ''
|
||||
default: ""
|
||||
use-sccache:
|
||||
description: 'Use sccache'
|
||||
description: "Use sccache"
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: useblacksmith/setup-node@v5
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@main
|
||||
|
||||
@@ -2,11 +2,19 @@
|
||||
"bracketSameLine": true,
|
||||
"endOfLine": "lf",
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"jsxSingleQuote": false,
|
||||
"semi": true,
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-sh"]
|
||||
"plugins": ["prettier-plugin-sh"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.css",
|
||||
"options": {
|
||||
"parser": "css",
|
||||
"printWidth": 160
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// 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 fs = require('fs');
|
||||
const MJS_FILES = ['src/zen/split-view/ZenViewSplitter.ts'];
|
||||
const fs = require("fs");
|
||||
const MJS_FILES = ["src/zen/split-view/ZenViewSplitter.ts"];
|
||||
|
||||
for (const file of MJS_FILES) {
|
||||
const code = fs.readFileSync(file, 'utf8');
|
||||
require('@babel/core').transformSync(code, {
|
||||
presets: ['@babel/preset-typescript'],
|
||||
const code = fs.readFileSync(file, "utf8");
|
||||
require("@babel/core").transformSync(code, {
|
||||
presets: ["@babel/preset-typescript"],
|
||||
filename: file,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,27 +1,492 @@
|
||||
// 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/.
|
||||
/* 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/. */
|
||||
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import zenGlobals from './src/zen/zen.globals.js';
|
||||
import sdl from "@microsoft/eslint-plugin-sdl";
|
||||
import eslintConfigPrettier from "eslint-config-prettier/flat";
|
||||
import html from "eslint-plugin-html";
|
||||
import importPlugin from "eslint-plugin-import";
|
||||
import json from "@eslint/json";
|
||||
import lit from "eslint-plugin-lit";
|
||||
import mozilla from "eslint-plugin-mozilla";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import zenGlobals from "./src/zen/zen.globals.mjs";
|
||||
|
||||
export default defineConfig([
|
||||
import fs from "fs";
|
||||
import globals from "globals";
|
||||
import path from "path";
|
||||
|
||||
import globalIgnores from "./engine/eslint-ignores.config.mjs";
|
||||
import testPathsConfig from "./engine/eslint-test-paths.config.mjs";
|
||||
import repositoryGlobals from "./engine/eslint-file-globals.config.mjs";
|
||||
import rollouts from "./engine/eslint-rollouts.config.mjs";
|
||||
import subdirConfigs from "./engine/eslint-subdirs.config.mjs";
|
||||
|
||||
const testPaths = testPathsConfig.testPaths;
|
||||
|
||||
function readFile(filePath) {
|
||||
return fs
|
||||
.readFileSync(filePath, { encoding: "utf-8" })
|
||||
.split("\n")
|
||||
.filter((p) => p && !p.startsWith("#"));
|
||||
}
|
||||
|
||||
const httpTestingPaths = [
|
||||
`**/*mixedcontent*.{${mozilla.allFileExtensions.join(",")}}`,
|
||||
`**/*CrossOrigin*.{${mozilla.allFileExtensions.join(",")}}`,
|
||||
`**/*crossorigin*.{${mozilla.allFileExtensions.join(",")}}`,
|
||||
`**/*cors*.{${mozilla.allFileExtensions.join(",")}}`,
|
||||
`**/*downgrade*.{${mozilla.allFileExtensions.join(",")}}`,
|
||||
`**/*Downgrade*.{${mozilla.allFileExtensions.join(",")}}`,
|
||||
];
|
||||
|
||||
globals.browser = {
|
||||
...globals.browser,
|
||||
...zenGlobals.reduce((obj, key) => {
|
||||
obj[key] = "readonly";
|
||||
return obj;
|
||||
}, {}),
|
||||
};
|
||||
|
||||
testPaths.browser = testPaths.browser.concat("src/zen/tests/");
|
||||
|
||||
/**
|
||||
* Takes each path in the paths array, and expands it with the list of extensions
|
||||
* that ESLint is watching.
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {string[]} options.paths
|
||||
* The list of paths to wrap.
|
||||
* @param {string[]} [options.excludedExtensions]
|
||||
* The list of extensions to be excluded from the wrapping.
|
||||
*/
|
||||
function wrapPaths({ paths, excludedExtensions }) {
|
||||
let extensions = excludedExtensions
|
||||
? mozilla.allFileExtensions.filter((f) => !excludedExtensions.includes(f))
|
||||
: mozilla.allFileExtensions;
|
||||
return paths.map((p) => {
|
||||
if (p.endsWith("**")) {
|
||||
return p + `/*.{${extensions.join(",")}}`;
|
||||
}
|
||||
if (p.endsWith("/")) {
|
||||
return p + `**/*.{${extensions.join(",")}}`;
|
||||
}
|
||||
if (p.endsWith("*")) {
|
||||
return p + `.{${extensions.join(",")}}`;
|
||||
}
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the paths listed in the files section of a configuration with the
|
||||
* file extensions that ESLint is watching.
|
||||
*
|
||||
* @param {object} configs
|
||||
*/
|
||||
function wrapPathsInConfig(configs) {
|
||||
for (let config of configs) {
|
||||
// add "engine/" to the paths in the files section.
|
||||
config.files = wrapPaths({ paths: config.files.map((p) => "engine/" + p) });
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
|
||||
let config = [
|
||||
{
|
||||
files: ['**/*.{js,mjs,cjs}'],
|
||||
plugins: { js },
|
||||
extends: ['js/recommended'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...zenGlobals.reduce((acc, global) => {
|
||||
acc[global] = 'readable';
|
||||
return acc;
|
||||
}, {}),
|
||||
name: "import-plugin-settings",
|
||||
settings: {
|
||||
"import/extensions": [".mjs"],
|
||||
"import/resolver": {
|
||||
[path.resolve(import.meta.dirname, "engine", "srcdir-resolver.js")]: {},
|
||||
node: {},
|
||||
},
|
||||
},
|
||||
ignores: ['**/vendor/**', '**/tests/**'],
|
||||
},
|
||||
globalIgnores(['**/mochitests/**']),
|
||||
]);
|
||||
{
|
||||
name: "ignores",
|
||||
ignores: [...globalIgnores, "src/zen/vendor/*"],
|
||||
},
|
||||
{
|
||||
name: "all-files",
|
||||
files: wrapPaths({ paths: ["**"] }),
|
||||
linterOptions: {
|
||||
// With this option on, if an inline comment disables a rule, and the
|
||||
// rule is able to be automatically fixed, then ESLint will remove the
|
||||
// inline comment and apply the fix. We don't want this because we have
|
||||
// some rules that intentionally need to be turned off in specific cases,
|
||||
// e.g. @microsoft/sdl/no-insecure-url.
|
||||
reportUnusedDisableDirectives: "off",
|
||||
},
|
||||
plugins: { lit },
|
||||
rules: {
|
||||
"lit/quoted-expressions": ["error", "never"],
|
||||
"lit/no-invalid-html": "error",
|
||||
"lit/no-value-attribute": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source-type-script",
|
||||
files: ["**/*.{js,json,html,sjs,xhtml}"],
|
||||
languageOptions: {
|
||||
sourceType: "script",
|
||||
},
|
||||
},
|
||||
...mozilla.configs["flat/recommended"],
|
||||
{
|
||||
name: "json-recommended-with-comments",
|
||||
files: ["**/*.json"],
|
||||
language: "json/jsonc",
|
||||
...json.configs.recommended,
|
||||
},
|
||||
{
|
||||
name: "json-recommended-no-comments",
|
||||
files: ["**/package.json"],
|
||||
language: "json/json",
|
||||
...json.configs.recommended,
|
||||
},
|
||||
{
|
||||
name: "json-empty-keys-off-for-image_builder",
|
||||
files: ["taskcluster/docker/image_builder/policy.json"],
|
||||
rules: {
|
||||
"json/no-empty-keys": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eslint-plugin-html",
|
||||
files: ["**/*.html", "**/*.xhtml"],
|
||||
plugins: { html },
|
||||
},
|
||||
|
||||
{
|
||||
name: "define-globals-for-browser-env",
|
||||
// Not available for sjs files.
|
||||
files: wrapPaths({ paths: ["**"], excludedExtensions: ["sjs"] }),
|
||||
ignores: [
|
||||
// Also not available for various other scopes and tools.
|
||||
"**/*.sys.mjs",
|
||||
"**/?(*.)worker.?(m)js",
|
||||
"**/?(*.)serviceworker.?(m)js",
|
||||
...wrapPaths({
|
||||
paths: testPaths.xpcshell,
|
||||
excludedExtensions: ["mjs", "sjs"],
|
||||
}),
|
||||
"tools/lint/eslint/**",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: globals.browser,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Generally we assume that all files, except mjs ones are in our
|
||||
// privileged and specific environment. mjs are handled separately by
|
||||
// the recommended configuration in eslint-plugin-mozilla.
|
||||
name: "define-privileged-and-specific-globals-for-most-files",
|
||||
files: wrapPaths({ paths: ["**"], excludedExtensions: ["json"] }),
|
||||
ignores: ["browser/components/storybook/**", "tools"],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...mozilla.environments.privileged.globals,
|
||||
...mozilla.environments.specific.globals,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "define-globals-for-node-files",
|
||||
files: [
|
||||
// All .eslintrc.mjs files are in the node environment, so turn that
|
||||
// on here.
|
||||
"**/.eslintrc*.mjs",
|
||||
// .js files in the top-level are generally assumed to be node.
|
||||
"\.*.js",
|
||||
// *.config.js files are generally assumed to be configuration files
|
||||
// based for node.
|
||||
"**/*.config.js",
|
||||
// The resolver for moz-src for eslint, vscode etc.
|
||||
"engine/srcdir-resolver.js",
|
||||
],
|
||||
languageOptions: {
|
||||
globals: { ...globals.node, ...mozilla.turnOff(globals.browser) },
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "browser-no-more-globals",
|
||||
files: ["browser/base/content/browser.js"],
|
||||
rules: {
|
||||
"mozilla/no-more-globals": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jsx-files",
|
||||
files: ["**/*.jsx", "browser/components/storybook/.storybook/**/*.mjs"],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "eslint-plugin-import-rules",
|
||||
files: ["**/*.mjs"],
|
||||
plugins: { import: importPlugin },
|
||||
rules: {
|
||||
"import/default": "error",
|
||||
"import/export": "error",
|
||||
"import/named": "error",
|
||||
"import/namespace": "error",
|
||||
"import/newline-after-import": "error",
|
||||
"import/no-duplicates": "error",
|
||||
"import/no-absolute-path": "error",
|
||||
"import/no-named-default": "error",
|
||||
"import/no-named-as-default": "error",
|
||||
"import/no-named-as-default-member": "error",
|
||||
"import/no-self-import": "error",
|
||||
"import/no-unassigned-import": "error",
|
||||
"import/no-unresolved": [
|
||||
"error",
|
||||
// Bug 1773473 - Ignore resolver URLs for chrome and resource as we
|
||||
// do not yet have a resolver for them.
|
||||
{ ignore: ["chrome://", "resource://"] },
|
||||
],
|
||||
"import/no-useless-path-segments": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "turn-off-unassigned-import-for-stories",
|
||||
// Turn off no-unassigned-import for files that typically test our
|
||||
// custom elements, which are imported for the side effects (ie
|
||||
// the custom element being registered) rather than any particular
|
||||
// export:
|
||||
files: ["**/*.stories.mjs"],
|
||||
plugins: { import: importPlugin },
|
||||
rules: {
|
||||
"import/no-unassigned-import": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
...mozilla.configs["flat/general-test"],
|
||||
files: wrapPaths({ paths: ["**/test/**", "**/tests/**"] }),
|
||||
},
|
||||
{
|
||||
...mozilla.configs["flat/xpcshell-test"],
|
||||
files: wrapPaths({
|
||||
paths: testPaths.xpcshell,
|
||||
excludedExtensions: ["mjs", "sjs"],
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "no-unused-vars-disable-on-headjs",
|
||||
// If it is an xpcshell head file, we turn off global unused variable checks, as it
|
||||
// would require searching the other test files to know if they are used or not.
|
||||
// This would be expensive and slow, and it isn't worth it for head files.
|
||||
// We could get developers to declare as exported, but that doesn't seem worth it.
|
||||
files: testPaths.xpcshell.map((filePath) => `${filePath}head*.js`),
|
||||
rules: {
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
caughtErrors: "none",
|
||||
vars: "local",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no-unused-vars-for-xpcshell",
|
||||
// This section enables errors of no-unused-vars globally for all test*.js
|
||||
// files in xpcshell test paths.
|
||||
// This is not done in the xpcshell-test configuration as we cannot pull
|
||||
// in overrides from there. We should at some stage, aim to enable this
|
||||
// for all files in xpcshell-tests.
|
||||
files: testPaths.xpcshell.map((filePath) => `${filePath}test*.js`),
|
||||
rules: {
|
||||
// No declaring variables that are never used
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
caughtErrors: "none",
|
||||
vars: "all",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
...mozilla.configs["flat/browser-test"],
|
||||
files: wrapPaths({
|
||||
paths: testPaths.browser,
|
||||
excludedExtensions: ["mjs", "sjs"],
|
||||
}),
|
||||
},
|
||||
{
|
||||
...mozilla.configs["flat/mochitest-test"],
|
||||
files: wrapPaths({
|
||||
paths: testPaths.mochitest,
|
||||
excludedExtensions: ["mjs"],
|
||||
}),
|
||||
ignores: ["security/manager/ssl/tests/mochitest/browser/**"],
|
||||
},
|
||||
{
|
||||
...mozilla.configs["flat/chrome-test"],
|
||||
files: wrapPaths({
|
||||
paths: testPaths.chrome,
|
||||
excludedExtensions: ["mjs", "sjs"],
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "simpletest",
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...mozilla.environments.simpletest.globals,
|
||||
},
|
||||
},
|
||||
files: [
|
||||
...testPaths.mochitest.map((filePath) => `${filePath}/**/*.js`),
|
||||
...testPaths.chrome.map((filePath) => `${filePath}/**/*.js`),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "multiple-test-kinds",
|
||||
// Some directories have multiple kinds of tests, and some rules
|
||||
// don't work well for HTML-based mochitests, so disable those.
|
||||
files: testPaths.xpcshell
|
||||
.concat(testPaths.browser)
|
||||
.map((filePath) => [`${filePath}/**/*.html`, `${filePath}/**/*.xhtml`])
|
||||
.flat(),
|
||||
rules: {
|
||||
// plain/chrome mochitests don't automatically include Assert, so
|
||||
// autofixing `ok()` to Assert.something is bad.
|
||||
"mozilla/no-comparison-or-assignment-inside-ok": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "test-file-reuse",
|
||||
// Some directories reuse `test_foo.js` files between mochitest-plain and
|
||||
// unit tests, or use custom postMessage-based assertion propagation into
|
||||
// browser tests. Ignore those too:
|
||||
files: wrapPaths({
|
||||
paths: [
|
||||
// Reuses xpcshell unit test scripts in mochitest-plain HTML files.
|
||||
"dom/indexedDB/test/**",
|
||||
// Dispatches functions to the webpage in ways that are hard to detect.
|
||||
"toolkit/components/antitracking/test/**",
|
||||
],
|
||||
}),
|
||||
rules: {
|
||||
"mozilla/no-comparison-or-assignment-inside-ok": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
// Rules of Hooks broadly checks for camelCase "use" identifiers, so
|
||||
// enable only for paths actually using React to avoid false positives.
|
||||
name: "react-hooks",
|
||||
files: [
|
||||
"browser/components/aboutwelcome/**",
|
||||
"browser/components/asrouter/**",
|
||||
"browser/extensions/newtab/**",
|
||||
"devtools/**",
|
||||
],
|
||||
...reactHooks.configs["recommended-latest"],
|
||||
plugins: { "react-hooks": reactHooks },
|
||||
rules: {
|
||||
// react-hooks/recommended has exhaustive-deps as a warning, we prefer
|
||||
// errors, so that raised issues get addressed one way or the other.
|
||||
"react-hooks/exhaustive-deps": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "disable-no-insecure-url-for-http-testing",
|
||||
// Exempt files with these paths since they have to use http for full coverage
|
||||
files: httpTestingPaths,
|
||||
plugins: { "@microsoft/sdl": sdl },
|
||||
rules: {
|
||||
"@microsoft/sdl/no-insecure-url": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mozilla/valid-jsdoc",
|
||||
files: wrapPaths({ paths: ["**"] }),
|
||||
...mozilla.configs["flat/valid-jsdoc"],
|
||||
},
|
||||
{
|
||||
name: "mozilla/require-jsdoc",
|
||||
files: wrapPaths({ paths: ["**"] }),
|
||||
...mozilla.configs["flat/require-jsdoc"],
|
||||
},
|
||||
{
|
||||
name: "rollout-no-browser-refs-in-toolkit",
|
||||
files: ["toolkit/**"],
|
||||
ignores: ["toolkit/**/test/**", "toolkit/**/tests/**"],
|
||||
plugins: { mozilla },
|
||||
rules: {
|
||||
"mozilla/no-browser-refs-in-toolkit": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no-newtab-refs-outside-newtab",
|
||||
files: ["**/*.mjs", "**/*.js", "**/*.sys.mjs"],
|
||||
ignores: [
|
||||
"tools/@types/generated/**",
|
||||
"tools/lint/eslint/eslint-plugin-mozilla/lib/rules/no-newtab-refs-outside-newtab.mjs",
|
||||
"tools/lint/eslint/eslint-plugin-mozilla/tests/no-newtab-refs-outside-newtab.mjs",
|
||||
],
|
||||
plugins: { mozilla },
|
||||
rules: {
|
||||
"mozilla/no-newtab-refs-outside-newtab": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "jsdoc/require-jsdoc",
|
||||
ignores: wrapPaths({ paths: ["**"] }),
|
||||
...mozilla.configs["flat/jsdoc-require-jsdoc"],
|
||||
},
|
||||
|
||||
...wrapPathsInConfig(subdirConfigs),
|
||||
...wrapPathsInConfig(repositoryGlobals),
|
||||
|
||||
/**
|
||||
* The items below should always be the last items in this order:
|
||||
*
|
||||
* - Enable eslint-config-prettier.
|
||||
* - Enable curly.
|
||||
* - Rollouts
|
||||
*/
|
||||
|
||||
// Turn off rules that conflict with Prettier.
|
||||
{ name: "eslint-config-prettier", ...eslintConfigPrettier },
|
||||
{
|
||||
name: "enable-curly",
|
||||
files: wrapPaths({ paths: ["**/"] }),
|
||||
rules: {
|
||||
// Require braces around blocks that start a new line. This must be
|
||||
// configured after eslint-config-prettier is included, as otherwise
|
||||
// eslint-config-prettier disables the curly rule. Hence, we do
|
||||
// not include it in
|
||||
// `tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js`.
|
||||
curly: ["error", "all"],
|
||||
},
|
||||
},
|
||||
...wrapPathsInConfig(rollouts),
|
||||
];
|
||||
|
||||
// The various places we get our globals from use true/false rather than
|
||||
// the strings required by ESLint, so translate those here.
|
||||
config.map((entry) => {
|
||||
if (entry.languageOptions?.globals) {
|
||||
let newGlobals = {};
|
||||
for (let [key, value] of Object.entries(entry.languageOptions.globals)) {
|
||||
if (typeof entry.languageOptions.globals[key] == "boolean") {
|
||||
newGlobals[key] = value ? "writable" : "readonly";
|
||||
} else {
|
||||
newGlobals[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
});
|
||||
|
||||
export default config;
|
||||
|
||||
1098
package-lock.json
generated
1098
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -51,20 +51,32 @@
|
||||
"homepage": "https://github.com/zen-browser/desktop#readme",
|
||||
"devDependencies": {
|
||||
"@babel/preset-typescript": "^7.27.0",
|
||||
"@eslint/js": "^9.32.0",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@eslint/json": "^0.14.0",
|
||||
"@microsoft/eslint-plugin-sdl": "^1.1.0",
|
||||
"@zen-browser/surfer": "^1.13.0",
|
||||
"eslint": "^9.32.0",
|
||||
"@zen-browser/surfer": "^1.13.1",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-eslint-plugin": "^7.3.0",
|
||||
"eslint-plugin-html": "^8.1.3",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jest": "^29.12.1",
|
||||
"eslint-plugin-json": "^4.0.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"eslint-plugin-lit": "^2.1.1",
|
||||
"eslint-plugin-mozilla": "^4.3.3",
|
||||
"eslint-plugin-no-unsanitized": "4.1.4",
|
||||
"eslint-plugin-promise": "7.2.1",
|
||||
"eslint-plugin-react": "7.37.5",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-spidermonkey-js": "file:tools/eslint-plugin-spidermonkey-js",
|
||||
"formal-git": "^1.2.9",
|
||||
"globals": "^16.3.0",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.3.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-sh": "^0.14.0"
|
||||
"prettier-plugin-sh": "^0.14.0",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.52.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,45 +5,45 @@
|
||||
# Smooth scrolling and mousewheel tuning preferences
|
||||
|
||||
- name: general.smoothScroll.msdPhysics.enabled
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: true
|
||||
|
||||
- name: general.smoothScroll.currentVelocityWeighting
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
value: '0.15'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: "0.15"
|
||||
|
||||
- name: general.smoothScroll.stopDecelerationWeighting
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
value: '0.6'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: "0.6"
|
||||
|
||||
- name: mousewheel.min_line_scroll_amount
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 10
|
||||
|
||||
- name: general.smoothScroll.mouseWheel.durationMinMS
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 80
|
||||
|
||||
- name: general.smoothScroll.msdPhysics.continuousMotionMaxDeltaMS
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 12
|
||||
|
||||
- name: general.smoothScroll.msdPhysics.motionBeginSpringConstant
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 600
|
||||
|
||||
- name: general.smoothScroll.msdPhysics.regularSpringConstant
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 650
|
||||
|
||||
- name: general.smoothScroll.msdPhysics.slowdownMinDeltaMS
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 25
|
||||
|
||||
- name: general.smoothScroll.msdPhysics.slowdownSpringConstant
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 250
|
||||
|
||||
- name: mousewheel.default.delta_multiplier_y
|
||||
condition: '!defined(XP_MACOSX)'
|
||||
condition: "!defined(XP_MACOSX)"
|
||||
value: 200
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
value: true
|
||||
|
||||
- name: browser.toolbars.bookmarks.visibility
|
||||
value: 'never'
|
||||
value: "never"
|
||||
|
||||
- name: widget.non-native-theme.scrollbar.style
|
||||
value: 2
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
- name: app.update.checkInstallTime.days
|
||||
value: 6
|
||||
condition: 'defined(MOZILLA_OFFICIAL)'
|
||||
condition: "defined(MOZILLA_OFFICIAL)"
|
||||
|
||||
- name: browser.profiles.enabled
|
||||
value: false
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
# Fullscreen API preferences
|
||||
- name: full-screen-api.transition-duration.enter
|
||||
value: '0 0'
|
||||
value: "0 0"
|
||||
|
||||
- name: full-screen-api.transition-duration.leave
|
||||
value: '0 0'
|
||||
value: "0 0"
|
||||
|
||||
- name: full-screen-api.warning.delay
|
||||
value: -1
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
- name: browser.lowMemoryResponseMask
|
||||
value: 3
|
||||
condition: 'defined(XP_MACOSX)'
|
||||
condition: "defined(XP_MACOSX)"
|
||||
|
||||
- name: network.predictor.enable-hover-on-ssl
|
||||
value: true
|
||||
@@ -14,6 +14,6 @@
|
||||
# Make sure its in sync with:
|
||||
# https://searchfox.org/firefox-main/rev/1477feb9706f4ccc5bd571c1c215832a6fbb7464/modules/libpref/init/StaticPrefList.yaml#7741-7748
|
||||
- name: gfx.webrender.compositor
|
||||
condition: 'defined(XP_WIN) || defined(XP_DARWIN)'
|
||||
value: '@cond'
|
||||
condition: "defined(XP_WIN) || defined(XP_DARWIN)"
|
||||
value: "@cond"
|
||||
mirror: once
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
- name: browser.privatebrowsing.vpnpromourl
|
||||
value: ''
|
||||
value: ""
|
||||
locked: true
|
||||
|
||||
- name: extensions.getAddons.showPane
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
locked: true
|
||||
|
||||
- name: toolkit.telemetry.server
|
||||
value: 'data:,'
|
||||
value: "data:,"
|
||||
locked: true
|
||||
|
||||
- name: toolkit.telemetry.archive.enabled
|
||||
@@ -56,7 +56,7 @@
|
||||
locked: true
|
||||
|
||||
- name: toolkit.coverage.endpoint.base
|
||||
value: ''
|
||||
value: ""
|
||||
locked: true
|
||||
|
||||
- name: browser.newtabpage.activity-stream.feeds.telemetry
|
||||
@@ -84,7 +84,7 @@
|
||||
value: false
|
||||
|
||||
- name: app.normandy.api_url
|
||||
value: ''
|
||||
value: ""
|
||||
locked: true
|
||||
|
||||
# Crash Reports
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
value: true
|
||||
|
||||
- name: zen.glance.activation-method
|
||||
value: 'alt' # ctrl, alt, shift
|
||||
value: "alt" # ctrl, alt, shift
|
||||
|
||||
- name: zen.glance.animation-duration
|
||||
value: 350 # in milliseconds
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
# GTK-specific preferences
|
||||
- name: widget.gtk.rounded-bottom-corners.enabled
|
||||
value: true
|
||||
condition: 'defined(MOZ_WIDGET_GTK)'
|
||||
condition: "defined(MOZ_WIDGET_GTK)"
|
||||
|
||||
- name: zen.widget.linux.transparency
|
||||
value: false
|
||||
condition: 'defined(MOZ_WIDGET_GTK)'
|
||||
condition: "defined(MOZ_WIDGET_GTK)"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Enable transparent background for macos
|
||||
- name: widget.macos.sidebar-blend-mode.behind-window
|
||||
value: true
|
||||
condition: 'defined(XP_MACOSX)'
|
||||
condition: "defined(XP_MACOSX)"
|
||||
|
||||
# 1. hudWindow
|
||||
# 2. fullScreenUI
|
||||
@@ -16,7 +16,7 @@
|
||||
# 7. underlay
|
||||
- name: zen.widget.macos.window-material
|
||||
value: 1
|
||||
condition: 'defined(XP_MACOSX)'
|
||||
condition: "defined(XP_MACOSX)"
|
||||
cpptype: uint32_t
|
||||
mirror: always
|
||||
type: static
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
value: 20 # In days
|
||||
|
||||
- name: zen.mods.auto-update
|
||||
value: '@cond'
|
||||
condition: 'defined(MOZILLA_OFFICIAL)'
|
||||
value: "@cond"
|
||||
condition: "defined(MOZILLA_OFFICIAL)"
|
||||
|
||||
- name: zen.rice.share.notice.accepted
|
||||
value: false
|
||||
@@ -18,10 +18,10 @@
|
||||
# === Mark: Site Injection ===
|
||||
|
||||
- name: zen.injections.match-urls
|
||||
value: 'https://zen-browser.app/*'
|
||||
value: "https://zen-browser.app/*"
|
||||
locked: true
|
||||
condition: 'defined(MOZILLA_OFFICIAL)'
|
||||
condition: "defined(MOZILLA_OFFICIAL)"
|
||||
|
||||
- name: zen.injections.match-urls
|
||||
value: 'http://localhost/*'
|
||||
condition: '!defined(MOZILLA_OFFICIAL)'
|
||||
value: "http://localhost/*"
|
||||
condition: "!defined(MOZILLA_OFFICIAL)"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
value: true
|
||||
|
||||
- name: zen.session-store.log
|
||||
value: '@IS_TWILIGHT@'
|
||||
value: "@IS_TWILIGHT@"
|
||||
|
||||
- name: zen.session-store.restore-unsynced-windows
|
||||
value: true
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
- name: zen.theme.accent-color
|
||||
value: 'AccentColor'
|
||||
value: "AccentColor"
|
||||
|
||||
- name: zen.theme.content-element-separation
|
||||
value: 8
|
||||
@@ -30,11 +30,11 @@
|
||||
value: true
|
||||
|
||||
- name: zen.theme.styled-status-panel
|
||||
value: '@IS_TWILIGHT@'
|
||||
value: "@IS_TWILIGHT@"
|
||||
|
||||
- name: zen.theme.styled-status-panel
|
||||
value: true
|
||||
condition: 'defined(XP_MACOSX)'
|
||||
condition: "defined(XP_MACOSX)"
|
||||
|
||||
- name: zen.theme.hide-unified-extensions-button
|
||||
value: true
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
|
||||
- name: zen.view.mac.show-three-dot-menu
|
||||
value: false
|
||||
condition: 'defined(XP_MACOSX)'
|
||||
condition: "defined(XP_MACOSX)"
|
||||
|
||||
- name: zen.widget.mac.mono-window-controls
|
||||
value: true
|
||||
condition: 'defined(XP_MACOSX)'
|
||||
condition: "defined(XP_MACOSX)"
|
||||
|
||||
- name: zen.view.use-single-toolbar
|
||||
value: true
|
||||
@@ -41,7 +41,7 @@
|
||||
value: 2
|
||||
|
||||
- name: zen.view.context-menu.refresh
|
||||
value: '@IS_TWILIGHT@'
|
||||
value: "@IS_TWILIGHT@"
|
||||
|
||||
- name: zen.view.borderless-fullscreen
|
||||
value: true
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
- name: zen.watermark.enabled
|
||||
value: '@cond'
|
||||
value: "@cond"
|
||||
sticky: true
|
||||
condition: 'defined(MOZILLA_OFFICIAL)'
|
||||
condition: "defined(MOZILLA_OFFICIAL)"
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
- name: zen.welcome-screen.seen
|
||||
value: '@cond'
|
||||
value: "@cond"
|
||||
sticky: true
|
||||
condition: '!defined(MOZILLA_OFFICIAL)'
|
||||
condition: "!defined(MOZILLA_OFFICIAL)"
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
# Mica effect preferences for Windows
|
||||
- name: widget.windows.mica
|
||||
value: true
|
||||
condition: 'defined(XP_WIN)'
|
||||
condition: "defined(XP_WIN)"
|
||||
|
||||
- name: widget.windows.mica.popups
|
||||
value: true
|
||||
condition: 'defined(XP_WIN)'
|
||||
condition: "defined(XP_WIN)"
|
||||
|
||||
# 1 = DWMSBT_MAINWINDOW
|
||||
# 2 = DWMSBT_TRANSIENTWINDOW (default, also used for popups)
|
||||
# 3 = DWMSBT_TABBEDWINDOW
|
||||
- name: widget.windows.mica.toplevel-backdrop
|
||||
value: 2
|
||||
condition: 'defined(XP_WIN)'
|
||||
condition: "defined(XP_WIN)"
|
||||
|
||||
@@ -36,8 +36,8 @@
|
||||
value: 10
|
||||
|
||||
- name: zen.workspaces.debug
|
||||
value: '@cond'
|
||||
condition: '!defined(MOZILLA_OFFICIAL)' # Section: Pinned tabs management
|
||||
value: "@cond"
|
||||
condition: "!defined(MOZILLA_OFFICIAL)" # Section: Pinned tabs management
|
||||
|
||||
- name: zen.pinned-tab-manager.wheel-close-if-pending
|
||||
value: true
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
2
src/zen/@types/index.d.ts
vendored
2
src/zen/@types/index.d.ts
vendored
@@ -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;
|
||||
|
||||
2398
src/zen/@types/lib.gecko.dom.d.ts
vendored
2398
src/zen/@types/lib.gecko.dom.d.ts
vendored
File diff suppressed because it is too large
Load Diff
6788
src/zen/@types/lib.gecko.glean.d.ts
vendored
6788
src/zen/@types/lib.gecko.glean.d.ts
vendored
File diff suppressed because it is too large
Load Diff
2566
src/zen/@types/lib.gecko.modules.d.ts
vendored
2566
src/zen/@types/lib.gecko.modules.d.ts
vendored
File diff suppressed because it is too large
Load Diff
8
src/zen/@types/lib.gecko.tweaks.d.ts
vendored
8
src/zen/@types/lib.gecko.tweaks.d.ts
vendored
@@ -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 {
|
||||
|
||||
34
src/zen/@types/zen.d.ts
vendored
34
src/zen/@types/zen.d.ts
vendored
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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"));
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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% {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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" */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
:root[inDOMFullscreen='true'] #zen-appcontent-navbar-wrapper {
|
||||
:root[inDOMFullscreen="true"] #zen-appcontent-navbar-wrapper {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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")
|
||||
);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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%;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 || [],
|
||||
});
|
||||
|
||||
@@ -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
@@ -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 } }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user