Compare commits

...

39 Commits

Author SHA1 Message Date
mr. m
60318bb64c Merge branch 'dev' of https://github.com/zen-browser/desktop into dev 2026-03-11 00:57:45 +01:00
mr. m
23ceaf7721 feat: Make sure to add checks for invalid essential items, b=no-bug, c=workspaces 2026-03-11 00:57:38 +01:00
mr. m
eb176edf8b fix: Fixed race condition happening when moving tabs to a synced window, b=closes #12707, c=common 2026-03-11 00:30:15 +01:00
mr. m
9c1164b9bc chore: Sync upstream to Firefox 148.0.2 (#12724) 2026-03-10 23:23:24 +00:00
mr. m
036cfb187c chore: Run lint and fund dependencies, p=#12718 2026-03-10 21:34:24 +01:00
mr. m
c4948ee0cd chore: Sync upstream Firefox to version 148.0.2, p=#12712 2026-03-10 12:52:35 +01:00
mr. m
4d56da4319 chore: Make sure to run patch imports when syncing upstream, b=no-bug, c=workflows 2026-03-10 11:18:02 +01:00
mr. m
f718d4414e perf: Improved performance when switiching spaces, p=#12698
* perf: Improved performance when switiching spaces, b=no-bug, c=common, compact-mode, workspaces

* chore: format, b=no-bug, c=workspaces
2026-03-09 20:16:41 +01:00
Ruben Fricke
25c5740331 fix: set zenDefaultUserContextId on live folder tabs, p=#12702 2026-03-09 18:04:08 +01:00
Lukas
64fc35658d feat: Change selected tab when resetting pinned tab, p=#12696 2026-03-09 13:42:15 +01:00
Lukas
dac4575a91 chore: Add .DS_Store to gitignore, p=#12695 2026-03-09 11:04:23 +01:00
Slowlife
58ffcd13c8 fix: allow all cross-origin loads for live folders, b=closes #12685, p=#12686
* fix: allow all cross-origin loads for live folders, b=closes #12685, c=folders

* chore: undo style changes
2026-03-08 16:43:21 +01:00
mr. m
0ee960e3a3 chore: Start making use of Mozilla's linter, p=#12656 2026-03-07 12:15:32 +01:00
mr. m
7c8ccdedd4 Merge branch 'dev' of https://github.com/zen-browser/desktop into dev 2026-03-06 00:44:08 +01:00
mr. m
ea35896484 feat: Small detail changes to control panel, b=no-bug, c=common 2026-03-06 00:43:38 +01:00
Hythera
dbf6daebdc chore: add ignored files in recalculate-patches, p=#12642 2026-03-05 16:47:34 +01:00
Hythera
3f0f07ac37 fix: script interpreters and permissions, p=#12641 2026-03-05 14:41:55 +01:00
Hythera
d25a99cd21 fix: remove duplicate patches, p=#12640 2026-03-05 13:35:05 +01:00
mr. m
efae7418c4 fix: Fixed new tabs not allowed to be opened, b=closes #12628, c=no-component 2026-03-05 10:04:14 +01:00
mr. m
34c2618ca0 feat: Increase drag over split threshold, b=no-bug, c=split-view 2026-03-04 13:05:07 +01:00
mr. m
84b7cf8ddd fix: Also apply auto appearance to non arrow popups, b=no-bug, c=common 2026-03-04 07:31:01 +01:00
mr. m
0d816b3cc2 chore: Sync external patches, p=#12607 2026-03-03 22:51:57 +01:00
mr. m
ad4eeee55a feat: Make sure to trim down parameters before fetching github PRs, b=no-bug, c=folders 2026-03-03 11:52:12 +01:00
mr. m
ad74b55dbf Revert "fix: github folder not getting pr list, p=#12578, c=folders", p=#12599 2026-03-03 11:28:32 +01:00
mr. m
5ffb2d8d69 feat: Don't search clipboard content when middle clicking the sidebar, b=no-bug, c=no-component 2026-03-03 01:01:19 +01:00
mr. m
5a91c0c70b feat: Add more spacings between the essentials paddings, b=no-bug, c=tabs 2026-03-03 00:49:55 +01:00
mr. m
3831af027e feat: Fixed wrong rendering when animating popover opens, b=no-bug, c=common 2026-03-03 00:46:30 +01:00
Mr. M
ee5c1894eb chore: Streamline surfer implementation to newer versions for win signs, b=no-bug, c=no-component 2026-03-03 00:14:13 +01:00
Kryštof Gärtner
e31d91282b feat: add specific toast for copying URL as Markdown, p=#12588 2026-03-02 19:35:58 +01:00
mr. m
32b355595c feat: Correctly assign containers to new live folder tabs, b=no-bug, c=folders 2026-03-02 18:13:57 +01:00
Slowlife
b5b31c02d0 fix: github folder not getting pr list, p=#12578, c=folders
Co-authored-by: mr. m <mr.m@tuta.com>
2026-03-02 15:03:16 +01:00
mr. m
bcdb905ad6 feat: Correctly mark tab visibility inside active folders, b=no-bug, c=common, folders 2026-03-02 09:58:49 +01:00
mr. m
3044b409fa chore: Always restore normal tabs when updating, b=no-bug, c=no-component 2026-03-02 00:09:10 +01:00
Niraj Yadav
747dd3d4bc feat: use sidebar-keep-hover delay while hiding sidebar, p=#12541
Co-authored-by: mr. m <mr.m@tuta.com>
2026-03-01 18:52:44 +01:00
mr. m
49225cf685 chore: Import external patches with replacements, b=no-bug, c=no-component 2026-03-01 18:09:35 +01:00
mr. m
0f4abf2237 Merge branch 'dev' of https://github.com/zen-browser/desktop into dev 2026-03-01 13:51:24 +01:00
mr. m
657d03821f feat: Start checking for spaces mroe robustly when restoring, b=no-bug, c=common, workspaces 2026-03-01 13:50:28 +01:00
mr. m
8fc2ecbb66 chore: Sync external patches, b=closes https://github.com/zen-browser/desktop/issues/12555, p=#12560 2026-03-01 11:52:59 +01:00
mr-cheffy
d78dcdddaf docs: Update monthly issue metrics, b=(no bug), c={docs} 2026-03-01 03:13:27 +00:00
227 changed files with 11506 additions and 8430 deletions

View File

@@ -28,20 +28,32 @@ jobs:
with:
node-version-file: ".nvmrc"
- 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') }}
run: |
sudo apt install python3-autopep8
autopep8 --diff scripts/ src/
- name: Install dependencies
run: npm ci
- name: Download Firefox
env:
ZEN_DOWNLOAD_DONT_INIT_GIT: "1"
- name: Restore Surfer engine cache
id: surfer-engine-cache
uses: actions/cache@v5
with:
path: .surfer/engine/
key: surfer-engine-${{ hashFiles('surfer.json') }}
- name: Setup Git
run: |
npm run download
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Download Firefox
run: npm run download
- name: Import patches
run: npm run import
- name: Add .hgignore file to the engine dir
run: touch engine/.hgignore
- name: Run Bootstrap
run: npm run bootstrap
- name: Lint
run: npm run lint

View File

@@ -28,13 +28,29 @@ jobs:
- name: Install dependencies
run: npm ci
- name: Restore Surfer engine cache
id: surfer-engine-cache
uses: actions/cache@v5
with:
path: .surfer/engine/
key: surfer-engine-${{ hashFiles('surfer.json') }}
- name: Setup Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Download Firefox and dependencies
env:
ZEN_DOWNLOAD_DONT_INIT_GIT: "1"
run: npm run download
- name: Run linting
run: npm run lint
- name: Run Bootstrap
run: npm run bootstrap
- name: Add .hgignore file to the engine dir
run: touch engine/.hgignore
- name: Import patches
run: npm run import
- name: Run linting
run: npm run lint

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
set -xe

View File

@@ -60,6 +60,13 @@ jobs:
npm run surfer -- ci --brand release
fi
- name: Restore Surfer engine cache
id: surfer-engine-cache
uses: actions/cache@v5
with:
path: .surfer/engine/
key: surfer-engine-${{ hashFiles('surfer.json') }}
- name: Download Firefox and dependencies
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
run: npm run download
@@ -73,8 +80,13 @@ jobs:
npm run sync
fi
- name: Install autopep8
run: sudo apt install python3-autopep8
- name: Run Import
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
run: npm run import
- name: Run Bootstrap
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
run: npm run bootstrap
- name: Install requirements
run: pip3 install -r requirements.txt
@@ -82,7 +94,7 @@ jobs:
- name: Check if any files changed
id: git-check
run: |
npm run pretty
npm run lint:fix
if [ -n "$(git status --porcelain)" ]; then
echo "files_changed=true" >> $GITHUB_OUTPUT
else
@@ -119,7 +131,7 @@ jobs:
- name: Run formatter
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
run: |
npm run pretty
npm run lint:fix
- name: Create pull request
uses: peter-evans/create-pull-request@v7

1
.gitignore vendored
View File

@@ -24,3 +24,4 @@ target/
locales/firefox-l10n/
!src/toolkit/themes/shared/design-system/dist/
.DS_Store

View File

@@ -1,42 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
engine/
**/*.html
**/*.xhtml
**/*.inc.xhtml
**/*.bundle.min.js
**/*.min.js
**/*.min.mjs
**/*.svg
**/*.inc.css
surfer.json
src/zen/tests/mochitests/*
src/browser/app/profile/*.js
pnpm-lock.yaml
**/engine/
docs/issue-metrics/*.md
.husky/
# Some CSS files are preprocessed and prettier doesn't handle them well
# We also dont want to format the CSS files that are generated by the build
src/zen/tabs/zen-tabs.css
src/zen/common/styles/zen-theme.css
src/zen/compact-mode/zen-compact-mode.css
src/zen/common/ZenEmojis.mjs
src/zen/split-view/zen-decks.css
src/zen/workspaces/zen-workspaces.css
src/zen/common/styles/zen-toolbar.css
*.inc

View File

@@ -1,20 +0,0 @@
{
"bracketSameLine": true,
"endOfLine": "lf",
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false,
"jsxSingleQuote": false,
"semi": true,
"printWidth": 100,
"plugins": ["prettier-plugin-sh"],
"overrides": [
{
"files": "*.css",
"options": {
"parser": "css",
"printWidth": 160
}
}
]
}

View File

@@ -34,8 +34,8 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
### Firefox Versions
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `148.0`! 🚀
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 148.0`!
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `148.0.2`! 🚀
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 148.0.2`!
### Contributing

View File

@@ -1 +1 @@
40d4c2395112d4188721e69d338ee75bded8858a
7b8f3620beb1de157d972de32f9f34320f0ae189

View File

@@ -23,6 +23,9 @@ mkdir windsign-temp -ErrorAction SilentlyContinue
# echo "Downloaded git objects repo to"
#} -Verbose -ArgumentList $PWD -Debug
$env:SURFER_MOZCONFIG_ONLY="1"
$env:SURFER_SIGNING_MODE=""
Start-Job -Name "DownloadGitl10n" -ScriptBlock {
param($PWD)
cd $PWD
@@ -31,14 +34,11 @@ Start-Job -Name "DownloadGitl10n" -ScriptBlock {
echo "Fetched l10n and Firefox's one"
} -Verbose -ArgumentList $PWD -Debug
Start-Job -Name "SurferInit" -ScriptBlock {
param($PWD)
cd $PWD
npm run import -- --verbose
$surferJson = Get-Content surfer.json | ConvertFrom-Json
$version = $surferJson.brands.release.release.displayVersion
npm run ci -- $version
} -Verbose -ArgumentList $PWD -Debug
$surferJson = Get-Content surfer.json | ConvertFrom-Json
$version = $surferJson.brands.release.release.displayVersion
npm run ci -- $version
npm run import -- --verbose
npm run build
echo "Downloading artifacts info"
$artifactsInfo=gh api repos/zen-browser/desktop/actions/runs/$GithubRunId/artifacts
@@ -120,7 +120,6 @@ signtool.exe sign /n "$SignIdentity" /t http://time.certum.pl/ /fd sha256 /v $fi
$env:ZEN_RELEASE="true"
$env:SURFER_SIGNING_MODE="true"
$env:SCCACHE_GHA_ENABLED="false"
Wait-Job -Name "SurferInit"
Wait-Job -Name "DownloadGitl10n"
function SignAndPackage($name) {

View File

@@ -0,0 +1,217 @@
# Issue Metrics
| Metric | Average | Median | 90th percentile |
| --- | --- | --- | ---: |
| Time to first response | 1 day, 1:26:40 | 2:07:50 | 2 days, 5:33:54 |
| Time to close | 1 day, 12:18:56 | 3:30:42 | 4 days, 7:35:38 |
| Metric | Count |
| --- | ---: |
| Number of items that remain open | 97 |
| Number of items closed | 102 |
| Total number of items created | 199 |
| Title | URL | Time to first response | Time to close |
| --- | --- | --- | --- |
| Zen browser highlight elements by itself | https://github.com/zen-browser/desktop/issues/12551 | 5:54:36 | None |
| pasted url revert to old one automaticaly ? | https://github.com/zen-browser/desktop/issues/12548 | 6:47:54 | None |
| chat.mistral.ai - site is not usable | https://github.com/zen-browser/desktop/issues/12547 | 10:45:42 | None |
| Horizontal Scrolling with mouse wheel is not working | https://github.com/zen-browser/desktop/issues/12545 | None | 1:30:19 |
| The Text color of search bar when press the "Ctrl + f" | https://github.com/zen-browser/desktop/issues/12537 | None | None |
| Buggy Native Popover for Tab Previews on Twilight | https://github.com/zen-browser/desktop/issues/12529 | 0:06:41 | 0:06:41 |
| Can't drag files directly from Downloads panel | https://github.com/zen-browser/desktop/issues/12520 | 11:56:10 | 11:56:24 |
| Repeated SIGSEGV in libxul.so on Linux (1.18.10b, Fedora 43, AMD) | https://github.com/zen-browser/desktop/issues/12516 | None | None |
| Previously closed windows recovery option missing | https://github.com/zen-browser/desktop/issues/12515 | 1:40:19 | 1:40:20 |
| Empty Spaces after waking laptop | https://github.com/zen-browser/desktop/issues/12512 | 4:14:32 | 1 day, 1:42:28 |
| New tab shortcut shows search input instead of tab input | https://github.com/zen-browser/desktop/issues/12510 | 8:46:21 | 8:46:21 |
| Folder tree breaks with live folders fetch | https://github.com/zen-browser/desktop/issues/12509 | 0:08:50 | 8:11:04 |
| Tabs bar shakes in compact mode | https://github.com/zen-browser/desktop/issues/12505 | 0:02:08 | None |
| Youtube Playlist issue | https://github.com/zen-browser/desktop/issues/12502 | None | 18:54:24 |
| Maps with very much data are very laggy | https://github.com/zen-browser/desktop/issues/12501 | 3:09:58 | 16:56:17 |
| Allow changing interface font for generic Linux tarball | https://github.com/zen-browser/desktop/issues/12500 | 1:05:58 | None |
| The transparent gradient background suddenly covers the current tab | https://github.com/zen-browser/desktop/issues/12497 | 8:59:58 | 8:59:58 |
| Obscene memory leak on Mac | https://github.com/zen-browser/desktop/issues/12496 | 0:35:11 | None |
| top tool bar and close/minimize buttons on title bar overlap on windows | https://github.com/zen-browser/desktop/issues/12495 | 1 day, 16:34:34 | None |
| Tabs in essentials disappear after closing Zen | https://github.com/zen-browser/desktop/issues/12493 | 14:53:54 | None |
| When you open a new window using the taskbar icon, it mirrors the tabs of another window. | https://github.com/zen-browser/desktop/issues/12492 | 0:11:21 | 0:11:21 |
| using my GoBack mouse button switches workspaces | https://github.com/zen-browser/desktop/issues/12491 | 0:03:40 | None |
| closing Folder tabs doesn't close them | https://github.com/zen-browser/desktop/issues/12490 | 0:08:26 | 0:08:26 |
| Zen compact hover mode time increase not respected | https://github.com/zen-browser/desktop/issues/12489 | 0:06:19 | 0:06:19 |
| White dots spreading everywhere on any website visited in Zen Browser, reset when interacting with UI layer; duplicate contour lines appearing at the same time as the dots on the Zen Browser UI - Windows 11 | https://github.com/zen-browser/desktop/issues/12488 | None | 2 days, 13:52:50 |
| What just happened to my tab??? (Also when I close Zen browser while I watching YouTube, the audio still exist, wth?) | https://github.com/zen-browser/desktop/issues/12486 | 0:27:29 | None |
| Reddit multi word enter search won't work | https://github.com/zen-browser/desktop/issues/12485 | None | None |
| Use a different default search engine in private windows defaults to true | https://github.com/zen-browser/desktop/issues/12484 | None | 1:52:44 |
| ALSA support disabled, no sound on ALSA only systems | https://github.com/zen-browser/desktop/issues/12483 | 10:13:00 | None |
| Addressbar closing when inputing german Umlauts with us_intl keymap | https://github.com/zen-browser/desktop/issues/12482 | 2:18:36 | 2:18:36 |
| Zen Browser Tabs: Backgroung Image is not working | https://github.com/zen-browser/desktop/issues/12479 | 7:28:03 | 17:51:35 |
| bookmarks keep vanishing | https://github.com/zen-browser/desktop/issues/12478 | 8:34:20 | None |
| The menu for my browser history button is moving down in KDE Plasma. | https://github.com/zen-browser/desktop/issues/12475 | None | 1:43:31 |
| Zen Browser is being blocked by BattlEye anti-cheat during game launch on Windows 11. | https://github.com/zen-browser/desktop/issues/12473 | 0:06:23 | None |
| CRUNCHYROLL NOT WORKING | https://github.com/zen-browser/desktop/issues/12467 | 0:05:42 | 0:05:42 |
| Holding rightclick will caues wrong mouse position | https://github.com/zen-browser/desktop/issues/12466 | None | None |
| Battery Drain MacOS - High CPU usage | https://github.com/zen-browser/desktop/issues/12464 | 3 days, 19:23:37 | None |
| Logged out of all Google accounts and can't log back in. | https://github.com/zen-browser/desktop/issues/12462 | 20:50:59 | None |
| Blank Window and Session Loss After Update | https://github.com/zen-browser/desktop/issues/12460 | 0:05:20 | None |
| Sometimes web lagging for a few second | https://github.com/zen-browser/desktop/issues/12458 | 0:00:47 | None |
| Mods don't work anymore | https://github.com/zen-browser/desktop/issues/12455 | 0:36:29 | 2:08:08 |
| Auto Update Failing To Update (Message Update Failed) | https://github.com/zen-browser/desktop/issues/12454 | 2:55:11 | 2:55:11 |
| Setting up keyboard shortcuts does not recognize azerty keyboard | https://github.com/zen-browser/desktop/issues/12451 | 0:12:44 | None |
| External links open new window with duplicated tabs when browser is minimized on Windows | https://github.com/zen-browser/desktop/issues/12450 | 6:32:08 | None |
| Browser doesn't know where mouse is until clicking out of the browser | https://github.com/zen-browser/desktop/issues/12447 | None | None |
| Beginning w/ v1.18.8b (?) my navigation started floating/popping/hiding; never asked for that. Then v1.18.9b (?) removed all my tabs incl auto/pinned | https://github.com/zen-browser/desktop/issues/12443 | 1:13:56 | 1:18:00 |
| Bookmarks not shown on site pages | https://github.com/zen-browser/desktop/issues/12442 | 0:01:11 | 0:01:11 |
| Side bar flickering | https://github.com/zen-browser/desktop/issues/12441 | None | None |
| Sidebar should not hide when mouse pointer is still at the edge of the screen | https://github.com/zen-browser/desktop/issues/12439 | 0:08:24 | None |
| Zen not respecting output audio device switching in Windows | https://github.com/zen-browser/desktop/issues/12438 | None | None |
| New tab does not make a new tab - it only activates the URL bar | https://github.com/zen-browser/desktop/issues/12432 | 0:26:23 | 0:26:23 |
| ZEN Ignoring DNS over HTTPS OFF | https://github.com/zen-browser/desktop/issues/12429 | 0:29:20 | None |
| The search window does not appear until you start typing | https://github.com/zen-browser/desktop/issues/12428 | 1:42:23 | 5 days, 22:42:30 |
| Toolbar icons overflow after uninstalling extension (requires restart to fix) | https://github.com/zen-browser/desktop/issues/12427 | 6:05:59 | 6:05:58 |
| Side Tab Flickering when minimized from full view - faced in mac desktop browser | https://github.com/zen-browser/desktop/issues/12425 | 4:54:13 | None |
| buggy Tabs drag and drop | https://github.com/zen-browser/desktop/issues/12423 | 0:28:12 | None |
| Spaces dissapear suddently | https://github.com/zen-browser/desktop/issues/12422 | 0:07:36 | 4 days, 0:53:47 |
| Tabs become New Tab when using Window Sync | https://github.com/zen-browser/desktop/issues/12421 | 2 days, 13:53:49 | 3 days, 15:49:00 |
| Closed the browser after a glitch, now the app remains full white | https://github.com/zen-browser/desktop/issues/12420 | 0:04:32 | 1 day, 2:01:15 |
| Search bar overflow over main screen from pining to overflow menu but also breaks ui in recreating | https://github.com/zen-browser/desktop/issues/12419 | None | None |
| Closing Sidebar Causes Unexpected Border Increase on the Other Side. | https://github.com/zen-browser/desktop/issues/12418 | 0:25:14 | None |
| Persistent Favicon Inconsistency/Tint on GitHub Bookmarks | https://github.com/zen-browser/desktop/issues/12415 | 1 day, 22:54:53 | None |
| Sometimes, the right-click menu for links will keep shifting to the right | https://github.com/zen-browser/desktop/issues/12413 | 6:45:26 | 10:55:38 |
| AppImage lacks version metadata, preventing AppImage update detection | https://github.com/zen-browser/desktop/issues/12412 | 13:17:50 | 8:27:29 |
| [Windows] Launching a new window (Ctrl + N) replicates the same tabs on the new window | https://github.com/zen-browser/desktop/issues/12411 | 11:10:43 | 11:10:43 |
| Tab preview text illegible in front of light background | https://github.com/zen-browser/desktop/issues/12410 | 11:14:21 | None |
| Temporary Containers broke with update | https://github.com/zen-browser/desktop/issues/12409 | 1:57:05 | 14:06:01 |
| Zen doesn't work with Simple Tab Groups | https://github.com/zen-browser/desktop/issues/12408 | 4:58:31 | None |
| Unable to set "Copy Current URL" to ctrl+shift+INSERT | https://github.com/zen-browser/desktop/issues/12406 | None | None |
| Browser Toolbox Error Loading | https://github.com/zen-browser/desktop/issues/12405 | 5:30:27 | 5:30:27 |
| Restoring Split Tabs Ignored | https://github.com/zen-browser/desktop/issues/12403 | 0:14:37 | None |
| Windows: Scroll bar in tab list causes layout shift when always show scroll bars is enabled | https://github.com/zen-browser/desktop/issues/12402 | 2 days, 3:59:15 | None |
| Trash icon appears in Change Icon menu for folders with no icon | https://github.com/zen-browser/desktop/issues/12401 | None | 8 days, 11:45:52 |
| Window sync has been forced back on | https://github.com/zen-browser/desktop/issues/12400 | 0:47:07 | 0:47:07 |
| Toolbar not opening when approaching with mouse to fast | https://github.com/zen-browser/desktop/issues/12398 | None | None |
| Can't use Proton Pass because of second password | https://github.com/zen-browser/desktop/issues/12393 | None | None |
| Can't Customize toolbar on "only sidebar" configuration | https://github.com/zen-browser/desktop/issues/12391 | None | None |
| Sync deletes tab (kind of) | https://github.com/zen-browser/desktop/issues/12390 | 9 days, 7:25:30 | None |
| Please allow us to increase the font size on the left tabs. | https://github.com/zen-browser/desktop/issues/12388 | 0:52:26 | 0:52:26 |
| Vertical Sidebar starts 'oscillating' when it is reduced in size. | https://github.com/zen-browser/desktop/issues/12387 | 0:05:02 | 0:05:41 |
| [Regression] Severe stuttering and long loading on Bilibili (4K) in v1.18.7b | https://github.com/zen-browser/desktop/issues/12386 | 8 days, 5:05:17 | None |
| [macOS] Now Playing widget completely non-functional (works in Firefox) | https://github.com/zen-browser/desktop/issues/12385 | 1:16:07 | 1 day, 23:03:30 |
| responsive design mode can't be enlarged by zooming | https://github.com/zen-browser/desktop/issues/12381 | 11 days, 16:50:20 | None |
| Pinned tab under a folder, opens and redirect to a new regular tab | https://github.com/zen-browser/desktop/issues/12379 | 2:37:39 | None |
| xdg-open fails to open files in existing Zen instance (Arch Linux and Hyprland) | https://github.com/zen-browser/desktop/issues/12378 | 23:23:25 | None |
| Sidebar coloring issues in private windows | https://github.com/zen-browser/desktop/issues/12377 | None | None |
| [Bug] Youtube shorts notplaying properly, and when using the shortcut "I' it gives an error. | https://github.com/zen-browser/desktop/issues/12376 | 13:44:07 | None |
| Sometimes, when opening a new tab, M4 and M5 buttons change spaces | https://github.com/zen-browser/desktop/issues/12375 | 0:41:41 | 0:41:41 |
| Private Windows don't function with Window Sync | https://github.com/zen-browser/desktop/issues/12374 | 0:33:47 | 0:33:47 |
| Passkey from qr code not showing on widows 10 os | https://github.com/zen-browser/desktop/issues/12372 | None | None |
| Relatively Low Audio Volume | https://github.com/zen-browser/desktop/issues/12370 | None | None |
| Workspace icon highlight missing after latest update | https://github.com/zen-browser/desktop/issues/12368 | 1:49:10 | 1:49:15 |
| Prime Video | https://github.com/zen-browser/desktop/issues/12365 | 0:18:36 | 0:18:36 |
| Taskbar Tabs create semi-transparent, empty, non-closeable windows | https://github.com/zen-browser/desktop/issues/12364 | 1:17:21 | None |
| [Bug] Enterprise Policies via macOS Managed Preferences (.plist) are not recognized | https://github.com/zen-browser/desktop/issues/12363 | None | None |
| Misaligned video fullscreen mode for 2 monitors | https://github.com/zen-browser/desktop/issues/12362 | 2 days, 5:21:33 | None |
| Choppy audio on YouTube when using a external DAC | https://github.com/zen-browser/desktop/issues/12361 | 2 days, 5:21:25 | 2 days, 5:47:20 |
| Performance difference between appimage and Flatpak | https://github.com/zen-browser/desktop/issues/12357 | 0:01:34 | None |
| "Close Pinned Tab Shortcut Behavior" ignored for "Places" tab | https://github.com/zen-browser/desktop/issues/12353 | 15 days, 10:51:28 | None |
| Menu flickers when pressed | https://github.com/zen-browser/desktop/issues/12352 | 9 days, 0:49:56 | None |
| Closing, Minimizing, and Maximizing Buttons squished | https://github.com/zen-browser/desktop/issues/12351 | 0:09:14 | 0:09:14 |
| New Tab bug on mac | https://github.com/zen-browser/desktop/issues/12350 | 0:02:33 | 0:02:32 |
| Redirect notification toast overlaps right sidebar | https://github.com/zen-browser/desktop/issues/12348 | None | 13:39:22 |
| macOS: close/minimize/maximize buttons are not displayed correctly | https://github.com/zen-browser/desktop/issues/12347 | 0:15:49 | 0:15:49 |
| After updating to 1.18.6b, minimize, maximize and close buttons are squished in Windows | https://github.com/zen-browser/desktop/issues/12346 | 0:09:07 | 0:09:56 |
| Layout bug for minimize/maximize/close window buttons on Windows 11 | https://github.com/zen-browser/desktop/issues/12345 | 0:11:27 | 0:11:28 |
| Disabling windows sync still results in same tabs being displayed throught multiple window sessions when restarting/restoring | https://github.com/zen-browser/desktop/issues/12344 | None | 0:20:21 |
| Picture-in-picture not working as intended | https://github.com/zen-browser/desktop/issues/12342 | 3:39:41 | 1 day, 2:32:57 |
| Icons aren't displaying correctly | https://github.com/zen-browser/desktop/issues/12340 | None | 5:45:13 |
| Workspaces aren't syncing to a new device | https://github.com/zen-browser/desktop/issues/12339 | 1:07:18 | 6:26:52 |
| All tabs and folders are missing after update to 1.18.5b | https://github.com/zen-browser/desktop/issues/12337 | 8:49:51 | 8:49:51 |
| macOS profile lost pinned tabs and Essentials after Windows sync folders remain but are empty | https://github.com/zen-browser/desktop/issues/12336 | 9:29:24 | None |
| Zen misses some color support | https://github.com/zen-browser/desktop/issues/12335 | 0:45:02 | 0:45:02 |
| Disabled "sync tabs" loose tabs | https://github.com/zen-browser/desktop/issues/12333 | 4:05:24 | None |
| MacOs: Intel-based Mac Pro - Zen fails to launch (GPU subprocess / IPC timeouts) | https://github.com/zen-browser/desktop/issues/12331 | None | None |
| Zen launch error | https://github.com/zen-browser/desktop/issues/12330 | None | 0:39:18 |
| When I attempted to rename the workspace, the compact mode failed and I was unable to enter the compact mode again. | https://github.com/zen-browser/desktop/issues/12329 | 3:21:05 | 3:21:05 |
| Cannot properly position or resize Zen with certain window managers | https://github.com/zen-browser/desktop/issues/12327 | None | None |
| Space resets when closing window (but not quitting) after clearing browser history | https://github.com/zen-browser/desktop/issues/12326 | 0:46:52 | 14:27:39 |
| New tabs don't change tab title | https://github.com/zen-browser/desktop/issues/12318 | 10:51:08 | None |
| Weird reopen closed tab behaviour for folders | https://github.com/zen-browser/desktop/issues/12316 | None | None |
| Per Workspace Essentials No Longer Work. | https://github.com/zen-browser/desktop/issues/12313 | 0:54:50 | 2:25:53 |
| Are Spaces supposed to sync between different devices? | https://github.com/zen-browser/desktop/issues/12311 | 1:26:09 | 1:26:09 |
| Open previous windows and tabs settings / continue where you left off being ignored. | https://github.com/zen-browser/desktop/issues/12307 | 12:51:38 | 13:53:11 |
| local access disappeared after 18.5 | https://github.com/zen-browser/desktop/issues/12305 | 16:24:35 | None |
| Transparency is weird on macOS | https://github.com/zen-browser/desktop/issues/12303 | 1:16:12 | None |
| Vertical Sidebar flickering/jittering during interaction | https://github.com/zen-browser/desktop/issues/12299 | 3:23:55 | None |
| "Sync only pinned tabs in workspaces" breaks "Open previous windows and tabs" | https://github.com/zen-browser/desktop/issues/12297 | 0:05:40 | 10:53:40 |
| Github Actions Artifacts downloads do not work on Zen | https://github.com/zen-browser/desktop/issues/12296 | None | None |
| Zen menu bar items take excessive horizontal space compared to other apps | https://github.com/zen-browser/desktop/issues/12294 | None | None |
| Workspaces lost after upgrade to 1.18.5b (Firefox 147.0.3) (64-bit) on Windows 11 Pro Intel | https://github.com/zen-browser/desktop/issues/12293 | 3:33:29 | 3:33:29 |
| Kernel panic on macOS Sequoia 15.7.3 when running Zen | https://github.com/zen-browser/desktop/issues/12290 | None | None |
| Opening a GitHub CodeSpace in the Browser throws a "Oh No, it looks like youre offline!" error tho i have a stable Internet connection, and it worked on older Versions of Zen before. Chrome on the same device/internet works. | https://github.com/zen-browser/desktop/issues/12288 | None | None |
| Zen does not read privacy.fingerprintingProtection from user.js | https://github.com/zen-browser/desktop/issues/12286 | 1:44:38 | 7:13:24 |
| Closing a window lead sometimes to window sync to stop working | https://github.com/zen-browser/desktop/issues/12284 | None | None |
| Pinned tabs reset to incorrect URL (pinned URL changes) | https://github.com/zen-browser/desktop/issues/12281 | 0:00:55 | None |
| Compact mode non hide stuck | https://github.com/zen-browser/desktop/issues/12279 | 15:23:06 | None |
| Recently closed windows/undo close window missing | https://github.com/zen-browser/desktop/issues/12278 | 4 days, 8:20:17 | 4 days, 8:20:17 |
| Opening about: pages causes 'new tab' bug with window sync | https://github.com/zen-browser/desktop/issues/12277 | 9 days, 16:39:47 | None |
| arm64 Flatpak compositor crash on ChromeOS Crostini (virgl / Mesa 25.x regression) | https://github.com/zen-browser/desktop/issues/12276 | 8 days, 18:31:53 | None |
| YouTube freezes when switching audio output in fxSound | https://github.com/zen-browser/desktop/issues/12275 | None | None |
| Button missing: Hamburger Menu > History > Restore Previous Session | https://github.com/zen-browser/desktop/issues/12272 | 0:10:35 | None |
| Next/Prev Tab Shortcut Conflict | https://github.com/zen-browser/desktop/issues/12267 | 0:03:09 | 0:03:09 |
| 1.18.5b Release Download Not Found | https://github.com/zen-browser/desktop/issues/12266 | 0:13:04 | 0:13:04 |
| Viedo streaming websites become unresponsive when multiple instances are open | https://github.com/zen-browser/desktop/issues/12265 | None | None |
| All workspaces deleted upon v1.18.5b installation | https://github.com/zen-browser/desktop/issues/12261 | 1:07:39 | 3:40:07 |
| Zen fails to start with sync only pinned tabs | https://github.com/zen-browser/desktop/issues/12260 | 0:04:34 | 0:41:21 |
| Thunderbird cannot open a new Zen window when clicking a link | https://github.com/zen-browser/desktop/issues/12259 | 14:35:21 | None |
| zen.urlbar.replace-newtab = False issues with new windows and tab syncing | https://github.com/zen-browser/desktop/issues/12258 | 2 days, 7:24:59 | None |
| Shortcuts Icon's not working | https://github.com/zen-browser/desktop/issues/12257 | 1 day, 7:22:00 | 15 days, 8:21:20 |
| ADD A METHOD TO DISABLE UPDATES , IM LITERALLY USING A TASK SCHEDULER TO DELETE YOUR STUPID UPDATES FOLDER AND YOU STILL FIND A WAY | https://github.com/zen-browser/desktop/issues/12256 | 2:34:58 | 0:05:06 |
| Broken essential tab URL after switching with keyboard shortcuts | https://github.com/zen-browser/desktop/issues/12255 | 0:19:28 | None |
| Closing glance bug with multiple windows | https://github.com/zen-browser/desktop/issues/12254 | None | None |
| Dragging tabs into folders shows selected folder highlight at incorrect position in some view modes. | https://github.com/zen-browser/desktop/issues/12252 | 1:31:56 | 3:52:46 |
| "New split view" in command bar (on a page accessed from an Essential tab) opens a new tab instead | https://github.com/zen-browser/desktop/issues/12251 | 0:10:54 | None |
| Zen starts as blank widows on macOS Tahoe Version 26.3 (25D122) beta | https://github.com/zen-browser/desktop/issues/12250 | 0:38:21 | 3 days, 23:19:20 |
| Pined extensions icons no longer visible in compact sidebar since last release | https://github.com/zen-browser/desktop/issues/12249 | 2 days, 20:44:58 | None |
| Facing Glitches On Start Opens 2 Windows for Same tabs. | https://github.com/zen-browser/desktop/issues/12248 | 1:25:01 | None |
| Separate windows mirroring | https://github.com/zen-browser/desktop/issues/12247 | 0:12:51 | 0:12:51 |
| H.264, HEVC, and AAC Not Supported in Kubuntu App Center Version (1.17.14b) | https://github.com/zen-browser/desktop/issues/12245 | 1 day, 12:07:19 | None |
| Private and blank windows ignore CloseWindowWithLastTab setting | https://github.com/zen-browser/desktop/issues/12242 | 9:22:25 | 2 days, 8:59:22 |
| Bookmark temporarily removes | https://github.com/zen-browser/desktop/issues/12241 | None | None |
| Multiple Windows Launch on Startup after Multiple Windows Have Been Closed | https://github.com/zen-browser/desktop/issues/12238 | 16:04:12 | None |
| Duplicated Toggle Full Screen and View Full Screen for keyboard shortcut | https://github.com/zen-browser/desktop/issues/12237 | 10 days, 20:34:41 | 11 days, 11:58:31 |
| Container no longer displayed when moving tabs between windows on different spaces | https://github.com/zen-browser/desktop/issues/12235 | 10 days, 13:27:01 | 10 days, 18:33:05 |
| Multi account container settings reset | https://github.com/zen-browser/desktop/issues/12234 | None | None |
| Clicking the “Copy” button opens an “Open With” dialog on KDE Plasma Wayland. | https://github.com/zen-browser/desktop/issues/12232 | 13 days, 7:34:57 | 14 days, 19:58:57 |
| Can't open a new window with clear context | https://github.com/zen-browser/desktop/issues/12229 | None | 0:01:26 |
| Can't play DRM content in Linux | https://github.com/zen-browser/desktop/issues/12228 | 4:21:30 | 6:06:50 |
| Missing icons in address bar: padlock (https) and star (to bookmark current page) | https://github.com/zen-browser/desktop/issues/12226 | None | 0:08:28 |
| Broken extension/browser tools sidebar keybind | https://github.com/zen-browser/desktop/issues/12225 | 5:45:59 | 9 days, 20:16:58 |
| Sidebar empty after copying profile from Firefox | https://github.com/zen-browser/desktop/issues/12224 | 0:25:56 | 0:25:56 |
| Lost all my folders with the latest update | https://github.com/zen-browser/desktop/issues/12223 | 0:55:54 | 0:55:54 |
| History window doesnt follow default system or browser theme | https://github.com/zen-browser/desktop/issues/12222 | None | None |
| when i have multiple windows and restart zen , all the windows will be the same , have the same tabs | https://github.com/zen-browser/desktop/issues/12221 | 0:35:11 | 0:22:16 |
| Deleting All Data | https://github.com/zen-browser/desktop/issues/12220 | 0:59:01 | None |
| Move to Space in Tab Context Menu not available | https://github.com/zen-browser/desktop/issues/12219 | 0:12:00 | None |
| When opening Zen after closing multiple windows, only one window has workspaces | https://github.com/zen-browser/desktop/issues/12218 | 0:59:47 | None |
| Forms don't allow to be processed | https://github.com/zen-browser/desktop/issues/12217 | 6:15:33 | 6:15:33 |
| Cannot drag and drop to create a split view | https://github.com/zen-browser/desktop/issues/12216 | 0:37:06 | 0:37:06 |
| Glance does not work via keybind+click in Reader VIew | https://github.com/zen-browser/desktop/issues/12214 | None | None |
| "New Blank Window" is not capitalized in Mac OS menu bar | https://github.com/zen-browser/desktop/issues/12213 | None | 7 days, 4:10:17 |
| Zen changes tab IDs without sending tabs.onReplaced events | https://github.com/zen-browser/desktop/issues/12212 | 1:12:47 | 1:12:47 |
| Private window is adopting Blank windows styling | https://github.com/zen-browser/desktop/issues/12211 | None | 0:19:10 |
| The loading indicator on tabs does not appear when a tab is loading. | https://github.com/zen-browser/desktop/issues/12210 | 1:23:55 | 1:23:55 |
| Page content cannot scroll fully to top; top area is hidden behind browser UI | https://github.com/zen-browser/desktop/issues/12209 | 13:06:36 | None |
| TURN OFF WINDOW SYNC | https://github.com/zen-browser/desktop/issues/12206 | 0:47:53 | 1:23:13 |
| Essentials not working correctly | https://github.com/zen-browser/desktop/issues/12205 | 3:18:34 | 3:27:55 |
| Tab titles not updating | https://github.com/zen-browser/desktop/issues/12204 | 3:40:45 | 5:54:14 |
| Folders disappeared after updating to the Zen version 1.18.3b (Firefox 147.0.2) (aarch64) | https://github.com/zen-browser/desktop/issues/12203 | 9:12:45 | 9:12:45 |
| Some websites don't load | https://github.com/zen-browser/desktop/issues/12202 | 1 day, 10:47:54 | None |
| Website favicons have the wrong icons | https://github.com/zen-browser/desktop/issues/12201 | 2:36:06 | 0:04:20 |
| tab indexes are off by 2 | https://github.com/zen-browser/desktop/issues/12199 | None | 3:02:10 |
| Zen doesn't identify itself in the extensions API | https://github.com/zen-browser/desktop/issues/12198 | 1 day, 21:45:16 | 6 days, 22:02:36 |
| Part of the screenshot overlay is rendered below glance windows | https://github.com/zen-browser/desktop/issues/12196 | None | 21 days, 5:30:56 |
| Glance opens without keyboard shortcut in Essential tabs | https://github.com/zen-browser/desktop/issues/12194 | 8:27:58 | 8:27:58 |
| Context menu extensions multiply | https://github.com/zen-browser/desktop/issues/12192 | None | None |
| Tab folder not closing properly when a tab is opened | https://github.com/zen-browser/desktop/issues/12190 | None | 10:15:16 |
| Can't set a theme | https://github.com/zen-browser/desktop/issues/12189 | 1:38:06 | None |
_This report was generated with the [Issue Metrics Action](https://github.com/github/issue-metrics)_
Search query used to find these items: `repo:zen-browser/desktop is:issue created:2026-02-01..2026-02-28`

View File

@@ -47,6 +47,7 @@ pictureinpicture-minimize-btn =
zen-panel-ui-gradient-generator-custom-color = Custom Color
zen-copy-current-url-confirmation = Copied current URL!
zen-copy-current-url-as-markdown-confirmation = Copied current URL as Markdown!
zen-general-cancel-label =
.label = Cancel

1
locales/update-supported-languages.sh Normal file → Executable file
View File

@@ -1,3 +1,4 @@
#!/usr/bin/env bash
LANGS_FILE="./supported-languages"
# Clean up the file

4407
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -21,9 +21,8 @@
"sync:raw": "surfer update",
"sync:rc": "python3 scripts/update_ff.py --rc",
"sync:l10n": "python3 scripts/update_ff.py --just-l10n",
"pretty": "prettier . --write --cache && autopep8 -r --in-place scripts/ src/ --exclude src/zen/tests/",
"lint": "npx eslint src/ && prettier . --check --cache",
"lint:fix": "npm run pretty && npx eslint src/ --fix",
"lint": "cd engine && ./mach lint zen",
"lint:fix": "npm run lint -- --fix",
"prepare": "husky",
"reset-ff": "surfer reset",
"surfer": "surfer",
@@ -51,32 +50,14 @@
"homepage": "https://github.com/zen-browser/desktop#readme",
"devDependencies": {
"@babel/preset-typescript": "^7.27.0",
"@eslint/js": "^9.39.2",
"@eslint/json": "^0.14.0",
"@microsoft/eslint-plugin-sdl": "^1.1.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",
"@zen-browser/prettier": "^3.9.3",
"@zen-browser/surfer": "^1.13.4",
"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",
"typescript": "^5.9.3",
"typescript-eslint": "^8.52.0"
}
"typescript": "^5.9.3"
},
"notes(private)": "We don't want to publish to npm, so this is marked as private",
"private": true
}

View File

@@ -17,6 +17,9 @@
- name: zen.view.compact.toolbar-hide-after-hover.duration
value: 1000
- name: zen.view.compact.sidebar-keep-hover.duration
value: 150
- name: zen.view.compact.animate-sidebar
value: true

View File

@@ -18,4 +18,4 @@
value: 1000
- name: zen.splitView.drag-over-split-threshold
value: 25
value: 40

View File

@@ -1,9 +0,0 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
[tool.autopep8]
max_line_length = 120
recursive = true
aggressive = 3
indent_size = 2

View File

@@ -2,7 +2,6 @@
# 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/.
autopep8==2.3.1
click==8.1.8
mypy-extensions==1.0.0
packaging==24.2

1
scripts/download-language-packs.sh Normal file → Executable file
View File

@@ -1,3 +1,4 @@
#!/usr/bin/env bash
# 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/.

2
scripts/fetch-formal-git-components.sh Normal file → Executable file
View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# 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/.

5
scripts/recalculate-patches.sh Normal file → Executable file
View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# 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/.
@@ -12,6 +12,9 @@ IGNORE_FILES=(
"shared.nsh"
"ignorePrefs.json"
"moz.configure"
"AsyncShutdown.sys.mjs"
"Info.plist.in"
"firefox.js"
)
# Recursively find all .patch files in the current directory and its subdirectories

2
scripts/remove-failed-jobs.sh Normal file → Executable file
View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# 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/.

2
scripts/update-surfer.sh Normal file → Executable file
View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# 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/.

17
src/-prettierignore.patch Normal file
View File

@@ -0,0 +1,17 @@
diff --git a/.prettierignore b/.prettierignore
index cbca8bb4b36cecc44e6b498e9ef15bc4bdc21871..8f3a14e14a2d58875bdd6f04bd31f57e23073148 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1795,3 +1795,12 @@ tools/ts/test/baselines/
try_task_config.json
xpcom/idl-parser/xpidl/fixtures/xpctest.d.json
**/package-lock.json
+
+
+*.bundle.min.js
+*.min.js
+*.min.mjs
+*.inc
+*/mochitests/*
+*.svg
+

View File

@@ -0,0 +1,24 @@
diff --git a/.stylelintignore b/.stylelintignore
index 185490999507b8a5032977237af50f5e61c71df1..e887fafa90b881e852a287ed8898638c995861ab 100644
--- a/.stylelintignore
+++ b/.stylelintignore
@@ -106,3 +106,19 @@ build/pgo/blueprint/**/*.css
# under our control or we don't want to modify at this point:
testing/web-platform/mozilla/
testing/web-platform/tests/
+
+*.inc.css
+
+zen/tests/mochitests/*
+
+# Some CSS files are preprocessed and prettier doesn't handle them well
+# We also dont want to format the CSS files that are generated by the build
+zen/tabs/zen-tabs.css
+zen/common/styles/zen-theme.css
+zen/compact-mode/zen-compact-mode.css
+
+zen/split-view/zen-decks.css
+zen/workspaces/zen-workspaces.css
+zen/common/styles/zen-toolbar.css
+
+*.inc

25
src/-stylelintrc-js.patch Normal file
View File

@@ -0,0 +1,25 @@
diff --git a/.stylelintrc.js b/.stylelintrc.js
index 36719c9e152c34da2aa76fc74d74e58cb9e6b1cc..4226db2e0af4b36923a93dcd0b76e59f8508ba36 100644
--- a/.stylelintrc.js
+++ b/.stylelintrc.js
@@ -67,7 +67,7 @@ module.exports = {
],
"max-nesting-depth": [
- 3,
+ 6,
{
ignore: ["blockless-at-rules"],
},
@@ -274,9 +274,9 @@ module.exports = {
// Remove this line setting `csscontrols/use-logical` to null after implementing fixes
"csstools/use-logical": null,
"stylelint-plugin-mozilla/no-base-design-tokens": true,
- "stylelint-plugin-mozilla/use-design-tokens": true,
+ "stylelint-plugin-mozilla/use-design-tokens": false,
"stylelint-plugin-mozilla/no-non-semantic-token-usage": true,
- "stylelint-plugin-mozilla/use-size-tokens": true,
+ "stylelint-plugin-mozilla/use-size-tokens": false,
},
overrides: [

View File

@@ -1,13 +0,0 @@
diff --git a/browser/app/macbuild/Contents/Info.plist.in b/browser/app/macbuild/Contents/Info.plist.in
index 0c4fb837a24490c66b284abf2bd9299c2e021de0..ea28831b90662b12bdcb137c35b6bb83626c77e7 100644
--- a/browser/app/macbuild/Contents/Info.plist.in
+++ b/browser/app/macbuild/Contents/Info.plist.in
@@ -190,8 +190,6 @@
<string>@MAC_APP_NAME@ @APP_VERSION@</string>
<key>CFBundleIconFile</key>
<string>firefox.icns</string>
- <key>CFBundleIconName</key>
- <string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>@MOZ_MACBUNDLE_ID@</string>
<key>CFBundleInfoDictionaryVersion</key>

View File

@@ -1,8 +1,18 @@
diff --git a/browser/base/content/browser-box.inc.xhtml b/browser/base/content/browser-box.inc.xhtml
index 2faed30e09511c381051bc40910a883d1d7bc10d..6ba2d0d91235ed33e4b4bad281c974b5960beaa2 100644
index 2faed30e09511c381051bc40910a883d1d7bc10d..3b8c89902502aa384473dd6f43be7ec49bad06ac 100644
--- a/browser/base/content/browser-box.inc.xhtml
+++ b/browser/base/content/browser-box.inc.xhtml
@@ -25,7 +25,13 @@
@@ -3,6 +3,9 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<hbox flex="1" id="browser">
+ <html:div id="zen-browser-background" class="zen-browser-generic-background">
+ <html:div class="zen-browser-grain" />
+ </html:div>
<box context="sidebar-context-menu" id="sidebar-main" hidden="true">
<html:sidebar-main flex="1">
<box id="vertical-tabs" slot="tabstrip" customizable="true" contextmenu="toolbar-context-menu"></box>
@@ -25,7 +28,13 @@
</stack>
</vbox>
<splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
@@ -16,7 +26,7 @@ index 2faed30e09511c381051bc40910a883d1d7bc10d..6ba2d0d91235ed33e4b4bad281c974b5
<tabpanels id="tabbrowser-tabpanels" flex="1" selectedIndex="0"/>
</tabbox>
<splitter id="ai-window-splitter" class="chromeclass-extrachrome sidebar-splitter" resizebefore="none" resizeafter="sibling" hidden="true"/>
@@ -34,3 +40,5 @@
@@ -34,3 +43,5 @@
</stack>
</vbox>
</hbox>

View File

@@ -1,5 +1,5 @@
diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
index 4d4223c508560136aba220adb18528aac913a188..7e7432f7adb761a598d3e3e5ca4c6385a3bfe223 100644
index 4d4223c508560136aba220adb18528aac913a188..10d4d9cecbb0e7cec9191d78fb81a57376b37ff1 100644
--- a/browser/base/content/navigator-toolbox.inc.xhtml
+++ b/browser/base/content/navigator-toolbox.inc.xhtml
@@ -2,7 +2,7 @@
@@ -11,7 +11,7 @@ index 4d4223c508560136aba220adb18528aac913a188..7e7432f7adb761a598d3e3e5ca4c6385
<script src="chrome://browser/content/navigator-toolbox.js" />
<!-- Menu -->
@@ -18,9 +18,9 @@
@@ -18,9 +18,12 @@
#include browser-menubar.inc
</toolbaritem>
<spacer flex="1" skipintoolbarset="true" style="order: 1000;"/>
@@ -19,10 +19,13 @@ index 4d4223c508560136aba220adb18528aac913a188..7e7432f7adb761a598d3e3e5ca4c6385
</toolbar>
+<hbox id="titlebar">
+ <html:div id="zen-toolbar-background" class="zen-toolbar-background zen-browser-generic-background">
+ <html:div class="zen-browser-grain" />
+ </html:div>
<toolbar id="TabsToolbar"
class="browser-toolbar browser-titlebar"
fullscreentoolbar="true"
@@ -62,6 +62,9 @@
@@ -62,6 +65,9 @@
<html:sidebar-pins-promo id="drag-to-pin-promo-card"></html:sidebar-pins-promo>
<arrowscrollbox id="pinned-tabs-container" orient="horizontal" clicktoscroll=""></arrowscrollbox>
<splitter orient="vertical" id="vertical-pinned-tabs-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
@@ -32,7 +35,7 @@ index 4d4223c508560136aba220adb18528aac913a188..7e7432f7adb761a598d3e3e5ca4c6385
<hbox class="tab-drop-indicator" hidden="true"/>
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" clicktoscroll="" scrolledtostart="" scrolledtoend="">
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="true" visuallyselected="" fadein=""/>
@@ -81,6 +84,7 @@
@@ -81,6 +87,7 @@
tooltip="dynamic-shortcut-tooltip"
data-l10n-id="tabs-toolbar-new-tab"/>
<html:span id="tabbrowser-tab-a11y-desc" hidden="true"/>
@@ -40,7 +43,7 @@ index 4d4223c508560136aba220adb18528aac913a188..7e7432f7adb761a598d3e3e5ca4c6385
</tabs>
<toolbarbutton id="new-tab-button"
@@ -114,9 +118,10 @@
@@ -114,9 +121,10 @@
<toolbarbutton class="content-analysis-indicator toolbarbutton-1 content-analysis-indicator-icon"/>

View File

@@ -1,5 +1,5 @@
diff --git a/browser/base/content/navigator-toolbox.js b/browser/base/content/navigator-toolbox.js
index 15469e9d9b91c1eaef2578c9e43b6999edac3392..553402b41bc15f7cd99bf87c54416dc66d7c03e7 100644
index 15469e9d9b91c1eaef2578c9e43b6999edac3392..95ae5036b57baeb5237603c0921f1e9252af6919 100644
--- a/browser/base/content/navigator-toolbox.js
+++ b/browser/base/content/navigator-toolbox.js
@@ -6,7 +6,7 @@
@@ -19,15 +19,25 @@ index 15469e9d9b91c1eaef2578c9e43b6999edac3392..553402b41bc15f7cd99bf87c54416dc6
#picture-in-picture-button,
#urlbar-zoom-button,
#star-button-box,
@@ -206,6 +207,7 @@ document.addEventListener(
case "vertical-tabs-newtab-button":
case "tabs-newtab-button":
case "new-tab-button":
+ case "zen-tabs-wrapper":
@@ -209,6 +210,17 @@ document.addEventListener(
gBrowser.handleNewTabMiddleClick(element, event);
break;
@@ -318,6 +320,7 @@ document.addEventListener(
+ case "zen-tabs-wrapper":
+ if (event.button == 1) {
+ BrowserCommands.openTab();
+ // Stop the propagation of the click event, to prevent the event from being
+ // handled more than once.
+ // E.g. see https://bugzilla.mozilla.org/show_bug.cgi?id=1657992#c4
+ event.stopPropagation();
+ event.preventDefault();
+ }
+ break;
+
case "back-button":
case "forward-button":
case "reload-button":
@@ -318,6 +330,7 @@ document.addEventListener(
#downloads-button,
#fxa-toolbar-menu-button,
#unified-extensions-button,
@@ -35,7 +45,7 @@ index 15469e9d9b91c1eaef2578c9e43b6999edac3392..553402b41bc15f7cd99bf87c54416dc6
#library-button,
#split-view-button
`);
@@ -401,6 +404,16 @@ document.addEventListener(
@@ -401,6 +414,16 @@ document.addEventListener(
gUnifiedExtensions.togglePanel(event);
break;

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js
index 836bee14d2b63604688ebe477a5d915a5e99b305..a675aed711560b4a44604fc17478cffa7fb68439 100644
index 836bee14d2b63604688ebe477a5d915a5e99b305..7e105a1ae07657b0a0e664a8e3d9d2eb894fa1d4 100644
--- a/browser/components/tabbrowser/content/tab.js
+++ b/browser/components/tabbrowser/content/tab.js
@@ -21,6 +21,7 @@
@@ -65,11 +65,11 @@ index 836bee14d2b63604688ebe477a5d915a5e99b305..a675aed711560b4a44604fc17478cffa
+ return false;
+ }
+ // Selected tabs are always visible
+ if (this.selected || this.multiselected || this.hasAttribute("folder-active")) return true;
+ if (this.selected || this.multiselected) return true;
+ // Recursively check all parent groups
+ let currentParent = this.group;
+ while (currentParent) {
+ if (currentParent.collapsed) {
+ if (currentParent.collapsed && !currentParent.activeTabs?.includes(this)) {
+ return false;
+ }
+ currentParent = currentParent.group;

View File

@@ -499,7 +499,7 @@
pointer-events: none;
}
&:is([open], [starred]) image {
&:where([starred]) image {
list-style-image: url("permissions-fill.svg");
}
}

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env bash
# 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/.

View File

@@ -0,0 +1,22 @@
diff --git a/eslint-file-globals.config.mjs b/eslint-file-globals.config.mjs
index 00e49fce00efecab254aa1b8f0f0fe9ed2c24057..e9f390e15537d3d03a87f1c87099cb34698aee49 100644
--- a/eslint-file-globals.config.mjs
+++ b/eslint-file-globals.config.mjs
@@ -22,6 +22,7 @@
import globals from "globals";
import mozilla from "eslint-plugin-mozilla";
+import zenGlobals from "./zen/zen.globals.mjs";
export default [
{
@@ -550,4 +551,9 @@ export default [
],
languageOptions: { globals: globals.worker },
},
+ {
+ name: "zen-globals",
+ files: ["zen/**/!(*.sys).mjs", "zen/**/*.js"],
+ languageOptions: { globals: zenGlobals.reduce((acc, name) => ({ ...acc, [name]: "readonly" }), {}) },
+ }
];

View File

@@ -0,0 +1,13 @@
diff --git a/eslint-ignores.config.mjs b/eslint-ignores.config.mjs
index 0cfd7e02ad58c331f48f1ba8e1588777e1ce2595..888674b5ed2b68dbe77eb177ba0947f94ed57c80 100644
--- a/eslint-ignores.config.mjs
+++ b/eslint-ignores.config.mjs
@@ -312,4 +312,8 @@ export default [
// Test files for circular import in modules.
"dom/base/test/jsmodules/import_circular.mjs",
"dom/base/test/jsmodules/import_circular_1.mjs",
+
+ "zen/common/emojis/ZenEmojisData.min.mjs",
+ "zen/tests/**",
+ "zen/vendor/**",
];

View File

@@ -0,0 +1,12 @@
diff --git a/eslint-test-paths.config.mjs b/eslint-test-paths.config.mjs
index 53d97521a676d04212abb0263cb166da06c889e0..fa8c261de7a8663a369fb41671476d314722c025 100644
--- a/eslint-test-paths.config.mjs
+++ b/eslint-test-paths.config.mjs
@@ -218,6 +218,7 @@ const extraBrowserTestPaths = [
"toolkit/components/windowwatcher/test/",
"toolkit/mozapps/extensions/test/xpinstall/",
"uriloader/exthandler/tests/mochitest/",
+ "zen/tests/",
];
// DO NOT add more items to this list. Please see the note at the top

View File

@@ -1,7 +1,31 @@
diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml
--- a/browser/base/content/main-popupset.inc.xhtml
+++ b/browser/base/content/main-popupset.inc.xhtml
@@ -556,10 +556,11 @@
@@ -193,10 +193,11 @@
<!-- Starting point for selection actions -->
<panel class="panel-no-padding"
id="selection-shortcut-action-panel"
noautofocus="true"
consumeoutsideclicks="never"
+ nonnativepopover="true"
type="arrow">
<hbox class="panel-subview-body">
<html:moz-button id="ai-action-button"/>
</hbox>
</panel>
@@ -204,10 +205,11 @@
<!-- Shortcut options for Gen AI action -->
<panel class="panel-no-padding"
id="chat-shortcuts-options-panel"
noautofocus="true"
+ nonnativepopover="true"
type="arrow">
<vbox class="panel-subview-body"/>
</panel>
<html:template id="screenshotsPagePanelTemplate">
@@ -556,10 +558,11 @@
type="arrow"
orient="vertical"
noautofocus="true"
@@ -43,6 +67,40 @@ diff --git a/browser/components/customizableui/content/panelUI.inc.xhtml b/brows
viewCacheId="appMenu-viewCache">
</panelmultiview>
</panel>
diff --git a/dom/xul/XULPopupElement.cpp b/dom/xul/XULPopupElement.cpp
--- a/dom/xul/XULPopupElement.cpp
+++ b/dom/xul/XULPopupElement.cpp
@@ -84,10 +84,15 @@
void XULPopupElement::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
bool aIsContextMenu,
Event* aTriggerEvent) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+ // TODO(cheff): We do the same at nsCocoaWindow::Show but it doesn't seem
+ // to trigger a restyle so `appearance: auto` doesn't apply the native
+ // popover style. We should remove this and use the other implementation
+ // because this is a bit of a hack, not sure how reliable it is.
+ SetXULBoolAttr(nsGkAtoms::nonnativepopover, true, IgnoreErrors());
if (pm) {
pm->ShowPopupAtScreen(this, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
}
}
@@ -96,10 +101,14 @@
int32_t aWidth, int32_t aHeight,
bool aIsContextMenu,
bool aAttributesOverride,
Event* aTriggerEvent) {
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
+ // TODO: See OpenPopupAtScreen. We should remove this and use the other
+ // implementation because this is a bit of a hacky way to determine whether to
+ // use a native popover or not.
+ SetXULBoolAttr(nsGkAtoms::nonnativepopover, true, IgnoreErrors());
if (pm) {
pm->ShowPopupAtScreenRect(
this, aPosition, nsIntRect(aXPos, aYPos, aWidth, aHeight),
aIsContextMenu, aAttributesOverride, aTriggerEvent);
}
diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -110,29 +168,29 @@ diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/Sta
diff --git a/toolkit/themes/shared/global-shared.css b/toolkit/themes/shared/global-shared.css
--- a/toolkit/themes/shared/global-shared.css
+++ b/toolkit/themes/shared/global-shared.css
@@ -100,10 +100,22 @@
--panel-padding: var(--arrowpanel-padding);
--panel-shadow-margin: var(--arrowpanel-shadow-margin);
@@ -102,10 +102,22 @@
--menuitem-border-radius: var(--arrowpanel-menuitem-border-radius);
--menuitem-padding: var(--arrowpanel-menuitem-padding);
--menuitem-margin: var(--arrowpanel-menuitem-margin);
+
+ /* stylelint-disable-next-line media-query-no-invalid */
+ @media -moz-pref("widget.macos.native-popovers") and (-moz-platform: macos) {
+ &:not([nonnativepopover="true"]) {
+ background-color: transparent;
+ --panel-background: transparent;
+ --panel-shadow: none;
+ --panel-border-color: transparent;
+ --panel-shadow-margin: 0px;
+ --panel-padding: 0px;
+ }
+ }
}
+/* stylelint-disable-next-line media-query-no-invalid */
+@media -moz-pref("widget.macos.native-popovers") and (-moz-platform: macos) {
+ panel:not(:where([nonnativepopover="true"])) {
+ background-color: transparent;
+ --panel-background: transparent;
+ --panel-shadow: none;
+ --panel-border-color: transparent;
+ --panel-shadow-margin: 0px;
+ --panel-padding: 0px;
+ }
+}
+
/* Lightweight theme roots */
:root[lwtheme] {
.browser-toolbox-background,
toolbar,
diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -176,7 +234,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h
@interface BorderlessWindow : BaseWindow {
}
@@ -201,10 +216,13 @@
@@ -201,10 +216,14 @@
typedef nsIWidget Inherited;
public:
@@ -184,6 +242,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h
+ // Check if this window should use NSPopover for popup/menu display
+ bool ShouldUseNSPopover() const;
+ bool ShouldShowAsNSPopover() const override;
+
[[nodiscard]] nsresult Create(nsIWidget* aParent, const DesktopIntRect& aRect,
const InitData&) override;
@@ -281,18 +340,32 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
if (!mWindow) {
@@ -5227,10 +5282,58 @@
@@ -5185,10 +5240,17 @@
}
NSWindow* nativeParentWindow =
mParent ? (NSWindow*)mParent->GetNativeData(NS_NATIVE_WINDOW) : nil;
+ bool shouldUseNativePopover = false;
+ if (mWindowType == WindowType::Popup && aState) {
+ nsMenuPopupFrame* popupFrame = GetPopupFrame();
+ popupFrame->PopupElement().SetXULBoolAttr(
+ nsGkAtoms::nonnativepopover, !ShouldShowAsNSPopover(), IgnoreErrors());
+ }
+
if (aState && !mBounds.IsEmpty()) {
// If we had set the activationPolicy to accessory, then right now we won't
// have a dock icon. Make sure that we undo that and show a dock icon now
// that we're going to show a window.
if (NSApp.activationPolicy != NSApplicationActivationPolicyRegular) {
@@ -5227,10 +5289,54 @@
mWindow.contentView.needsDisplay = YES;
if (!nativeParentWindow || mPopupLevel != PopupLevel::Parent) {
[mWindow orderFront:nil];
}
NS_OBJC_END_TRY_IGNORE_BLOCK;
+ nsMenuPopupFrame* popupFrame = GetPopupFrame();
+ if ([mWindow isKindOfClass:[PopupWindow class]] &&
+ [(PopupWindow*)mWindow usePopover] && popupFrame &&
+ popupFrame->ShouldFollowAnchor() &&
+ !popupFrame->PopupElement().GetBoolAttr(
+ nsGkAtoms::nonnativepopover)) {
+ if (ShouldShowAsNSPopover()) {
+ nsMenuPopupFrame* popupFrame = GetPopupFrame();
+ if (nativeParentWindow) {
+ NSRectEdge preferredEdge =
+ AlignmentPositionToNSRectEdge(popupFrame->GetAlignmentPosition());
@@ -340,7 +413,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
// close other programs' context menus when ours open.
if ([mWindow isKindOfClass:[PopupWindow class]] &&
[(PopupWindow*)mWindow isContextMenu]) {
@@ -5301,10 +5404,15 @@
@@ -5301,10 +5407,15 @@
// of a window it hides the parent window.
if (mWindowType == WindowType::Popup && nativeParentWindow) {
[nativeParentWindow removeChildWindow:mWindow];
@@ -356,7 +429,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
// other programs) that a menu has closed.
if ([mWindow isKindOfClass:[PopupWindow class]] &&
[(PopupWindow*)mWindow isContextMenu]) {
@@ -5351,10 +5459,17 @@
@@ -5351,10 +5462,28 @@
return false;
}
return nsIWidget::ShouldUseOffMainThreadCompositing();
@@ -365,8 +438,19 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
+bool nsCocoaWindow::ShouldUseNSPopover() const {
+ // Use NSPopover for panel popups when the preference is enabled
+ // But not for detached popups - they should use traditional window logic
+ return mWindowType == WindowType::Popup && mPopupType == PopupType::Panel &&
+ mozilla::StaticPrefs::widget_macos_native_popovers();
+ return (mWindowType == WindowType::Popup && mPopupType == PopupType::Panel &&
+ mozilla::StaticPrefs::widget_macos_native_popovers());
+}
+
+bool nsCocoaWindow::ShouldShowAsNSPopover() const {
+ if (!ShouldUseNSPopover()) {
+ return false;
+ }
+ nsMenuPopupFrame* popupFrame = GetPopupFrame();
+ return [mWindow isKindOfClass:[PopupWindow class]] &&
+ [(PopupWindow*)mWindow usePopover] && popupFrame &&
+ popupFrame->ShouldFollowAnchor() &&
+ !popupFrame->PopupElement().GetBoolAttr(nsGkAtoms::nonnativepopover);
+}
+
TransparencyMode nsCocoaWindow::GetTransparencyMode() {
@@ -374,7 +458,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
return mWindow.isOpaque ? TransparencyMode::Opaque
: TransparencyMode::Transparent;
@@ -6313,10 +6428,20 @@
@@ -6313,10 +6442,20 @@
// We ignore aRepaint -- we have to call display:YES, otherwise the
// title bar doesn't immediately get repainted and is displayed in
// the wrong place, leading to a visual jump.
@@ -395,7 +479,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
void nsCocoaWindow::Resize(const DesktopRect& aRect, bool aRepaint) {
DoResize(aRect.x, aRect.y, aRect.width, aRect.height, aRepaint, false);
@@ -8277,18 +8402,27 @@
@@ -8277,18 +8416,27 @@
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)deferCreation {
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
@@ -423,7 +507,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
// Return 0 in order to match what the system does for sheet windows and
// _NSPopoverWindows.
- (CGFloat)_backdropBleedAmount {
@@ -8342,10 +8476,120 @@
@@ -8342,10 +8490,120 @@
- (void)setIsContextMenu:(BOOL)flag {
mIsContextMenu = flag;
@@ -544,6 +628,25 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
return NO;
}
diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -836,10 +836,15 @@
virtual void SuppressAnimation(bool aSuppress) {}
/** Sets windows-specific mica backdrop on this widget. */
virtual void SetMicaBackdrop(bool) {}
+ /**
+ * Determine whether this widget should be shown as an NSPopover.
+ */
+ virtual bool ShouldShowAsNSPopover() const { return false; }
+
/**
* Return size mode (minimized, maximized, normalized).
* Returns a value from nsSizeMode (see nsIWidgetListener.h)
*/
virtual nsSizeMode SizeMode() = 0;
diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py
--- a/xpcom/ds/StaticAtoms.py
+++ b/xpcom/ds/StaticAtoms.py

View File

@@ -18,7 +18,8 @@
// Specifically trying to target FeatureCallout.sys.mjs's change.
// IMPORTANT: Make sure Feature callouts STILL use native popopvers when
// syncing from upstream, as this is a critical part of the patch.
"+ nonnativepopover=\"true\"": "+ "
"+ nonnativepopover=\"true\"": "+ ",
"body,": ".browser-toolbox-background,"
}
},
{

View File

@@ -0,0 +1,12 @@
diff --git a/python/mozlint/mozlint/roller.py b/python/mozlint/mozlint/roller.py
index aeafa93cc525d2846614b600e95fd817b832b0ef..69414ed032523f1b53b78ad867145efaea422c63 100644
--- a/python/mozlint/mozlint/roller.py
+++ b/python/mozlint/mozlint/roller.py
@@ -92,7 +92,6 @@ def _run_worker(config, paths, **lintargs):
res = res or []
else:
log.error(f"Unexpected result type received: {type(res)}")
- assert False
except Exception:
log.exception(f"{config['name']} failed")
res = 1

View File

@@ -1,28 +0,0 @@
diff --git a/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs b/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs
index 2aaef80411b2cef9563c49f23d36b08222b06b03..7bd15ebb0d9d09da57a287b47beb1f0e2e17d229 100644
--- a/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs
+++ b/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs
@@ -492,6 +492,23 @@ function getPhase(topic) {
}
return undefined;
},
+
+ /**
+ * Reset the phase after a call to _trigger().
+ * For testing purposes only.
+ */
+ get _reset() {
+ let accepted = Services.prefs.getBoolPref(
+ "toolkit.asyncshutdown.testing",
+ false
+ );
+ if (accepted) {
+ return () => {
+ spinner = new Spinner(topic);
+ };
+ }
+ return undefined;
+ },
});
gPhases.set(topic, phase);
return phase;

View File

@@ -0,0 +1,13 @@
diff --git a/tools/lint/eslint/__init__.py b/tools/lint/eslint/__init__.py
index cd45822500a8b5e1112efad81ed34e01c0dbcc19..9f47b4a46bf1c36db06b45e047a939ae08bcb703 100644
--- a/tools/lint/eslint/__init__.py
+++ b/tools/lint/eslint/__init__.py
@@ -114,7 +114,7 @@ def lint(paths, config, binary=None, fix=None, rules=[], setup=None, **lintargs)
[
binary,
os.path.join(
- module_path, "node_modules", "prettier", "bin", "prettier.cjs"
+ module_path, "..", "node_modules", "@zen-browser", "prettier", "bin", "prettier.cjs"
),
"--list-different",
"--no-error-on-unmatched-pattern",

View File

@@ -0,0 +1,13 @@
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/require-jsdoc.mjs b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/require-jsdoc.mjs
index 87fc32f6a1bdf21a56fb3ce18c767ebbb12c6d67..174fcc3a679ae655c9bce907461f9c3a9030c2a9 100644
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/require-jsdoc.mjs
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/require-jsdoc.mjs
@@ -13,7 +13,7 @@ export default {
"error",
{
require: {
- ClassDeclaration: true,
+ ClassDeclaration: false,
FunctionDeclaration: false,
},
},

View File

@@ -0,0 +1,12 @@
diff --git a/tools/lint/ignorefile.yml b/tools/lint/ignorefile.yml
index 5ae3b282a54c129bb16bca461470154e4a882618..f46c6256037cbef1392f8d070726d45dadac1289 100644
--- a/tools/lint/ignorefile.yml
+++ b/tools/lint/ignorefile.yml
@@ -3,7 +3,6 @@ ignorefile:
description: Linter for .gitignore and .hgignore files
include:
- '.gitignore'
- - '.hgignore'
support-files:
- 'tools/lint/ignorefile**'
type: external

View File

@@ -0,0 +1,12 @@
diff --git a/tools/lint/rejected-words.yml b/tools/lint/rejected-words.yml
index d5ca2e05fb335fcd17d1559d5332ec4a43d7cd1d..1f34e8d5e05508fc541bc7aa6a779cd98206032a 100644
--- a/tools/lint/rejected-words.yml
+++ b/tools/lint/rejected-words.yml
@@ -8,7 +8,6 @@ avoid-blacklist-and-whitelist:
ignore-case: true
# Based on codespell with idl and webidl added.
extensions:
- - js
- mjs
- jsx
- idl

View File

@@ -53,9 +53,15 @@ declare global {
dockMenu: nsIStandaloneNativeMenu;
activateApplication(aIgnoreOtherApplications: boolean): void;
badgeText: string;
setBadgeImage(aBadgeImage: imgIContainer, aPaintContext?: nsISVGPaintContext): void;
setBadgeImage(
aBadgeImage: imgIContainer,
aPaintContext?: nsISVGPaintContext
): void;
readonly isAppInDock: boolean;
ensureAppIsPinnedToDock(aAppPath?: string, aAppToReplacePath?: string): boolean;
ensureAppIsPinnedToDock(
aAppPath?: string,
aAppToReplacePath?: string
): boolean;
launchAppBundle(
aAppBundle: nsIFile,
aArgs: string[],
@@ -70,7 +76,10 @@ declare global {
}>;
interface nsIMacFinderProgress extends nsISupports {
init(path: string, canceledCallback: nsIMacFinderProgressCanceledCallback): void;
init(
path: string,
canceledCallback: nsIMacFinderProgressCanceledCallback
): void;
updateProgress(currentProgress: u64, totalProgress: u64): void;
end(): void;
}
@@ -86,7 +95,11 @@ declare global {
// https://searchfox.org/mozilla-central/source/widget/nsIMacUserActivityUpdater.idl
interface nsIMacUserActivityUpdater extends nsISupports {
updateLocation(pageUrl: string, pageTitle: string, window: nsIBaseWindow): void;
updateLocation(
pageUrl: string,
pageTitle: string,
window: nsIBaseWindow
): void;
}
// https://searchfox.org/mozilla-central/source/widget/nsIMacWebAppUtils.idl
@@ -120,7 +133,11 @@ declare global {
readonly STATE_ERROR?: 3;
readonly STATE_PAUSED?: 4;
setProgressState(state: nsTaskbarProgressState, currentValue?: u64, maxValue?: u64): void;
setProgressState(
state: nsTaskbarProgressState,
currentValue?: u64,
maxValue?: u64
): void;
}
// https://searchfox.org/mozilla-central/source/widget/nsITouchBarHelper.idl
@@ -157,11 +174,18 @@ declare global {
// https://searchfox.org/mozilla-central/source/widget/nsITouchBarUpdater.idl
interface nsITouchBarUpdater extends nsISupports {
updateTouchBarInputs(aWindow: nsIBaseWindow, aInputs: nsITouchBarInput[]): void;
updateTouchBarInputs(
aWindow: nsIBaseWindow,
aInputs: nsITouchBarInput[]
): void;
enterCustomizeMode(): void;
isTouchBarInitialized(): boolean;
setTouchBarInitialized(aIsInitialized: boolean): void;
showPopover(aWindow: nsIBaseWindow, aPopover: nsITouchBarInput, aShowing: boolean): void;
showPopover(
aWindow: nsIBaseWindow,
aPopover: nsITouchBarInput,
aShowing: boolean
): void;
}
// https://searchfox.org/mozilla-central/source/xpcom/base/nsIMacPreferencesReader.idl

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -51,7 +51,11 @@ declare global {
readonly STATE_ERROR?: 3;
readonly STATE_PAUSED?: 4;
setProgressState(state: nsTaskbarProgressState, currentValue?: u64, maxValue?: u64): void;
setProgressState(
state: nsTaskbarProgressState,
currentValue?: u64,
maxValue?: u64
): void;
}
interface nsIXPCComponents_Interfaces {

View File

@@ -705,4 +705,5 @@ interface nsIXPCComponents_Results {
NS_ERROR_DOM_QM_CLIENT_INIT_ORIGIN_UNINITIALIZED: 0x80730001;
}
type nsIXPCComponents_Values = nsIXPCComponents_Results[keyof nsIXPCComponents_Results];
type nsIXPCComponents_Values =
nsIXPCComponents_Results[keyof nsIXPCComponents_Results];

View File

@@ -33,11 +33,15 @@ interface Document {
}
type nsIGleanPingNoReason = {
[K in keyof nsIGleanPing]: K extends "submit" ? (_?: never) => void : nsIGleanPing[K];
[K in keyof nsIGleanPing]: K extends "submit"
? (_?: never) => void
: nsIGleanPing[K];
};
type nsIGleanPingWithReason<T> = {
[K in keyof nsIGleanPing]: K extends "submit" ? (reason: T) => void : nsIGleanPing[K];
[K in keyof nsIGleanPing]: K extends "submit"
? (reason: T) => void
: nsIGleanPing[K];
};
interface MessageListenerManagerMixin {

View File

@@ -56,14 +56,18 @@ declare global {
}
interface nsIWindowsAlertNotification
extends nsIAlertNotification,
extends
nsIAlertNotification,
Enums<typeof nsIWindowsAlertNotification_ImagePlacement> {
imagePlacement: nsIWindowsAlertNotification.ImagePlacement;
}
interface nsIWindowsAlertsService extends nsIAlertsService {
handleWindowsTag(aWindowsTag: string): Promise<any>;
getXmlStringForWindowsAlert(aAlert: nsIAlertNotification, aWindowsTag?: string): string;
getXmlStringForWindowsAlert(
aAlert: nsIAlertNotification,
aWindowsTag?: string
): string;
removeAllNotificationsForInstall(): void;
}
@@ -86,9 +90,18 @@ declare global {
aNotificationAction: string,
daysSinceLastAppLaunch: u32
): void;
setDefaultBrowserUserChoice(aAumid: string, aExtraFileExtensions: string[]): void;
setDefaultBrowserUserChoiceAsync(aAumid: string, aExtraFileExtensions: string[]): Promise<any>;
setDefaultExtensionHandlersUserChoice(aAumid: string, aFileExtensions: string[]): void;
setDefaultBrowserUserChoice(
aAumid: string,
aExtraFileExtensions: string[]
): void;
setDefaultBrowserUserChoiceAsync(
aAumid: string,
aExtraFileExtensions: string[]
): Promise<any>;
setDefaultExtensionHandlersUserChoice(
aAumid: string,
aFileExtensions: string[]
): void;
agentDisabled(): boolean;
}
@@ -124,11 +137,13 @@ declare enum nsIWindowsShellService_LaunchOnLoginEnabledEnumerator {
declare global {
namespace nsIWindowsShellService {
type LaunchOnLoginEnabledEnumerator = nsIWindowsShellService_LaunchOnLoginEnabledEnumerator;
type LaunchOnLoginEnabledEnumerator =
nsIWindowsShellService_LaunchOnLoginEnabledEnumerator;
}
interface nsIWindowsShellService
extends nsIShellService,
extends
nsIShellService,
Enums<typeof nsIWindowsShellService_LaunchOnLoginEnabledEnumerator> {
createShortcut(
aBinary: nsIFile,
@@ -149,13 +164,19 @@ declare global {
pinCurrentAppToTaskbarAsync(aPrivateBrowsing: boolean): Promise<any>;
checkPinCurrentAppToTaskbarAsync(aPrivateBrowsing: boolean): Promise<any>;
isCurrentAppPinnedToTaskbarAsync(aumid: string): Promise<any>;
pinShortcutToTaskbar(aAppUserModelId: string, aShortcutPath: string): Promise<any>;
pinShortcutToTaskbar(
aAppUserModelId: string,
aShortcutPath: string
): Promise<any>;
createWindowsIcon(aFile: nsIFile, aContainer: imgIContainer): Promise<any>;
unpinShortcutFromTaskbar(aShortcutPath: string): void;
getTaskbarTabShortcutPath(aShortcutName: string): string;
getTaskbarTabPins(): string[];
classifyShortcut(aPath: string): string;
hasPinnableShortcut(aAUMID: string, aPrivateBrowsing: boolean): Promise<any>;
hasPinnableShortcut(
aAUMID: string,
aPrivateBrowsing: boolean
): Promise<any>;
canSetDefaultBrowserUserChoice(): boolean;
checkAllProgIDsExist(): boolean;
checkBrowserUserChoiceHashes(): boolean;
@@ -241,7 +262,11 @@ declare global {
readonly height: u32;
readonly thumbnailAspectRatio: float;
requestPreview(aCallback: nsITaskbarPreviewCallback): void;
requestThumbnail(aCallback: nsITaskbarPreviewCallback, width: u32, height: u32): void;
requestThumbnail(
aCallback: nsITaskbarPreviewCallback,
width: u32,
height: u32
): void;
onClose(): void;
onActivate(): boolean;
onClick(button: nsITaskbarPreviewButton): void;
@@ -256,7 +281,11 @@ declare global {
readonly STATE_ERROR?: 3;
readonly STATE_PAUSED?: 4;
setProgressState(state: nsTaskbarProgressState, currentValue?: u64, maxValue?: u64): void;
setProgressState(
state: nsTaskbarProgressState,
currentValue?: u64,
maxValue?: u64
): void;
}
// https://searchfox.org/mozilla-central/source/widget/nsITaskbarTabPreview.idl
@@ -288,7 +317,9 @@ declare global {
): nsITaskbarTabPreview;
getTaskbarWindowPreview(shell: nsIDocShell): nsITaskbarWindowPreview;
getTaskbarProgress(shell: nsIDocShell): nsITaskbarProgress;
getOverlayIconController(shell: nsIDocShell): nsITaskbarOverlayIconController;
getOverlayIconController(
shell: nsIDocShell
): nsITaskbarOverlayIconController;
createJumpListBuilder(aPrivateBrowsing: boolean): nsIJumpListBuilder;
getGroupIdForWindow(aParent: mozIDOMWindow): string;
setGroupIdForWindow(aParent: mozIDOMWindow, aIdentifier: string): void;
@@ -304,7 +335,11 @@ declare global {
aSmallIcon: imgIContainer,
aLargeIcon: imgIContainer
): void;
setWindowIconFromExe(aWindow: mozIDOMWindowProxy, aExe: string, aIndex: u16): void;
setWindowIconFromExe(
aWindow: mozIDOMWindowProxy,
aExe: string,
aIndex: u16
): void;
setWindowIconNoData(aWindow: mozIDOMWindowProxy): void;
readonly inWin10TabletMode: boolean;
readonly inWin11TabletMode: boolean;

File diff suppressed because it is too large Load Diff

View File

@@ -88,7 +88,9 @@ declare namespace MockedExports {
*
* Then add the file path to the KnownModules above.
*/
importESModule: <S extends keyof KnownModules>(module: S) => KnownModules[S];
importESModule: <S extends keyof KnownModules>(
module: S
) => KnownModules[S];
defineESModuleGetters: (target: any, mappings: any) => void;
}
@@ -160,7 +162,11 @@ declare namespace MockedExports {
setIntPref: SetPref<number>;
getBoolPref: GetPref<boolean>;
setBoolPref: SetPref<boolean>;
addObserver: (aDomain: string, aObserver: PrefObserver, aHoldWeak?: boolean) => void;
addObserver: (
aDomain: string,
aObserver: PrefObserver,
aHoldWeak?: boolean
) => void;
removeObserver: (aDomain: string, aObserver: PrefObserver) => void;
};
@@ -299,7 +305,11 @@ declare namespace MockedExports {
class nsIFilePicker {}
interface FilePicker {
init: (browsingContext: BrowsingContext, title: string, mode: number) => void;
init: (
browsingContext: BrowsingContext,
title: string,
mode: number
) => void;
open: (callback: (rv: number) => unknown) => void;
// The following are enum values.
modeGetFolder: number;
@@ -330,7 +340,11 @@ declare namespace MockedExports {
* This function sets the attributes data-l10n-id and possibly data-l10n-args
* on the element.
*/
setAttributes(target: Element, id?: string, args?: Record<string, string>): void;
setAttributes(
target: Element,
id?: string,
args?: Record<string, string>
): void;
}
}
@@ -365,7 +379,8 @@ 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.
@@ -406,7 +421,9 @@ declare interface Window {
userContextId: number;
forceNonPrivate: boolean;
relatedToCurrent: boolean;
resolveOnContentBrowserCreated: (contentBrowser: MockedExports.ChromeBrowser) => unknown;
resolveOnContentBrowserCreated: (
contentBrowser: MockedExports.ChromeBrowser
) => unknown;
}>
) => void;
openTrustedLinkIn: (
@@ -417,7 +434,9 @@ declare interface Window {
userContextId: number;
forceNonPrivate: boolean;
relatedToCurrent: boolean;
resolveOnContentBrowserCreated: (contentBrowser: MockedExports.ChromeBrowser) => unknown;
resolveOnContentBrowserCreated: (
contentBrowser: MockedExports.ChromeBrowser
) => unknown;
}>
) => void;
}

View File

@@ -63,7 +63,9 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
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") {
this.#changePage(true);
@@ -104,7 +106,9 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
#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",
@@ -137,15 +141,19 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
const value = input.value.trim().toLowerCase();
// search for emojis.tags and order by emojis.order
const filteredEmojis = this.#emojis
.filter((emoji) => {
return emoji.tags.some((tag) => tag.toLowerCase().includes(value));
.filter(emoji => {
return emoji.tags.some(tag => tag.toLowerCase().includes(value));
})
.sort((a, b) => a.order - b.order);
for (const button of this.emojiList.children) {
const buttonEmoji = button.getAttribute("label");
const emojiObject = filteredEmojis.find((emoji) => emoji.emoji === buttonEmoji);
const emojiObject = filteredEmojis.find(
emoji => emoji.emoji === buttonEmoji
);
if (emojiObject) {
button.hidden = !emojiObject.tags.some((tag) => tag.toLowerCase().includes(value));
button.hidden = !emojiObject.tags.some(tag =>
tag.toLowerCase().includes(value)
);
button.style.order = emojiObject.order;
} else {
button.hidden = true;
@@ -205,7 +213,9 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature {
this.svgList.innerHTML = "";
if (!this.#hasSelection) {
this.#currentPromiseReject?.(new Error("Emoji picker closed without selection"));
this.#currentPromiseReject?.(
new Error("Emoji picker closed without selection")
);
} else if (!this.#closeOnSelect) {
this.#currentPromiseResolve?.(this.#lastSelectedEmoji);
}

File diff suppressed because one or more lines are too long

View File

@@ -78,7 +78,9 @@ export class nsZenDOMOperatedFeature {
export class nsZenPreloadedFeature {
constructor() {
var initBound = this.init.bind(this);
document.addEventListener("MozBeforeInitialXULLayout", initBound, { once: true });
document.addEventListener("MozBeforeInitialXULLayout", initBound, {
once: true,
});
}
}
@@ -92,7 +94,7 @@ window.gZenCommonActions = {
if (Services.zen.canShare() && displaySpec.startsWith("http")) {
button = {
id: "zen-copy-current-url-button",
command: (event) => {
command: event => {
const buttonRect = event.target.getBoundingClientRect();
/* eslint-disable mozilla/valid-services */
Services.zen.share(
@@ -107,7 +109,10 @@ window.gZenCommonActions = {
},
};
}
gZenUIManager.showToast("zen-copy-current-url-confirmation", { button, timeout: 3000 });
gZenUIManager.showToast("zen-copy-current-url-confirmation", {
button,
timeout: 3000,
});
},
copyCurrentURLAsMarkdownToClipboard() {
@@ -115,7 +120,9 @@ 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-as-markdown-confirmation", {
timeout: 3000,
});
},
throttle(f, delay) {
@@ -134,10 +141,17 @@ window.gZenCommonActions = {
* @returns {boolean} True if the tab should be closed on back
*/
shouldCloseTabOnBack() {
if (!Services.prefs.getBoolPref("zen.tabs.close-on-back-with-no-history", true)) {
if (
!Services.prefs.getBoolPref(
"zen.tabs.close-on-back-with-no-history",
true
)
) {
return false;
}
const tab = gBrowser.selectedTab;
return Boolean(tab.owner && !tab.pinned && !tab.hasAttribute("zen-empty-tab"));
return Boolean(
tab.owner && !tab.pinned && !tab.hasAttribute("zen-empty-tab")
);
},
};

View File

@@ -14,7 +14,12 @@ class nsHasPolyfill {
* @param {string} stateAttribute
* @param {Array<string>} attributeFilter
*/
observeSelectorExistence(element, descendantSelectors, stateAttribute, attributeFilter = []) {
observeSelectorExistence(
element,
descendantSelectors,
stateAttribute,
attributeFilter = []
) {
const updateState = () => {
const exists = descendantSelectors.some(({ selector }) => {
let selected = element.querySelector(selector);
@@ -26,10 +31,18 @@ class nsHasPolyfill {
const { exists: shouldExist = true } = descendantSelectors;
if (exists === shouldExist) {
if (!element.hasAttribute(stateAttribute)) {
gZenCompactModeManager._setElementExpandAttribute(element, true, stateAttribute);
gZenCompactModeManager._setElementExpandAttribute(
element,
true,
stateAttribute
);
}
} else if (element.hasAttribute(stateAttribute)) {
gZenCompactModeManager._setElementExpandAttribute(element, false, stateAttribute);
gZenCompactModeManager._setElementExpandAttribute(
element,
false,
stateAttribute
);
}
};
@@ -46,31 +59,35 @@ class nsHasPolyfill {
}
disconnectObserver(observerId) {
const index = this.observers.findIndex((o) => o.id === observerId);
const index = this.observers.findIndex(o => o.id === observerId);
if (index !== -1) {
this.observers[index].observer.disconnect();
}
}
connectObserver(observerId) {
const observer = this.observers.find((o) => o.id === observerId);
const observer = this.observers.find(o => o.id === observerId);
if (observer) {
observer.observer.observe(observer.element, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: observer.attributeFilter.length ? observer.attributeFilter : undefined,
attributeFilter: observer.attributeFilter.length
? observer.attributeFilter
: undefined,
});
}
}
destroy() {
this.observers.forEach((observer) => observer.observer.disconnect());
this.observers.forEach(observer => observer.observer.disconnect());
this.observers = [];
}
}
const hasPolyfillInstance = new nsHasPolyfill();
window.addEventListener("unload", () => hasPolyfillInstance.destroy(), { once: true });
window.addEventListener("unload", () => hasPolyfillInstance.destroy(), {
once: true,
});
window.ZenHasPolyfill = hasPolyfillInstance;

View File

@@ -38,7 +38,7 @@ export class nsZenMenuBar {
</menupopup>
</menu>`);
const menu = appearanceMenu.querySelector("menu");
menu.addEventListener("command", (event) => {
menu.addEventListener("command", event => {
const type = event.target.getAttribute("data-type");
const schemeValue = WINDOW_SCHEME_MAPPING[type];
Services.prefs.setIntPref(WINDOW_SCHEME_PREF, schemeValue);
@@ -97,15 +97,17 @@ export class nsZenMenuBar {
</menupopup>
</menu>`);
document.getElementById("view-menu").after(spacesMenubar);
document.getElementById("zen-spaces-menubar").addEventListener("popupshowing", () => {
if (AppConstants.platform === "linux") {
// On linux, there seems to be a bug where the menu freezes up and makes the browser
// suppiciously unresponsive if we try to update the menu while it's opening.
// See https://github.com/zen-browser/desktop/issues/12024
return;
}
gZenWorkspaces.updateWorkspacesChangeContextMenu();
});
document
.getElementById("zen-spaces-menubar")
.addEventListener("popupshowing", () => {
if (AppConstants.platform === "linux") {
// On linux, there seems to be a bug where the menu freezes up and makes the browser
// suppiciously unresponsive if we try to update the menu while it's opening.
// See https://github.com/zen-browser/desktop/issues/12024
return;
}
gZenWorkspaces.updateWorkspacesChangeContextMenu();
});
}
#initAppMenu() {
@@ -133,7 +135,10 @@ export class nsZenMenuBar {
if (!Services.prefs.getBoolPref("zen.window-sync.enabled", true)) {
return;
}
const itemsToHide = ["appMenuRecentlyClosedWindows", "historyUndoWindowMenu"];
const itemsToHide = [
"appMenuRecentlyClosedWindows",
"historyUndoWindowMenu",
];
for (const id of itemsToHide) {
const element = PanelMultiView.getViewNode(document, id);
element.setAttribute("hidden", "true");

View File

@@ -9,7 +9,7 @@ class ZenSessionStore extends nsZenPreloadedFeature {
this.#waitAndCleanup();
}
promiseInitialized = new Promise((resolve) => {
promiseInitialized = new Promise(resolve => {
this._resolveInitialized = resolve;
});

View File

@@ -47,19 +47,24 @@ class ZenSidebarNotification extends MozLitElement {
return html`
<link
rel="stylesheet"
href="chrome://browser/content/zen-styles/zen-sidebar-notification.css" />
href="chrome://browser/content/zen-styles/zen-sidebar-notification.css"
/>
<div class="zen-sidebar-notification-header">
<label
class="zen-sidebar-notification-heading"
flex="1"
data-l10n-id=${this.headingL10nId}></label>
<div class="zen-sidebar-notification-close-button" @click=${() => this.remove()}>
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>
</div>
<div class="zen-sidebar-notification-body">
${this.links.map(
(link) => html`
link => html`
<div
class="zen-sidebar-notification-link-container"
data-l10n-id="${link.l10nId}-tooltip"
@@ -70,15 +75,21 @@ class ZenSidebarNotification extends MozLitElement {
return;
}
window.openLinkIn(link.url, "tab", {
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
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>
data-l10n-id="${link.l10nId}-label"
></label>
</div>
`
)}

View File

@@ -11,10 +11,12 @@ class ZenStartup {
#hasInitializedLayout = false;
isReady = false;
promiseInitialized = new Promise(resolve => {
this.promiseInitializedResolve = resolve;
});
init() {
this.openWatermark();
this.#initBrowserBackground();
this.#changeSidebarLocation();
this.#zenInitBrowserLayout();
}
@@ -26,20 +28,6 @@ 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");
background.appendChild(grain);
document.getElementById("browser").prepend(background);
const toolbarBackground = background.cloneNode(true);
toolbarBackground.removeAttribute("id");
toolbarBackground.classList.add("zen-toolbar-background");
document.getElementById("titlebar").prepend(toolbarBackground);
}
#zenInitBrowserLayout() {
if (this.#hasInitializedLayout) {
return;
@@ -60,7 +48,9 @@ class ZenStartup {
}
// 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);
}
@@ -103,8 +93,12 @@ class ZenStartup {
// 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;
this.promiseInitializedResolve();
delete this.promiseInitializedResolve;
});
}
@@ -121,10 +115,14 @@ class ZenStartup {
closeWatermark() {
document.documentElement.removeAttribute("zen-before-loaded");
if (this.#shouldUseWatermark) {
let elementsToIgnore = this.#watermarkIgnoreElements.map((id) => "#" + id).join(", ");
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],
},
@@ -163,8 +161,14 @@ 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);
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",
window

View File

@@ -10,7 +10,10 @@ window.gZenUIManager = {
_hoverPausedForExpand: false,
_hasLoadedDOM: false,
testingEnabled: Services.prefs.getBoolPref("zen.testing.enabled", false),
profilingEnabled: Services.prefs.getBoolPref("zen.testing.profiling.enabled", false),
profilingEnabled: Services.prefs.getBoolPref(
"zen.testing.profiling.enabled",
false
),
_lastClickPosition: null,
@@ -22,7 +25,11 @@ window.gZenUIManager = {
document.addEventListener("popupshowing", this.onPopupShowing.bind(this));
document.addEventListener("popuphidden", this.onPopupHidden.bind(this));
document.addEventListener("mousedown", this.handleMouseDown.bind(this), true);
document.addEventListener(
"mousedown",
this.handleMouseDown.bind(this),
true
);
ChromeUtils.defineLazyGetter(this, "motion", () => {
Services.scriptloader.loadSubScript(
@@ -40,7 +47,9 @@ window.gZenUIManager = {
new ResizeObserver(
gZenCommonActions.throttle(
gZenCompactModeManager.getAndApplySidebarWidth.bind(gZenCompactModeManager),
gZenCompactModeManager.getAndApplySidebarWidth.bind(
gZenCompactModeManager
),
Services.prefs.getIntPref("zen.view.sidebar-height-throttle", 500)
)
).observe(gNavToolbox);
@@ -82,7 +91,10 @@ window.gZenUIManager = {
rawKeyframes = { ...rawKeyframes };
// Convert 'y' property to 'transform' with translateY and 'x' to translateX,
// and 'scale' to 'transform' with scale.
if ((rawKeyframes.y || rawKeyframes.x || rawKeyframes.scale) && !rawKeyframes.transform) {
if (
(rawKeyframes.y || rawKeyframes.x || rawKeyframes.scale) &&
!rawKeyframes.transform
) {
const yValues = rawKeyframes.y || [];
const xValues = rawKeyframes.x || [];
const scaleValues = rawKeyframes.scale || [];
@@ -90,14 +102,23 @@ window.gZenUIManager = {
delete rawKeyframes.x;
delete rawKeyframes.scale;
rawKeyframes.transform = [];
if (yValues.length !== 0 && xValues.length !== 0 && yValues.length !== xValues.length) {
if (
yValues.length !== 0 &&
xValues.length !== 0 &&
yValues.length !== xValues.length
) {
console.error("y and x keyframes must have the same length");
}
const keyframeLength = Math.max(yValues.length, xValues.length, scaleValues.length);
const keyframeLength = Math.max(
yValues.length,
xValues.length,
scaleValues.length
);
for (let i = 0; i < keyframeLength; i++) {
const y = yValues[i] !== undefined ? `translateY(${yValues[i]}px)` : "";
const x = xValues[i] !== undefined ? `translateX(${xValues[i]}px)` : "";
const scale = scaleValues[i] !== undefined ? `scale(${scaleValues[i]})` : "";
const scale =
scaleValues[i] !== undefined ? `scale(${scaleValues[i]})` : "";
rawKeyframes.transform.push(`${x} ${y} ${scale}`.trim());
}
}
@@ -109,7 +130,7 @@ window.gZenUIManager = {
}
keyframes.push(frame);
}
return await new Promise((resolve) => {
return await new Promise(resolve => {
const animation = element.animate(keyframes, ...args);
animation.onfinish = () => resolve();
});
@@ -117,10 +138,19 @@ window.gZenUIManager = {
_addNewCustomizableButtonsIfNeeded() {
const kPref = "zen.ui.migration.compact-mode-button-added";
let navbarPlacements = CustomizableUI.getWidgetIdsInArea("zen-sidebar-top-buttons");
let navbarPlacements = CustomizableUI.getWidgetIdsInArea(
"zen-sidebar-top-buttons"
);
try {
if (!navbarPlacements.length && !Services.prefs.getBoolPref(kPref, false)) {
CustomizableUI.addWidgetToArea("zen-toggle-compact-mode", "zen-sidebar-top-buttons", 0);
if (
!navbarPlacements.length &&
!Services.prefs.getBoolPref(kPref, false)
) {
CustomizableUI.addWidgetToArea(
"zen-toggle-compact-mode",
"zen-sidebar-top-buttons",
0
);
gZenVerticalTabsManager._topButtonsSeparatorElement.before(
document.getElementById("zen-toggle-compact-mode")
);
@@ -138,7 +168,7 @@ window.gZenUIManager = {
// is ran before this function.
document.documentElement.setAttribute("zen-has-bookmarks", "true");
}
bookmarkToolbar.addEventListener("toolbarvisibilitychange", (event) => {
bookmarkToolbar.addEventListener("toolbarvisibilitychange", event => {
const visible = event.detail.visible;
if (visible) {
document.documentElement.setAttribute("zen-has-bookmarks", "true");
@@ -221,11 +251,16 @@ window.gZenUIManager = {
const kUrlbarHeight = 335;
gURLBar.style.setProperty(
"--zen-urlbar-top",
`${window.innerHeight / 2 - Math.max(kUrlbarHeight, gURLBar.getBoundingClientRect().height) / 2}px`
`${window.innerHeight / 2 - Math.max(kUrlbarHeight, window.windowUtils.getBoundsWithoutFlushing(gURLBar).height) / 2}px`
);
gURLBar.style.setProperty("--zen-urlbar-width", `${Math.min(window.innerWidth / 2, 750)}px`);
gZenVerticalTabsManager.actualWindowButtons.removeAttribute("zen-has-hover");
gZenVerticalTabsManager.recalculateURLBarHeight();
gURLBar.style.setProperty(
"--zen-urlbar-width",
`${Math.min(window.innerWidth / 2, 750)}px`
);
gZenVerticalTabsManager.actualWindowButtons.removeAttribute(
"zen-has-hover"
);
gZenVerticalTabsManager.recalculateURLBarHeight(true);
if (!this._preventToolbarRebuild) {
setTimeout(() => {
gZenWorkspaces.updateTabsContainers();
@@ -256,7 +291,10 @@ window.gZenUIManager = {
openAndChangeToTab(url, options) {
if (window.ownerGlobal.parent) {
const tab = window.ownerGlobal.parent.gBrowser.addTrustedTab(url, options);
const tab = window.ownerGlobal.parent.gBrowser.addTrustedTab(
url,
options
);
window.ownerGlobal.parent.gBrowser.selectedTab = tab;
return tab;
}
@@ -270,7 +308,10 @@ window.gZenUIManager = {
},
createValidXULText(text) {
return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
return text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
},
/**
@@ -302,7 +343,11 @@ window.gZenUIManager = {
continue;
}
document.removeEventListener("mousemove", this.__removeHasPopupAttribute);
gZenCompactModeManager._setElementExpandAttribute(el, true, "has-popup-menu");
gZenCompactModeManager._setElementExpandAttribute(
el,
true,
"has-popup-menu"
);
this.__currentPopup = showEvent.target;
this.__currentPopupTrackElement = el;
break;
@@ -315,11 +360,21 @@ window.gZenUIManager = {
}
const element = this.__currentPopupTrackElement;
if (document.getElementById("main-window").matches(":hover")) {
gZenCompactModeManager._setElementExpandAttribute(element, false, "has-popup-menu");
gZenCompactModeManager._setElementExpandAttribute(
element,
false,
"has-popup-menu"
);
} else {
this.__removeHasPopupAttribute = () =>
gZenCompactModeManager._setElementExpandAttribute(element, false, "has-popup-menu");
document.addEventListener("mousemove", this.__removeHasPopupAttribute, { once: true });
gZenCompactModeManager._setElementExpandAttribute(
element,
false,
"has-popup-menu"
);
document.addEventListener("mousemove", this.__removeHasPopupAttribute, {
once: true,
});
}
this.__currentPopup = null;
this.__currentPopupTrackElement = null;
@@ -347,9 +402,11 @@ window.gZenUIManager = {
const input = gURLBar;
if (gURLBar.hasAttribute("breakout-extend") && !this._animatingSearchMode) {
this._animatingSearchMode = true;
this.motion.animate(input, { scale: [1, 0.98, 1] }, { duration: 0.25 }).then(() => {
delete this._animatingSearchMode;
});
this.motion
.animate(input, { scale: [1, 0.98, 1] }, { duration: 0.25 })
.then(() => {
delete this._animatingSearchMode;
});
if (searchMode) {
gURLBar.setAttribute("animate-searchmode", "true");
this._animatingSearchModeTimeout = setTimeout(() => {
@@ -416,7 +473,12 @@ window.gZenUIManager = {
return true;
},
handleNewTab(werePassedURL, searchClipboard, where, overridePreferance = false) {
handleNewTab(
werePassedURL,
searchClipboard,
where,
overridePreferance = false
) {
// Validate browser state first
if (!this._validateBrowserState()) {
console.warn("Browser state invalid for new tab operation");
@@ -548,7 +610,9 @@ window.gZenUIManager = {
if (isFocusedBefore) {
setTimeout(() => {
window.dispatchEvent(
new CustomEvent("ZenURLBarClosed", { detail: { onSwitch, onElementPicked } })
new CustomEvent("ZenURLBarClosed", {
detail: { onSwitch, onElementPicked },
})
);
gURLBar.view.close({ elementPicked: onElementPicked });
gURLBar.updateTextOverflow();
@@ -559,8 +623,15 @@ window.gZenUIManager = {
// Ensure tab and browser are valid before updating state
const selectedTab = gBrowser.selectedTab;
if (selectedTab && selectedTab.linkedBrowser && !selectedTab.closing && onSwitch) {
const browserState = gURLBar.getBrowserState(selectedTab.linkedBrowser);
if (
selectedTab &&
selectedTab.linkedBrowser &&
!selectedTab.closing &&
onSwitch
) {
const browserState = gURLBar.getBrowserState(
selectedTab.linkedBrowser
);
if (browserState) {
browserState.urlbarFocused = false;
}
@@ -574,7 +645,10 @@ window.gZenUIManager = {
if (gURLBar.hasAttribute("breakout-extend")) {
return aURL;
}
if (gZenVerticalTabsManager._hasSetSingleToolbar && this.urlbarShowDomainOnly) {
if (
gZenVerticalTabsManager._hasSetSingleToolbar &&
this.urlbarShowDomainOnly
) {
let url = BrowserUIUtils.removeSingleTrailingSlashFromURL(aURL);
return url.startsWith("https://") ? url.split("/")[2] : url;
}
@@ -639,7 +713,11 @@ window.gZenUIManager = {
return;
}
this.motion
.animate(toast, { opacity: [1, 0], scale: [1, 0.5] }, { duration: 0.2, bounce: 0 })
.animate(
toast,
{ opacity: [1, 0], scale: [1, 0.5] },
{ duration: 0.2, bounce: 0 }
)
.then(() => {
toast.remove();
if (this._toastContainer.children.length === 0) {
@@ -648,7 +726,11 @@ window.gZenUIManager = {
});
};
if (reused) {
await this.motion.animate(toast, { scale: 0.2 }, { duration: 0.1, bounce: 0 });
await this.motion.animate(
toast,
{ scale: 0.2 },
{ duration: 0.1, bounce: 0 }
);
} else {
toast.addEventListener("mouseover", () => {
if (this._toastTimeouts[messageId]) {
@@ -659,17 +741,27 @@ window.gZenUIManager = {
if (this._toastTimeouts[messageId]) {
clearTimeout(this._toastTimeouts[messageId]);
}
this._toastTimeouts[messageId] = setTimeout(timeoutFunction, options.timeout || 2000);
this._toastTimeouts[messageId] = setTimeout(
timeoutFunction,
options.timeout || 2000
);
});
}
if (!toast.style.transform) {
toast.style.transform = "scale(0)";
}
await this.motion.animate(toast, { scale: 1 }, { type: "spring", bounce: 0.2, duration: 0.5 });
await this.motion.animate(
toast,
{ scale: 1 },
{ type: "spring", bounce: 0.2, duration: 0.5 }
);
if (this._toastTimeouts[messageId]) {
clearTimeout(this._toastTimeouts[messageId]);
}
this._toastTimeouts[messageId] = setTimeout(timeoutFunction, options.timeout || 2000);
this._toastTimeouts[messageId] = setTimeout(
timeoutFunction,
options.timeout || 2000
);
},
panelUIPosition(panel, anchor) {
@@ -722,10 +814,12 @@ window.gZenUIManager = {
block = "topleft";
}
if (
(gZenVerticalTabsManager._hasSetSingleToolbar && gZenVerticalTabsManager._prefsRightSide) ||
(gZenVerticalTabsManager._hasSetSingleToolbar &&
gZenVerticalTabsManager._prefsRightSide) ||
(panel?.id === "zen-unified-site-data-panel" &&
!gZenVerticalTabsManager._hasSetSingleToolbar) ||
(panel?.id === "unified-extensions-panel" && gZenVerticalTabsManager._hasSetSingleToolbar)
(panel?.id === "unified-extensions-panel" &&
gZenVerticalTabsManager._hasSetSingleToolbar)
) {
block = "bottomright";
inline = "topright";
@@ -787,14 +881,20 @@ window.gZenVerticalTabsManager = {
return !(
window.AppConstants.platform === "macosx" ||
window.matchMedia("(-moz-gtk-csd-reversed-placement)").matches ||
Services.prefs.getBoolPref("zen.view.experimental-force-window-controls-left")
Services.prefs.getBoolPref(
"zen.view.experimental-force-window-controls-left"
)
);
});
ChromeUtils.defineLazyGetter(this, "hidesTabsToolbar", () => {
return (
document.documentElement.getAttribute("chromehidden")?.includes("toolbar") ||
document.documentElement.getAttribute("chromehidden")?.includes("menubar")
document.documentElement
.getAttribute("chromehidden")
?.includes("toolbar") ||
document.documentElement
.getAttribute("chromehidden")
?.includes("menubar")
);
});
@@ -808,22 +908,35 @@ window.gZenVerticalTabsManager = {
var onPrefChange = this._onPrefChange.bind(this);
this.initializePreferences(onPrefChange);
this._toolbarOriginalParent = document.getElementById("nav-bar").parentElement;
this._toolbarOriginalParent =
document.getElementById("nav-bar").parentElement;
gZenCompactModeManager.addEventListener(updateEvent);
this.initRightSideOrderContextMenu();
window.addEventListener("customizationstarting", this._preCustomize.bind(this));
window.addEventListener("aftercustomization", this._postCustomize.bind(this));
window.addEventListener(
"customizationstarting",
this._preCustomize.bind(this)
);
window.addEventListener(
"aftercustomization",
this._postCustomize.bind(this)
);
this._updateEvent();
if (!this.isWindowsStyledButtons) {
document.documentElement.setAttribute("zen-window-buttons-reversed", true);
document.documentElement.setAttribute(
"zen-window-buttons-reversed",
true
);
}
this._renameTabHalt = this.renameTabHalt.bind(this);
gBrowser.tabContainer.addEventListener("dblclick", this.renameTabStart.bind(this));
gBrowser.tabContainer.addEventListener(
"dblclick",
this.renameTabStart.bind(this)
);
},
toggleExpand() {
@@ -896,7 +1009,7 @@ window.gZenVerticalTabsManager = {
}
)
.then(() => {})
.catch((err) => {
.catch(err => {
console.error(err);
})
.finally(() => {
@@ -905,7 +1018,8 @@ window.gZenVerticalTabsManager = {
aItem.style.removeProperty("opacity");
});
const itemLabel =
aItem.querySelector(".tab-group-label-container") || aItem.querySelector(".tab-content");
aItem.querySelector(".tab-group-label-container") ||
aItem.querySelector(".tab-content");
gZenUIManager.motion
.animate(
itemLabel,
@@ -918,7 +1032,7 @@ window.gZenVerticalTabsManager = {
}
)
.then(() => {})
.catch((err) => {
.catch(err => {
console.error(err);
})
.finally(() => {
@@ -971,7 +1085,7 @@ window.gZenVerticalTabsManager = {
},
async _preCustomize() {
await this._multiWindowFeature.foreachWindowAsActive(async (browser) => {
await this._multiWindowFeature.foreachWindowAsActive(async browser => {
browser.gZenVerticalTabsManager._updateEvent({
forCustomizableMode: true,
dontRebuildAreas: true,
@@ -984,7 +1098,7 @@ window.gZenVerticalTabsManager = {
_postCustomize() {
// No need to use `await` here, because the customization is already done
this._multiWindowFeature.foreachWindowAsActive(async (browser) => {
this._multiWindowFeature.foreachWindowAsActive(async browser => {
browser.gZenVerticalTabsManager._updateEvent({ dontRebuildAreas: true });
});
},
@@ -1028,7 +1142,7 @@ window.gZenVerticalTabsManager = {
},
_initWaitPromise() {
this._waitPromise = new Promise((resolve) => {
this._waitPromise = new Promise(resolve => {
this._resolveWaitPromise = resolve;
});
},
@@ -1037,8 +1151,12 @@ window.gZenVerticalTabsManager = {
this._resolveWaitPromise();
// only run if we are in the active window
await this._multiWindowFeature.foreachWindowAsActive(async (browser) => {
if (browser.gZenVerticalTabsManager._multiWindowFeature.windowIsActive(browser)) {
await this._multiWindowFeature.foreachWindowAsActive(async browser => {
if (
browser.gZenVerticalTabsManager._multiWindowFeature.windowIsActive(
browser
)
) {
return;
}
await browser.gZenVerticalTabsManager._waitPromise;
@@ -1052,7 +1170,7 @@ window.gZenVerticalTabsManager = {
}
},
recalculateURLBarHeight() {
recalculateURLBarHeight(updateFormat = false) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
gURLBar.removeAttribute("--urlbar-height");
@@ -1065,7 +1183,9 @@ window.gZenVerticalTabsManager = {
if (typeof height !== "undefined") {
gURLBar.style.setProperty("--urlbar-height", `${height}px`);
}
gURLBar.zenFormatURLValue();
if (updateFormat) {
gURLBar.zenFormatURLValue();
}
});
});
},
@@ -1087,17 +1207,22 @@ window.gZenVerticalTabsManager = {
}
const topButtons = document.getElementById("zen-sidebar-top-buttons");
const isCompactMode = gZenCompactModeManager.preference && !forCustomizableMode;
const isCompactMode =
gZenCompactModeManager.preference && !forCustomizableMode;
const isVerticalTabs = this._prefsVerticalTabs || forCustomizableMode;
const isSidebarExpanded = this._prefsSidebarExpanded || !isVerticalTabs;
const isRightSide = this._prefsRightSide && isVerticalTabs;
const isSingleToolbar =
((this._prefsUseSingleToolbar && isVerticalTabs && isSidebarExpanded) || !isVerticalTabs) &&
((this._prefsUseSingleToolbar && isVerticalTabs && isSidebarExpanded) ||
!isVerticalTabs) &&
!forCustomizableMode &&
!this.hidesTabsToolbar;
const titlebar = document.getElementById("titlebar");
gBrowser.tabContainer.setAttribute("orient", isVerticalTabs ? "vertical" : "horizontal");
gBrowser.tabContainer.setAttribute(
"orient",
isVerticalTabs ? "vertical" : "horizontal"
);
gBrowser.tabContainer.arrowScrollbox.setAttribute(
"orient",
isVerticalTabs ? "vertical" : "horizontal"
@@ -1108,7 +1233,9 @@ window.gZenVerticalTabsManager = {
isVerticalTabs ? "vertical" : "horizontal"
);
const buttonsTarget = document.getElementById("zen-sidebar-top-buttons-customization-target");
const buttonsTarget = document.getElementById(
"zen-sidebar-top-buttons-customization-target"
);
if (isRightSide) {
this.navigatorToolbox.setAttribute("zen-right-side", "true");
document.documentElement.setAttribute("zen-right-side", "true");
@@ -1119,7 +1246,9 @@ window.gZenVerticalTabsManager = {
delete this._hadSidebarCollapse;
if (isSidebarExpanded) {
this._hadSidebarCollapse = !document.documentElement.hasAttribute("zen-sidebar-expanded");
this._hadSidebarCollapse = !document.documentElement.hasAttribute(
"zen-sidebar-expanded"
);
this.navigatorToolbox.setAttribute("zen-sidebar-expanded", "true");
document.documentElement.setAttribute("zen-sidebar-expanded", "true");
gBrowser.tabContainer.setAttribute("expanded", "true");
@@ -1129,8 +1258,12 @@ window.gZenVerticalTabsManager = {
gBrowser.tabContainer.removeAttribute("expanded");
}
const appContentNavbarContaienr = document.getElementById("zen-appcontent-navbar-container");
const appContentNavbarWrapper = document.getElementById("zen-appcontent-navbar-wrapper");
const appContentNavbarContaienr = document.getElementById(
"zen-appcontent-navbar-container"
);
const appContentNavbarWrapper = document.getElementById(
"zen-appcontent-navbar-wrapper"
);
appContentNavbarWrapper.style.transition = "none";
let shouldHide = false;
if (
@@ -1146,12 +1279,16 @@ window.gZenVerticalTabsManager = {
}
// Check if the sidebar is in hover mode
if (!this.navigatorToolbox.hasAttribute("zen-right-side") && !isCompactMode) {
if (
!this.navigatorToolbox.hasAttribute("zen-right-side") &&
!isCompactMode
) {
this.navigatorToolbox.prepend(topButtons);
}
let windowButtons = this.actualWindowButtons;
let doNotChangeWindowButtons = !isCompactMode && isRightSide && this.isWindowsStyledButtons;
let doNotChangeWindowButtons =
!isCompactMode && isRightSide && this.isWindowsStyledButtons;
const navBar = document.getElementById("nav-bar");
if (isSingleToolbar) {
@@ -1167,20 +1304,24 @@ window.gZenVerticalTabsManager = {
for (const button of elements) {
this._topButtonsSeparatorElement.after(button);
}
buttonsTarget.prepend(document.getElementById("unified-extensions-button"));
buttonsTarget.prepend(
document.getElementById("unified-extensions-button")
);
const panelUIButton = document.getElementById("PanelUI-button");
buttonsTarget.prepend(panelUIButton);
panelUIButton.setAttribute("overflows", "false");
buttonsTarget.parentElement.append(document.getElementById("nav-bar-overflow-button"));
buttonsTarget.parentElement.append(
document.getElementById("nav-bar-overflow-button")
);
if (this.isWindowsStyledButtons && !doNotChangeWindowButtons) {
appContentNavbarContaienr.append(windowButtons);
}
if (isCompactMode) {
titlebar.prepend(navBar);
titlebar.prepend(topButtons);
titlebar.moveBefore(navBar, titlebar.firstChild);
titlebar.moveBefore(topButtons, titlebar.firstChild);
} else {
titlebar.before(topButtons);
titlebar.before(navBar);
titlebar.parentNode.moveBefore(topButtons, titlebar);
titlebar.parentNode.moveBefore(navBar, titlebar);
}
document.documentElement.setAttribute("zen-single-toolbar", true);
this._hasSetSingleToolbar = true;
@@ -1192,7 +1333,9 @@ window.gZenVerticalTabsManager = {
'#zen-sidebar-top-buttons-customization-target > :is([cui-areatype="toolbar"], .chromeclass-toolbar-additional)'
);
for (const button of elements) {
document.getElementById("nav-bar-customization-target").append(button);
document
.getElementById("nav-bar-customization-target")
.append(button);
}
this._topButtonsSeparatorElement.remove();
document.documentElement.removeAttribute("zen-single-toolbar");
@@ -1225,7 +1368,9 @@ window.gZenVerticalTabsManager = {
topButtons.prepend(windowButtons);
}
const canHideTabBarPref = Services.prefs.getBoolPref("zen.view.compact.hide-tabbar");
const canHideTabBarPref = Services.prefs.getBoolPref(
"zen.view.compact.hide-tabbar"
);
const captionsShouldStayOnSidebar =
!canHideTabBarPref &&
((!this.isWindowsStyledButtons && !isRightSide) ||
@@ -1238,7 +1383,12 @@ window.gZenVerticalTabsManager = {
}
// Case: single toolbar, compact mode, right side and windows styled buttons
if (isSingleToolbar && isCompactMode && isRightSide && this.isWindowsStyledButtons) {
if (
isSingleToolbar &&
isCompactMode &&
isRightSide &&
this.isWindowsStyledButtons
) {
topButtons.prepend(windowButtons);
}
@@ -1284,9 +1434,15 @@ window.gZenVerticalTabsManager = {
this._hasSetSingleToolbar &&
Services.prefs.getBoolPref("zen.view.overflow-webext-toolbar", true)
) {
topButtons.setAttribute("addon-webext-overflowtarget", "zen-overflow-extensions-list");
topButtons.setAttribute(
"addon-webext-overflowtarget",
"zen-overflow-extensions-list"
);
} else {
topButtons.setAttribute("addon-webext-overflowtarget", "overflowed-extensions-list");
topButtons.setAttribute(
"addon-webext-overflowtarget",
"overflowed-extensions-list"
);
}
gZenCompactModeManager.updateCompactModeContext(isSingleToolbar);
@@ -1319,11 +1475,15 @@ window.gZenVerticalTabsManager = {
},
rebuildAreas() {
CustomizableUI.zenInternalCU._rebuildRegisteredAreas(/* zenDontRebuildCollapsed */ true);
CustomizableUI.zenInternalCU._rebuildRegisteredAreas(
/* zenDontRebuildCollapsed */ true
);
},
_updateMaxWidth() {
const maxWidth = Services.prefs.getIntPref("zen.view.sidebar-expanded.max-width");
const maxWidth = Services.prefs.getIntPref(
"zen.view.sidebar-expanded.max-width"
);
const toolbox = gNavToolbox;
if (!this._prefsCompactMode) {
toolbox.style.maxWidth = `${maxWidth}px`;
@@ -1396,7 +1556,9 @@ window.gZenVerticalTabsManager = {
);
}
const editorContainer = this._tabEdited.querySelector(".tab-editor-container");
const editorContainer = this._tabEdited.querySelector(
".tab-editor-container"
);
if (editorContainer) {
editorContainer.remove();
}
@@ -1424,21 +1586,30 @@ window.gZenVerticalTabsManager = {
) {
return;
}
if (isTab && !target.closest(".tab-label-container") && event.type === "dblclick") {
if (
isTab &&
!target.closest(".tab-label-container") &&
event.type === "dblclick"
) {
return;
}
this._tabEdited =
target.closest(".tabbrowser-tab") ||
target.closest(".zen-current-workspace-indicator-name") ||
(event.explicit && target.closest(".tab-group-label"));
if (!this._tabEdited || (this._tabEdited.hasAttribute("zen-essential") && isTab)) {
if (
!this._tabEdited ||
(this._tabEdited.hasAttribute("zen-essential") && isTab)
) {
this._tabEdited = null;
return;
}
gZenFolders.cancelPopupTimer();
event.stopPropagation?.();
document.documentElement.setAttribute("zen-renaming-tab", "true");
const label = isTab ? this._tabEdited.querySelector(".tab-label-container") : this._tabEdited;
const label = isTab
? this._tabEdited.querySelector(".tab-label-container")
: this._tabEdited;
label.classList.add("tab-label-container-editing");
if (isTab) {
@@ -1455,7 +1626,9 @@ window.gZenVerticalTabsManager = {
input.addEventListener("keydown", this.renameTabKeydown.bind(this));
if (isTab) {
const containerHtml = this._tabEdited.querySelector(".tab-editor-container");
const containerHtml = this._tabEdited.querySelector(
".tab-editor-container"
);
containerHtml.appendChild(input);
} else {
this._tabEdited.after(input);
@@ -1471,7 +1644,9 @@ window.gZenVerticalTabsManager = {
return;
}
document.documentElement.removeAttribute("zen-renaming-tab");
const editorContainer = this._tabEdited.querySelector(".tab-editor-container");
const editorContainer = this._tabEdited.querySelector(
".tab-editor-container"
);
let input = document.getElementById("tab-label-input");
input.remove();
if (editorContainer) {

View File

@@ -17,12 +17,17 @@ export default function checkForZenUpdates() {
!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",
links: [
{
url: Services.urlFormatter.formatURL(updateUrl.replace("%VERSION%", version)),
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",

View File

@@ -22,12 +22,14 @@
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media not -moz-pref("layout.css.prefers-color-scheme.content-override", 2) {
& browser[type="content"] {
color-scheme: env(-moz-content-preferred-color-scheme);
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media -moz-pref("zen.theme.acrylic-elements") {
& browser[type="content"] {
/* For the rendering engine to apply layering optimizations. This
@@ -37,6 +39,7 @@
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@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);

View File

@@ -142,9 +142,10 @@
#zen-main-app-wrapper {
background: var(--zen-themed-toolbar-bg-transparent);
/* See bug #8814, don't an overflow here as it causes issues
/* See bug #8814, don't add overflow here as it causes issues
* with firefox's rendering of the tab bar */
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-pref("zen.view.grey-out-inactive-windows")) {
&:-moz-window-inactive {
background: InactiveCaption;
@@ -155,6 +156,7 @@
z-index: 1;
}
/* stylelint-disable-next-line media-query-no-invalid */
@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;
@@ -207,6 +209,7 @@
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media -moz-pref("zen.widget.mac.mono-window-controls") {
:root:not([window-modal-open="true"]) .titlebar-buttonbox-container {
color: var(--toolbox-textcolor);
@@ -220,7 +223,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-size: 20px 22px;
background-size: var(--icon-size-medium) 22px;
background-position: 53% 50%;
@media (-moz-mac-tahoe-theme) {

View File

@@ -119,7 +119,7 @@
}
#urlbar .urlbar-input {
border-radius: 0px !important;
border-radius: 0 !important;
}
#urlbar .urlbar-input-box {
@@ -174,7 +174,7 @@
& #identity-box {
order: 999;
margin: 0px !important;
margin: 0 !important;
}
}
@@ -189,12 +189,14 @@
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media -moz-pref("zen.urlbar.single-toolbar-show-copy-url", false) {
:root[zen-single-toolbar="true"] #zen-copy-url-button {
display: none !important;
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media not -moz-pref("zen.urlbar.show-pip-button") {
#picture-in-picture-button {
display: none !important;
@@ -259,14 +261,17 @@
& .urlbar-background {
--zen-urlbar-background-base: light-dark(#fbfbfb, color-mix(in srgb, hsl(0, 0%, 6.7%), var(--zen-colors-primary) 30%));
/* stylelint-disable-next-line media-query-no-invalid */
@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;
box-shadow: 0px 30px 140px -15px light-dark(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.6)) !important;
box-shadow: 0 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;
/* stylelint-disable-next-line media-query-no-invalid */
@media -moz-pref("zen.theme.acrylic-elements") {
backdrop-filter: blur(42px) saturate(110%) brightness(0.25) contrast(100%) !important;
}
@@ -324,8 +329,8 @@
& > image {
margin-top: auto;
margin-bottom: auto;
height: 24px; /* double 12px */
width: 24px;
height: var(--size-item-medium); /* double 12px */
width: var(--size-item-medium);
padding: 4px !important;
&:hover {
@@ -502,13 +507,14 @@
height: var(--urlbar-height) !important;
margin-inline: 0.15rem !important;
:root:not([zen-single-toolbar="true"]) & {
max-height: 32px !important;
max-height: var(--size-item-large) !important;
min-height: unset !important;
margin-block: -1px !important;
}
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media not -moz-pref("zen.urlbar.show-protections-icon") {
#tracking-protection-icon-container {
display: none !important;
@@ -573,8 +579,8 @@
& img {
-moz-context-properties: fill;
fill: currentColor;
width: 16px;
height: 16px;
width: var(--size-item-small);
height: var(--size-item-small);
}
&[hidden] {
@@ -702,7 +708,7 @@
}
#identity-box {
margin-inline-end: 0px;
margin-inline-end: 0;
}
}
@@ -714,7 +720,7 @@
#urlbar-search-mode-indicator-title {
font-weight: 600;
padding: 0px;
padding: 0;
}
/* These are buttons that we dont need to be
@@ -727,6 +733,7 @@
display: none !important;
}
/* stylelint-disable-next-line media-query-no-invalid */
@media not -moz-pref("zen.urlbar.show-contextual-id") {
#userContext-icons {
display: none !important;

View File

@@ -9,7 +9,7 @@
display: flex;
gap: 8px;
padding: 8px 2px;
padding-bottom: 0px;
padding-bottom: 0;
& .unified-extensions-item {
flex: 1;

View File

@@ -22,7 +22,7 @@ panel[type="arrow"]:not(#feature-callout) {
transition-duration: 0s !important;
&::part(content) {
/* Refrain from animating for now as we haven't found a
/* Refrain from animating for now as we haven't found a
* way to properly animate the popup without having the mica
* backdrop staying still while the popup animates */
animation: none !important;
@@ -30,7 +30,7 @@ panel[type="arrow"]:not(#feature-callout) {
}
@media (-moz-platform: macos) {
&:where([followanchor="false"], [nonnativepopover="true"]) {
&:where([nonnativepopover="true"], :not([type="arrow"])) {
appearance: auto !important;
-moz-default-appearance: menupopup;
/* We set the default background here, rather than on ::part(content),
@@ -45,7 +45,7 @@ panel[type="arrow"]:not(#feature-callout) {
/* Remove the shadow for the native panels, as macos already
* adds the shadows to the window. This is specially important
* on Tahoe, where we *dont* apply an image mask, meaning that
* on Tahoe, where we *don't* apply an image mask, meaning that
* trying to render a shadow would end up in having weird borders
* around the panel */
--panel-shadow: none;

View File

@@ -21,8 +21,8 @@
}
#zenEditBookmarkPanelFavicon {
width: 20px;
height: 20px;
width: var(--icon-size-medium);
height: var(--icon-size-medium);
}
#editBookmarkPanel .panel-header {

View File

@@ -4,7 +4,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
.dialogBox {
border: none;
outline: 1px solid light-dark(transparent, #646464);
animation: zen-dialog-fade-in 0.3s ease-out;
border-radius: 12px !important;

View File

@@ -92,8 +92,8 @@ panel {
#appMenu-fxa-label2::before {
content: "";
display: -moz-box;
height: 16px;
width: 16px;
height: var(--size-item-small);
width: var(--size-item-small);
background: var(--avatar-image-url) 0/16px;
scale: 1.25;
border-radius: 99px;
@@ -139,7 +139,7 @@ panel {
border-inline-start: 1px solid var(--panel-separator-color);
display: block;
position: relative;
height: 32px;
height: var(--size-item-large);
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)
@@ -147,8 +147,8 @@ panel {
}
#appMenu-zoomReset-button2 {
height: calc(16px + var(--uc-panel-zoom-button-padding) * 2);
min-height: calc(16px + var(--uc-panel-zoom-button-padding) * 2);
height: calc(var(--size-item-small) + var(--uc-panel-zoom-button-padding) * 2);
min-height: calc(var(--size-item-small) + var(--uc-panel-zoom-button-padding) * 2);
}
#appMenu-zoomReduce-button2:not([disabled], [open], :active):is(:hover),
@@ -191,7 +191,7 @@ panel {
#identity-popup-mainView-panel-header,
#protections-popup-mainView-panel-header,
.panel-header {
min-height: calc((var(--arrowpanel-menuitem-padding-block) + 4px) * 2 + 16px);
min-height: calc((var(--arrowpanel-menuitem-padding-block) + 4px) * 2 + var(--size-item-small));
}
/* URL bar popup */
@@ -223,7 +223,7 @@ panel {
.permission-popup-permission-item,
#permission-popup-storage-access-permission-list-header {
padding-block: 4px;
margin-block: 0px;
margin-block: 0;
}
#editBookmarkPanel > #editBookmarkHeaderSeparator,
@@ -353,7 +353,7 @@ menuseparator {
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%));
box-shadow: light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.4)) 0px 0px 22px 2px;
box-shadow: light-dark(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.4)) 0 0 22px 2px;
border: none;
display: flex;
font-weight: 600;
@@ -386,10 +386,10 @@ menuseparator {
& button {
width: min-content;
padding: 0px 8px !important;
padding: 0 8px !important;
min-width: unset !important;
min-height: 28px;
margin: 0px !important;
margin: 0 !important;
border-radius: 6px !important;
border-top: 2px solid light-dark(transparent, rgba(255, 255, 255, 0.1));
color: light-dark(rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0.8)) !important;

View File

@@ -107,8 +107,8 @@
& .zen-sidebar-notification-link-icon {
pointer-events: none;
width: 16px;
height: 16px;
width: var(--size-item-small);
height: var(--size-item-small);
-moz-context-properties: fill, fill-opacity;
fill: var(--special-color, currentColor);
}

View File

@@ -24,6 +24,7 @@
display: none !important;
}
/* stylelint-disable-next-line media-query-no-invalid */
@media -moz-pref("zen.theme.disable-lightweight") {
#customization-lwtheme-link {
display: none !important;
@@ -60,7 +61,7 @@
#PanelUI-zen-emojis-picker-header {
gap: 10px;
align-items: center;
padding: 0px 10px;
padding: 0 10px;
padding-bottom: 6px;
}
@@ -147,7 +148,7 @@
.zen-emojis-picker-emoji {
font-size: 14px;
padding: 0px !important;
padding: 0 !important;
& image {
display: none;
}
@@ -262,6 +263,7 @@
/* Status panel */
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-pref("zen.theme.styled-status-panel")) {
#statuspanel {
padding: 6px;
@@ -334,8 +336,8 @@
& > * {
background-color: color-mix(in srgb, currentcolor 6%, transparent);
width: 48px;
height: 32px;
width: var(--size-item-xlarge);
height: var(--size-item-large);
margin: 0;
justify-content: center;
align-items: center;
@@ -377,6 +379,7 @@
.zen-site-data-section-header {
font-weight: 600;
font-size: 12px;
& label {
margin: 0;
@@ -415,7 +418,7 @@
}
.permission-popup-permission-label {
margin: 0px;
margin: 0;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
@@ -446,8 +449,8 @@
position: absolute;
inset: 1px;
border-radius: 99px;
width: 32px;
height: 32px;
width: var(--size-item-large);
height: var(--size-item-large);
background: var(--button-background-color-primary);
opacity: 0.6;
transition:
@@ -490,12 +493,14 @@
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media -moz-pref("zen.theme.hide-unified-extensions-button") {
#unified-extensions-button:not([showing]) {
display: none !important;
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@media not -moz-pref("zen.theme.hide-unified-extensions-button") {
#zen-site-data-section-addons {
display: none;
@@ -518,8 +523,8 @@
-moz-context-properties: fill;
fill: currentColor;
color: light-dark(rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0.8));
width: 48px;
height: 32px;
width: var(--size-item-xlarge);
height: var(--size-item-large);
position: relative;
&[disabled] {
@@ -546,11 +551,11 @@
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),
inset 0px 1px 0px light-dark(transparent, rgba(255, 255, 255, 0.15));
0 1px 2px rgba(0, 0, 0, 0.1),
inset 0 1px 0 light-dark(transparent, rgba(255, 255, 255, 0.15));
border-radius: 6px;
--base-border-color: light-dark(rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0.1));
border: 1px solid light-dark(var(--base-border-color), rgb(21, 21, 21));
border: 0.5px solid light-dark(var(--base-border-color), rgb(21, 21, 21));
}
@media not (-moz-platform: macos) {

View File

@@ -8,7 +8,11 @@ export const ZenCustomizableUI = new (class {
constructor() {}
TYPE_TOOLBAR = "toolbar";
defaultSidebarIcons = ["downloads-button", "zen-workspaces-button", "zen-create-new-button"];
defaultSidebarIcons = [
"downloads-button",
"zen-workspaces-button",
"zen-create-new-button",
];
startup(CustomizableUIInternal) {
CustomizableUIInternal.registerArea(
@@ -39,7 +43,8 @@ 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
@@ -81,7 +86,7 @@ export const ZenCustomizableUI = new (class {
</toolbar>
`);
toolbox.prepend(sidebarBox);
new window.MutationObserver((e) => {
new window.MutationObserver(e => {
if (e[0].type !== "attributes" || e[0].attributeName !== "width") {
return;
}
@@ -96,7 +101,7 @@ export const ZenCustomizableUI = new (class {
toolbox.style.width = width;
toolbox.setAttribute("width", width);
splitter.addEventListener("dblclick", (e) => {
splitter.addEventListener("dblclick", e => {
if (e.button !== 0) {
return;
}
@@ -104,7 +109,9 @@ export const ZenCustomizableUI = new (class {
toolbox.setAttribute("width", kDefaultSidebarWidth);
});
const newTab = window.document.getElementById("vertical-tabs-newtab-button");
const newTab = window.document.getElementById(
"vertical-tabs-newtab-button"
);
newTab.classList.add("zen-sidebar-action-button");
for (let id of this.defaultSidebarIcons) {
@@ -124,7 +131,7 @@ export const ZenCustomizableUI = new (class {
// If we use "mousedown" event for private windows (which open a new tab on "click"), we might end up with
// the urlbar flicking and therefore we use "command" event to avoid that.
let isPrivateMode = window.gZenWorkspaces.privateWindowOrDisabled;
button.addEventListener(isPrivateMode ? "command" : "mousedown", (event) => {
button.addEventListener(isPrivateMode ? "command" : "mousedown", event => {
if (isPrivateMode) {
window.document.getElementById("cmd_newNavigatorTab").doCommand();
return;
@@ -146,7 +153,9 @@ 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"
);
@@ -173,7 +182,9 @@ export const ZenCustomizableUI = new (class {
wrapper.prepend(elem);
}
}
window.document.getElementById("stop-reload-button").removeAttribute("overflows");
window.document
.getElementById("stop-reload-button")
.removeAttribute("overflows");
}
_dispatchResizeEvent(window) {

View File

@@ -24,7 +24,9 @@ class nsZenUIMigration {
}
this.clearVariables();
if (this.shouldRestart) {
Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
Services.startup.quit(
Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart
);
}
}
@@ -61,13 +63,24 @@ class nsZenUIMigration {
userContentFile.append("userContent.css");
Services.prefs.setBoolPref(
"zen.workspaces.separate-essentials",
Services.prefs.getBoolPref("zen.workspaces.container-specific-essentials-enabled", false)
Services.prefs.getBoolPref(
"zen.workspaces.container-specific-essentials-enabled",
false
)
);
const theme = Services.prefs.getIntPref(
"layout.css.prefers-color-scheme.content-override",
0
);
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.warn("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;
}
}
@@ -79,7 +92,11 @@ class nsZenUIMigration {
}
_migrateV3() {
if (Services.prefs.getStringPref("zen.theme.accent-color", "").startsWith("system")) {
if (
Services.prefs
.getStringPref("zen.theme.accent-color", "")
.startsWith("system")
) {
Services.prefs.setStringPref("zen.theme.accent-color", "AccentColor");
}
}
@@ -100,20 +117,23 @@ class nsZenUIMigration {
lazy.SessionStore.promiseAllWindowsRestored.then(() => {
const win = Services.wm.getMostRecentWindow("navigator:browser");
win.setTimeout(async () => {
const [title, message, learnMore, accept] = await win.document.l10n.formatMessages([
"zen-window-sync-migration-dialog-title",
"zen-window-sync-migration-dialog-message",
"zen-window-sync-migration-dialog-learn-more",
"zen-window-sync-migration-dialog-accept",
]);
const [title, message, learnMore, accept] =
await win.document.l10n.formatMessages([
"zen-window-sync-migration-dialog-title",
"zen-window-sync-migration-dialog-message",
"zen-window-sync-migration-dialog-learn-more",
"zen-window-sync-migration-dialog-accept",
]);
// buttonPressed will be 0 for cancel, 1 for "more info"
let buttonPressed = Services.prompt.confirmEx(
win,
title.value,
message.value,
Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_IS_STRING,
Services.prompt.BUTTON_POS_0 *
Services.prompt.BUTTON_TITLE_IS_STRING +
Services.prompt.BUTTON_POS_1 *
Services.prompt.BUTTON_TITLE_IS_STRING,
learnMore.value,
accept.value,
null,
@@ -122,7 +142,10 @@ class nsZenUIMigration {
);
// User has clicked on "Learn More"
if (buttonPressed === 0) {
win.openTrustedLinkIn("https://docs.zen-browser.app/user-manual/window-sync", "tab");
win.openTrustedLinkIn(
"https://docs.zen-browser.app/user-manual/window-sync",
"tab"
);
}
}, 1000);
});

View File

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

View File

@@ -38,7 +38,8 @@
* 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();
},
@@ -91,14 +92,23 @@
},
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 ? 16 : 10;
document.documentElement.style.setProperty("--zen-border-radius", targetRadius + "px");
const targetRadius = window.matchMedia("(-moz-mac-tahoe-theme)")
.matches
? 16
: 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(
@@ -107,11 +117,17 @@
);
} 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"
);
}
},
@@ -121,14 +137,19 @@
if (
document.documentElement.hasAttribute("inFullscreen") &&
window.gZenCompactModeManager?.preference &&
!document.getElementById("tabbrowser-tabbox")?.hasAttribute("zen-split-view") &&
!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);
} else {
@@ -147,8 +168,13 @@
* 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
);
},
};

View File

@@ -44,14 +44,20 @@ 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",
false
);
this._canDebugLog = Services.prefs.getBoolPref("zen.view.compact.debug", false);
this._canDebugLog = Services.prefs.getBoolPref(
"zen.view.compact.debug",
false
);
this.addContextMenu();
},
@@ -60,12 +66,18 @@ 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",
() => {
Services.prefs.removeObserver("zen.tabs.vertical.right-side", tabIsRightObserver);
Services.prefs.removeObserver(
"zen.tabs.vertical.right-side",
tabIsRightObserver
);
},
{ once: true }
);
@@ -78,7 +90,9 @@ window.gZenCompactModeManager = {
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",
@@ -86,7 +100,7 @@ window.gZenCompactModeManager = {
);
if (AppConstants.platform == "macosx") {
window.addEventListener("mouseover", (event) => {
window.addEventListener("mouseover", event => {
const buttons = gZenVerticalTabsManager.actualWindowButtons;
if (event.target.closest(".titlebar-buttonbox-container") === buttons) {
return;
@@ -112,7 +126,9 @@ window.gZenCompactModeManager = {
},
get shouldBeCompact() {
return !document.documentElement.getAttribute("chromehidden")?.includes("toolbar");
return !document.documentElement
.getAttribute("chromehidden")
?.includes("toolbar");
},
set preference(value) {
@@ -147,7 +163,9 @@ window.gZenCompactModeManager = {
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;
},
@@ -156,7 +174,12 @@ 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,
[
@@ -187,7 +210,7 @@ window.gZenCompactModeManager = {
// This function is called after exiting DOM fullscreen mode,
// so we do a bit of a hack to re-calculate the URL height
if (aInstant) {
gZenVerticalTabsManager.recalculateURLBarHeight();
gZenVerticalTabsManager.recalculateURLBarHeight(true);
}
if (
!aInstant &&
@@ -230,7 +253,9 @@ window.gZenCompactModeManager = {
updateCompactModeContext(isSingleToolbar) {
const isIllegalState = this.checkIfIllegalState();
const menuitem = document.getElementById("zen-context-menu-compact-mode-toggle");
const menuitem = document.getElementById(
"zen-context-menu-compact-mode-toggle"
);
const menu = document.getElementById("zen-context-menu-compact-mode");
if (!menu) {
return;
@@ -292,7 +317,8 @@ window.gZenCompactModeManager = {
// on macos: collapsed + left side + only toolbar
// on windows: collapsed + right side + only toolbar
const closelyIllegalState =
(isLeftSideButtons && !isRightSidebar) || (!isLeftSideButtons && isRightSidebar);
(isLeftSideButtons && !isRightSidebar) ||
(!isLeftSideButtons && isRightSidebar);
if (closelyIllegalState && canHideToolbar && !canHideSidebar) {
// This state is illegal
Services.prefs.setBoolPref("zen.view.compact.hide-tabbar", true);
@@ -304,7 +330,7 @@ window.gZenCompactModeManager = {
},
callAllEventListeners() {
this._eventListeners.forEach((callback) => callback());
this._eventListeners.forEach(callback => callback());
},
addEventListener(callback) {
@@ -330,7 +356,6 @@ window.gZenCompactModeManager = {
await this.animateCompactMode();
this.callAllEventListeners();
}
gZenUIManager.updateTabsToolbar();
if (isUrlbarFocused) {
gURLBar.focus();
}
@@ -339,7 +364,9 @@ 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
@@ -351,14 +378,20 @@ 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`);
this.sidebar.style.setProperty(
"--actual-zen-sidebar-width",
`${sidebarWidth}px`
);
window.dispatchEvent(new window.Event("resize")); // To recalculate the layout
if (
event &&
@@ -369,7 +402,10 @@ 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;
},
@@ -391,14 +427,16 @@ window.gZenCompactModeManager = {
animateCompactMode() {
// Get the splitter width before hiding it (we need to hide it before animating on right)
document.documentElement.setAttribute("zen-compact-animating", "true");
return new Promise((resolve) => {
return new Promise(resolve => {
// We need to set the splitter width before hiding it
let splitterWidth = document
.getElementById("zen-sidebar-splitter")
.getBoundingClientRect().width;
const isCompactMode = this.preference;
const canHideSidebar = this.canHideSidebar;
let canAnimate = lazy.COMPACT_MODE_CAN_ANIMATE_SIDEBAR && !this.isSidebarPotentiallyOpen();
let canAnimate =
lazy.COMPACT_MODE_CAN_ANIMATE_SIDEBAR &&
!this.isSidebarPotentiallyOpen();
if (typeof this._wasInCompactMode !== "undefined") {
canAnimate = false;
delete this._wasInCompactMode;
@@ -444,8 +482,14 @@ window.gZenCompactModeManager = {
.animate(
this.sidebar,
{
marginRight: [0, this.sidebarIsOnRight ? `-${sidebarWidth}px` : 0],
marginLeft: [0, this.sidebarIsOnRight ? 0 : `-${sidebarWidth}px`],
marginRight: [
0,
this.sidebarIsOnRight ? `-${sidebarWidth}px` : 0,
],
marginLeft: [
0,
this.sidebarIsOnRight ? 0 : `-${sidebarWidth}px`,
],
},
{
ease: "easeIn",
@@ -512,7 +556,9 @@ window.gZenCompactModeManager = {
)
.then(() => {
this.sidebar.removeAttribute("animate");
document.getElementById("browser").style.removeProperty("overflow");
document
.getElementById("browser")
.style.removeProperty("overflow");
this.sidebar.style.transition = "none";
this.sidebar.style.removeProperty("margin-right");
this.sidebar.style.removeProperty("margin-left");
@@ -534,7 +580,9 @@ 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;
}
@@ -570,7 +618,9 @@ window.gZenCompactModeManager = {
},
_updateSidebarIsOnRight() {
this._sidebarIsOnRight = Services.prefs.getBoolPref("zen.tabs.vertical.right-side");
this._sidebarIsOnRight = Services.prefs.getBoolPref(
"zen.tabs.vertical.right-side"
);
},
toggleSidebar() {
@@ -581,7 +631,9 @@ window.gZenCompactModeManager = {
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() {
@@ -589,7 +641,9 @@ window.gZenCompactModeManager = {
{
element: this.sidebar,
screenEdge: this.sidebarIsOnRight ? "right" : "left",
keepHoverDuration: 100,
keepHoverDuration: Services.prefs.getIntPref(
"zen.view.compact.sidebar-keep-hover.duration"
),
},
{
element: document.getElementById("zen-appcontent-navbar-wrapper"),
@@ -612,7 +666,9 @@ window.gZenCompactModeManager = {
if (this._flashTimeouts[id]) {
clearTimeout(this._flashTimeouts[id]);
} else {
requestAnimationFrame(() => this._setElementExpandAttribute(element, true, attrName));
requestAnimationFrame(() =>
this._setElementExpandAttribute(element, true, attrName)
);
}
this._flashTimeouts[id] = setTimeout(() => {
window.requestAnimationFrame(() => {
@@ -628,11 +684,18 @@ window.gZenCompactModeManager = {
},
_setElementExpandAttribute(element, value, attr = "zen-has-hover") {
const kVerifiedAttributes = ["zen-has-hover", "has-popup-menu", "zen-compact-mode-active"];
const kVerifiedAttributes = [
"zen-has-hover",
"has-popup-menu",
"zen-compact-mode-active",
];
const isToolbar = element.id === "zen-appcontent-navbar-wrapper";
this.log("Setting", attr, "to", value, "on element", element?.id);
if (value) {
if (attr === "zen-has-hover" && element !== gZenVerticalTabsManager.actualWindowButtons) {
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;
@@ -658,7 +721,9 @@ window.gZenCompactModeManager = {
// Only remove if none of the verified attributes are present
if (
isToolbar &&
!kVerifiedAttributes.some((verifiedAttr) => element.hasAttribute(verifiedAttr))
!kVerifiedAttributes.some(verifiedAttr =>
element.hasAttribute(verifiedAttr)
)
) {
gBrowser.tabpanels.removeAttribute("has-toolbar-hovered");
}
@@ -666,11 +731,14 @@ window.gZenCompactModeManager = {
},
addMouseActions() {
gURLBar.addEventListener("mouseenter", (event) => {
gURLBar.addEventListener("mouseenter", event => {
this.log("Mouse entered URL bar:", event.target);
if (event.target.closest("#urlbar[zen-floating-urlbar]")) {
window.requestAnimationFrame(() => {
this._setElementExpandAttribute(gZenVerticalTabsManager.actualWindowButtons, false);
this._setElementExpandAttribute(
gZenVerticalTabsManager.actualWindowButtons,
false
);
});
this._hasHoveredUrlbar = true;
}
@@ -684,7 +752,7 @@ window.gZenCompactModeManager = {
this._setElementExpandAttribute(target, true);
}
const onEnter = (event) => {
const onEnter = event => {
setTimeout(() => {
if (event.type === "mouseenter" && !event.target.matches(":hover")) {
return;
@@ -696,7 +764,9 @@ window.gZenCompactModeManager = {
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")
@@ -708,9 +778,10 @@ window.gZenCompactModeManager = {
}, this.HOVER_HACK_DELAY);
};
const onLeave = (event) => {
const onLeave = event => {
if (AppConstants.platform == "macosx") {
const buttonRect = gZenVerticalTabsManager.actualWindowButtons.getBoundingClientRect();
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;
if (
@@ -733,8 +804,12 @@ window.gZenCompactModeManager = {
}
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 ||
@@ -757,8 +832,8 @@ window.gZenCompactModeManager = {
"zen-has-hover"
);
} else {
this._removeHoverFrames[target.id] = window.requestAnimationFrame(() =>
this._setElementExpandAttribute(target, false)
this._removeHoverFrames[target.id] = window.requestAnimationFrame(
() => this._setElementExpandAttribute(target, false)
);
}
}, this.HOVER_HACK_DELAY);
@@ -771,9 +846,12 @@ window.gZenCompactModeManager = {
target.addEventListener("dragleave", onLeave);
}
document.documentElement.addEventListener("mouseleave", (event) => {
document.documentElement.addEventListener("mouseleave", event => {
setTimeout(() => {
const screenEdgeCrossed = this._getCrossedEdge(event.pageX, event.pageY);
const screenEdgeCrossed = this._getCrossedEdge(
event.pageX,
event.pageY
);
if (!screenEdgeCrossed) {
return;
}
@@ -782,8 +860,19 @@ window.gZenCompactModeManager = {
continue;
}
const target = entry.element;
const boundAxis = entry.screenEdge === "right" || entry.screenEdge === "left" ? "y" : "x";
if (!this._positionInBounds(boundAxis, target, event.pageX, event.pageY, 7)) {
const boundAxis =
entry.screenEdge === "right" || entry.screenEdge === "left"
? "y"
: "x";
if (
!this._positionInBounds(
boundAxis,
target,
event.pageX,
event.pageY,
7
)
) {
continue;
}
window.cancelAnimationFrame(this._removeHoverFrames[target.id]);
@@ -820,7 +909,12 @@ window.gZenCompactModeManager = {
});
},
_getCrossedEdge(posX, posY, element = document.documentElement, maxDistance = 10) {
_getCrossedEdge(
posX,
posY,
element = document.documentElement,
maxDistance = 10
) {
const targetBox = element.getBoundingClientRect();
posX = Math.max(targetBox.left, Math.min(posX, targetBox.right));
posY = Math.max(targetBox.top, Math.min(posY, targetBox.bottom));
@@ -842,7 +936,11 @@ window.gZenCompactModeManager = {
// 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);
}

View File

@@ -50,7 +50,7 @@
#navigator-toolbox {
--zen-toolbox-max-width: 74px !important;
--zen-compact-float: var(--zen-element-separation);
:root[zen-no-padding='true'] & {
--zen-compact-float: 10px;
--zen-compact-top-toolbar-hidden-fix: var(--zen-compact-float);
@@ -78,7 +78,7 @@
}
:root:not([zen-single-toolbar='true']) & {
bottom: calc(var(--zen-compact-float) / 2);
height: calc(100% - var(--zen-toolbar-height-with-bookmarks));
height: calc(100% - var(--zen-toolbar-height-with-bookmarks));
@media -moz-pref('zen.view.compact.hide-toolbar') {
height: calc(100% - var(--zen-compact-top-toolbar-hidden-fix, 0px));
}
@@ -145,9 +145,9 @@
}
#navigator-toolbox:is(
[zen-has-hover], [zen-user-show],
[zen-has-hover], [zen-user-show],
[zen-has-empty-tab], [flash-popup],
[has-popup-menu], [movingtab],
[has-popup-menu], [movingtab],
[zen-compact-mode-active]
),
&[zen-renaming-tab='true'] #navigator-toolbox {

View File

@@ -30,7 +30,7 @@
display: flex;
}
transition: height var(--zen-hidden-toolbar-transition);
height: var(--zen-element-separation);
overflow: clip;

View File

@@ -86,7 +86,9 @@ class nsZenDownloadAnimationElement extends HTMLElement {
);
this.shadowRoot.appendChild(link);
} catch (error) {
console.error(`[${nsZenDownloadAnimationElement.name}] Error loading arc styles: ${error}`);
console.error(
`[${nsZenDownloadAnimationElement.name}] Error loading arc styles: ${error}`
);
}
}
@@ -99,7 +101,8 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
// Determine animation target position
const { endPosition, isDownloadButtonVisible } = this.#determineEndPosition();
const { endPosition, isDownloadButtonVisible } =
this.#determineEndPosition();
const areTabsPositionedRight = this.#areTabsOnRightSide();
// Create and prepare the arc animation element
@@ -131,7 +134,10 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
#areTabsOnRightSide() {
const position = Services.prefs.getIntPref("zen.downloads.icon-popup-position", 0);
const position = Services.prefs.getIntPref(
"zen.downloads.icon-popup-position",
0
);
if (position === 1) {
return false;
}
@@ -143,7 +149,8 @@ class nsZenDownloadAnimationElement extends HTMLElement {
#determineEndPosition() {
const downloadsButton = document.getElementById("downloads-button");
const isDownloadButtonVisible = downloadsButton && this.#isElementVisible(downloadsButton);
const isDownloadButtonVisible =
downloadsButton && this.#isElementVisible(downloadsButton);
let endPosition = { clientX: 0, clientY: 0 };
@@ -161,7 +168,9 @@ class nsZenDownloadAnimationElement extends HTMLElement {
const wrapperRect = wrapper.getBoundingClientRect();
endPosition = {
clientX: areTabsPositionedRight ? wrapperRect.right - 42 : wrapperRect.left + 42,
clientX: areTabsPositionedRight
? wrapperRect.right - 42
: wrapperRect.left + 42,
clientY: wrapperRect.bottom - 40,
};
}
@@ -179,7 +188,9 @@ 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`,
@@ -194,7 +205,10 @@ class nsZenDownloadAnimationElement extends HTMLElement {
#calculateOptimalArc(startPosition, endPosition, distance) {
// Calculate available space for the arc
const availableTopSpace = Math.min(startPosition.clientY, endPosition.clientY);
const availableTopSpace = Math.min(
startPosition.clientY,
endPosition.clientY
);
const viewportHeight = window.innerHeight;
const availableBottomSpace =
viewportHeight - Math.max(startPosition.clientY, endPosition.clientY);
@@ -203,7 +217,9 @@ class nsZenDownloadAnimationElement extends HTMLElement {
const shouldArcDownward = availableBottomSpace > availableTopSpace;
// Use the space in the direction we're arcing
const availableSpace = shouldArcDownward ? availableBottomSpace : availableTopSpace;
const availableSpace = shouldArcDownward
? availableBottomSpace
: availableTopSpace;
// Limit arc height to a percentage of the available space
const arcHeight = Math.min(
@@ -233,19 +249,30 @@ class nsZenDownloadAnimationElement extends HTMLElement {
}
await gZenUIManager.motion.animate(arcAnimationElement, sequence, {
duration: Services.prefs.getIntPref("zen.downloads.download-animation-duration") / 1000,
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);
}
}
#createArcAnimationSequence(distanceX, distanceY, arcHeight, shouldArcDownward) {
#createArcAnimationSequence(
distanceX,
distanceY,
arcHeight,
shouldArcDownward
) {
const sequence = { offset: [], opacity: [], transform: [] };
const arcDirection = shouldArcDownward ? 1 : -1;
@@ -284,7 +311,9 @@ class nsZenDownloadAnimationElement extends HTMLElement {
// Position on arc
const x = distanceX * eased;
const y = distanceY * eased + arcDirection * arcHeight * (1 - (2 * eased - 1) ** 2);
const y =
distanceY * eased +
arcDirection * arcHeight * (1 - (2 * eased - 1) ** 2);
// Calculate rotation to point in the direction of movement
let rotation = previousRotation;
@@ -293,10 +322,12 @@ class nsZenDownloadAnimationElement extends HTMLElement {
const prevX = distanceX * prevEased;
const prevAdjustedProgress = prevEased * 2 - 1;
const prevVerticalOffset = arcDirection * arcHeight * (1 - prevAdjustedProgress * 2);
const prevVerticalOffset =
arcDirection * arcHeight * (1 - prevAdjustedProgress * 2);
const prevY = distanceY * prevEased + prevVerticalOffset;
const targetRotation = Math.atan2(y - prevY, x - prevX) * (180 / Math.PI);
const targetRotation =
Math.atan2(y - prevY, x - prevX) * (180 / Math.PI);
rotation += (targetRotation - previousRotation) * 0.01;
previousRotation = rotation;
@@ -353,8 +384,11 @@ class nsZenDownloadAnimationElement extends HTMLElement {
const sideProp = areTabsPositionedRight ? "right" : "left";
const fragment = window.MozXULElement.parseXULToFragment(boxAnimationHTML);
this.#boxAnimationElement = fragment.querySelector(".zen-download-box-animation");
const fragment =
window.MozXULElement.parseXULToFragment(boxAnimationHTML);
this.#boxAnimationElement = fragment.querySelector(
".zen-download-box-animation"
);
Object.assign(this.#boxAnimationElement.style, {
bottom: "24px",
@@ -405,7 +439,10 @@ 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) {

View File

@@ -8,9 +8,10 @@
// Wrap in a block to prevent leaking to window scope.
{
const isTab = (element) => gBrowser.isTab(element);
const isTabGroupLabel = (element) => gBrowser.isTabGroupLabel(element);
const isEssentialsPromo = (element) => element?.tagName.toUpperCase() == "ZEN-ESSENTIALS-PROMO";
const isTab = element => gBrowser.isTab(element);
const isTabGroupLabel = element => gBrowser.isTabGroupLabel(element);
const isEssentialsPromo = element =>
element?.tagName.toUpperCase() == "ZEN-ESSENTIALS-PROMO";
/**
* The elements in the tab strip from `this.ariaFocusableItems` that contain
@@ -34,7 +35,7 @@
* @param {MozTabbrowserTab|typeof MozTabbrowserTabGroup.labelElement} element
* @returns {MozTabbrowserTab|vbox}
*/
const elementToMove = (element) => {
const elementToMove = element => {
if (
!element ||
element.closest(".zen-current-workspace-indicator") ||
@@ -118,9 +119,13 @@
init() {
super.init();
this.handle_windowDragEnter = this.handle_windowDragEnter.bind(this);
window.addEventListener("dragleave", this.handle_windowDragLeave.bind(this), {
capture: true,
});
window.addEventListener(
"dragleave",
this.handle_windowDragLeave.bind(this),
{
capture: true,
}
);
}
startTabDrag(event, tab, ...args) {
@@ -133,7 +138,11 @@
tab = tab.group;
}
const draggingTabs = tab.multiselected ? gBrowser.selectedTabs : [tab];
const { offsetX, offsetY } = this.#getDragImageOffset(event, tab, draggingTabs);
const { offsetX, offsetY } = this.#getDragImageOffset(
event,
tab,
draggingTabs
);
const dragImage = this.#createDragImageForTabs(draggingTabs);
this.originalDragImageArgs = [dragImage, offsetX, offsetY];
dt.setDragImage(...this.originalDragImageArgs);
@@ -146,7 +155,9 @@
const periphery = gZenWorkspaces.activeWorkspaceElement.querySelector(
"#tabbrowser-arrowscrollbox-periphery"
);
const tabRect = window.windowUtils.getBoundsWithoutFlushing(movingTabs[0]);
const tabRect = window.windowUtils.getBoundsWithoutFlushing(
movingTabs[0]
);
const wrapper = document.createElement("div");
let movingTabsCount = Math.min(movingTabs.length, 3);
wrapper.style.width = tabRect.width + "px";
@@ -160,7 +171,8 @@
if (tab.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`;
tabClone.style.minHeight =
tabClone.style.maxHeight = `${rect.height}px`;
if (tabClone.hasAttribute("visuallyselected")) {
tabClone.style.transform = "translate(-50%, -50%)";
}
@@ -181,9 +193,16 @@
if (isTab(tabClone)) {
// 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;
label.textContent = label.textContent.slice(0, Math.floor(tabLabelParentWidth / 6));
} else if (gBrowser.isTabGroup(tabClone) && tabClone.hasAttribute("split-view-group")) {
const tabLabelParentWidth =
label.parentElement.getBoundingClientRect().width;
label.textContent = label.textContent.slice(
0,
Math.floor(tabLabelParentWidth / 6)
);
} else if (
gBrowser.isTabGroup(tabClone) &&
tabClone.hasAttribute("split-view-group")
) {
let tabs = tab.tabs;
for (let j = 0; j < tabs.length; j++) {
const tabInGroup = tabs[j];
@@ -220,7 +239,10 @@
// eslint-disable-next-line complexity
_animateTabMove(event) {
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
if (event.target.closest("#zen-essentials") && !isEssentialsPromo(event.target)) {
if (
event.target.closest("#zen-essentials") &&
!isEssentialsPromo(event.target)
) {
if (!isTab(draggedTab)) {
this.clearDragOverVisuals();
return;
@@ -242,7 +264,9 @@
tabs = [...movingTabs];
}
let screen = this._tabbrowserTabs.verticalMode ? event.screenY : event.screenX;
let screen = this._tabbrowserTabs.verticalMode
? event.screenY
: event.screenX;
if (screen == dragData.animLastScreenPos) {
return;
}
@@ -255,9 +279,11 @@
tabs.reverse();
}
let bounds = (ele) => window.windowUtils.getBoundsWithoutFlushing(ele);
let bounds = ele => window.windowUtils.getBoundsWithoutFlushing(ele);
let logicalForward = screenForward != this._rtlMode;
let screenAxis = this._tabbrowserTabs.verticalMode ? "screenY" : "screenX";
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;
@@ -275,7 +301,7 @@
);
let lastMovingTab = movingTabs.at(-1);
let firstMovingTab = movingTabs[0];
let endEdge = (ele) => ele[screenAxis] + bounds(ele)[size];
let endEdge = ele => ele[screenAxis] + bounds(ele)[size];
let lastMovingTabScreen = endEdge(lastMovingTab);
let firstMovingTabScreen = firstMovingTab[screenAxis];
let shiftSize = lastMovingTabScreen - firstMovingTabScreen;
@@ -298,7 +324,8 @@
// Center the tab under the cursor if the tab is not under the cursor while dragging
let draggedTabScreenAxis = draggedTab[screenAxis] + translate;
if (
(screen < draggedTabScreenAxis || screen > draggedTabScreenAxis + tabSize) &&
(screen < draggedTabScreenAxis ||
screen > draggedTabScreenAxis + tabSize) &&
draggedTabScreenAxis + tabSize < endBound &&
draggedTabScreenAxis > startBound
) {
@@ -309,7 +336,7 @@
dragData.translatePos = translate;
tabs = tabs.filter((t) => !movingTabsSet.has(t) || t == draggedTab);
tabs = tabs.filter(t => !movingTabsSet.has(t) || t == draggedTab);
/**
* When the `draggedTab` is just starting to move, the `draggedTab` is in
@@ -333,16 +360,23 @@
* @returns {number}
*/
let getTabShift = (item, dropElementIndex) => {
if (item.elementIndex < draggedTab.elementIndex && item.elementIndex >= dropElementIndex) {
if (
item.elementIndex < draggedTab.elementIndex &&
item.elementIndex >= dropElementIndex
) {
return this._rtlMode ? -shiftSize : shiftSize;
}
if (item.elementIndex > draggedTab.elementIndex && item.elementIndex < dropElementIndex) {
if (
item.elementIndex > draggedTab.elementIndex &&
item.elementIndex < dropElementIndex
) {
return this._rtlMode ? shiftSize : -shiftSize;
}
return 0;
};
let oldDropElementIndex = dragData.animDropElementIndex ?? movingTabs[0].elementIndex;
let oldDropElementIndex =
dragData.animDropElementIndex ?? movingTabs[0].elementIndex;
/**
* Returns the higher % by which one element overlaps another
@@ -423,7 +457,9 @@
* time.
*/
let getOverlappedElement = () => {
let point = (screenForward ? lastMovingTabScreen : firstMovingTabScreen) + translate;
let point =
(screenForward ? lastMovingTabScreen : firstMovingTabScreen) +
translate;
let low = 0;
let high = tabs.length - 1;
while (low <= high) {
@@ -433,7 +469,9 @@
}
let element = tabs[mid];
let elementForSize = elementToMove(element);
screen = elementForSize[screenAxis] + getTabShift(element, oldDropElementIndex);
screen =
elementForSize[screenAxis] +
getTabShift(element, oldDropElementIndex);
if (screen > point) {
high = mid - 1;
@@ -489,11 +527,18 @@
// 4) we just started dragging and the `oldDropElementIndex` has its default
// valuë of `movingTabs[0].elementIndex`. In this case, the drop element
// shouldn't be a moving tab, so keep it `undefined`.
let lastPossibleDropElement = this._rtlMode ? tabs.find((t) => t != draggedTab) : undefined;
let maxElementIndexForDropElement = lastPossibleDropElement?.elementIndex;
let lastPossibleDropElement = this._rtlMode
? tabs.find(t => t != draggedTab)
: undefined;
let maxElementIndexForDropElement =
lastPossibleDropElement?.elementIndex;
if (Number.isInteger(maxElementIndexForDropElement)) {
let index = Math.min(oldDropElementIndex, maxElementIndexForDropElement);
let oldDropElementCandidate = this._tabbrowserTabs.ariaFocusableItems.at(index);
let index = Math.min(
oldDropElementIndex,
maxElementIndexForDropElement
);
let oldDropElementCandidate =
this._tabbrowserTabs.ariaFocusableItems.at(index);
if (!movingTabsSet.has(oldDropElementCandidate)) {
dropElement = oldDropElementCandidate;
}
@@ -507,7 +552,8 @@
let dropElementForOverlap = elementToMove(dropElement);
let dropElementScreen = dropElementForOverlap[screenAxis];
let dropElementPos = dropElementScreen + getTabShift(dropElement, oldDropElementIndex);
let dropElementPos =
dropElementScreen + getTabShift(dropElement, oldDropElementIndex);
let dropElementSize = bounds(dropElementForOverlap)[size];
let firstMovingTabPos = firstMovingTabScreen + translate;
overlapPercent = greatestOverlap(
@@ -518,7 +564,9 @@
);
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;
@@ -536,7 +584,8 @@
// Recalculate the overlap with the updated drop index for when the
// drop element moves over.
dropElementPos = dropElementScreen + getTabShift(dropElement, newDropElementIndex);
dropElementPos =
dropElementScreen + getTabShift(dropElement, newDropElementIndex);
overlapPercent = greatestOverlap(
firstMovingTabPos,
shiftSize,
@@ -611,17 +660,25 @@
}
#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");
let rect = window.windowUtils.getBoundsWithoutFlushing(gNavToolbox);
if (!(gZenCompactModeManager.preference && gZenCompactModeManager.canHideSidebar)) {
rect.width += window.windowUtils.getBoundsWithoutFlushing(splitter).width;
if (!(
gZenCompactModeManager.preference &&
gZenCompactModeManager.canHideSidebar
)) {
rect.width +=
window.windowUtils.getBoundsWithoutFlushing(splitter).width;
}
const { clientX } = event;
const isNearLeftEdge = clientX >= rect.left - padding && clientX <= rect.left + padding;
const isNearRightEdge = clientX >= rect.right - padding && clientX <= rect.right + padding;
const isNearLeftEdge =
clientX >= rect.left - padding && clientX <= rect.left + padding;
const isNearRightEdge =
clientX >= rect.right - padding && clientX <= rect.right + padding;
return { isNearLeftEdge, isNearRightEdge };
}
@@ -639,14 +696,19 @@
this.clearSpaceSwitchTimer();
return;
}
const { isNearLeftEdge, isNearRightEdge } = this.#shouldSwitchSpace(event);
const { isNearLeftEdge, isNearRightEdge } =
this.#shouldSwitchSpace(event);
if (isNearLeftEdge || isNearRightEdge) {
if (!this.#changeSpaceTimer) {
this.#changeSpaceTimer = setTimeout(() => {
this.clearDragOverVisuals();
gZenWorkspaces
.changeWorkspaceShortcut(isNearLeftEdge ? -1 : 1, false, /* Disable wrapping */ true)
.then((spaceChanged) => {
.changeWorkspaceShortcut(
isNearLeftEdge ? -1 : 1,
false,
/* Disable wrapping */ true
)
.then(spaceChanged => {
if (AppConstants.platform !== "macosx") {
// See the hack in #createDragImageForTabs for more details which
// explains why we need to do this on non-macOS platforms.
@@ -654,7 +716,9 @@
}
let tabs = this.originalDragImageArgs[0].children;
const { isDarkMode, isExplicitMode } =
gZenThemePicker.getGradientForWorkspace(spaceChanged);
gZenThemePicker.getGradientForWorkspace(spaceChanged, {
getGradient: false,
});
for (let tab of tabs) {
if (isExplicitMode) {
tab.style.colorScheme = isDarkMode ? "dark" : "light";
@@ -725,7 +789,10 @@
const edgeZoneThreshold = this._dndSplitThreshold / 100;
const overlapRatioY = (clientY - targetTop) / targetHeight;
if (overlapRatioY < edgeZoneThreshold || overlapRatioY > 1 - edgeZoneThreshold) {
if (
overlapRatioY < edgeZoneThreshold ||
overlapRatioY > 1 - edgeZoneThreshold
) {
this._clearDragOverSplit();
return;
}
@@ -815,7 +882,10 @@
return;
}
const { innerWidth: winWidth, innerHeight: winHeight } = window;
let allowedMargin = Services.prefs.getIntPref("zen.tabs.dnd-outside-window-margin", 5);
let allowedMargin = Services.prefs.getIntPref(
"zen.tabs.dnd-outside-window-margin",
5
);
const isOutOfWindow =
clientX <= allowedMargin ||
clientX >= winWidth - allowedMargin ||
@@ -881,7 +951,9 @@
gBrowser.selectedTab = draggedTab;
} else if (isTabGroupLabel(draggedTab)) {
draggedTab = draggedTab.group;
gZenFolders.changeFolderToSpace(draggedTab, activeWorkspace, { hasDndSwitch: true });
gZenFolders.changeFolderToSpace(draggedTab, activeWorkspace, {
hasDndSwitch: true,
});
}
}
}
@@ -922,7 +994,8 @@
}
if (
isTabGroupLabel(draggedTab) ||
(isTab(draggedTab) && draggedTab.group?.hasAttribute("split-view-group"))
(isTab(draggedTab) &&
draggedTab.group?.hasAttribute("split-view-group"))
) {
draggedTab = draggedTab.group;
}
@@ -939,7 +1012,8 @@
!dropElement ||
dropElement.hasAttribute("zen-essential") ||
draggedTab.hasAttribute("zen-essential") ||
draggedTab.getAttribute("zen-workspace-id") != gZenWorkspaces.activeWorkspace ||
draggedTab.getAttribute("zen-workspace-id") !=
gZenWorkspaces.activeWorkspace ||
!dropElement.visible ||
!draggedTab.visible ||
draggedTab.ownerGlobal !== window
@@ -949,7 +1023,7 @@
this.#isAnimatingTabMove = true;
const animateElement = (ele, translateY) => {
ele.style.transform = `translateY(${translateY}px)`;
let animateInternal = (resolve) => {
let animateInternal = resolve => {
const clearStyles = () => {
ele.style.transform = "";
ele.style.zIndex = "";
@@ -960,7 +1034,11 @@
return;
}
gZenUIManager
.elementAnimate(ele, { y: [translateY, 0] }, { duration: 100, easing: "ease-out" })
.elementAnimate(
ele,
{ y: [translateY, 0] },
{ duration: 100, easing: "ease-out" }
)
.then(() => {
clearStyles();
})
@@ -969,7 +1047,7 @@
// Wait for the next event loop tick to ensure the initial transform style is applied.
// We need to ensure the element has already been moved in the DOM before starting the animation.
animations.push(
new Promise((resolve) =>
new Promise(resolve =>
setTimeout(() => {
setTimeout(() => animateInternal(resolve), 0);
})
@@ -1025,7 +1103,9 @@
: -rect.height * tabsInBetween.length;
draggedTabTranslateY +=
extraTranslate *
(focusableDraggedTab.elementIndex > focusableDropElement.elementIndex ? 1 : -1);
(focusableDraggedTab.elementIndex > focusableDropElement.elementIndex
? 1
: -1);
draggedTab.style.zIndex = "9";
animateElement(draggedTab, draggedTabTranslateY);
} catch (e) {
@@ -1043,7 +1123,8 @@
let ownerGlobal = draggedTab?.ownerGlobal;
draggedTab.style.visibility = "";
let thisFromGlobal = ownerGlobal?.gBrowser.tabContainer.tabDragAndDrop;
let currentEssenialContainer = ownerGlobal.gZenWorkspaces.getCurrentEssentialsContainer();
let currentEssenialContainer =
ownerGlobal.gZenWorkspaces.getCurrentEssentialsContainer();
if (currentEssenialContainer?.essentialsPromo) {
currentEssenialContainer.essentialsPromo.remove();
}
@@ -1057,9 +1138,13 @@
thisFromGlobal._clearDragOverSplit();
this.#maybeClearVerticalPinnedGridDragOver();
thisFromGlobal.originalDragImageArgs = [];
window.removeEventListener("dragenter", thisFromGlobal.handle_windowDragEnter, {
capture: true,
});
window.removeEventListener(
"dragenter",
thisFromGlobal.handle_windowDragEnter,
{
capture: true,
}
);
this.#isOutOfWindow = false;
if (thisFromGlobal._browserDragImageWrapper) {
thisFromGlobal._browserDragImageWrapper.remove();
@@ -1119,8 +1204,13 @@
return true;
}
if (folder.isLiveFolder) {
const liveFolderItemId = draggedTab.getAttribute("zen-live-folder-item-id");
if (!liveFolderItemId || !liveFolderItemId.startsWith(`${folder.id}:`)) {
const liveFolderItemId = draggedTab.getAttribute(
"zen-live-folder-item-id"
);
if (
!liveFolderItemId ||
!liveFolderItemId.startsWith(`${folder.id}:`)
) {
return false;
}
}
@@ -1139,17 +1229,25 @@
let showIndicatorUnderNewTabButton = false;
let dropBefore = false;
let dropElementFromEvent = event.target.closest(dropZoneSelector);
if (!dropElement && dropElementFromEvent?.isZenFolder) {
// If we're dragging over a folder, we want to show the indicator on the folder itself, not the label.
dropElementFromEvent = dropElementFromEvent.labelElement;
}
dropElement = dropElementFromEvent || dropElement;
if (!dropElementFromEvent) {
let hoveringPeriphery = !!event.target.closest(
":is(#tabbrowser-arrowscrollbox-periphery, .pinned-tabs-container-separator)"
);
if (event.target.classList.contains("zen-workspace-empty-space") || hoveringPeriphery) {
if (
event.target.classList.contains("zen-workspace-empty-space") ||
hoveringPeriphery
) {
let lastTab = gBrowser.tabs.at(-1);
let pinnedTabsCount = gBrowser._numVisiblePinTabsWithoutCollapsed;
// Only if there are no normal tabs to drop after
showIndicatorUnderNewTabButton = lastTab.hasAttribute("zen-empty-tab");
showIndicatorUnderNewTabButton =
lastTab.hasAttribute("zen-empty-tab");
let useLastPinnd =
(hoveringPeriphery ||
(showIndicatorUnderNewTabButton &&
@@ -1187,12 +1285,18 @@
let possibleFolderElement = dropElement.parentElement;
let isZenFolder = possibleFolderElement?.isZenFolder;
let canHightlightGroup =
gZenFolders.highlightGroupOnDragOver(possibleFolderElement, movingTabs) || !isZenFolder;
gZenFolders.highlightGroupOnDragOver(
possibleFolderElement,
movingTabs
) || !isZenFolder;
let rect = window.windowUtils.getBoundsWithoutFlushing(dropElement);
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 ||
@@ -1211,7 +1315,8 @@
if (
isTabGroupLabel(draggedTab) &&
draggedTab.group?.isZenFolder &&
(((isTab(dropElement) || dropElement.hasAttribute("split-view-group")) &&
(((isTab(dropElement) ||
dropElement.hasAttribute("split-view-group")) &&
(!dropElement.pinned || dropElement.hasAttribute("zen-essential"))) ||
showIndicatorUnderNewTabButton)
) {
@@ -1226,12 +1331,16 @@
dropElement.hasAttribute("split-view-group")
) {
if (showIndicatorUnderNewTabButton) {
rect = window.windowUtils.getBoundsWithoutFlushing(this.#dragShiftableItems.at(-1));
rect = window.windowUtils.getBoundsWithoutFlushing(
this.#dragShiftableItems.at(-1)
);
}
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 || showIndicatorUnderNewTabButton) {
top = Math.round(rect.top + rect.height) + "px";
dropBefore = false;
@@ -1243,23 +1352,36 @@
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.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");
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;
this.#applyDragOverBackground(dropElement) &&
!gZenPinnedTabManager._dragIndicator;
gZenPinnedTabManager.removeTabContainersDragoverClass();
dropElement = dropElement.parentElement?.labelElement || dropElement;
if (dropElement.classList.contains("zen-current-workspace-indicator")) {
dropElement =
elementToMove(this._tabbrowserTabs.ariaFocusableItems.at(gBrowser._numZenEssentials)) ||
dropElement;
elementToMove(
this._tabbrowserTabs.ariaFocusableItems.at(
gBrowser._numZenEssentials
)
) || dropElement;
dropBefore = true;
}
}
@@ -1305,12 +1427,17 @@
if (!this._fakeEssentialTab) {
const numEssentials = gBrowser._numZenEssentials;
let pinnedTabs = this._tabbrowserTabs.ariaFocusableItems.slice(0, numEssentials);
let pinnedTabs = this._tabbrowserTabs.ariaFocusableItems.slice(
0,
numEssentials
);
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);
event.target
.closest(".zen-essentials-container")
.appendChild(this._fakeEssentialTab);
gZenWorkspaces.updateTabsContainers();
pinnedTabs.push(this._fakeEssentialTab);
this._fakeEssentialTab.getBoundingClientRect(); // Initialize layout
@@ -1318,8 +1445,9 @@
this.#makeDragImageEssential(event);
let tabsPerRow = 0;
let position = RTL_UI
? window.windowUtils.getBoundsWithoutFlushing(this._tabbrowserTabs.pinnedTabsContainer)
.right
? window.windowUtils.getBoundsWithoutFlushing(
this._tabbrowserTabs.pinnedTabsContainer
).right
: 0;
for (let pinnedTab of pinnedTabs) {
let tabPosition;
@@ -1341,13 +1469,19 @@
this.#maxTabsPerRow = tabsPerRow;
}
let usingFakeElement = !!this._fakeEssentialTab.parentElement;
let elementMoving = usingFakeElement ? this._fakeEssentialTab : draggedTab;
let elementMoving = usingFakeElement
? this._fakeEssentialTab
: draggedTab;
if (usingFakeElement) {
movingTabs = [this._fakeEssentialTab];
}
let dragDataScreenX = usingFakeElement ? this._fakeEssentialTab.screenX : dragData.screenX;
let dragDataScreenY = usingFakeElement ? this._fakeEssentialTab.screenY : dragData.screenY;
let dragDataScreenX = usingFakeElement
? this._fakeEssentialTab.screenX
: dragData.screenX;
let dragDataScreenY = usingFakeElement
? this._fakeEssentialTab.screenY
: dragData.screenY;
dragData.animLastScreenX ??= dragDataScreenX;
dragData.animLastScreenY ??= dragDataScreenY;
@@ -1355,11 +1489,17 @@
let screenX = event.screenX;
let screenY = event.screenY;
if (screenY == dragData.animLastScreenY && screenX == dragData.animLastScreenX) {
if (
screenY == dragData.animLastScreenY &&
screenX == dragData.animLastScreenX
) {
return;
}
let tabs = this._tabbrowserTabs.visibleTabs.slice(0, gBrowser._numZenEssentials);
let tabs = this._tabbrowserTabs.visibleTabs.slice(
0,
gBrowser._numZenEssentials
);
if (usingFakeElement) {
tabs.push(this._fakeEssentialTab);
}
@@ -1369,7 +1509,8 @@
dragData.animLastScreenY = screenY;
dragData.animLastScreenX = screenX;
let { width: tabWidth, height: tabHeight } = elementMoving.getBoundingClientRect();
let { width: tabWidth, height: tabHeight } =
elementMoving.getBoundingClientRect();
tabWidth += 4; // Add 6px to account for the gap
tabHeight += 4;
let shiftSizeX = tabWidth;
@@ -1383,11 +1524,16 @@
let lastTab = tabs.at(-1);
if (RTL_UI) {
firstTabInRow =
tabs.length >= this.#maxTabsPerRow ? tabs[this.#maxTabsPerRow - 1] : lastTab;
tabs.length >= this.#maxTabsPerRow
? tabs[this.#maxTabsPerRow - 1]
: lastTab;
lastTabInRow = tabs[0];
} else {
firstTabInRow = tabs[0];
lastTabInRow = tabs.length >= this.#maxTabsPerRow ? tabs[this.#maxTabsPerRow - 1] : lastTab;
lastTabInRow =
tabs.length >= this.#maxTabsPerRow
? tabs[this.#maxTabsPerRow - 1]
: lastTab;
}
let lastMovingTabScreenX = movingTabs.at(-1).screenX;
let lastMovingTabScreenY = movingTabs.at(-1).screenY;
@@ -1436,7 +1582,7 @@
// * We're doing a binary search in order to reduce the amount of
// tabs we need to check.
tabs = tabs.filter((t) => !movingTabs.includes(t) || t == elementMoving);
tabs = tabs.filter(t => !movingTabs.includes(t) || t == elementMoving);
let firstTabCenterX = firstMovingTabScreenX + translateX + tabWidth / 2;
let lastTabCenterX = lastMovingTabScreenX + translateX + tabWidth / 2;
let tabCenterX = directionX ? lastTabCenterX : firstTabCenterX;
@@ -1447,25 +1593,37 @@
let shiftNumber = this.#maxTabsPerRow - movingTabs.length;
let getTabShift = (tab, dropIndex) => {
if (tab.elementIndex < elementMoving.elementIndex && tab.elementIndex >= dropIndex) {
if (
tab.elementIndex < elementMoving.elementIndex &&
tab.elementIndex >= dropIndex
) {
// If tab is at the end of a row, shift back and down
let tabRow = Math.ceil((tab.elementIndex + 1) / this.#maxTabsPerRow);
let shiftedTabRow = Math.ceil(
(tab.elementIndex + 1 + movingTabs.length) / this.#maxTabsPerRow
);
if (tab.elementIndex && tabRow != shiftedTabRow) {
return [RTL_UI ? tabWidth * shiftNumber : -tabWidth * shiftNumber, shiftSizeY];
return [
RTL_UI ? tabWidth * shiftNumber : -tabWidth * shiftNumber,
shiftSizeY,
];
}
return [RTL_UI ? -shiftSizeX : shiftSizeX, 0];
}
if (tab.elementIndex > elementMoving.elementIndex && tab.elementIndex < dropIndex) {
if (
tab.elementIndex > elementMoving.elementIndex &&
tab.elementIndex < dropIndex
) {
// If tab is not index 0 and at the start of a row, shift across and up
let tabRow = Math.floor(tab.elementIndex / this.#maxTabsPerRow);
let shiftedTabRow = Math.floor(
(tab.elementIndex - movingTabs.length) / this.#maxTabsPerRow
);
if (tab.elementIndex && tabRow != shiftedTabRow) {
return [RTL_UI ? -tabWidth * shiftNumber : tabWidth * shiftNumber, -shiftSizeY];
return [
RTL_UI ? -tabWidth * shiftNumber : tabWidth * shiftNumber,
-shiftSizeY,
];
}
return [RTL_UI ? shiftSizeX : -shiftSizeX, 0];
}
@@ -1475,7 +1633,8 @@
let low = 0;
let high = tabs.length - 1;
let newIndex = -1;
let oldIndex = dragData.animDropElementIndex ?? movingTabs[0].elementIndex;
let oldIndex =
dragData.animDropElementIndex ?? movingTabs[0].elementIndex;
while (low <= high) {
let mid = Math.floor((low + high) / 2);
if (tabs[mid] == elementMoving && ++mid > high) {
@@ -1489,9 +1648,13 @@
low = mid + 1;
} else if (screenY > tabCenterY) {
high = mid - 1;
} else if (RTL_UI ? screenX + tabWidth < tabCenterX : screenX > tabCenterX) {
} else if (
RTL_UI ? screenX + tabWidth < tabCenterX : screenX > tabCenterX
) {
high = mid - 1;
} else if (RTL_UI ? screenX > tabCenterX : screenX + tabWidth < tabCenterX) {
} else if (
RTL_UI ? screenX > tabCenterX : screenX + tabWidth < tabCenterX
) {
low = mid + 1;
} else {
newIndex = tabs[mid].elementIndex;
@@ -1523,7 +1686,8 @@
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)` : "";
}
}
}
@@ -1532,7 +1696,10 @@
if (this._fakeEssentialTab) {
this._fakeEssentialTab.remove();
delete this._fakeEssentialTab;
for (let tab of this._tabbrowserTabs.visibleTabs.slice(0, gBrowser._numZenEssentials)) {
for (let tab of this._tabbrowserTabs.visibleTabs.slice(
0,
gBrowser._numZenEssentials
)) {
tab.style.transform = "";
}
gZenWorkspaces.updateTabsContainers();
@@ -1551,8 +1718,13 @@
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";
const draggedTabRect = window.windowUtils.getBoundsWithoutFlushing(
this._fakeEssentialTab
);
tab.style.minWidth =
tab.style.maxWidth =
wrapper.style.width =
draggedTabRect.width + "px";
tab.style.minHeight =
tab.style.maxHeight =
wrapper.style.height =

View File

@@ -22,4 +22,3 @@ interface nsIZenDragAndDrop : nsISupports {
*/
void onDragEnd();
};

View File

@@ -10,26 +10,25 @@ namespace {
static constexpr auto kZenDefaultDragImageOpacity =
#if defined(MOZ_WIDGET_GTK)
// For GTK, the default is 0.5 (DRAG_IMAGE_ALPHA_LEVEL) to match
// the native behavior. Make sure its synced with the following variable:
// https://searchfox.org/firefox-main/rev/14c08f0368ead8bfdddec62f43e0bb5c8fd61289/widget/gtk/nsDragService.cpp#75
// For GTK, the default is 0.5 (DRAG_IMAGE_ALPHA_LEVEL) to match
// the native behavior. Make sure its synced with the following variable:
// https://searchfox.org/firefox-main/rev/14c08f0368ead8bfdddec62f43e0bb5c8fd61289/widget/gtk/nsDragService.cpp#75
0.5f;
#else
// For other platforms, the default is whatever the value of DRAG_TRANSLUCENCY
// is, defined in nsBaseDragService.h
// For other platforms, the default is whatever the value of
// DRAG_TRANSLUCENCY is, defined in nsBaseDragService.h
DRAG_TRANSLUCENCY;
#endif
} // namespace: <empty>
} // namespace
// Use the macro to inject all of the definitions for nsISupports.
NS_IMPL_ISUPPORTS(nsZenDragAndDrop, nsIZenDragAndDrop)
nsZenDragAndDrop::nsZenDragAndDrop() {
(void)this->OnDragEnd();
}
nsZenDragAndDrop::nsZenDragAndDrop() { (void)this->OnDragEnd(); }
auto nsZenDragAndDrop::GetZenDragAndDropInstance() -> nsCOMPtr<nsZenDragAndDrop> {
auto nsZenDragAndDrop::GetZenDragAndDropInstance()
-> nsCOMPtr<nsZenDragAndDrop> {
return do_GetService(ZEN_BOOSTS_BACKEND_CONTRACTID);
}
@@ -45,4 +44,4 @@ nsZenDragAndDrop::OnDragEnd() {
return NS_OK;
}
} // namespace: zen
} // namespace zen

View File

@@ -28,10 +28,11 @@ class nsZenDragAndDrop final : public nsIZenDragAndDrop {
auto GetDragImageOpacity() const { return mDragImageOpacity; }
/**
* @brief Get the singleton instance of nsZenDragAndDrop. There may be occasions
* where it won't be available (e.g. on the content process), so this may return
* nullptr.
* @return nsZenDragAndDrop* The singleton instance, or nullptr if not available
* @brief Get the singleton instance of nsZenDragAndDrop. There may be
* occasions where it won't be available (e.g. on the content process), so
* this may return nullptr.
* @return nsZenDragAndDrop* The singleton instance, or nullptr if not
* available
*/
static auto GetZenDragAndDropInstance() -> nsCOMPtr<nsZenDragAndDrop>;
@@ -40,6 +41,6 @@ class nsZenDragAndDrop final : public nsIZenDragAndDrop {
float mDragImageOpacity{};
};
} // namespace zen
} // namespace zen
#endif

View File

@@ -4,7 +4,8 @@
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ZenLiveFoldersManager: "resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
ZenLiveFoldersManager:
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
});
export class nsZenFolder extends MozTabbrowserTabGroup {
@@ -77,7 +78,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
this.labelElement.parentElement.setAttribute("context", "zenFolderActions");
this.labelElement.onRenameFinished = (newLabel) => {
this.labelElement.onRenameFinished = newLabel => {
this.name = newLabel.trim() || "Folder";
const event = new CustomEvent("ZenFolderRenamed", {
bubbles: true,
@@ -127,7 +128,9 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
get childActiveGroups() {
if (this.tagName === "zen-workspace-collapsible-pins") {
return Array.from(this.parentElement.querySelectorAll("zen-folder[has-active]"));
return Array.from(
this.parentElement.querySelectorAll("zen-folder[has-active]")
);
}
return Array.from(this.querySelectorAll("zen-folder[has-active]"));
}
@@ -193,7 +196,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
get allItems() {
return [...this.groupContainer.children].filter(
(child) =>
child =>
!(
child.classList.contains("zen-tab-group-start") ||
child.classList.contains("pinned-tabs-container-separator")
@@ -227,7 +230,9 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
} 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));
}
@@ -247,7 +252,10 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
}
get resetButton() {
return this.labelElement.parentElement?.querySelector(".tab-reset-button") ?? null;
return (
this.labelElement.parentElement?.querySelector(".tab-reset-button") ??
null
);
}
unloadAllTabs(event) {
@@ -280,8 +288,13 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
addTabs(tabs) {
super.addTabs(tabs);
if (this.collapsed && !gZenFolders._sessionRestoring && this.isLiveFolder && tabs.length) {
tabs.forEach((tab) => {
if (
this.collapsed &&
!gZenFolders._sessionRestoring &&
this.isLiveFolder &&
tabs.length
) {
tabs.forEach(tab => {
tab.setAttribute("folder-active", "true");
});
gZenFolders.animateCollapse(this);

View File

@@ -36,7 +36,10 @@ function groupIsCollapsiblePins(group) {
}
class nsZenFolders extends nsZenDOMOperatedFeature {
#ZEN_MAX_SUBFOLDERS = Services.prefs.getIntPref("zen.folders.max-subfolders", 5);
#ZEN_MAX_SUBFOLDERS = Services.prefs.getIntPref(
"zen.folders.max-subfolders",
5
);
#popup = null;
#popupTimer = null;
@@ -69,10 +72,12 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const contextMenuItemsToolbar = window.MozXULElement.parseXULToFragment(
`<menuitem id="zen-context-menu-new-folder-toolbar" data-l10n-id="zen-toolbar-context-new-folder"/>`
);
document.getElementById("toolbar-context-openANewTab").after(contextMenuItemsToolbar);
document
.getElementById("toolbar-context-openANewTab")
.after(contextMenuItemsToolbar);
const folderActionsMenu = document.getElementById("zenFolderActions");
folderActionsMenu.addEventListener("popupshowing", (event) => {
folderActionsMenu.addEventListener("popupshowing", event => {
const target = event.explicitOriginalTarget;
let folder;
if (gBrowser.isTabGroupLabel(target)) {
@@ -93,7 +98,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
this.#lastFolderContextMenu = folder;
gZenLiveFoldersUI.buildContextMenu(folder);
const newSubfolderItem = document.getElementById("context_zenFolderNewSubfolder");
const newSubfolderItem = document.getElementById(
"context_zenFolderNewSubfolder"
);
newSubfolderItem.setAttribute(
"disabled",
folder.level >= this.#ZEN_MAX_SUBFOLDERS - 1 ? "true" : "false"
@@ -105,7 +112,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
changeFolderSpace.innerHTML = "";
for (const workspace of [...gZenWorkspaces.getWorkspaces()].reverse()) {
const item = gZenWorkspaces.generateMenuItemForWorkspace(workspace);
item.addEventListener("command", (event) => {
item.addEventListener("command", event => {
if (!this.#lastFolderContextMenu) {
return;
}
@@ -120,7 +127,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
folderActionsMenu.addEventListener(
"popuphidden",
(event) => {
event => {
if (event.target === folderActionsMenu) {
this.#lastFolderContextMenu = null;
}
@@ -128,7 +135,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
{ once: true }
);
folderActionsMenu.addEventListener("command", (event) => {
folderActionsMenu.addEventListener("command", event => {
if (!this.#lastFolderContextMenu) {
return;
}
@@ -198,12 +205,17 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
window.addEventListener("TabSelect", this);
window.addEventListener("TabOpen", this);
const onNewFolder = this.#onNewFolder.bind(this);
document.getElementById("zen-context-menu-new-folder").addEventListener("command", onNewFolder);
document
.getElementById("zen-context-menu-new-folder")
.addEventListener("command", onNewFolder);
document
.getElementById("zen-context-menu-new-folder-toolbar")
.addEventListener("command", onNewFolder);
SessionStore.promiseInitialized.then(() => {
gBrowser.tabContainer.addEventListener("dragstart", this.cancelPopupTimer.bind(this));
gBrowser.tabContainer.addEventListener(
"dragstart",
this.cancelPopupTimer.bind(this)
);
});
}
@@ -234,7 +246,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
}
if (group.hasAttribute("split-view-group") && group.hasAttribute("zen-pinned-changed")) {
if (
group.hasAttribute("split-view-group") &&
group.hasAttribute("zen-pinned-changed")
) {
// zen-pinned-changed remove it and set it to had-zen-pinned-changed to keep
// track of the original pinned state
group.removeAttribute("zen-pinned-changed");
@@ -258,9 +273,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const isActiveFolder = parentFolder?.activeGroups?.length > 0;
const isSplitView = folder.hasAttribute("split-view-group");
if (isActiveFolder && isSplitView) {
parentFolder.activeTabs = [...new Set([...parentFolder.activeTabs, ...folder.tabs])].sort(
(a, b) => a._tPos > b._tPos
);
parentFolder.activeTabs = [
...new Set([...parentFolder.activeTabs, ...folder.tabs]),
].sort((a, b) => a._tPos > b._tPos);
}
parentFolder.collapsed = isActiveFolder;
}
@@ -314,7 +329,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
async on_TabUngrouped(event) {
const tab = event.detail;
const group = event.target;
if (group.hasAttribute("split-view-group") && tab.hasAttribute("had-zen-pinned-changed")) {
if (
group.hasAttribute("split-view-group") &&
tab.hasAttribute("had-zen-pinned-changed")
) {
tab.setAttribute("zen-pinned-changed", true);
tab.removeAttribute("had-zen-pinned-changed");
}
@@ -381,7 +399,8 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
#onNewFolder(event) {
const isFromToolbar = event.target.id === "zen-context-menu-new-folder-toolbar";
const isFromToolbar =
event.target.id === "zen-context-menu-new-folder-toolbar";
const contextMenu = event.target.parentElement;
let tabs = TabContextMenu.contextTab?.multiselected
? gBrowser.selectedTabs
@@ -401,7 +420,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
// Prevent create folder inside Live Folder
const thereIsOneLiveFolderTab = tabs?.some((tab) =>
const thereIsOneLiveFolderTab = tabs?.some(tab =>
tab.hasAttribute("zen-live-folder-item-id")
);
if (thereIsOneLiveFolderTab) {
@@ -423,7 +442,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
async #convertFolderToSpace(folder) {
const currentWorkspace = gZenWorkspaces.getActiveWorkspaceFromCache();
let selectedTab = folder.tabs.find((tab) => tab.selected);
let selectedTab = folder.tabs.find(tab => tab.selected);
const icon = folder.icon?.querySelector("svg .icon image");
const newSpace = await gZenWorkspaces.createAndSaveWorkspace(
@@ -432,20 +451,23 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
/* dontChange= */ false,
currentWorkspace.containerTabId,
{
beforeChangeCallback: async (newWorkspace) => {
await new Promise((resolve) => {
beforeChangeCallback: async newWorkspace => {
await new Promise(resolve => {
requestAnimationFrame(async () => {
const workspacePinnedContainer = gZenWorkspaces.workspaceElement(
newWorkspace.uuid
).pinnedTabsContainer;
const tabs = folder.allItems.filter((tab) => !tab.hasAttribute("zen-empty-tab"));
const tabs = folder.allItems.filter(
tab => !tab.hasAttribute("zen-empty-tab")
);
workspacePinnedContainer.append(...tabs);
await folder.delete();
gBrowser.tabContainer._invalidateCachedTabs();
if (selectedTab) {
selectedTab.setAttribute("zen-workspace-id", newWorkspace.uuid);
selectedTab.removeAttribute("folder-active");
gZenWorkspaces.lastSelectedWorkspaceTabs[newWorkspace.uuid] = selectedTab;
gZenWorkspaces.lastSelectedWorkspaceTabs[newWorkspace.uuid] =
selectedTab;
}
resolve();
});
@@ -461,7 +483,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
tab.style.height = "";
}
gBrowser.TabStateFlusher.flush(tab.linkedBrowser);
if (gZenWorkspaces.lastSelectedWorkspaceTabs[currentWorkspace.uuid] === tab) {
if (
gZenWorkspaces.lastSelectedWorkspaceTabs[currentWorkspace.uuid] === tab
) {
// This tab is no longer the last selected tab in the previous workspace because it's being moved to
// the current workspace
delete gZenWorkspaces.lastSelectedWorkspaceTabs[currentWorkspace.uuid];
@@ -496,7 +520,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
}
folder.dispatchEvent(new CustomEvent("ZenFolderChangedWorkspace", { bubbles: true }));
folder.dispatchEvent(
new CustomEvent("ZenFolderChangedWorkspace", { bubbles: true })
);
if (!hasDndSwitch) {
gZenWorkspaces.changeWorkspaceWithID(workspaceId).then(() => {
@@ -513,8 +539,8 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
createFolder(tabs = [], options = {}) {
const filteredTabs = tabs
.filter((tab) => !tab.hasAttribute("zen-essential"))
.map((tab) => {
.filter(tab => !tab.hasAttribute("zen-essential"))
.map(tab => {
gBrowser.pinTab(tab);
if (tab?.group?.hasAttribute("split-view-group")) {
tab = tab.group;
@@ -526,9 +552,12 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
options.workspaceId
)?.pinnedTabsContainer;
const pinnedContainer =
options.workspaceId && workspacePinned ? workspacePinned : gZenWorkspaces.pinnedTabsContainer;
options.workspaceId && workspacePinned
? workspacePinned
: gZenWorkspaces.pinnedTabsContainer;
const insertBefore =
options.insertBefore || pinnedContainer.querySelector(".pinned-tabs-container-separator");
options.insertBefore ||
pinnedContainer.querySelector(".pinned-tabs-container-separator");
const emptyTab = gBrowser.addTab("about:blank", {
skipAnimation: true,
pinned: true,
@@ -557,7 +586,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
// deliberate user action indicating the tab has importance for the user.
// Without this, it is not possible to save and close a tab group with
// a short lifetime.
folder.tabs.forEach((tab) => {
folder.tabs.forEach(tab => {
gBrowser.TabStateFlusher.flush(tab.linkedBrowser);
});
@@ -572,7 +601,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
_createFolderNode(options = {}) {
const folder = document.createXULElement("zen-folder", { is: "zen-folder" });
const folder = document.createXULElement("zen-folder", {
is: "zen-folder",
});
let id = options.id;
if (!id) {
// Note: If this changes, make sure to also update the
@@ -587,14 +618,17 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
folder.color = "zen-workspace-color";
folder.isLiveFolder = options.isLiveFolder;
folder.setAttribute("zen-workspace-id", options.workspaceId || gZenWorkspaces.activeWorkspace);
folder.setAttribute(
"zen-workspace-id",
options.workspaceId || gZenWorkspaces.activeWorkspace
);
// note: We set if the folder is collapsed some time after creation.
// we do this to ensure marginBottom is set correctly in the case
// that we want it to initially be collapsed.
setTimeout(
// eslint-disable-next-line no-shadow
(folder) => {
folder => {
folder.collapsed = !!options.collapsed;
},
0,
@@ -618,7 +652,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
gBrowser.pinTab(otherTab);
}
this._piningFolder = false;
gBrowser.pinnedTabsContainer.insertBefore(group, gBrowser.pinnedTabsContainer.lastChild);
gBrowser.pinnedTabsContainer.insertBefore(
group,
gBrowser.pinnedTabsContainer.lastChild
);
gBrowser.tabContainer._invalidateCachedTabs();
return true;
}
@@ -649,13 +686,18 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
openTabsPopup(event) {
event.stopPropagation();
if (document.documentElement.getAttribute("zen-renaming-tab") || gURLBar.focused) {
if (
document.documentElement.getAttribute("zen-renaming-tab") ||
gURLBar.focused
) {
return;
}
const activeGroup = event.target.parentElement;
if (
activeGroup.tabs.filter((tab) => this.#shouldAppearOnTabSearch(tab, activeGroup)).length === 0
activeGroup.tabs.filter(tab =>
this.#shouldAppearOnTabSearch(tab, activeGroup)
).length === 0
) {
// If the group has no tabs, we don't show the popup
return;
@@ -679,31 +721,38 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
foundTabs++;
}
}
document.getElementById("zen-folder-tabs-search-no-results").hidden = foundTabs > 0;
document.getElementById("zen-folder-tabs-search-no-results").hidden =
foundTabs > 0;
};
search.addEventListener("input", onSearchInput);
const onKeyDown = (event) => {
const onKeyDown = event => {
// Arrow down and up to navigate through the list
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
event.preventDefault();
const items = Array.from(tabsList.children).filter((item) => !item.hidden);
const items = Array.from(tabsList.children).filter(
item => !item.hidden
);
if (items.length === 0) {
return;
}
let index = items.indexOf(tabsList.querySelector(".folders-tabs-list-item[selected]"));
let index = items.indexOf(
tabsList.querySelector(".folders-tabs-list-item[selected]")
);
if (event.key === "ArrowDown") {
index = (index + 1) % items.length;
} else if (event.key === "ArrowUp") {
index = (index - 1 + items.length) % items.length;
}
items.forEach((item) => item.removeAttribute("selected"));
items.forEach(item => item.removeAttribute("selected"));
const targetItem = items[index];
targetItem.setAttribute("selected", "true");
targetItem.scrollIntoView({ block: "start", behavior: "smooth" });
} else if (event.key === "Enter") {
// Enter to select the currently highlighted item
const highlightedItem = tabsList.querySelector(".folders-tabs-list-item[selected]");
const highlightedItem = tabsList.querySelector(
".folders-tabs-list-item[selected]"
);
if (highlightedItem) {
highlightedItem.click();
}
@@ -714,7 +763,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const target = event.target;
target.setAttribute("open", true);
const handlePopupHidden = (event) => {
const handlePopupHidden = event => {
if (event.target !== this.#popup) {
return;
}
@@ -733,14 +782,19 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
{ once: true }
);
this.#popup.addEventListener("popuphidden", handlePopupHidden, { once: true });
this.#popup.addEventListener("popuphidden", handlePopupHidden, {
once: true,
});
this.#popup.openPopup(target, this.#searchPopupOptions);
}
get #searchPopupOptions() {
const isRightSide = gZenVerticalTabsManager._prefsRightSide;
const position = isRightSide ? "topleft topright" : "topright topleft";
let size = Math.min(this.#popup.querySelector("#zen-folder-tabs-list").children.length, 6);
let size = Math.min(
this.#popup.querySelector("#zen-folder-tabs-list").children.length,
6
);
size *= 48;
return {
position,
@@ -756,7 +810,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
// account for the visibility of the tab itself, it's just a literal
// representation of the `hidden` attribute.
const tabIsInActiveGroup = group.activeTabs.includes(tab);
return !tabIsInActiveGroup && !(tab.hidden || tab.hasAttribute("zen-empty-tab"));
return (
!tabIsInActiveGroup && !(tab.hidden || tab.hasAttribute("zen-empty-tab"))
);
}
#populateTabsList(group) {
@@ -786,7 +842,8 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
// We don't need to do anything if the URL is invalid. e.g. about:blank
}
let tabLabel = tab.label || "";
let iconURL = gBrowser.getIcon(tab) || PlacesUtils.favicons.defaultFavicon.spec;
let iconURL =
gBrowser.getIcon(tab) || PlacesUtils.favicons.defaultFavicon.spec;
icon.src = iconURL;
@@ -809,7 +866,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
item.setAttribute("selected", "true");
}
item.setAttribute("data-label", `${tabLabel.toLowerCase()} ${tabURL.toLowerCase()}`);
item.setAttribute(
"data-label",
`${tabLabel.toLowerCase()} ${tabURL.toLowerCase()}`
);
item.addEventListener("click", () => {
gBrowser.selectedTab = tab;
@@ -846,11 +906,17 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
// eslint-disable-next-line complexity
setFolderIndentation(tabs, groupElem = undefined, forCollapse = true, animate = true) {
setFolderIndentation(
tabs,
groupElem = undefined,
forCollapse = true,
animate = true
) {
if (!gZenPinnedTabManager.expandedSidebarMode) {
return;
}
const isSpaceCollapsed = gZenWorkspaces.activeWorkspaceElement?.hasCollapsedPinnedTabs;
const isSpaceCollapsed =
gZenWorkspaces.activeWorkspaceElement?.hasCollapsedPinnedTabs;
let tab = tabs[0];
let isTab = false;
@@ -863,7 +929,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
if (
gBrowser.isTab(groupElem) &&
(!(groupElem.hasAttribute("zen-empty-tab") && groupElem.group === tab.group) ||
(!(
groupElem.hasAttribute("zen-empty-tab") && groupElem.group === tab.group
) ||
groupElem?.hasAttribute("zen-empty-tab"))
) {
groupElem = groupElem.group;
@@ -893,7 +961,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
}
for (const tabItem of tabs) {
if (gBrowser.isTabGroupLabel(tabItem) || tabItem.group?.hasAttribute("split-view-group")) {
if (
gBrowser.isTabGroupLabel(tabItem) ||
tabItem.group?.hasAttribute("split-view-group")
) {
tabItem.group.style.setProperty("--zen-folder-indent", `${spacing}px`);
continue;
}
@@ -915,9 +986,11 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
onlySvgIcons: true,
allowNone: Boolean(group.iconURL),
closeOnSelect: false,
onSelect: (icon) => {
onSelect: icon => {
this.setFolderUserIcon(group, icon);
group.dispatchEvent(new CustomEvent("TabGroupUpdate", { bubbles: true }));
group.dispatchEvent(
new CustomEvent("TabGroupUpdate", { bubbles: true })
);
},
});
}
@@ -948,7 +1021,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const labelContainer = group.querySelector(".tab-group-label-container");
// Setup mouseenter/mouseleave events for the folder
labelContainer.addEventListener("mouseenter", (event) => {
labelContainer.addEventListener("mouseenter", event => {
if (
!group.collapsed ||
!Services.prefs.getBoolPref("zen.folders.search.enabled") ||
@@ -977,7 +1050,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
storeDataForSessionStore() {
const folders = Array.from(gBrowser.tabContainer.querySelectorAll("zen-folder"));
const folders = Array.from(
gBrowser.tabContainer.querySelectorAll("zen-folder")
);
const splitGroups = Array.from(
gBrowser.tabContainer.querySelectorAll("tab-group[split-view-group]")
);
@@ -1004,8 +1079,8 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
continue;
}
const emptyFolderTabs = folder.tabs
.filter((tab) => tab.hasAttribute("zen-empty-tab"))
.map((tab) => tab.getAttribute("id"));
.filter(tab => tab.hasAttribute("zen-empty-tab"))
.map(tab => tab.getAttribute("id"));
let prevSiblingInfo = null;
const prevSibling = folder.previousElementSibling;
@@ -1014,7 +1089,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
if (prevSibling) {
if (gBrowser.isTabGroup(prevSibling)) {
prevSiblingInfo = { type: "group", id: prevSibling.id };
} else if (gBrowser.isTab(prevSibling) && prevSibling.hasAttribute("id")) {
} else if (
gBrowser.isTab(prevSibling) &&
prevSibling.hasAttribute("id")
) {
prevSiblingInfo = { type: "tab", id: prevSibling.getAttribute("id") };
} else {
prevSiblingInfo = { type: "start", id: null };
@@ -1061,8 +1139,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
tabFolderWorkingData.set(folderData.id, workingData);
const oldGroup = document.getElementById(folderData.id);
folderData.emptyTabIds.forEach((id) => {
oldGroup?.querySelector(`tab[id="${id}"]`)?.setAttribute("zen-empty-tab", true);
folderData.emptyTabIds.forEach(id => {
oldGroup
?.querySelector(`tab[id="${id}"]`)
?.setAttribute("zen-empty-tab", true);
});
if (gBrowser.isTabGroup(oldGroup)) {
if (!folderData.splitViewGroup) {
@@ -1097,7 +1177,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
}
for (const { node, containingTabsFragment } of tabFolderWorkingData.values()) {
for (const {
node,
containingTabsFragment,
} of tabFolderWorkingData.values()) {
if (node) {
node.appendChild(containingTabsFragment);
}
@@ -1111,7 +1194,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
switch (stateData?.prevSiblingInfo?.type) {
case "tab":
case "group": {
const item = document.getElementById(stateData.prevSiblingInfo.id);
const item = document.getElementById(
stateData.prevSiblingInfo.id
);
if (item) {
item.after(node);
break;
@@ -1124,7 +1209,8 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
default: {
// Should insert after zen-empty-tab
const start = parentWorkingData.node.groupStartElement.nextElementSibling;
const start =
parentWorkingData.node.groupStartElement.nextElementSibling;
start.after(node);
}
}
@@ -1140,9 +1226,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
gBrowser.tabContainer._invalidateCachedTabs();
setTimeout(() => {
delete this._sessionRestoring;
}, 0);
delete this._sessionRestoring;
}
/**
@@ -1163,10 +1247,11 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
if (
folder?.isZenFolder &&
(!folder.hasAttribute("split-view-group") || !folder.hasAttribute("selected")) &&
(!folder.hasAttribute("split-view-group") ||
!folder.hasAttribute("selected")) &&
!(
folder.level >= this.#ZEN_MAX_SUBFOLDERS &&
movingTabs?.some((t) => gBrowser.isTabGroupLabel(t))
movingTabs?.some(t => gBrowser.isTabGroupLabel(t))
)
) {
if (folder.collapsed) {
@@ -1191,8 +1276,8 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
#normalizeGroupItems(items) {
return items
.filter((item) => !item.hasAttribute("zen-empty-tab"))
.map((item) => {
.filter(item => !item.hasAttribute("zen-empty-tab"))
.map(item => {
if (gBrowser.isTabGroup(item)) {
item = item.firstChild;
} else if (gBrowser.isTabGroupLabel(item)) {
@@ -1219,11 +1304,15 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
#collectGroupItems(group, opts = {}) {
const { selectedTabs = [], splitViewIds = new Set(), activeFoldersIds = new Set() } = opts;
const {
selectedTabs = [],
splitViewIds = new Set(),
activeFoldersIds = new Set(),
} = opts;
const folders = new Map();
return group.childGroupsAndTabs
.filter((item) => !item.hasAttribute("zen-empty-tab"))
.map((item) => {
.filter(item => !item.hasAttribute("zen-empty-tab"))
.map(item => {
const isSplitView = item.group?.hasAttribute?.("split-view-group");
const itemGroup = isSplitView ? item.group.group : item.group;
if (!folders.has(itemGroup?.id)) {
@@ -1257,7 +1346,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
#createAnimation(items, targetState, opts, callback = () => {}) {
items = Array.isArray(items) ? items : [items];
return items.map((item) =>
return items.map(item =>
gZenUIManager.motion.animate(item, targetState, opts).then(callback)
);
}
@@ -1267,7 +1356,8 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
if (selectedTabs.length) {
return heightShift;
}
heightShift += window.windowUtils.getBoundsWithoutFlushing(tabsContainer).height;
heightShift +=
window.windowUtils.getBoundsWithoutFlushing(tabsContainer).height;
if (tabsContainer.separatorElement) {
heightShift -= window.windowUtils.getBoundsWithoutFlushing(
tabsContainer.separatorElement
@@ -1278,7 +1368,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
get #folderAnimationDuration() {
return this._sessionRestoring || this._dontAnimateFolder ? 0 : 0.12;
return this._dontAnimateFolder ? 0 : 0.12;
}
async animateCollapse(group) {
@@ -1298,7 +1388,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
splitViewIds,
activeFoldersIds,
});
const collapsedHeight = this.#calculateHeightShift(tabsContainer, selectedTabs);
const collapsedHeight = this.#calculateHeightShift(
tabsContainer,
selectedTabs
);
if (selectedTabs.length) {
for (let i = 0; i < groupItems.length; i++) {
@@ -1318,7 +1411,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
if (activeFolderId && activeFoldersIds.has(activeFolderId)) {
// If item is tab-group-label-container we should hide it.
// Other items between tab-group-labe-container and folder-active tab should be visible cuz they are hidden by margin-top
if (item.parentElement.id !== activeFolderId && !item.hasAttribute("folder-active")) {
if (
item.parentElement.id !== activeFolderId &&
!item.hasAttribute("folder-active")
) {
continue;
}
}
@@ -1331,7 +1427,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
group.setAttribute("has-active", "true");
group.activeTabs = selectedTabs;
selectedTabs.forEach((tab) => {
selectedTabs.forEach(tab => {
this.setFolderIndentation([tab], group, /* for collapse = */ true);
});
}
@@ -1348,7 +1444,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
...this.#createAnimation(
groupStart,
{
marginTop: -(collapsedHeight + 4 * (selectedTabs.length === 0 ? 1 : 0)),
marginTop: -(
collapsedHeight +
4 * (selectedTabs.length === 0 ? 1 : 0)
),
},
{ duration, ease: "easeInOut" }
)
@@ -1440,7 +1539,11 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
let activeGroup = folders.get(tabGroup?.id);
if (activeGroup) {
this.setFolderIndentation([tab], activeGroup, /* for collapse = */ true);
this.setFolderIndentation(
[tab],
activeGroup,
/* for collapse = */ true
);
} else {
// Since the folder is now expanded, we should remove active attribute
// to the tab that was previously visible
@@ -1538,7 +1641,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
async animateUnload(group, tabToUnload, ungroup = false) {
const isSplitView = tabToUnload.group?.hasAttribute("split-view-group");
if ((!group?.isZenFolder || !isSplitView) && !tabToUnload.hasAttribute("folder-active")) {
if (
(!group?.isZenFolder || !isSplitView) &&
!tabToUnload.hasAttribute("folder-active")
) {
return;
}
const animations = [];
@@ -1546,7 +1652,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
const activeGroups = group.activeGroups;
for (const folder of activeGroups) {
folder.activeTabs = folder.activeTabs.filter((tab) => tab !== tabToUnload);
folder.activeTabs = folder.activeTabs.filter(tab => tab !== tabToUnload);
if (folder.activeTabs.length === 0) {
lastTab = true;
@@ -1563,7 +1669,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
// the correct container size in the DOM
tabsContainer.offsetHeight;
tabsContainer.setAttribute("hidden", true);
const collapsedHeight = this.#calculateHeightShift(tabsContainer, []);
const collapsedHeight = this.#calculateHeightShift(
tabsContainer,
[]
);
groupStart.style.marginTop = `${-(collapsedHeight + 4)}px`;
};
@@ -1614,7 +1723,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
// Await the tab unload animation first
await Promise.all(tabUnloadAnimations);
await Promise.all(animations.map((item) => (typeof item === "function" ? item() : item)));
await Promise.all(
animations.map(item => (typeof item === "function" ? item() : item))
);
this.#animationCount -= 1;
gBrowser.tabContainer._invalidateCachedTabs();
}
@@ -1641,7 +1752,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
? tab.group.group
: tab?.group;
while (currentGroup) {
const activeTabs = selectedTabs.filter((t) => currentGroup.tabs.includes(t));
const activeTabs = selectedTabs.filter(t =>
currentGroup.tabs.includes(t)
);
if (activeTabs.length) {
if (currentGroup.collapsed) {
if (currentGroup.hasAttribute("has-active")) {
@@ -1696,7 +1809,10 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
for (let i = 0; i < groupItems.length; i++) {
const { item, splitViewId } = groupItems[i];
itemsToShow.push(item);
let itemVisible = item.visible;
if (itemVisible) {
itemsToShow.push(item);
}
// Skip selected items
if (selectedTabs.includes(item)) {
@@ -1708,17 +1824,15 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
continue;
}
if (!item.hasAttribute?.("folder-active")) {
if (!itemsToHide.includes(item)) {
itemsToHide.push(item);
}
if (!itemVisible && !itemsToHide.includes(item)) {
itemsToHide.push(item);
}
}
}
// FIXME: This is a hack to fix the animations not working properly
this.styleCleanup(itemsToShow);
itemsToHide.forEach((item) => {
itemsToHide.forEach(item => {
item.style.opacity = 0;
item.style.height = 0;
});
@@ -1756,7 +1870,6 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
// Cleanup
this.styleCleanup(itemsToHide);
this.styleCleanup(selectedTabs);
}
@@ -1766,7 +1879,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
const groupStart = group.groupStartElement;
const tabsContainer = group.groupContainer;
const heightContainer = expand ? 0 : this.#calculateHeightShift(tabsContainer, []);
const heightContainer = expand
? 0
: this.#calculateHeightShift(tabsContainer, []);
tabsContainer.style.overflow = "clip";
this.#createAnimation(
@@ -1779,7 +1894,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
}
styleCleanup(items) {
items.forEach((item) => {
items.forEach(item => {
item.style.removeProperty("opacity");
item.style.removeProperty("height");
});

View File

@@ -4,4 +4,4 @@
content/browser/zen-components/ZenFolder.mjs (../../zen/folders/ZenFolder.mjs)
content/browser/zen-components/ZenFolders.mjs (../../zen/folders/ZenFolders.mjs)
content/browser/zen-styles/zen-folders.css (../../zen/folders/zen-folders.css)
content/browser/zen-styles/zen-folders.css (../../zen/folders/zen-folders.css)

View File

@@ -88,7 +88,6 @@ zen-folder {
width: 28px;
height: 28px;
align-content: center;
pointer-events: none;
position: absolute;
pointer-events: none;
@@ -266,8 +265,8 @@ zen-folder[collapsed] > .tab-group-container {
}
#zen-folder-tabs-popup .zen-folder-tabs-list-search-icon {
width: 16px;
height: 16px;
width: var(--size-item-small);
height: var(--size-item-small);
margin: 10px 2px 10px 10px;
-moz-context-properties: fill;
fill: currentColor;
@@ -275,8 +274,8 @@ zen-folder[collapsed] > .tab-group-container {
}
.folders-tabs-list-item-icon {
width: 16px;
height: 16px;
width: var(--size-item-small);
height: var(--size-item-small);
flex-shrink: 0;
margin-inline-end: 10px;
margin-inline-start: 4px;

View File

@@ -37,7 +37,8 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
ARC_HEIGHT_RATIO: 0.2, // Arc height = distance * ratio (capped at MAX_ARC_HEIGHT)
});
#GLANCE_ANIMATION_DURATION = Services.prefs.getIntPref("zen.glance.animation-duration") / 1000;
#GLANCE_ANIMATION_DURATION =
Services.prefs.getIntPref("zen.glance.animation-duration") / 1000;
init() {
this.#setupEventListeners();
@@ -74,9 +75,13 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
menuitem.setAttribute("hidden", "true");
menuitem.setAttribute("data-l10n-id", "zen-open-link-in-glance");
menuitem.addEventListener("command", () => this.openGlance({ url: gContextMenu.linkURL }));
menuitem.addEventListener("command", () =>
this.openGlance({ url: gContextMenu.linkURL })
);
document.getElementById("context-sep-open").insertAdjacentElement("beforebegin", menuitem);
document
.getElementById("context-sep-open")
.insertAdjacentElement("beforebegin", menuitem);
}
/**
@@ -175,7 +180,8 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
currentTab._selected = true;
const newTab =
existingTab ?? gBrowser.addTrustedTab(Services.io.newURI(url).spec, newTabOptions);
existingTab ??
gBrowser.addTrustedTab(Services.io.newURI(url).spec, newTabOptions);
this.#configureNewTab(newTab, currentTab, newUUID);
this.#registerGlance(newTab, currentTab, newUUID);
@@ -355,7 +361,11 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.#setAnimationState(true);
const currentTab = ownerTab ?? gBrowser.selectedTab;
const browserElement = this.#createBrowserElement(data.url, currentTab, existingTab);
const browserElement = this.#createBrowserElement(
data.url,
currentTab,
existingTab
);
this.fillOverlay(browserElement);
this.overlay.classList.add("zen-glance-overlay");
@@ -386,7 +396,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
// until a better solution is found). If we do it inside the requestAnimationFrame,
// we see flashing and if we do it directly, the animation does not play at all.
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
return new Promise(async resolve => {
// Recalculate location. When opening from pinned tabs,
// view splitter doesn't catch if the tab is a glance tab or not.
gZenViewSplitter.onLocationChange(browserElement);
@@ -496,7 +506,8 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
const imageDataElement = this.#createGlancePreviewElement(data.elementData);
this.browserWrapper.prepend(imageDataElement);
this.#glances.get(this.#currentGlanceID).elementImageData = data.elementData;
this.#glances.get(this.#currentGlanceID).elementImageData =
data.elementData;
gZenUIManager.motion.animate(
imageDataElement,
@@ -518,7 +529,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @param {Browser} browserElement - The browser element
*/
#configureBrowserElement(browserElement) {
const rect = window.windowUtils.getBoundsWithoutFlushing(this.browserWrapper.parentElement);
const rect = window.windowUtils.getBoundsWithoutFlushing(
this.browserWrapper.parentElement
);
const minWidth = rect.width * 0.85;
const minHeight = rect.height * 0.85;
@@ -574,7 +587,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.#animateParentBackground();
gZenUIManager.motion
.animate(this.browserWrapper, arcSequence, {
duration: gZenUIManager.testingEnabled ? 0 : this.#GLANCE_ANIMATION_DURATION,
duration: gZenUIManager.testingEnabled
? 0
: this.#GLANCE_ANIMATION_DURATION,
ease: "easeInOut",
})
.then(() => {
@@ -595,7 +610,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
// Calculate start and end positions based on direction
let startPosition, endPosition;
const tabPanelsRect = window.windowUtils.getBoundsWithoutFlushing(gBrowser.tabpanels);
const tabPanelsRect = window.windowUtils.getBoundsWithoutFlushing(
gBrowser.tabpanels
);
const widthPercent = 0.85;
if (direction === "opening") {
@@ -658,12 +675,17 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
// First, create the main animation steps
for (let i = 0; i <= steps; i++) {
const progress = i / steps;
const eased = direction === "opening" ? easeOutBack(progress) : easeOutCubic(progress);
const eased =
direction === "opening"
? easeOutBack(progress)
: easeOutCubic(progress);
// Calculate size interpolation
const currentWidth = startPosition.width + (endPosition.width - startPosition.width) * eased;
const currentWidth =
startPosition.width + (endPosition.width - startPosition.width) * eased;
const currentHeight =
startPosition.height + (endPosition.height - startPosition.height) * eased;
startPosition.height +
(endPosition.height - startPosition.height) * eased;
// Calculate position on arc
const distanceX = endPosition.x - startPosition.x;
@@ -671,7 +693,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
const x = startPosition.x + distanceX * eased;
const y =
startPosition.y + distanceY * eased + arcDirection * arcHeight * (1 - (2 * eased - 1) ** 2);
startPosition.y +
distanceY * eased +
arcDirection * arcHeight * (1 - (2 * eased - 1) ** 2);
sequence.top.push(`${y}px`);
sequence.left.push(`${x}px`);
@@ -707,13 +731,16 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
// Calculate available space for the arc
const availableTopSpace = Math.min(startPosition.y, endPosition.y);
const viewportHeight = window.innerHeight;
const availableBottomSpace = viewportHeight - Math.max(startPosition.y, endPosition.y);
const availableBottomSpace =
viewportHeight - Math.max(startPosition.y, endPosition.y);
// Determine if we should arc downward or upward based on available space
const shouldArcDownward = availableBottomSpace > availableTopSpace;
// Use the space in the direction we're arcing
const availableSpace = shouldArcDownward ? availableBottomSpace : availableTopSpace;
const availableSpace = shouldArcDownward
? availableBottomSpace
: availableTopSpace;
// Limit arc height to a percentage of the available space
const arcHeight = Math.min(
@@ -792,12 +819,17 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
return;
}
const browserSidebarContainer = this.#currentParentTab?.linkedBrowser?.closest(
".browserSidebarContainer"
const browserSidebarContainer =
this.#currentParentTab?.linkedBrowser?.closest(
".browserSidebarContainer"
);
const sidebarButtons = this.browserWrapper.querySelector(
".zen-glance-sidebar-container"
);
const sidebarButtons = this.browserWrapper.querySelector(".zen-glance-sidebar-container");
if (this.#handleConfirmationTimeout(onTabClose, hasFocused, sidebarButtons)) {
if (
this.#handleConfirmationTimeout(onTabClose, hasFocused, sidebarButtons)
) {
return;
}
@@ -851,8 +883,15 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @returns {boolean} True if should return early
*/
#handleConfirmationTimeout(onTabClose, hasFocused, sidebarButtons) {
if (onTabClose && hasFocused && !this.#confirmationTimeout && sidebarButtons) {
const cancelButton = sidebarButtons.querySelector(".zen-glance-sidebar-close");
if (
onTabClose &&
hasFocused &&
!this.#confirmationTimeout &&
sidebarButtons
) {
const cancelButton = sidebarButtons.querySelector(
".zen-glance-sidebar-close"
);
cancelButton.setAttribute("waitconfirmation", true);
this.#confirmationTimeout = setTimeout(() => {
cancelButton.removeAttribute("waitconfirmation");
@@ -871,7 +910,12 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @param {Element} sidebarButtons - The sidebar buttons
* @param {string} setNewID - New glance ID to set
*/
#animateGlanceClosing(onTabClose, browserSidebarContainer, sidebarButtons, setNewID) {
#animateGlanceClosing(
onTabClose,
browserSidebarContainer,
sidebarButtons,
setNewID
) {
if (this.closingGlance) {
return;
}
@@ -976,14 +1020,19 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @returns {Promise} Promise that resolves when complete
*/
#executeClosingAnimation(setNewID, onTabClose) {
return new Promise((resolve) => {
const originalPosition = this.#glances.get(this.#currentGlanceID).originalPosition;
const elementImageData = this.#glances.get(this.#currentGlanceID).elementImageData;
return new Promise(resolve => {
const originalPosition = this.#glances.get(
this.#currentGlanceID
).originalPosition;
const elementImageData = this.#glances.get(
this.#currentGlanceID
).elementImageData;
this.#addElementPreview(elementImageData);
// Create curved closing animation sequence
const closingData = this.#createClosingDataFromOriginalPosition(originalPosition);
const closingData =
this.#createClosingDataFromOriginalPosition(originalPosition);
const arcSequence = this.#createGlanceArcSequence(closingData, "closing");
gZenUIManager.motion
@@ -993,7 +1042,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
})
.then(() => {
// Remove element preview after closing animation
const elementPreview = this.browserWrapper.querySelector(".zen-glance-element-preview");
const elementPreview = this.browserWrapper.querySelector(
".zen-glance-element-preview"
);
if (elementPreview) {
elementPreview.remove();
}
@@ -1031,7 +1082,8 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
*/
#addElementPreview(elementImageData) {
if (elementImageData) {
const imageDataElement = this.#createGlancePreviewElement(elementImageData);
const imageDataElement =
this.#createGlancePreviewElement(elementImageData);
this.browserWrapper.prepend(imageDataElement);
}
}
@@ -1081,7 +1133,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.overlay.classList.remove("zen-glance-overlay");
gBrowser
._getSwitcher()
.setTabStateNoAction(lastCurrentTab, gBrowser.AsyncTabSwitcher.STATE_UNLOADED);
.setTabStateNoAction(
lastCurrentTab,
gBrowser.AsyncTabSwitcher.STATE_UNLOADED
);
if (!this.#currentParentTab.selected) {
this.#currentParentTab._visuallySelected = false;
@@ -1107,7 +1162,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.#ignoreClose = true;
lastCurrentTab.dispatchEvent(new Event("GlanceClose", { bubbles: true }));
gBrowser.removeTab(lastCurrentTab, { animate: true, skipPermitUnload: true });
gBrowser.removeTab(lastCurrentTab, {
animate: true,
skipPermitUnload: true,
});
gBrowser.tabContainer._invalidateCachedTabs();
}
@@ -1192,7 +1250,12 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.#removeParentBackground(parentHasBrowser, browserContainer);
if (!justAnimateParent && this.overlay) {
this.#resetGlanceStates(closeCurrentTab, closeParentTab, parentHasBrowser, browserContainer);
this.#resetGlanceStates(
closeCurrentTab,
closeParentTab,
parentHasBrowser,
browserContainer
);
}
if (clearID) {
@@ -1220,8 +1283,16 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @param {boolean} parentHasBrowser - Whether parent has browser
* @param {Element} browserContainer - The browser container
*/
#resetGlanceStates(closeCurrentTab, closeParentTab, parentHasBrowser, browserContainer) {
if (parentHasBrowser && !this.#currentParentTab.hasAttribute("split-view")) {
#resetGlanceStates(
closeCurrentTab,
closeParentTab,
parentHasBrowser,
browserContainer
) {
if (
parentHasBrowser &&
!this.#currentParentTab.hasAttribute("split-view")
) {
if (closeParentTab) {
browserContainer.classList.remove("deck-selected");
}
@@ -1258,7 +1329,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.quickOpenGlance();
if (prevTab && prevTab.linkedBrowser) {
prevTab.linkedBrowser.docShellIsActive = false;
prevTab.linkedBrowser.closest(".browserSidebarContainer").classList.remove("deck-selected");
prevTab.linkedBrowser
.closest(".browserSidebarContainer")
.classList.remove("deck-selected");
}
}
}
@@ -1284,7 +1357,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
return;
}
if (this.#currentGlanceID && this.#currentGlanceID !== tab.getAttribute("glance-id")) {
if (
this.#currentGlanceID &&
this.#currentGlanceID !== tab.getAttribute("glance-id")
) {
this.quickCloseGlance();
}
@@ -1375,7 +1451,11 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @returns {boolean} True if valid
*/
#isValidGlanceUrl(urlSpec) {
return urlSpec.startsWith("http") || urlSpec.startsWith("https") || urlSpec.startsWith("file");
return (
urlSpec.startsWith("http") ||
urlSpec.startsWith("https") ||
urlSpec.startsWith("file")
);
}
/**
@@ -1465,10 +1545,14 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.#handleZenFolderPinning();
gBrowser.moveTabAfter(this.#currentTab, this.#currentParentTab);
const browserRect = window.windowUtils.getBoundsWithoutFlushing(this.browserWrapper);
const browserRect = window.windowUtils.getBoundsWithoutFlushing(
this.browserWrapper
);
this.#prepareTabForFullOpen();
const sidebarButtons = this.browserWrapper.querySelector(".zen-glance-sidebar-container");
const sidebarButtons = this.browserWrapper.querySelector(
".zen-glance-sidebar-container"
);
if (sidebarButtons) {
sidebarButtons.remove();
}
@@ -1493,7 +1577,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
*/
#handleZenFolderPinning() {
const isZenFolder = this.#currentParentTab?.group?.isZenFolder;
if (Services.prefs.getBoolPref("zen.folders.owned-tabs-in-folder") && isZenFolder) {
if (
Services.prefs.getBoolPref("zen.folders.owned-tabs-in-folder") &&
isZenFolder
) {
gBrowser.pinTab(this.#currentTab);
}
}
@@ -1551,7 +1638,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @param {Event} event - The bookmark click event
*/
openGlanceForBookmark(event) {
const activationMethod = Services.prefs.getStringPref("zen.glance.activation-method", "ctrl");
const activationMethod = Services.prefs.getStringPref(
"zen.glance.activation-method",
"ctrl"
);
if (!this.#isActivationKeyPressed(event, activationMethod)) {
return;
@@ -1590,7 +1680,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
*/
#createGlanceDataFromBookmark(event) {
const rect = window.windowUtils.getBoundsWithoutFlushing(event.target);
const tabPanelRect = window.windowUtils.getBoundsWithoutFlushing(gBrowser.tabpanels);
const tabPanelRect = window.windowUtils.getBoundsWithoutFlushing(
gBrowser.tabpanels
);
// the bookmark is most likely outisde the tabpanel, so we need to give a negative number
// so it can be corrected later
// eslint-disable-next-line no-shadow
@@ -1631,7 +1723,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
gZenViewSplitter.splitTabs([currentTab, currentParentTab], "vsep", 1);
const browserContainer = currentTab.linkedBrowser?.closest(".browserSidebarContainer");
const browserContainer = currentTab.linkedBrowser?.closest(
".browserSidebarContainer"
);
if (!gReduceMotion && browserContainer) {
gZenViewSplitter.animateBrowserDrop(browserContainer);
}
@@ -1644,7 +1738,10 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
*/
#handleZenFolderPinningForSplit(parentTab) {
const isZenFolder = parentTab?.group?.isZenFolder;
if (Services.prefs.getBoolPref("zen.folders.owned-tabs-in-folder") && isZenFolder) {
if (
Services.prefs.getBoolPref("zen.folders.owned-tabs-in-folder") &&
isZenFolder
) {
gBrowser.pinTab(this.#currentTab);
}
}
@@ -1657,7 +1754,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
*/
getTabOrGlanceParent(tab) {
if (tab?.hasAttribute("glance-id") && this.#glances) {
const parentTab = this.#glances.get(tab.getAttribute("glance-id"))?.parentTab;
const parentTab = this.#glances.get(
tab.getAttribute("glance-id")
)?.parentTab;
if (parentTab) {
return parentTab;
}
@@ -1702,7 +1801,8 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
if (currentGlanceID && oldGlanceID) {
return (
currentGlanceID === oldGlanceID && oldPanel.classList.contains("zen-glance-background")
currentGlanceID === oldGlanceID &&
oldPanel.classList.contains("zen-glance-background")
);
}
@@ -1752,7 +1852,9 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
* @param {Tab} parentTab - Parent tab
*/
#openGlanceForSearch(currentTab, parentTab) {
const browserRect = window.windowUtils.getBoundsWithoutFlushing(gBrowser.tabbox);
const browserRect = window.windowUtils.getBoundsWithoutFlushing(
gBrowser.tabbox
);
const clickPosition = gZenUIManager._lastClickPosition || {
clientX: browserRect.width / 2,
clientY: browserRect.height / 2,

View File

@@ -17,7 +17,9 @@ export class ZenGlanceChild extends JSWindowActorChild {
}
async #initActivationMethod() {
this.#activationMethod = await this.sendQuery("ZenGlance:GetActivationMethod");
this.#activationMethod = await this.sendQuery(
"ZenGlance:GetActivationMethod"
);
}
#ensureOnlyKeyModifiers(event) {
@@ -114,7 +116,9 @@ export class ZenGlanceChild extends JSWindowActorChild {
return;
}
this.sendAsyncMessage("ZenGlance:CloseGlance", {
hasFocused: this.contentWindow.document.activeElement !== this.contentWindow.document.body,
hasFocused:
this.contentWindow.document.activeElement !==
this.contentWindow.document.body,
});
}

View File

@@ -12,7 +12,10 @@ export class ZenGlanceParent extends JSWindowActorParent {
async receiveMessage(message) {
switch (message.name) {
case "ZenGlance:GetActivationMethod": {
return Services.prefs.getStringPref("zen.glance.activation-method", "ctrl");
return Services.prefs.getStringPref(
"zen.glance.activation-method",
"ctrl"
);
}
case "ZenGlance:OpenGlance": {
this.openGlance(this.browsingContext.topChromeWindow, message.data);
@@ -23,11 +26,14 @@ export class ZenGlanceParent extends JSWindowActorParent {
onTabClose: true,
...message.data,
};
this.browsingContext.topChromeWindow.gZenGlanceManager.closeGlance(params);
this.browsingContext.topChromeWindow.gZenGlanceManager.closeGlance(
params
);
break;
}
case "ZenGlance:RecordLinkClickData": {
this.browsingContext.topChromeWindow.gZenGlanceManager.lastLinkClickData = message.data;
this.browsingContext.topChromeWindow.gZenGlanceManager.lastLinkClickData =
message.data;
break;
}
default:

View File

@@ -3,4 +3,4 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
content/browser/zen-components/ZenGlanceManager.mjs (../../zen/glance/ZenGlanceManager.mjs)
content/browser/zen-styles/zen-glance.css (../../zen/glance/zen-glance.css)
content/browser/zen-styles/zen-glance.css (../../zen/glance/zen-glance.css)

View File

@@ -4,7 +4,7 @@
export function openGlanceOnTab(window, callback, close = true) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
return new Promise(async resolve => {
window.gZenGlanceManager
.openGlance({
url: "https://example.com",
@@ -13,7 +13,7 @@ export function openGlanceOnTab(window, callback, close = true) {
width: 0,
height: 0,
})
.then(async (glanceTab) => {
.then(async glanceTab => {
await callback(glanceTab);
if (close) {
window.gZenGlanceManager

View File

@@ -23,8 +23,8 @@
}
& toolbarbutton {
width: 32px;
height: 32px;
width: var(--size-item-large);
height: var(--size-item-large);
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,
@@ -65,7 +65,7 @@
width: fit-content;
& label {
display: block;
max-width: 0px;
max-width: 0;
margin: 0;
overflow: hidden;
transition:

View File

@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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 https://mozilla.org/MPL/2.0/. -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="192" height="192">
<path d="M0 0 C46.53 0 93.06 0 141 0 C140.31337286 6.17964422 139.55249061 11.27288504 137.70605469 17.05029297 C137.47297387 17.80257864 137.23989305 18.55486431 136.99974918 19.32994652 C136.23144234 21.80315256 135.45168558 24.27258703 134.671875 26.7421875 C134.12437759 28.49738282 133.57765617 30.25282037 133.03166199 32.00848389 C131.87637142 35.71831589 130.71622139 39.42657597 129.55197144 43.13360596 C127.74764855 48.8788063 125.95370897 54.62720979 124.16235352 60.37646484 C123.86778165 61.32180147 123.57320978 62.2671381 123.26971149 63.24112129 C122.67820023 65.13942545 122.08671887 67.03773892 121.49526787 68.93606186 C120.61596105 71.75702774 119.73559404 74.57766091 118.85499573 77.39822388 C113.93371601 93.16794093 109.12231506 108.96839561 104.39160156 124.79638672 C104.15798416 125.57612854 103.92436676 126.35587036 103.68367004 127.15924072 C103.08515835 129.15844483 102.48956633 131.15852242 101.89428711 133.15869141 C101 136 101 136 100 138 C53.47 138 6.94 138 -41 138 C-40.30154873 133.1108411 -39.57595592 129.15411541 -38.15258789 124.53222656 C-37.57916405 122.65642914 -37.57916405 122.65642914 -36.99415588 120.74273682 C-36.57039663 119.37534329 -36.14656076 118.0079735 -35.72265625 116.640625 C-35.27348999 115.1778587 -34.82480765 113.71494372 -34.37657166 112.25189209 C-33.18301778 108.36047716 -31.98331296 104.47098593 -30.78216553 100.58190918 C-29.63602455 96.86810525 -28.49491032 93.15276556 -27.35351562 89.4375 C-24.23585848 79.29161092 -21.11791678 69.14580929 -18 59 C-12.06 39.53 -6.12 20.06 0 0 Z " fill="#C00002" transform="translate(51,54)"/>
<path d="M0 0 C18.3328319 -0.77792059 36.66127963 -1.35606988 55.00715542 -1.70980167 C63.53040721 -1.87858134 72.04320263 -2.10845198 80.55981445 -2.48950195 C142.46067644 -5.20608208 142.46067644 -5.20608208 159.53827381 9.52021503 C166.76889916 16.3955246 173.28323862 24.18336817 178 33 C178 34.32 178 35.64 178 37 C159.57187597 37.07007601 141.14378652 37.12298126 122.71555805 37.15543652 C114.15904092 37.17090649 105.60260658 37.19199848 97.04614258 37.22631836 C89.58846853 37.25621675 82.13085443 37.27557406 74.67312211 37.28226548 C70.72416302 37.28617701 66.77537545 37.29537225 62.82647133 37.31719017 C59.10909816 37.33756234 55.39196707 37.34383237 51.67454338 37.33932304 C49.66086617 37.34054104 47.64721527 37.35667936 45.63360596 37.3732605 C44.43192276 37.36913651 43.23023956 37.36501251 41.99214172 37.36076355 C40.42831993 37.36491162 40.42831993 37.36491162 38.83290577 37.36914349 C32.93264951 36.60030705 29.62184448 32.77709579 25.875 28.5 C19.58131594 21.47164064 12.89888852 14.86095567 6.14794922 8.2734375 C5.35146973 7.48839844 4.55499023 6.70335937 3.734375 5.89453125 C3.01475586 5.19175049 2.29513672 4.48896973 1.55371094 3.76489258 C0 2 0 2 0 0 Z " fill="#C00002" transform="translate(14,0)"/>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -111,16 +111,15 @@ const defaultKeyboardGroups = {
"zen-bidi-switch-direction-shortcut",
"zen-screenshot-shortcut",
],
devTools: [
/*Filled automatically*/
],
devTools: [/*Filled automatically*/],
};
const fixedL10nIds = {
cmd_findPrevious: "zen-search-find-again-shortcut-prev",
"Browser:ReloadSkipCache": "zen-nav-reload-shortcut-skip-cache",
cmd_close: "zen-close-tab-shortcut",
"History:RestoreLastClosedTabOrWindowOrSession": "zen-restore-last-closed-tab-shortcut",
"History:RestoreLastClosedTabOrWindowOrSession":
"zen-restore-last-closed-tab-shortcut",
};
const ZEN_MAIN_KEYSET_ID = "mainKeyset";
@@ -191,7 +190,13 @@ export class nsKeyShortcutModifiers {
}
// used to avoid any future changes to the object
static fromObject({ ctrl = false, alt = false, shift = false, meta = false, accel = false }) {
static fromObject({
ctrl = false,
alt = false,
shift = false,
meta = false,
accel = false,
}) {
return new nsKeyShortcutModifiers(ctrl, alt, shift, meta, accel);
}
@@ -270,7 +275,9 @@ export class nsKeyShortcutModifiers {
}
areAnyActive() {
return this.#control || this.#alt || this.#shift || this.#meta || this.#accel;
return (
this.#control || this.#alt || this.#shift || this.#meta || this.#accel
);
}
get control() {
@@ -385,7 +392,9 @@ class KeyShortcut {
KeyShortcut.sanitizeL10nId(key.getAttribute("data-l10n-id")),
key.getAttribute("id")
),
nsKeyShortcutModifiers.parseFromXHTMLAttribute(key.getAttribute("modifiers")),
nsKeyShortcutModifiers.parseFromXHTMLAttribute(
key.getAttribute("modifiers")
),
key.getAttribute("command"),
key.getAttribute("data-l10n-id"),
key.getAttribute("disabled") == "true",
@@ -589,7 +598,11 @@ class KeyShortcut {
}
isUserEditable() {
if (!this.#id || this.#internal || (this.#group == FIREFOX_SHORTCUTS_GROUP && this.#disabled)) {
if (
!this.#id ||
this.#internal ||
(this.#group == FIREFOX_SHORTCUTS_GROUP && this.#disabled)
) {
return false;
}
return true;
@@ -653,10 +666,14 @@ class nsZenKeyboardShortcutsLoader {
let keySet = document.getElementById(ZEN_MAIN_KEYSET_ID);
let newShortcutList = [];
const correctDefaultShortcut = (shortcut) => {
const correctDefaultShortcut = shortcut => {
if (shortcut.getID() === "key_savePage") {
shortcut.setModifiers(
nsKeyShortcutModifiers.fromObject({ accel: true, alt: true, shift: true })
nsKeyShortcutModifiers.fromObject({
accel: true,
alt: true,
shift: true,
})
);
}
};
@@ -801,7 +818,10 @@ class nsZenKeyboardShortcutsLoader {
}
let parsed = KeyShortcut.parseFromXHTML(key, { group: "devTools" });
// Move "inspector" shortcut to use "L" key instead of "I"
if (parsed.getID() == "key_inspector" || parsed.getID() == "key_inspectorMac") {
if (
parsed.getID() == "key_inspector" ||
parsed.getID() == "key_inspectorMac"
) {
parsed.setNewBinding("L");
}
newShortcutList.push(parsed);
@@ -869,7 +889,7 @@ class nsZenKeyboardShortcutsVersioner {
fillDefaultIfNotPresent(data) {
for (let shortcut of nsZenKeyboardShortcutsLoader.zenGetDefaultShortcuts()) {
// If it has an ID and we dont find it in the data, we add it
if (shortcut.getID() && !data.find((s) => s.getID() == shortcut.getID())) {
if (shortcut.getID() && !data.find(s => s.getID() == shortcut.getID())) {
data.push(shortcut);
}
}
@@ -919,7 +939,8 @@ class nsZenKeyboardShortcutsVersioner {
// detection for internal keys was not working properly, so every internal
// shortcut was being saved as a user-editable shortcut.
// This migration will fix this issue.
const defaultShortcuts = nsZenKeyboardShortcutsLoader.zenGetDefaultShortcuts();
const defaultShortcuts =
nsZenKeyboardShortcutsLoader.zenGetDefaultShortcuts();
// Get the default shortcut, compare the id and set the internal flag if needed
for (let shortcut of data) {
for (let defaultShortcut of defaultShortcuts) {
@@ -933,7 +954,7 @@ class nsZenKeyboardShortcutsVersioner {
// Migrate from 3 to 4
// In this new version, we are just removing the 'zen-toggle-sidebar' shortcut
// since it's not used anymore.
data = data.filter((shortcut) => shortcut.getID() != "zen-toggle-sidebar");
data = data.filter(shortcut => shortcut.getID() != "zen-toggle-sidebar");
}
if (version < 5) {
// Migrate from 4 to 5
@@ -968,11 +989,14 @@ class nsZenKeyboardShortcutsVersioner {
if (version < 7) {
// Migrate from 6 to 7
// In this new version, we add the devtools shortcuts
const listener = (event) => {
const listener = event => {
event.stopPropagation();
const devToolsShortcuts = nsZenKeyboardShortcutsLoader.zenGetDefaultDevToolsShortcuts();
gZenKeyboardShortcutsManager.updatedDefaultDevtoolsShortcuts(devToolsShortcuts);
const devToolsShortcuts =
nsZenKeyboardShortcutsLoader.zenGetDefaultDevToolsShortcuts();
gZenKeyboardShortcutsManager.updatedDefaultDevtoolsShortcuts(
devToolsShortcuts
);
window.removeEventListener("zen-devtools-keyset-added", listener);
};
@@ -991,7 +1015,11 @@ class nsZenKeyboardShortcutsVersioner {
"C",
"",
ZEN_OTHER_SHORTCUTS_GROUP,
nsKeyShortcutModifiers.fromObject({ accel: true, shift: true, alt: true }),
nsKeyShortcutModifiers.fromObject({
accel: true,
shift: true,
alt: true,
}),
"cmd_zenCopyCurrentURLMarkdown",
"zen-text-action-copy-url-markdown-shortcut"
)
@@ -1001,7 +1029,9 @@ class nsZenKeyboardShortcutsVersioner {
// Migrate from version 8 to 9
// Due to security concerns, replace "code:" actions with corresponding <command> IDs
// we also remove 'zen-toggle-web-panel' since it's not used anymore
data = data.filter((shortcut) => shortcut.getID() != "zen-toggle-web-panel");
data = data.filter(
shortcut => shortcut.getID() != "zen-toggle-web-panel"
);
for (let shortcut of data) {
if (shortcut.getAction()?.startsWith("code:")) {
const id = shortcut.getID();
@@ -1084,7 +1114,11 @@ class nsZenKeyboardShortcutsVersioner {
// - Remove the built-in "Open File" keybinding; menu item remains available
// - Remove default "Bookmark All Tabs" keybinding (Ctrl+Shift+D) to avoid conflict
// - Remove "Stop" keybinding to avoid conflict with Firefox's built-in binding
const shouldBeEmptyShortcuts = ["openFileKb", "bookmarkAllTabsKb", "key_stop"];
const shouldBeEmptyShortcuts = [
"openFileKb",
"bookmarkAllTabsKb",
"key_stop",
];
for (let shortcut of data) {
if (shouldBeEmptyShortcuts.includes(shortcut.getID?.())) {
shortcut.shouldBeEmpty = true;
@@ -1092,7 +1126,9 @@ class nsZenKeyboardShortcutsVersioner {
}
// Also remove zen-compact-mode-show-toolbar
data = data.filter((shortcut) => shortcut.getID() != "zen-compact-mode-show-toolbar");
data = data.filter(
shortcut => shortcut.getID() != "zen-compact-mode-show-toolbar"
);
}
if (version < 13) {
@@ -1130,7 +1166,10 @@ class nsZenKeyboardShortcutsVersioner {
let emptySplitFound = false,
undoCloseWindowFound = false;
for (let shortcut of data) {
if (shortcut.getID() == "zen-new-empty-split-view" && AppConstants.platform == "macosx") {
if (
shortcut.getID() == "zen-new-empty-split-view" &&
AppConstants.platform == "macosx"
) {
if (shortcut.getKeyName() == "+") {
shortcut.setNewBinding("*");
}
@@ -1179,7 +1218,10 @@ window.gZenKeyboardShortcutsManager = {
"zen.keyboard.shortcuts.disable-mainkeyset-clear",
false
);
window.addEventListener("zen-devtools-keyset-added", this._hasAddedDevtoolShortcuts.bind(this));
window.addEventListener(
"zen-devtools-keyset-added",
this._hasAddedDevtoolShortcuts.bind(this)
);
this.init();
},
@@ -1188,11 +1230,14 @@ window.gZenKeyboardShortcutsManager = {
if (this.inBrowserView) {
const loadedShortcuts = await this._loadSaved();
this._currentShortcutList = this.versioner.fixedKeyboardShortcuts(loadedShortcuts);
this._currentShortcutList =
this.versioner.fixedKeyboardShortcuts(loadedShortcuts);
this._applyShortcuts();
await this._saveShortcuts();
window.dispatchEvent(new Event("ZenKeyboardShortcutsReady", { bubbles: true }));
window.dispatchEvent(
new Event("ZenKeyboardShortcutsReady", { bubbles: true })
);
}
},
@@ -1210,12 +1255,16 @@ window.gZenKeyboardShortcutsManager = {
try {
return KeyShortcut.parseFromSaved(data);
} catch (e) {
console.error("Zen CKS: Error parsing saved shortcuts. Resetting to defaults...", e);
console.error(
"Zen CKS: Error parsing saved shortcuts. Resetting to defaults...",
e
);
gNotificationBox.appendNotification(
"zen-shortcuts-corrupted",
{
label: { "l10n-id": "zen-shortcuts-corrupted" },
image: "chrome://browser/skin/notification-icons/persistent-storage-blocked.svg",
image:
"chrome://browser/skin/notification-icons/persistent-storage-blocked.svg",
priority: gNotificationBox.PRIORITY_WARNING_HIGH,
},
[]
@@ -1325,12 +1374,17 @@ window.gZenKeyboardShortcutsManager = {
if (!browser.gZenKeyboardShortcutsManager?._hasToLoadDevtools) {
return;
}
let devtoolsKeyset = browser.gZenKeyboardShortcutsManager.getZenDevtoolsKeyset(browser);
let devtoolsKeyset =
browser.gZenKeyboardShortcutsManager.getZenDevtoolsKeyset(browser);
for (let key of this._currentShortcutList) {
if (key.getGroup() != "devTools") {
continue;
}
if (nsZenKeyboardShortcutsLoader.IGNORED_DEVTOOLS_SHORTCUTS.includes(key.getID())) {
if (
nsZenKeyboardShortcutsLoader.IGNORED_DEVTOOLS_SHORTCUTS.includes(
key.getID()
)
) {
continue;
}
const originalKey = browser.document.getElementById(key.getID());
@@ -1345,7 +1399,9 @@ window.gZenKeyboardShortcutsManager = {
}
}
const originalDevKeyset = browser.document.getElementById(ZEN_DEVTOOLS_KEYSET_ID);
const originalDevKeyset = browser.document.getElementById(
ZEN_DEVTOOLS_KEYSET_ID
);
originalDevKeyset.after(devtoolsKeyset);
},

View File

@@ -5,7 +5,8 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
NetUtil: "resource://gre/modules/NetUtil.sys.mjs",
DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs",
NetworkHelper: "resource://devtools/shared/network-observer/NetworkHelper.sys.mjs",
NetworkHelper:
"resource://devtools/shared/network-observer/NetworkHelper.sys.mjs",
});
export class nsZenLiveFolderProvider {
@@ -135,7 +136,10 @@ export class nsZenLiveFolderProvider {
userContextId = space.containerTabId || 0;
}
}
const principal = Services.scriptSecurityManager.createContentPrincipal(uri, { userContextId });
const principal = Services.scriptSecurityManager.createContentPrincipal(
uri,
{ userContextId }
);
const channel = lazy.NetUtil.newChannel({
uri,
@@ -146,7 +150,8 @@ export class nsZenLiveFolderProvider {
contentPolicyType: Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD,
loadingPrincipal: principal,
securityFlags:
Ci.nsILoadInfo.SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT | Ci.nsILoadInfo.SEC_COOKIES_INCLUDE,
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL |
Ci.nsILoadInfo.SEC_COOKIES_INCLUDE,
triggeringPrincipal: principal,
}).QueryInterface(Ci.nsIHttpChannel);
@@ -168,7 +173,7 @@ export class nsZenLiveFolderProvider {
byteChunks.push(lazy.NetUtil.readInputStream(stream, count));
}
},
onStartRequest: (request) => {
onStartRequest: request => {
const http = request.QueryInterface(Ci.nsIHttpChannel);
try {
@@ -181,7 +186,10 @@ export class nsZenLiveFolderProvider {
contentType = http.getResponseHeader("content-type");
} catch (ex) {}
if (contentType && !lazy.NetworkHelper.isTextMimeType(contentType.split(";")[0].trim())) {
if (
contentType &&
!lazy.NetworkHelper.isTextMimeType(contentType.split(";")[0].trim())
) {
request.cancel(Cr.NS_ERROR_FILE_UNKNOWN_TYPE);
}
@@ -214,7 +222,9 @@ export class nsZenLiveFolderProvider {
let effectiveCharset = "utf-8";
const mimeType = contentType ? contentType.split(";")[0].trim().toLowerCase() : "";
const mimeType = contentType
? contentType.split(";")[0].trim().toLowerCase()
: "";
if (mimeType === "text/html") {
effectiveCharset = this.sniffCharset(bytes, headerCharset);
} else if (headerCharset) {
@@ -251,7 +261,12 @@ export class nsZenLiveFolderProvider {
*/
sniffCharset(bytes, headerCharset = "") {
// 1. BOM detection (highest priority)
if (bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) {
if (
bytes.length >= 3 &&
bytes[0] === 0xef &&
bytes[1] === 0xbb &&
bytes[2] === 0xbf
) {
return "utf-8";
}
if (bytes.length >= 2) {
@@ -268,7 +283,9 @@ export class nsZenLiveFolderProvider {
// is more likely to be correct.
try {
const headLen = Math.min(bytes.length, 8192);
const head = new TextDecoder("windows-1252").decode(bytes.subarray(0, headLen));
const head = new TextDecoder("windows-1252").decode(
bytes.subarray(0, headLen)
);
const metaCharsetRegex = /<meta\s+charset\s*=\s*["']?([a-z0-9_-]+)/i;
let match = head.match(metaCharsetRegex);

View File

@@ -51,7 +51,9 @@ class nsZenLiveFoldersManager {
}
for (const provider of providers) {
const module = ChromeUtils.importESModule(provider.path, { global: "current" });
const module = ChromeUtils.importESModule(provider.path, {
global: "current",
});
const ProviderClass = module[provider.module];
this.registry.set(ProviderClass.type, ProviderClass);
}
@@ -114,7 +116,8 @@ class nsZenLiveFoldersManager {
#onTabDismiss(event) {
const itemIdAttr = "zen-live-folder-item-id";
const itemId =
event.target.getAttribute(itemIdAttr) || event.detail?.getAttribute?.(itemIdAttr);
event.target.getAttribute(itemIdAttr) ||
event.detail?.getAttribute?.(itemIdAttr);
if (itemId) {
if (event.type === "TabUngrouped") {
@@ -139,7 +142,9 @@ class nsZenLiveFoldersManager {
#onActionButtonClick(event) {
const liveFolderId = event.target.getAttribute("live-folder-action");
this.getFolder(liveFolderId)?.onActionButtonClick(event.target.getAttribute("data-l10n-id"));
this.getFolder(liveFolderId)?.onActionButtonClick(
event.target.getAttribute("data-l10n-id")
);
}
#onTabGroupRemoved(event) {
@@ -317,7 +322,9 @@ class nsZenLiveFoldersManager {
// Remove the dismissed items associated with the folder from the set
this.dismissedItems = new Set(
Array.from(this.dismissedItems).filter((itemId) => !itemId.startsWith(prefix))
Array.from(this.dismissedItems).filter(
itemId => !itemId.startsWith(prefix)
)
);
if (deleteFolder) {
@@ -351,7 +358,9 @@ class nsZenLiveFoldersManager {
}
// itemid -> id:itemid
const itemIds = new Set(items.map((item) => this.#makeCompositeId(liveFolder.id, item.id)));
const itemIds = new Set(
items.map(item => this.#makeCompositeId(liveFolder.id, item.id))
);
const outdatedTabs = [];
const existingItemIds = new Set();
@@ -377,27 +386,45 @@ class nsZenLiveFoldersManager {
// Remove the dismissed items that are no longer in the given list
for (const dismissedItemId of this.dismissedItems) {
if (dismissedItemId.startsWith(`${liveFolder.id}:`) && !itemIds.has(dismissedItemId)) {
if (
dismissedItemId.startsWith(`${liveFolder.id}:`) &&
!itemIds.has(dismissedItemId)
) {
this.dismissedItems.delete(dismissedItemId);
}
}
let userContextId = 0;
let space = folder.ownerGlobal.gZenWorkspaces.getWorkspaceFromId(
folder.getAttribute("zen-workspace-id")
);
if (space) {
userContextId = space.containerTabId || 0;
}
// Only add the items that are not already in the folder and was not dismissed by the user
const newItems = items
.filter((item) => {
.filter(item => {
const compositeId = this.#makeCompositeId(liveFolder.id, item.id);
return !existingItemIds.has(compositeId) && !this.dismissedItems.has(compositeId);
return (
!existingItemIds.has(compositeId) &&
!this.dismissedItems.has(compositeId)
);
})
.map((item) => {
.map(item => {
const tab = this.window.gBrowser.addTrustedTab(item.url, {
createLazyBrowser: true,
inBackground: true,
skipAnimation: true,
noInitialLabel: true,
lazyTabTitle: item.title,
userContextId,
});
// createLazyBrowser can't be pinned by default
this.window.gBrowser.pinTab(tab);
if (userContextId) {
tab.setAttribute("zenDefaultUserContextId", "true");
}
if (item.icon) {
this.window.gBrowser.setIcon(tab, item.icon);
if (tab.linkedBrowser) {
@@ -406,7 +433,10 @@ class nsZenLiveFoldersManager {
});
}
}
tab.setAttribute("zen-live-folder-item-id", this.#makeCompositeId(liveFolder.id, item.id));
tab.setAttribute(
"zen-live-folder-item-id",
this.#makeCompositeId(liveFolder.id, item.id)
);
if (item.subtitle) {
tab.setAttribute("zen-show-sublabel", item.subtitle);
const tabLabel = tab.querySelector(".zen-tab-sublabel");
@@ -459,7 +489,10 @@ class nsZenLiveFoldersManager {
if (!this.window) {
return null;
}
const folder = lazy.ZenWindowSync.getItemFromWindow(this.window, liveFolder.id);
const folder = lazy.ZenWindowSync.getItemFromWindow(
this.window,
liveFolder.id
);
if (folder?.isZenFolder) {
return folder;
}
@@ -504,7 +537,7 @@ class nsZenLiveFoldersManager {
let data = [];
for (let [id, liveFolder] of this.liveFolders) {
const prefix = `${id}:`;
const dismissedItems = Array.from(this.dismissedItems).filter((itemId) =>
const dismissedItems = Array.from(this.dismissedItems).filter(itemId =>
itemId.startsWith(prefix)
);
@@ -556,7 +589,7 @@ class nsZenLiveFoldersManager {
continue;
}
const folder = folders.find((x) => x.id === entry.id);
const folder = folders.find(x => x.id === entry.id);
if (!folder) {
// No point restore if the live folder can't find its folder
continue;
@@ -573,7 +606,7 @@ class nsZenLiveFoldersManager {
liveFolder.tabsState = entry.tabsState || [];
liveFolder.state.lastErrorId = entry.data.state.lastErrorId;
if (entry.dismissedItems && Array.isArray(entry.dismissedItems)) {
entry.dismissedItems.forEach((id) => this.dismissedItems.add(id));
entry.dismissedItems.forEach(id => this.dismissedItems.add(id));
}
liveFolder.start();

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