mirror of
https://github.com/zen-browser/desktop.git
synced 2026-09-18 18:54:43 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04e7db5d3a | ||
|
|
644bf48b6c | ||
|
|
d2acc61a88 | ||
|
|
f84278317f | ||
|
|
4980f3ce18 | ||
|
|
5362ddbccd | ||
|
|
6c32eaad68 | ||
|
|
610e7bfbae | ||
|
|
b43785de65 | ||
|
|
787f9c5e02 | ||
|
|
22961e97d8 | ||
|
|
cb6a607c67 | ||
|
|
267c9aabe1 | ||
|
|
d54e12359c | ||
|
|
c89645a787 | ||
|
|
0a548c7572 | ||
|
|
6d158223b5 | ||
|
|
76fcd5c822 | ||
|
|
ed6900d762 | ||
|
|
2e9aecd41b | ||
|
|
da995e8653 | ||
|
|
64d73ab3e3 | ||
|
|
9551444c61 | ||
|
|
fdf9588b7b | ||
|
|
b07b17c87e | ||
|
|
c9d3cb3dc9 | ||
|
|
2c030369c5 | ||
|
|
88a90206ce | ||
|
|
6d398dec63 | ||
|
|
243a8791a0 | ||
|
|
412731f37e | ||
|
|
7a78848177 | ||
|
|
a323036995 | ||
|
|
abc69a1fcb | ||
|
|
8df45e5c9a | ||
|
|
58e83c137f |
1
.github/workflows/macos-profile-build.yml
vendored
1
.github/workflows/macos-profile-build.yml
vendored
@@ -23,7 +23,6 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [x86_64, aarch64]
|
arch: [x86_64, aarch64]
|
||||||
|
|
||||||
runs-on: ${{ matrix.arch == 'x86_64' && 'macos-15-intel' || 'macos-26' }}
|
runs-on: ${{ matrix.arch == 'x86_64' && 'macos-15-intel' || 'macos-26' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
1
.github/workflows/windows-profile-build.yml
vendored
1
.github/workflows/windows-profile-build.yml
vendored
@@ -27,7 +27,6 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
arch: [x86_64, aarch64]
|
arch: [x86_64, aarch64]
|
||||||
|
|
||||||
runs-on: ${{ inputs.release-branch == 'release' && 'windows-latest' || 'windows-latest' }}
|
runs-on: ${{ inputs.release-branch == 'release' && 'windows-latest' || 'windows-latest' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.94.1
|
1.95.0
|
||||||
@@ -34,8 +34,8 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
|
|||||||
|
|
||||||
### Firefox Versions
|
### Firefox Versions
|
||||||
|
|
||||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `155.0.1`!
|
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `156.0`!
|
||||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 155.0.1`!
|
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 156.0`!
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
b6d45eac914fd4886c9b6e5f1447f613771228ff
|
07c99209a6e4c794752e9a242215199ad3ea10f6
|
||||||
@@ -147,9 +147,9 @@ function SignAndPackage($name) {
|
|||||||
$env:ZEN_SETUP_EXE_PATH="$PWD\windsign-temp\windows-x64-obj-$name\browser\installer\windows\instgen\setup.exe"
|
$env:ZEN_SETUP_EXE_PATH="$PWD\windsign-temp\windows-x64-obj-$name\browser\installer\windows\instgen\setup.exe"
|
||||||
|
|
||||||
if ($name -eq "arm64") {
|
if ($name -eq "arm64") {
|
||||||
$env:WIN32_REDIST_DIR="$PWD\win-cross\vs2026\VC\Redist\MSVC\14.50.35710\arm64\Microsoft.VC145.CRT"
|
$env:WIN32_REDIST_DIR="$PWD\win-cross\vs2026\VC\Redist\MSVC\14.51.36231\arm64\Microsoft.VC145.CRT"
|
||||||
} else {
|
} else {
|
||||||
$env:WIN32_REDIST_DIR="$PWD\win-cross\vs2026\VC\Redist\MSVC\14.50.35710\x64\Microsoft.VC145.CRT"
|
$env:WIN32_REDIST_DIR="$PWD\win-cross\vs2026\VC\Redist\MSVC\14.51.36231\x64\Microsoft.VC145.CRT"
|
||||||
}
|
}
|
||||||
|
|
||||||
$env:MAR="..\\build\\windows\\mar.exe"
|
$env:MAR="..\\build\\windows\\mar.exe"
|
||||||
|
|||||||
@@ -53,7 +53,10 @@ fi
|
|||||||
if test "$ZEN_RELEASE"; then
|
if test "$ZEN_RELEASE"; then
|
||||||
|
|
||||||
ac_add_options --enable-clang-plugin
|
ac_add_options --enable-clang-plugin
|
||||||
ac_add_options --enable-bootstrap=-sccache
|
|
||||||
|
if ! test "$ZEN_DISABLE_BOOTSTRAP"; then
|
||||||
|
ac_add_options --enable-bootstrap=-sccache
|
||||||
|
fi
|
||||||
|
|
||||||
ac_add_options --enable-optimize
|
ac_add_options --enable-optimize
|
||||||
|
|
||||||
@@ -69,16 +72,11 @@ if test "$ZEN_RELEASE"; then
|
|||||||
ac_add_options --disable-geckodriver
|
ac_add_options --disable-geckodriver
|
||||||
ac_add_options --disable-rust-tests
|
ac_add_options --disable-rust-tests
|
||||||
|
|
||||||
if ! test "$ZEN_DISABLE_LTO"; then
|
if test "$ZEN_DISABLE_LTO"; then
|
||||||
# only enable full LTO when ZEN_RELEASE_BRANCH is 'release'
|
ac_add_options --disable-lto
|
||||||
if test "$ZEN_RELEASE_BRANCH" = "release"; then
|
else
|
||||||
# TODO: make it "full" once we have the resources to build it
|
export MOZ_LTO=cross,thin
|
||||||
export MOZ_LTO=cross,full
|
ac_add_options --enable-lto=cross,thin
|
||||||
ac_add_options --enable-lto=cross,full
|
|
||||||
else
|
|
||||||
export MOZ_LTO=cross,thin
|
|
||||||
ac_add_options --enable-lto=cross,thin
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mk_add_options MOZILLA_OFFICIAL=1
|
mk_add_options MOZILLA_OFFICIAL=1
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ if test "$ZEN_RELEASE"; then
|
|||||||
|
|
||||||
# Enable Profile Guided Optimization
|
# Enable Profile Guided Optimization
|
||||||
if ! test "$ZEN_GA_DISABLE_PGO"; then
|
if ! test "$ZEN_GA_DISABLE_PGO"; then
|
||||||
|
export MOZ_LTO=cross,full
|
||||||
|
ac_add_options --enable-lto=cross,full
|
||||||
|
|
||||||
if test "$ZEN_GA_GENERATE_PROFILE"; then
|
if test "$ZEN_GA_GENERATE_PROFILE"; then
|
||||||
mk_add_options "export MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES=0"
|
mk_add_options "export MOZ_AUTOMATION_PACKAGE_GENERATED_SOURCES=0"
|
||||||
ac_add_options --enable-profile-generate=cross
|
ac_add_options --enable-profile-generate=cross
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ if test "$ZEN_CROSS_COMPILING"; then
|
|||||||
CROSS_COMPILE=1
|
CROSS_COMPILE=1
|
||||||
|
|
||||||
if test "$SURFER_COMPAT" = "aarch64"; then
|
if test "$SURFER_COMPAT" = "aarch64"; then
|
||||||
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.50.35710/arm64/Microsoft.VC145.CRT"
|
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.51.36231/arm64/Microsoft.VC145.CRT"
|
||||||
else
|
else
|
||||||
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.50.35710/x64/Microsoft.VC145.CRT"
|
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.51.36231/x64/Microsoft.VC145.CRT"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -45,6 +45,9 @@ if test "$ZEN_CROSS_COMPILING"; then
|
|||||||
ac_add_options --enable-profile-use=cross
|
ac_add_options --enable-profile-use=cross
|
||||||
ac_add_options --with-pgo-profile-path=$(echo ~)/artifact/merged.profdata
|
ac_add_options --with-pgo-profile-path=$(echo ~)/artifact/merged.profdata
|
||||||
ac_add_options --with-pgo-jarlog=$(echo ~)/artifact/en-US.log
|
ac_add_options --with-pgo-jarlog=$(echo ~)/artifact/en-US.log
|
||||||
|
|
||||||
|
export MOZ_LTO=cross,full
|
||||||
|
ac_add_options --enable-lto=cross,full
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -26,3 +26,5 @@ files:
|
|||||||
translation: browser/browser/zen-space-routing.ftl
|
translation: browser/browser/zen-space-routing.ftl
|
||||||
- source: en-US/browser/browser/zen-command-palette.ftl
|
- source: en-US/browser/browser/zen-command-palette.ftl
|
||||||
translation: browser/browser/zen-command-palette.ftl
|
translation: browser/browser/zen-command-palette.ftl
|
||||||
|
- source: en-US/browser/browser/zen-share.ftl
|
||||||
|
translation: browser/browser/zen-share.ftl
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ zen-settings-workspaces-sync =
|
|||||||
.label = Sync your sidebar across devices
|
.label = Sync your sidebar across devices
|
||||||
.description = Keep your workspaces, pinned tabs and folders in sync on all your devices through your Mozilla account.
|
.description = Keep your workspaces, pinned tabs and folders in sync on all your devices through your Mozilla account.
|
||||||
|
|
||||||
|
zen-settings-normal-tabs-sync =
|
||||||
|
.label = Include unpinned tabs
|
||||||
|
.description = Also sync the regular tabs of each space, not just your pinned tabs and folders.
|
||||||
|
|
||||||
zen-settings-workspaces-sync-unpinned-tabs =
|
zen-settings-workspaces-sync-unpinned-tabs =
|
||||||
.label = Sync only pinned tabs in workspaces
|
.label = Sync only pinned tabs in workspaces
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
zen-action-toggle-compact-mode = Toggle Compact Mode
|
zen-action-toggle-compact-mode = Toggle Compact Mode
|
||||||
zen-action-open-theme-picker = Open Theme Picker
|
zen-action-open-theme-picker = Open Theme Picker
|
||||||
zen-action-new-split-view = New Split View
|
zen-action-new-split-view = New Split View
|
||||||
|
zen-action-unsplit-view = Expand current view
|
||||||
|
zen-action-new-space = New Space
|
||||||
zen-action-new-folder = New Folder
|
zen-action-new-folder = New Folder
|
||||||
zen-action-copy-current-url = Copy Current URL
|
zen-action-copy-current-url = Copy Current URL
|
||||||
zen-action-settings = Settings
|
zen-action-settings = Settings
|
||||||
@@ -18,6 +20,9 @@ zen-action-new-boost = New Boost
|
|||||||
zen-action-next-space = Next Space
|
zen-action-next-space = Next Space
|
||||||
zen-action-previous-space = Previous Space
|
zen-action-previous-space = Previous Space
|
||||||
zen-action-close-tab = Close Tab
|
zen-action-close-tab = Close Tab
|
||||||
|
zen-action-reopen-closed-tab = Reopen Closed Tab
|
||||||
|
zen-action-duplicate-tab = Duplicate Current Tab
|
||||||
|
zen-action-reset-pinned-tab = Reset Pinned Tab
|
||||||
zen-action-reload-tab = Reload Tab
|
zen-action-reload-tab = Reload Tab
|
||||||
zen-action-reload-tab-without-cache = Reload Tab Without Cache
|
zen-action-reload-tab-without-cache = Reload Tab Without Cache
|
||||||
zen-action-next-tab = Next Tab
|
zen-action-next-tab = Next Tab
|
||||||
|
|||||||
43
locales/en-US/browser/browser/zen-share.ftl
Normal file
43
locales/en-US/browser/browser/zen-share.ftl
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# 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/.
|
||||||
|
|
||||||
|
zen-share-space =
|
||||||
|
.label = Share Space…
|
||||||
|
zen-share-folder =
|
||||||
|
.label = Share Folder…
|
||||||
|
zen-share-split-view =
|
||||||
|
.label = Share Split View…
|
||||||
|
|
||||||
|
zen-share-link-copied-toast = Share link copied!
|
||||||
|
zen-share-link-expires-description = Anyone with the link can open it until { $date }
|
||||||
|
zen-share-link-permanent-description = Anyone with the link can open it
|
||||||
|
|
||||||
|
zen-share-error-toast = Couldn't create a share link
|
||||||
|
zen-share-error-auth-description = The share server rejected your key
|
||||||
|
zen-share-error-too-large-description = This share is too big to upload
|
||||||
|
zen-share-error-rate-limited-description = You're sharing too fast, try again in a minute
|
||||||
|
zen-share-error-network-description = Couldn't reach the share server
|
||||||
|
zen-share-error-empty-description = There's nothing shareable here
|
||||||
|
zen-share-error-server-description = The share server returned an error
|
||||||
|
|
||||||
|
zen-share-overlay-loading = Loading shared tabs…
|
||||||
|
zen-share-overlay-from-space = A Space from { $name }
|
||||||
|
zen-share-overlay-from-folder = A Folder from { $name }
|
||||||
|
zen-share-overlay-shared-with-you = Shared with you
|
||||||
|
zen-share-overlay-add-space = Add Space to Zen
|
||||||
|
zen-share-overlay-add-folder = Add Folder to Zen
|
||||||
|
zen-share-imported-toast = Added to your browser!
|
||||||
|
zen-share-import-error-toast = Couldn't import this share
|
||||||
|
zen-share-import-error-dead-description = The link has expired or doesn't exist
|
||||||
|
zen-share-import-error-invalid-description = The shared data is invalid
|
||||||
|
|
||||||
|
zen-share-confirm-title = Share link
|
||||||
|
zen-share-confirm-dialog =
|
||||||
|
.buttonlabelaccept = Share
|
||||||
|
zen-share-confirm-description = Zen uploads a copy of these tabs to the share server and copies a link anyone can open. The link expires after 30 days.
|
||||||
|
zen-share-confirm-anonymous = Sharing is anonymous unless you add a name.
|
||||||
|
zen-share-confirm-name-input =
|
||||||
|
.placeholder = Your name (optional)
|
||||||
|
zen-share-confirm-dont-ask =
|
||||||
|
.label = Don't ask me again
|
||||||
@@ -24,6 +24,11 @@ zen-welcome-default-search-description = Choose your default search engine. You
|
|||||||
zen-welcome-essentials-title = Choose the apps you use most.
|
zen-welcome-essentials-title = Choose the apps you use most.
|
||||||
zen-welcome-essentials-description = Select your favorite apps to keep them handy in your sidebar.
|
zen-welcome-essentials-description = Select your favorite apps to keep them handy in your sidebar.
|
||||||
|
|
||||||
|
zen-welcome-block-ads-title = Block ads and trackers?
|
||||||
|
zen-welcome-block-ads-description = { -brand-short-name } can install uBlock Origin for you, so pages load cleaner and faster. You can remove it any time.
|
||||||
|
zen-welcome-block-ads-yes = <strong>YES</strong>, block ads for me.
|
||||||
|
zen-welcome-block-ads-no = <strong>NO</strong>, show me everything.
|
||||||
|
|
||||||
zen-welcome-workspace-colors-title = Your space, your colors.
|
zen-welcome-workspace-colors-title = Your space, your colors.
|
||||||
zen-welcome-workspace-colors-description = Personalize your browser by giving each space its own unique color identity.
|
zen-welcome-workspace-colors-description = Personalize your browser by giving each space its own unique color identity.
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,18 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
- name: zen.share.enabled
|
- name: zen.share.base-url
|
||||||
|
value: "https://share.zen-browser.app"
|
||||||
|
|
||||||
|
- name: zen.share.secret-key
|
||||||
|
value: ""
|
||||||
|
|
||||||
|
- name: zen.share.display-name
|
||||||
|
value: ""
|
||||||
|
|
||||||
|
# Allow zen.share.display-name to be synced across devices.
|
||||||
|
- name: services.sync.prefs.sync.zen.share.display-name
|
||||||
value: true
|
value: true
|
||||||
|
|
||||||
|
- name: zen.share.dont-ask-before-sharing
|
||||||
|
value: false
|
||||||
|
|||||||
@@ -8,3 +8,9 @@
|
|||||||
|
|
||||||
- name: zen.spaces-sync.debug
|
- name: zen.spaces-sync.debug
|
||||||
value: false
|
value: false
|
||||||
|
|
||||||
|
- name: zen.spaces-sync.normal-tabs
|
||||||
|
value: false
|
||||||
|
|
||||||
|
- name: services.sync.prefs.sync.zen.spaces-sync.normal-tabs
|
||||||
|
value: true
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
- name: zen.theme.acrylic-elements
|
- name: zen.theme.acrylic-elements
|
||||||
value: "@IS_TWILIGHT@"
|
value: "@IS_TWILIGHT@"
|
||||||
|
|
||||||
|
- name: zen.theme.squircle-browser-view
|
||||||
|
value: "@IS_TWILIGHT@"
|
||||||
|
|
||||||
- name: zen.theme.disable-lightweight
|
- name: zen.theme.disable-lightweight
|
||||||
value: true
|
value: true
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
|
diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
|
||||||
index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5361e060f 100644
|
index a76bb7aae7636c07989a4acb35281777d3103505..c5eafbdad5270cd9926ed4f1d850d134440d775b 100644
|
||||||
--- a/browser/base/content/navigator-toolbox.inc.xhtml
|
--- a/browser/base/content/navigator-toolbox.inc.xhtml
|
||||||
+++ b/browser/base/content/navigator-toolbox.inc.xhtml
|
+++ b/browser/base/content/navigator-toolbox.inc.xhtml
|
||||||
@@ -2,7 +2,7 @@
|
@@ -2,7 +2,7 @@
|
||||||
@@ -26,7 +26,7 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
|||||||
<toolbar id="TabsToolbar"
|
<toolbar id="TabsToolbar"
|
||||||
class="browser-toolbar browser-titlebar"
|
class="browser-toolbar browser-titlebar"
|
||||||
fullscreentoolbar="true"
|
fullscreentoolbar="true"
|
||||||
@@ -54,6 +58,8 @@
|
@@ -56,6 +60,8 @@
|
||||||
<html:sidebar-pins-promo id="drag-to-pin-promo-card"></html:sidebar-pins-promo>
|
<html:sidebar-pins-promo id="drag-to-pin-promo-card"></html:sidebar-pins-promo>
|
||||||
<arrowscrollbox id="pinned-tabs-container" orient="horizontal" clicktoscroll=""></arrowscrollbox>
|
<arrowscrollbox id="pinned-tabs-container" orient="horizontal" clicktoscroll=""></arrowscrollbox>
|
||||||
<splitter orient="vertical" id="vertical-pinned-tabs-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
<splitter orient="vertical" id="vertical-pinned-tabs-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
||||||
@@ -35,7 +35,7 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
|||||||
<hbox class="tab-drop-indicator" hidden="true"/>
|
<hbox class="tab-drop-indicator" hidden="true"/>
|
||||||
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" clicktoscroll="" scrolledtostart="" scrolledtoend="">
|
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" clicktoscroll="" scrolledtostart="" scrolledtoend="">
|
||||||
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="" visuallyselected="" fadein=""/>
|
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="" visuallyselected="" fadein=""/>
|
||||||
@@ -73,6 +79,7 @@
|
@@ -75,6 +81,7 @@
|
||||||
tooltip="dynamic-shortcut-tooltip"
|
tooltip="dynamic-shortcut-tooltip"
|
||||||
data-l10n-id="tabs-toolbar-new-tab"/>
|
data-l10n-id="tabs-toolbar-new-tab"/>
|
||||||
<html:span id="tabbrowser-tab-a11y-desc" hidden="true"/>
|
<html:span id="tabbrowser-tab-a11y-desc" hidden="true"/>
|
||||||
@@ -43,7 +43,7 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
|||||||
</tabs>
|
</tabs>
|
||||||
|
|
||||||
<toolbarbutton id="new-tab-button"
|
<toolbarbutton id="new-tab-button"
|
||||||
@@ -99,9 +106,10 @@
|
@@ -102,9 +109,10 @@
|
||||||
|
|
||||||
<toolbarbutton class="content-analysis-indicator toolbarbutton-1 content-analysis-indicator-icon"/>
|
<toolbarbutton class="content-analysis-indicator toolbarbutton-1 content-analysis-indicator-icon"/>
|
||||||
|
|
||||||
@@ -54,4 +54,4 @@ index dd2f391096968564086911c532f696dc7ffb8ae1..c968e5f0ebb5f0151fb124bafe10d8d5
|
|||||||
+</hbox>
|
+</hbox>
|
||||||
|
|
||||||
<toolbar id="nav-bar"
|
<toolbar id="nav-bar"
|
||||||
class="browser-toolbar chromeclass-location"
|
class="browser-toolbar"
|
||||||
|
|||||||
@@ -21,3 +21,4 @@
|
|||||||
#include ../../../zen/boosts/jar.inc.mn
|
#include ../../../zen/boosts/jar.inc.mn
|
||||||
#include ../../../zen/live-folders/jar.inc.mn
|
#include ../../../zen/live-folders/jar.inc.mn
|
||||||
#include ../../../zen/space-routing/jar.inc.mn
|
#include ../../../zen/space-routing/jar.inc.mn
|
||||||
|
#include ../../../zen/share/jar.inc.mn
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
<command id="cmd_zenSplitViewUnsplit" />
|
<command id="cmd_zenSplitViewUnsplit" />
|
||||||
<command id="cmd_zenSplitViewLinkInNewTab" />
|
<command id="cmd_zenSplitViewLinkInNewTab" />
|
||||||
<command id="cmd_zenSplitViewContextMenu" />
|
<command id="cmd_zenSplitViewContextMenu" />
|
||||||
|
<command id="cmd_zenCtxShareSplitView" />
|
||||||
<command id="cmd_zenNewEmptySplit" />
|
<command id="cmd_zenNewEmptySplit" />
|
||||||
|
|
||||||
<!-- Workspace commands -->
|
<!-- Workspace commands -->
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
<command id="cmd_contextZenRemoveFromEssentials" />
|
<command id="cmd_contextZenRemoveFromEssentials" />
|
||||||
|
|
||||||
<command id="cmd_zenCtxDeleteWorkspace" />
|
<command id="cmd_zenCtxDeleteWorkspace" />
|
||||||
|
<command id="cmd_zenCtxShareWorkspace" />
|
||||||
<command id="cmd_zenUnloadWorkspace" />
|
<command id="cmd_zenUnloadWorkspace" />
|
||||||
<command id="cmd_zenUnloadAllOtherWorkspace" />
|
<command id="cmd_zenUnloadAllOtherWorkspace" />
|
||||||
<command id="cmd_zenOpenSpaceRoutingSettings" />
|
<command id="cmd_zenOpenSpaceRoutingSettings" />
|
||||||
|
|||||||
@@ -12,4 +12,5 @@
|
|||||||
<link rel="localization" href="browser/zen-boosts.ftl"/>
|
<link rel="localization" href="browser/zen-boosts.ftl"/>
|
||||||
<link rel="localization" href="browser/zen-live-folders.ftl"/>
|
<link rel="localization" href="browser/zen-live-folders.ftl"/>
|
||||||
<link rel="localization" href="browser/zen-space-routing.ftl"/>
|
<link rel="localization" href="browser/zen-space-routing.ftl"/>
|
||||||
|
<link rel="localization" href="browser/zen-share.ftl"/>
|
||||||
</linkset>
|
</linkset>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
<menuitem id="context_zenUnloadAllOtherWorkspace" data-l10n-id="zen-workspaces-panel-unload-others" command="cmd_zenUnloadAllOtherWorkspace"/>
|
<menuitem id="context_zenUnloadAllOtherWorkspace" data-l10n-id="zen-workspaces-panel-unload-others" command="cmd_zenUnloadAllOtherWorkspace"/>
|
||||||
<menuseparator/>
|
<menuseparator/>
|
||||||
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation"/>
|
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation"/>
|
||||||
|
<menuitem id="context_zenShareWorkspace" data-l10n-id="zen-share-space" command="cmd_zenCtxShareWorkspace"/>
|
||||||
<menuitem id="context_zenDeleteWorkspace" data-l10n-id="zen-workspaces-panel-context-delete" command="cmd_zenCtxDeleteWorkspace"/>
|
<menuitem id="context_zenDeleteWorkspace" data-l10n-id="zen-workspaces-panel-context-delete" command="cmd_zenCtxDeleteWorkspace"/>
|
||||||
<menuseparator/>
|
<menuseparator/>
|
||||||
<menuitem id="context_zenSpaceRoutingSettings" data-l10n-id="zen-space-routing-settings" command="cmd_zenOpenSpaceRoutingSettings"/>
|
<menuitem id="context_zenSpaceRoutingSettings" data-l10n-id="zen-space-routing-settings" command="cmd_zenOpenSpaceRoutingSettings"/>
|
||||||
@@ -55,6 +56,7 @@
|
|||||||
<menupopup />
|
<menupopup />
|
||||||
</menu>
|
</menu>
|
||||||
<menuitem id="context_zenFolderToSpace" data-l10n-id="zen-folders-panel-convert-folder-to-space" />
|
<menuitem id="context_zenFolderToSpace" data-l10n-id="zen-folders-panel-convert-folder-to-space" />
|
||||||
|
<menuitem id="context_zenShareFolder" data-l10n-id="zen-share-folder"/>
|
||||||
<menuseparator />
|
<menuseparator />
|
||||||
<menuitem id="context_zenFolderUnpack" data-l10n-id="zen-folders-panel-unpack-folder"/>
|
<menuitem id="context_zenFolderUnpack" data-l10n-id="zen-folders-panel-unpack-folder"/>
|
||||||
<menuitem id="context_zenFolderDelete" data-l10n-id="zen-folders-panel-delete-folder"/>
|
<menuitem id="context_zenFolderDelete" data-l10n-id="zen-folders-panel-delete-folder"/>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/components/customizableui/CustomizableUI.sys.mjs b/browser/components/customizableui/CustomizableUI.sys.mjs
|
diff --git a/browser/components/customizableui/CustomizableUI.sys.mjs b/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||||
index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa13303d3a3 100644
|
index 875f8b03d979353ef44a57c15ef1ae09d33ab730..3d6e092e7ed126cdee8c32229df2cfa13303d3a3 100644
|
||||||
--- a/browser/components/customizableui/CustomizableUI.sys.mjs
|
--- a/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||||
+++ b/browser/components/customizableui/CustomizableUI.sys.mjs
|
+++ b/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||||
@@ -13,6 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
@@ -13,6 +13,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
@@ -19,7 +19,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
},
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
@@ -362,27 +363,23 @@ var CustomizableUIInternal = {
|
@@ -362,20 +363,15 @@ var CustomizableUIInternal = {
|
||||||
"back-button",
|
"back-button",
|
||||||
"forward-button",
|
"forward-button",
|
||||||
"stop-reload-button",
|
"stop-reload-button",
|
||||||
@@ -41,27 +41,29 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
this.registerArea(
|
this.registerArea(
|
||||||
CustomizableUI.AREA_NAVBAR,
|
CustomizableUI.AREA_NAVBAR,
|
||||||
{
|
{
|
||||||
type: CustomizableUI.TYPE_TOOLBAR,
|
@@ -383,9 +379,6 @@ var CustomizableUIInternal = {
|
||||||
overflowable: true,
|
overflowable: true,
|
||||||
defaultPlacements: navbarPlacements,
|
defaultPlacements: navbarPlacements,
|
||||||
- verticalTabsDefaultPlacements: ["alltabs-button", "ai-window-toggle"],
|
verticalTabsDefaultPlacements: [
|
||||||
+ verticalTabsDefaultPlacements: [
|
- "alltabs-button",
|
||||||
+ ],
|
- "smartwindow-group-tabs-button",
|
||||||
|
- "ai-window-toggle",
|
||||||
|
],
|
||||||
defaultCollapsed: false,
|
defaultCollapsed: false,
|
||||||
},
|
},
|
||||||
true
|
@@ -410,11 +403,6 @@ var CustomizableUIInternal = {
|
||||||
@@ -406,10 +403,6 @@ var CustomizableUIInternal = {
|
|
||||||
type: CustomizableUI.TYPE_TOOLBAR,
|
type: CustomizableUI.TYPE_TOOLBAR,
|
||||||
defaultPlacements: [
|
defaultPlacements: [
|
||||||
"tabbrowser-tabs",
|
"tabbrowser-tabs",
|
||||||
- "new-tab-button",
|
- "new-tab-button",
|
||||||
- "spring",
|
- "spring",
|
||||||
- "alltabs-button",
|
- "alltabs-button",
|
||||||
|
- "smartwindow-group-tabs-button",
|
||||||
- "ai-window-toggle",
|
- "ai-window-toggle",
|
||||||
],
|
],
|
||||||
verticalTabsDefaultPlacements: [],
|
verticalTabsDefaultPlacements: [],
|
||||||
defaultCollapsed: null,
|
defaultCollapsed: null,
|
||||||
@@ -502,6 +495,7 @@ var CustomizableUIInternal = {
|
@@ -507,6 +495,7 @@ var CustomizableUIInternal = {
|
||||||
CustomizableUI.AREA_NAVBAR,
|
CustomizableUI.AREA_NAVBAR,
|
||||||
CustomizableUI.AREA_BOOKMARKS,
|
CustomizableUI.AREA_BOOKMARKS,
|
||||||
CustomizableUI.AREA_TABSTRIP,
|
CustomizableUI.AREA_TABSTRIP,
|
||||||
@@ -69,7 +71,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
]);
|
]);
|
||||||
if (AppConstants.platform != "macosx") {
|
if (AppConstants.platform != "macosx") {
|
||||||
toolbars.add(CustomizableUI.AREA_MENUBAR);
|
toolbars.add(CustomizableUI.AREA_MENUBAR);
|
||||||
@@ -1334,6 +1328,9 @@ var CustomizableUIInternal = {
|
@@ -1339,6 +1328,9 @@ var CustomizableUIInternal = {
|
||||||
placements = gPlacements.get(area);
|
placements = gPlacements.get(area);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +81,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
// For toolbars that need it, mark as dirty.
|
// For toolbars that need it, mark as dirty.
|
||||||
let defaultPlacements = areaProperties.get("defaultPlacements");
|
let defaultPlacements = areaProperties.get("defaultPlacements");
|
||||||
if (
|
if (
|
||||||
@@ -1842,7 +1839,6 @@ var CustomizableUIInternal = {
|
@@ -1847,7 +1839,6 @@ var CustomizableUIInternal = {
|
||||||
lazy.log.info(
|
lazy.log.info(
|
||||||
"Widget " + aWidgetId + " not found, unable to remove from " + aArea
|
"Widget " + aWidgetId + " not found, unable to remove from " + aArea
|
||||||
);
|
);
|
||||||
@@ -87,7 +89,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.notifyDOMChange(widgetNode, null, container, true, () => {
|
this.notifyDOMChange(widgetNode, null, container, true, () => {
|
||||||
@@ -1852,7 +1848,7 @@ var CustomizableUIInternal = {
|
@@ -1857,7 +1848,7 @@ var CustomizableUIInternal = {
|
||||||
// We also need to remove the panel context menu if it's there:
|
// We also need to remove the panel context menu if it's there:
|
||||||
this.ensureButtonContextMenu(widgetNode);
|
this.ensureButtonContextMenu(widgetNode);
|
||||||
if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
|
if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
|
||||||
@@ -96,7 +98,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
} else {
|
} else {
|
||||||
window.gNavToolbox.palette.appendChild(widgetNode);
|
window.gNavToolbox.palette.appendChild(widgetNode);
|
||||||
}
|
}
|
||||||
@@ -2020,16 +2016,16 @@ var CustomizableUIInternal = {
|
@@ -2025,16 +2016,16 @@ var CustomizableUIInternal = {
|
||||||
elem.setAttribute("skipintoolbarset", "true");
|
elem.setAttribute("skipintoolbarset", "true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +118,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
// Handle initial state of vertical tabs.
|
// Handle initial state of vertical tabs.
|
||||||
if (isVerticalTabs) {
|
if (isVerticalTabs) {
|
||||||
// Show the vertical tabs toolbar
|
// Show the vertical tabs toolbar
|
||||||
@@ -2271,6 +2267,10 @@ var CustomizableUIInternal = {
|
@@ -2276,6 +2267,10 @@ var CustomizableUIInternal = {
|
||||||
* The identifier string of the area that aNode is being inserted into.
|
* The identifier string of the area that aNode is being inserted into.
|
||||||
*/
|
*/
|
||||||
insertWidgetBefore(aNode, aNextNode, aContainer, aAreaId) {
|
insertWidgetBefore(aNode, aNextNode, aContainer, aAreaId) {
|
||||||
@@ -127,7 +129,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
this.notifyDOMChange(aNode, aNextNode, aContainer, false, () => {
|
this.notifyDOMChange(aNode, aNextNode, aContainer, false, () => {
|
||||||
this.setLocationAttributes(aNode, aAreaId);
|
this.setLocationAttributes(aNode, aAreaId);
|
||||||
aContainer.insertBefore(aNode, aNextNode);
|
aContainer.insertBefore(aNode, aNextNode);
|
||||||
@@ -4647,7 +4647,7 @@ var CustomizableUIInternal = {
|
@@ -4652,7 +4647,7 @@ var CustomizableUIInternal = {
|
||||||
* For all registered areas, builds those areas to reflect the current
|
* For all registered areas, builds those areas to reflect the current
|
||||||
* placement state of all widgets.
|
* placement state of all widgets.
|
||||||
*/
|
*/
|
||||||
@@ -136,7 +138,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
for (let [areaId, areaNodes] of gBuildAreas) {
|
for (let [areaId, areaNodes] of gBuildAreas) {
|
||||||
let placements = gPlacements.get(areaId);
|
let placements = gPlacements.get(areaId);
|
||||||
let isFirstChangedToolbar = true;
|
let isFirstChangedToolbar = true;
|
||||||
@@ -4658,7 +4658,7 @@ var CustomizableUIInternal = {
|
@@ -4663,7 +4658,7 @@ var CustomizableUIInternal = {
|
||||||
if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) {
|
if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) {
|
||||||
let defaultCollapsed = area.get("defaultCollapsed");
|
let defaultCollapsed = area.get("defaultCollapsed");
|
||||||
let win = areaNode.documentGlobal;
|
let win = areaNode.documentGlobal;
|
||||||
@@ -145,7 +147,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
win.setToolbarVisibility(
|
win.setToolbarVisibility(
|
||||||
areaNode,
|
areaNode,
|
||||||
typeof defaultCollapsed == "string"
|
typeof defaultCollapsed == "string"
|
||||||
@@ -5971,6 +5971,7 @@ export var CustomizableUI = {
|
@@ -5976,6 +5971,7 @@ export var CustomizableUI = {
|
||||||
unregisterArea(aName, aDestroyPlacements) {
|
unregisterArea(aName, aDestroyPlacements) {
|
||||||
CustomizableUIInternal.unregisterArea(aName, aDestroyPlacements);
|
CustomizableUIInternal.unregisterArea(aName, aDestroyPlacements);
|
||||||
},
|
},
|
||||||
@@ -153,7 +155,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
/**
|
/**
|
||||||
* Add a widget to an area.
|
* Add a widget to an area.
|
||||||
* If the area to which you try to add is not known to CustomizableUI,
|
* If the area to which you try to add is not known to CustomizableUI,
|
||||||
@@ -7946,7 +7947,9 @@ class OverflowableToolbar {
|
@@ -7951,7 +7947,9 @@ class OverflowableToolbar {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (webExtList && CustomizableUI.isWebExtensionWidget(child.id)) {
|
if (webExtList && CustomizableUI.isWebExtensionWidget(child.id)) {
|
||||||
@@ -163,7 +165,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
webExtList.insertBefore(child, webExtList.firstElementChild);
|
webExtList.insertBefore(child, webExtList.firstElementChild);
|
||||||
} else {
|
} else {
|
||||||
child.setAttribute("cui-anchorid", this.#defaultListButton.id);
|
child.setAttribute("cui-anchorid", this.#defaultListButton.id);
|
||||||
@@ -7995,6 +7998,7 @@ class OverflowableToolbar {
|
@@ -8000,6 +7998,7 @@ class OverflowableToolbar {
|
||||||
return aElement.getBoundingClientRect().width;
|
return aElement.getBoundingClientRect().width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +173,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
function sumChildrenInlineSize(aParent, aExceptChild = null) {
|
function sumChildrenInlineSize(aParent, aExceptChild = null) {
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
for (let child of aParent.children) {
|
for (let child of aParent.children) {
|
||||||
@@ -8006,7 +8010,10 @@ class OverflowableToolbar {
|
@@ -8011,7 +8010,10 @@ class OverflowableToolbar {
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -183,7 +185,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
if (child != aExceptChild) {
|
if (child != aExceptChild) {
|
||||||
sum += getInlineSize(child);
|
sum += getInlineSize(child);
|
||||||
}
|
}
|
||||||
@@ -8030,11 +8037,11 @@ class OverflowableToolbar {
|
@@ -8035,11 +8037,11 @@ class OverflowableToolbar {
|
||||||
parseFloat(style.paddingLeft) -
|
parseFloat(style.paddingLeft) -
|
||||||
parseFloat(style.paddingRight) -
|
parseFloat(style.paddingRight) -
|
||||||
toolbarChildrenWidth;
|
toolbarChildrenWidth;
|
||||||
@@ -197,7 +199,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
});
|
});
|
||||||
|
|
||||||
lazy.log.debug(
|
lazy.log.debug(
|
||||||
@@ -8049,7 +8056,39 @@ class OverflowableToolbar {
|
@@ -8054,7 +8056,39 @@ class OverflowableToolbar {
|
||||||
Math.max(targetWidth, targetChildrenWidth)
|
Math.max(targetWidth, targetChildrenWidth)
|
||||||
);
|
);
|
||||||
totalAvailWidth = Math.ceil(totalAvailWidth);
|
totalAvailWidth = Math.ceil(totalAvailWidth);
|
||||||
@@ -238,7 +240,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
return { isOverflowing, targetContentWidth, totalAvailWidth };
|
return { isOverflowing, targetContentWidth, totalAvailWidth };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8110,7 +8149,11 @@ class OverflowableToolbar {
|
@@ -8115,7 +8149,11 @@ class OverflowableToolbar {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,7 +253,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
lazy.log.debug(
|
lazy.log.debug(
|
||||||
`Need ${minSize} but width is ${totalAvailWidth} so bailing`
|
`Need ${minSize} but width is ${totalAvailWidth} so bailing`
|
||||||
);
|
);
|
||||||
@@ -8143,7 +8186,7 @@ class OverflowableToolbar {
|
@@ -8148,7 +8186,7 @@ class OverflowableToolbar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
@@ -260,7 +262,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
}
|
}
|
||||||
child.removeAttribute("cui-anchorid");
|
child.removeAttribute("cui-anchorid");
|
||||||
child.removeAttribute("overflowedItem");
|
child.removeAttribute("overflowedItem");
|
||||||
@@ -8269,6 +8312,9 @@ class OverflowableToolbar {
|
@@ -8274,6 +8312,9 @@ class OverflowableToolbar {
|
||||||
* if no such list exists.
|
* if no such list exists.
|
||||||
*/
|
*/
|
||||||
get #webExtList() {
|
get #webExtList() {
|
||||||
@@ -270,7 +272,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
if (!this.#webExtListRef) {
|
if (!this.#webExtListRef) {
|
||||||
let targetID = this.#toolbar.getAttribute("addon-webext-overflowtarget");
|
let targetID = this.#toolbar.getAttribute("addon-webext-overflowtarget");
|
||||||
if (!targetID) {
|
if (!targetID) {
|
||||||
@@ -8280,6 +8326,9 @@ class OverflowableToolbar {
|
@@ -8285,6 +8326,9 @@ class OverflowableToolbar {
|
||||||
let win = this.#toolbar.documentGlobal;
|
let win = this.#toolbar.documentGlobal;
|
||||||
let { panel } = win.gUnifiedExtensions;
|
let { panel } = win.gUnifiedExtensions;
|
||||||
this.#webExtListRef = panel.querySelector(`#${targetID}`);
|
this.#webExtListRef = panel.querySelector(`#${targetID}`);
|
||||||
@@ -280,7 +282,7 @@ index 6d1885a54815d10b3a4e79f7e5acd61ab3abb159..3d6e092e7ed126cdee8c32229df2cfa1
|
|||||||
}
|
}
|
||||||
return this.#webExtListRef;
|
return this.#webExtListRef;
|
||||||
}
|
}
|
||||||
@@ -8488,7 +8537,7 @@ class OverflowableToolbar {
|
@@ -8493,7 +8537,7 @@ class OverflowableToolbar {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "mousedown": {
|
case "mousedown": {
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
diff --git a/browser/components/preferences/config/account-sync.mjs b/browser/components/preferences/config/account-sync.mjs
|
diff --git a/browser/components/preferences/config/account-sync.mjs b/browser/components/preferences/config/account-sync.mjs
|
||||||
index b01fd4bb163ad53139fcbd8e79e12ef994d1fa13..dd60be4fe268618d6596cd5cfac3342975bd241a 100644
|
index b01fd4bb163ad53139fcbd8e79e12ef994d1fa13..7e3c2f6852b77192b4505bb3d5a7b58586da6548 100644
|
||||||
--- a/browser/components/preferences/config/account-sync.mjs
|
--- a/browser/components/preferences/config/account-sync.mjs
|
||||||
+++ b/browser/components/preferences/config/account-sync.mjs
|
+++ b/browser/components/preferences/config/account-sync.mjs
|
||||||
@@ -46,6 +46,7 @@ Preferences.addAll([
|
@@ -46,6 +46,8 @@ Preferences.addAll([
|
||||||
{ id: "services.sync.engine.creditcards", type: "bool" },
|
{ id: "services.sync.engine.creditcards", type: "bool" },
|
||||||
{ id: "services.sync.engine.addons", type: "bool" },
|
{ id: "services.sync.engine.addons", type: "bool" },
|
||||||
{ id: "services.sync.engine.prefs", type: "bool" },
|
{ id: "services.sync.engine.prefs", type: "bool" },
|
||||||
+ { id: "services.sync.engine.spaces", type: "bool" },
|
+ { id: "services.sync.engine.spaces", type: "bool" },
|
||||||
|
+ { id: "zen.spaces-sync.normal-tabs", type: "bool" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -557,6 +558,7 @@ const SYNC_ENGINE_SETTINGS = [
|
@@ -557,6 +559,7 @@ const SYNC_ENGINE_SETTINGS = [
|
||||||
type: "payments",
|
type: "payments",
|
||||||
},
|
},
|
||||||
{ id: "syncAddons", pref: "services.sync.engine.addons", type: "addons" },
|
{ id: "syncAddons", pref: "services.sync.engine.addons", type: "addons" },
|
||||||
@@ -18,7 +19,7 @@ index b01fd4bb163ad53139fcbd8e79e12ef994d1fa13..dd60be4fe268618d6596cd5cfac33429
|
|||||||
{ id: "syncSettings", pref: "services.sync.engine.prefs", type: "settings" },
|
{ id: "syncSettings", pref: "services.sync.engine.prefs", type: "settings" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -564,6 +566,12 @@ SYNC_ENGINE_SETTINGS.forEach(({ id, pref }) => {
|
@@ -564,6 +567,18 @@ SYNC_ENGINE_SETTINGS.forEach(({ id, pref }) => {
|
||||||
Preferences.addSetting({ id, pref });
|
Preferences.addSetting({ id, pref });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,11 +28,17 @@ index b01fd4bb163ad53139fcbd8e79e12ef994d1fa13..dd60be4fe268618d6596cd5cfac33429
|
|||||||
+ id: "zenSyncWorkspaces",
|
+ id: "zenSyncWorkspaces",
|
||||||
+ pref: "services.sync.engine.spaces",
|
+ pref: "services.sync.engine.spaces",
|
||||||
+});
|
+});
|
||||||
|
+Preferences.addSetting({
|
||||||
|
+ id: "zenSyncNormalTabs",
|
||||||
|
+ pref: "zen.spaces-sync.normal-tabs",
|
||||||
|
+ deps: ["zenSyncWorkspaces"],
|
||||||
|
+ visible: deps => !!deps.zenSyncWorkspaces.value,
|
||||||
|
+});
|
||||||
+
|
+
|
||||||
Preferences.addSetting({
|
Preferences.addSetting({
|
||||||
id: "syncEngines",
|
id: "syncEngines",
|
||||||
deps: SYNC_ENGINE_SETTINGS.map(({ id }) => id),
|
deps: SYNC_ENGINE_SETTINGS.map(({ id }) => id),
|
||||||
@@ -995,6 +1003,20 @@ SettingGroupManager.registerGroups({
|
@@ -995,6 +1010,27 @@ SettingGroupManager.registerGroups({
|
||||||
id: "syncEnginesList",
|
id: "syncEnginesList",
|
||||||
control: "sync-engines-list",
|
control: "sync-engines-list",
|
||||||
},
|
},
|
||||||
@@ -46,6 +53,13 @@ index b01fd4bb163ad53139fcbd8e79e12ef994d1fa13..dd60be4fe268618d6596cd5cfac33429
|
|||||||
+ controlAttrs: {
|
+ controlAttrs: {
|
||||||
+ inputlayout: "inline-end",
|
+ inputlayout: "inline-end",
|
||||||
+ },
|
+ },
|
||||||
|
+ items: [
|
||||||
|
+ {
|
||||||
|
+ id: "zenSyncNormalTabs",
|
||||||
|
+ l10nId: "zen-settings-normal-tabs-sync",
|
||||||
|
+ control: "moz-checkbox",
|
||||||
|
+ },
|
||||||
|
+ ],
|
||||||
+ },
|
+ },
|
||||||
+ ],
|
+ ],
|
||||||
+ },
|
+ },
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js
|
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js
|
||||||
index 88675d1bcbf000b10d85a9c0980bc6069d88052c..ed3a1e809eb0fcccc5a957be7affb77be8978e32 100644
|
index 5a56d348146c1c37c088ced60327fffebcf8fac0..abd65594d365fbc0a74af3953c71f410301898ad 100644
|
||||||
--- a/browser/components/preferences/main.js
|
--- a/browser/components/preferences/main.js
|
||||||
+++ b/browser/components/preferences/main.js
|
+++ b/browser/components/preferences/main.js
|
||||||
@@ -528,6 +528,11 @@ function createStartupConfig(hidden = false) {
|
@@ -529,6 +529,11 @@ function createStartupConfig(hidden = false) {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -14,7 +14,7 @@ index 88675d1bcbf000b10d85a9c0980bc6069d88052c..ed3a1e809eb0fcccc5a957be7affb77b
|
|||||||
{
|
{
|
||||||
id: "windowsLaunchOnLogin",
|
id: "windowsLaunchOnLogin",
|
||||||
l10nId: "windows-launch-on-login",
|
l10nId: "windows-launch-on-login",
|
||||||
@@ -575,7 +580,7 @@ function createStartupConfig(hidden = false) {
|
@@ -576,7 +581,7 @@ function createStartupConfig(hidden = false) {
|
||||||
SettingGroupManager.registerGroups({
|
SettingGroupManager.registerGroups({
|
||||||
defaultBrowser: createDefaultBrowserConfig(),
|
defaultBrowser: createDefaultBrowserConfig(),
|
||||||
startup: createStartupConfig(
|
startup: createStartupConfig(
|
||||||
@@ -23,7 +23,7 @@ index 88675d1bcbf000b10d85a9c0980bc6069d88052c..ed3a1e809eb0fcccc5a957be7affb77b
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -628,7 +633,7 @@ function getBundleForLocales(newLocales) {
|
@@ -636,7 +641,7 @@ function getBundleForLocales(newLocales) {
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
return new Localization(
|
return new Localization(
|
||||||
|
|||||||
@@ -38,9 +38,16 @@ var gZenMarketplaceManager = {
|
|||||||
|
|
||||||
this.__hasInitializedEvents = true;
|
this.__hasInitializedEvents = true;
|
||||||
|
|
||||||
await this._buildModsList();
|
|
||||||
|
|
||||||
Services.prefs.addObserver(gZenMods.updatePref, this);
|
Services.prefs.addObserver(gZenMods.updatePref, this);
|
||||||
|
window.addEventListener(
|
||||||
|
"unload",
|
||||||
|
() => {
|
||||||
|
Services.prefs.removeObserver(gZenMods.updatePref, this);
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
await this._buildModsList();
|
||||||
|
|
||||||
const checkForUpdateClick = (event) => {
|
const checkForUpdateClick = (event) => {
|
||||||
if (event.target === checkForUpdates) {
|
if (event.target === checkForUpdates) {
|
||||||
@@ -69,7 +76,6 @@ var gZenMarketplaceManager = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("unload", () => {
|
window.addEventListener("unload", () => {
|
||||||
Services.prefs.removeObserver(gZenMods.updatePref, this);
|
|
||||||
this.__hasInitializedEvents = false;
|
this.__hasInitializedEvents = false;
|
||||||
|
|
||||||
document.removeEventListener("ZenModsMarketplace:CheckForUpdatesFinished", this);
|
document.removeEventListener("ZenModsMarketplace:CheckForUpdatesFinished", this);
|
||||||
@@ -735,7 +741,6 @@ var gZenWorkspacesSettings = {
|
|||||||
|
|
||||||
Services.prefs.addObserver("zen.glance.enabled", tabsUnloaderPrefListener); // We can use the same listener for both prefs
|
Services.prefs.addObserver("zen.glance.enabled", tabsUnloaderPrefListener); // We can use the same listener for both prefs
|
||||||
Services.prefs.addObserver("zen.workspaces.separate-essentials", tabsUnloaderPrefListener);
|
Services.prefs.addObserver("zen.workspaces.separate-essentials", tabsUnloaderPrefListener);
|
||||||
Services.prefs.addObserver("zen.glance.activation-method", tabsUnloaderPrefListener);
|
|
||||||
Services.prefs.addObserver("zen.window-sync.sync-only-pinned-tabs", tabsUnloaderPrefListener);
|
Services.prefs.addObserver("zen.window-sync.sync-only-pinned-tabs", tabsUnloaderPrefListener);
|
||||||
Services.prefs.addObserver(
|
Services.prefs.addObserver(
|
||||||
"zen.tabs.ctrl-tab.ignore-essential-tabs",
|
"zen.tabs.ctrl-tab.ignore-essential-tabs",
|
||||||
@@ -744,7 +749,6 @@ var gZenWorkspacesSettings = {
|
|||||||
Services.prefs.addObserver("browser.ctrlTab.sortByRecentlyUsed", toggleZenCycleByAttrWarning);
|
Services.prefs.addObserver("browser.ctrlTab.sortByRecentlyUsed", toggleZenCycleByAttrWarning);
|
||||||
window.addEventListener("unload", () => {
|
window.addEventListener("unload", () => {
|
||||||
Services.prefs.removeObserver("zen.glance.enabled", tabsUnloaderPrefListener);
|
Services.prefs.removeObserver("zen.glance.enabled", tabsUnloaderPrefListener);
|
||||||
Services.prefs.removeObserver("zen.glance.activation-method", tabsUnloaderPrefListener);
|
|
||||||
Services.prefs.removeObserver("zen.workspaces.separate-essentials", tabsUnloaderPrefListener);
|
Services.prefs.removeObserver("zen.workspaces.separate-essentials", tabsUnloaderPrefListener);
|
||||||
Services.prefs.removeObserver(
|
Services.prefs.removeObserver(
|
||||||
"zen.window-sync.sync-only-pinned-tabs",
|
"zen.window-sync.sync-only-pinned-tabs",
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
diff --git a/browser/components/sessionstore/SessionFile.sys.mjs b/browser/components/sessionstore/SessionFile.sys.mjs
|
diff --git a/browser/components/sessionstore/SessionFile.sys.mjs b/browser/components/sessionstore/SessionFile.sys.mjs
|
||||||
index 5580838acd72bf0e1189d367984859529d89f5b4..e5fa6076a9cc6ada016ccc4e129cad455010a522 100644
|
index 370e5c105c3d9bee05c2d9d7b63d0ee45b8331e1..1c37c19794ebe863a25f780e9a74d63526b929d7 100644
|
||||||
--- a/browser/components/sessionstore/SessionFile.sys.mjs
|
--- a/browser/components/sessionstore/SessionFile.sys.mjs
|
||||||
+++ b/browser/components/sessionstore/SessionFile.sys.mjs
|
+++ b/browser/components/sessionstore/SessionFile.sys.mjs
|
||||||
@@ -22,6 +22,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
@@ -25,6 +25,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||||
RunState: "resource:///modules/sessionstore/RunState.sys.mjs",
|
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
SessionWriter:
|
||||||
SessionWriter: "resource:///modules/sessionstore/SessionWriter.sys.mjs",
|
"moz-src:///browser/components/sessionstore/SessionWriter.sys.mjs",
|
||||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||||
});
|
});
|
||||||
|
|
||||||
const PREF_UPGRADE_BACKUP = "browser.sessionstore.upgradeBackup.latestBuildID";
|
const PREF_UPGRADE_BACKUP = "browser.sessionstore.upgradeBackup.latestBuildID";
|
||||||
@@ -381,7 +382,7 @@ var SessionFileInternal = {
|
@@ -384,7 +385,7 @@ var SessionFileInternal = {
|
||||||
this._readOrigin = result.origin;
|
this._readOrigin = result.origin;
|
||||||
|
|
||||||
result.noFilesFound = noFilesFound;
|
result.noFilesFound = noFilesFound;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
diff --git a/browser/components/sessionstore/SessionSaver.sys.mjs b/browser/components/sessionstore/SessionSaver.sys.mjs
|
diff --git a/browser/components/sessionstore/SessionSaver.sys.mjs b/browser/components/sessionstore/SessionSaver.sys.mjs
|
||||||
index 9141793550f7c7ff6aa63d4c85bf571b4499e2d0..6906fd9be7ae6ca4316133e0d6552b797c54a7ec 100644
|
index 1f26bc5fdb83f55bdf0b9b7d01fafe1cd37f77f4..5916f741d0fa04c392dcdd10f843e595fe5e058c 100644
|
||||||
--- a/browser/components/sessionstore/SessionSaver.sys.mjs
|
--- a/browser/components/sessionstore/SessionSaver.sys.mjs
|
||||||
+++ b/browser/components/sessionstore/SessionSaver.sys.mjs
|
+++ b/browser/components/sessionstore/SessionSaver.sys.mjs
|
||||||
@@ -20,6 +20,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
@@ -20,6 +20,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||||
SessionFile: "resource:///modules/sessionstore/SessionFile.sys.mjs",
|
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
sessionStoreLogger:
|
||||||
sessionStoreLogger: "resource:///modules/sessionstore/SessionLogger.sys.mjs",
|
"moz-src:///browser/components/sessionstore/SessionLogger.sys.mjs",
|
||||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
diff --git a/browser/components/sessionstore/SessionStartup.sys.mjs b/browser/components/sessionstore/SessionStartup.sys.mjs
|
diff --git a/browser/components/sessionstore/SessionStartup.sys.mjs b/browser/components/sessionstore/SessionStartup.sys.mjs
|
||||||
index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b595052264c67d351 100644
|
index 919d4536c5462603346684bbe26794ae9279b517..5a8fae0708e4a9a82c5e85f8a473ebaeafebe71f 100644
|
||||||
--- a/browser/components/sessionstore/SessionStartup.sys.mjs
|
--- a/browser/components/sessionstore/SessionStartup.sys.mjs
|
||||||
+++ b/browser/components/sessionstore/SessionStartup.sys.mjs
|
+++ b/browser/components/sessionstore/SessionStartup.sys.mjs
|
||||||
@@ -40,6 +40,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
@@ -41,6 +41,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||||
StartupPerformance:
|
"moz-src:///browser/components/sessionstore/StartupPerformance.sys.mjs",
|
||||||
"resource:///modules/sessionstore/StartupPerformance.sys.mjs",
|
sessionStoreLogger:
|
||||||
sessionStoreLogger: "resource:///modules/sessionstore/SessionLogger.sys.mjs",
|
"moz-src:///browser/components/sessionstore/SessionLogger.sys.mjs",
|
||||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||||
});
|
});
|
||||||
|
|
||||||
const STATE_RUNNING_STR = "running";
|
const STATE_RUNNING_STR = "running";
|
||||||
@@ -85,7 +86,7 @@ export var SessionStartup = {
|
@@ -86,7 +87,7 @@ export var SessionStartup = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not need to initialize anything in auto-started private browsing sessions
|
// do not need to initialize anything in auto-started private browsing sessions
|
||||||
@@ -19,7 +19,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
|||||||
this._initialized = true;
|
this._initialized = true;
|
||||||
gOnceInitializedDeferred.resolve();
|
gOnceInitializedDeferred.resolve();
|
||||||
return;
|
return;
|
||||||
@@ -179,6 +180,8 @@ export var SessionStartup = {
|
@@ -180,6 +181,8 @@ export var SessionStartup = {
|
||||||
this._initialState = parsed;
|
this._initialState = parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
|||||||
if (this._initialState == null) {
|
if (this._initialState == null) {
|
||||||
// No valid session found.
|
// No valid session found.
|
||||||
this._sessionType = this.NO_SESSION;
|
this._sessionType = this.NO_SESSION;
|
||||||
@@ -276,6 +279,8 @@ export var SessionStartup = {
|
@@ -277,6 +280,8 @@ export var SessionStartup = {
|
||||||
`Previous shutdown ok? ${this._previousSessionCrashed}, reason: ${previousSessionCrashedReason}`
|
`Previous shutdown ok? ${this._previousSessionCrashed}, reason: ${previousSessionCrashedReason}`
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
|||||||
Services.obs.addObserver(this, "sessionstore-windows-restored", true);
|
Services.obs.addObserver(this, "sessionstore-windows-restored", true);
|
||||||
|
|
||||||
if (this.sessionType == this.NO_SESSION) {
|
if (this.sessionType == this.NO_SESSION) {
|
||||||
@@ -336,12 +341,7 @@ export var SessionStartup = {
|
@@ -337,12 +342,7 @@ export var SessionStartup = {
|
||||||
isAutomaticRestoreEnabled() {
|
isAutomaticRestoreEnabled() {
|
||||||
if (this._resumeSessionEnabled === null) {
|
if (this._resumeSessionEnabled === null) {
|
||||||
this._resumeSessionEnabled =
|
this._resumeSessionEnabled =
|
||||||
@@ -51,7 +51,7 @@ index 86600ffb5178599ab23270a964064ca657a3283f..70d7b5c7d69d3700475d663b59505226
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this._resumeSessionEnabled;
|
return this._resumeSessionEnabled;
|
||||||
@@ -354,8 +354,7 @@ export var SessionStartup = {
|
@@ -355,8 +355,7 @@ export var SessionStartup = {
|
||||||
*/
|
*/
|
||||||
willRestore() {
|
willRestore() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
|
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
|
||||||
index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2ab6e6c967 100644
|
index 52fc803050cd257d6de52b1e4a92f3211cbaba88..a9841832ddce540dc0f9b14c29e5eadac7510935 100644
|
||||||
--- a/browser/components/sessionstore/SessionStore.sys.mjs
|
--- a/browser/components/sessionstore/SessionStore.sys.mjs
|
||||||
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
|
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
|
||||||
@@ -129,6 +129,11 @@ const TAB_EVENTS = [
|
@@ -111,6 +111,11 @@ const TAB_EVENTS = [
|
||||||
"TabSplitViewActivate",
|
"TabSplitViewActivate",
|
||||||
"SplitViewRemoved",
|
"SplitViewRemoved",
|
||||||
"SplitViewCreated",
|
"SplitViewCreated",
|
||||||
@@ -14,16 +14,39 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
];
|
];
|
||||||
|
|
||||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||||
@@ -201,6 +206,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
@@ -185,6 +190,8 @@ const lazy = XPCOMUtils.declareLazy({
|
||||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
TabStateFlusher:
|
||||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs",
|
||||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
+ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||||
+ ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
+ ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||||
});
|
blankURI: () => Services.io.newURI("about:blank"),
|
||||||
|
gRestoreWindowsToVirtualDesktop: {
|
||||||
|
pref: "browser.sessionstore.restore_windows_to_virtual_desktop",
|
||||||
|
@@ -348,6 +355,22 @@ class _SessionStore {
|
||||||
|
return this.#shouldRestoreLastSession;
|
||||||
|
}
|
||||||
|
|
||||||
ChromeUtils.defineLazyGetter(lazy, "blankURI", () => {
|
+ get _windows() {
|
||||||
@@ -1317,10 +1324,7 @@ var SessionStoreInternal = {
|
+ return this.#windows;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ get _browserWindows() {
|
||||||
|
+ return this.#browserWindows;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ set _deferredInitialState(aState) {
|
||||||
|
+ this.#deferredInitialState = aState;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ initializeWindow(aWindow, aInitialState) {
|
||||||
|
+ this.#initializeWindow(aWindow, aInitialState);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// whether we will potentially be restoring the session
|
||||||
|
// more than once without Firefox restarting in between
|
||||||
|
#restoreWithoutRestart = false;
|
||||||
|
@@ -515,10 +538,7 @@ class _SessionStore {
|
||||||
*/
|
*/
|
||||||
get willAutoRestore() {
|
get willAutoRestore() {
|
||||||
return (
|
return (
|
||||||
@@ -33,9 +56,9 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
- BROWSER_STARTUP_RESUME_SESSION)
|
- BROWSER_STARTUP_RESUME_SESSION)
|
||||||
+ true
|
+ true
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@@ -2008,6 +2012,11 @@ var SessionStoreInternal = {
|
@@ -1215,6 +1235,11 @@ class _SessionStore {
|
||||||
case "TabPinned":
|
case "TabPinned":
|
||||||
case "TabUnpinned":
|
case "TabUnpinned":
|
||||||
case "SwapDocShells":
|
case "SwapDocShells":
|
||||||
@@ -44,47 +67,47 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
+ case "TabMove":
|
+ case "TabMove":
|
||||||
+ case "TabGroupMoved":
|
+ case "TabGroupMoved":
|
||||||
+ case "ZenWorkspaceDataChanged":
|
+ case "ZenWorkspaceDataChanged":
|
||||||
this.saveStateDelayed(win);
|
this.#saveStateDelayed(win);
|
||||||
break;
|
break;
|
||||||
case "TabGroupCreate":
|
case "TabGroupCreate":
|
||||||
@@ -2117,6 +2126,10 @@ var SessionStoreInternal = {
|
@@ -1341,6 +1366,10 @@ class _SessionStore {
|
||||||
this._windows[aWindow.__SSi].isTaskbarTab = true;
|
this.#windows[aWindow.__SSi].isTaskbarTab = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ if (aWindow.document.documentElement.hasAttribute("zen-unsynced-window")) {
|
+ if (aWindow.document.documentElement.hasAttribute("zen-unsynced-window")) {
|
||||||
+ this._windows[aWindow.__SSi].isZenUnsynced = true;
|
+ this.#windows[aWindow.__SSi].isZenUnsynced = true;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
if (lazy.AIWindow.isAIWindowActiveAndEnabled(aWindow)) {
|
if (lazy.AIWindow.isAIWindowActiveAndEnabled(aWindow)) {
|
||||||
this._windows[aWindow.__SSi].isAIWindow = true;
|
this.#windows[aWindow.__SSi].isAIWindow = true;
|
||||||
}
|
}
|
||||||
@@ -2153,7 +2166,7 @@ var SessionStoreInternal = {
|
@@ -1377,7 +1406,7 @@ class _SessionStore {
|
||||||
let isTaskbarTab = this._windows[aWindow.__SSi].isTaskbarTab;
|
let isTaskbarTab = this.#windows[aWindow.__SSi].isTaskbarTab;
|
||||||
// A regular window is not a private window, taskbar tab window, or popup window
|
// A regular window is not a private window, taskbar tab window, or popup window
|
||||||
let isRegularWindow =
|
let isRegularWindow =
|
||||||
- !isPrivateWindow && !isTaskbarTab && aWindow.toolbar.visible;
|
- !isPrivateWindow && !isTaskbarTab && aWindow.toolbar.visible;
|
||||||
+ !isPrivateWindow && !isTaskbarTab && aWindow.toolbar.visible && !this._windows[aWindow.__SSi].isZenUnsynced;
|
+ !isPrivateWindow && !isTaskbarTab && aWindow.toolbar.visible && !this.#windows[aWindow.__SSi].isZenUnsynced;
|
||||||
|
|
||||||
// perform additional initialization when the first window is loading
|
// perform additional initialization when the first window is loading
|
||||||
if (lazy.RunState.isStopped) {
|
if (lazy.RunState.isStopped) {
|
||||||
@@ -2165,7 +2178,7 @@ var SessionStoreInternal = {
|
@@ -1389,7 +1418,7 @@ class _SessionStore {
|
||||||
// to disk to NOW() to enforce a full interval before the next write.
|
// to disk to NOW() to enforce a full interval before the next write.
|
||||||
lazy.SessionSaver.updateLastSaveTime();
|
lazy.SessionSaver.updateLastSaveTime();
|
||||||
|
|
||||||
- if (isPrivateWindow || isTaskbarTab) {
|
- if (isPrivateWindow || isTaskbarTab) {
|
||||||
+ if (isPrivateWindow || isTaskbarTab || aWindow.document.documentElement.hasAttribute("zen-unsynced-window")) {
|
+ if (isPrivateWindow || isTaskbarTab || aWindow.document.documentElement.hasAttribute("zen-unsynced-window")) {
|
||||||
this._log.debug(
|
this.#log.debug(
|
||||||
"initializeWindow, the window is private or a web app. Saving SessionStartup.state for possibly restoring later"
|
"initializeWindow, the window is private or a web app. Saving SessionStartup.state for possibly restoring later"
|
||||||
);
|
);
|
||||||
@@ -2209,6 +2222,7 @@ var SessionStoreInternal = {
|
@@ -1433,6 +1462,7 @@ class _SessionStore {
|
||||||
null,
|
null,
|
||||||
"sessionstore-one-or-no-tab-restored"
|
"sessionstore-one-or-no-tab-restored"
|
||||||
);
|
);
|
||||||
+ lazy.ZenSessionStore.onNewEmptySession(aWindow);
|
+ lazy.ZenSessionStore.onNewEmptySession(aWindow);
|
||||||
this._deferredAllWindowsRestored.resolve();
|
this.#deferredAllWindowsRestored.resolve();
|
||||||
}
|
}
|
||||||
// this window was opened by _openWindowWithState
|
// this window was opened by #openWindowWithState
|
||||||
@@ -2258,7 +2272,6 @@ var SessionStoreInternal = {
|
@@ -1482,7 +1512,6 @@ class _SessionStore {
|
||||||
if (closedWindowState) {
|
if (closedWindowState) {
|
||||||
let newWindowState;
|
let newWindowState;
|
||||||
if (
|
if (
|
||||||
@@ -92,25 +115,25 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
!lazy.SessionStartup.willRestore()
|
!lazy.SessionStartup.willRestore()
|
||||||
) {
|
) {
|
||||||
// We want to split the window up into pinned tabs and unpinned tabs.
|
// We want to split the window up into pinned tabs and unpinned tabs.
|
||||||
@@ -2294,6 +2307,7 @@ var SessionStoreInternal = {
|
@@ -1518,6 +1547,7 @@ class _SessionStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newWindowState) {
|
if (newWindowState) {
|
||||||
+ lazy.ZenSessionStore.onRestoringClosedWindow(newWindowState);
|
+ lazy.ZenSessionStore.onRestoringClosedWindow(newWindowState);
|
||||||
// Ensure that the window state isn't hidden
|
// Ensure that the window state isn't hidden
|
||||||
this._restoreCount = 1;
|
this.#restoreCount = 1;
|
||||||
let state = { windows: [newWindowState] };
|
let state = { windows: [newWindowState] };
|
||||||
@@ -2330,6 +2344,9 @@ var SessionStoreInternal = {
|
@@ -1554,6 +1584,9 @@ class _SessionStore {
|
||||||
});
|
});
|
||||||
this._shouldRestoreLastSession = false;
|
this.#shouldRestoreLastSession = false;
|
||||||
}
|
}
|
||||||
+ else if (!aInitialState && isRegularWindow) {
|
+ else if (!aInitialState && isRegularWindow) {
|
||||||
+ lazy.ZenSessionStore.restoreNewWindow(aWindow, this);
|
+ lazy.ZenSessionStore.restoreNewWindow(aWindow, this);
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
if (this._restoreLastWindow && aWindow.toolbar.visible) {
|
if (this.#restoreLastWindow && aWindow.toolbar.visible) {
|
||||||
// always reset (if not a popup window)
|
// always reset (if not a popup window)
|
||||||
@@ -2480,7 +2497,7 @@ var SessionStoreInternal = {
|
@@ -1704,7 +1737,7 @@ class _SessionStore {
|
||||||
|
|
||||||
var tabbrowser = aWindow.gBrowser;
|
var tabbrowser = aWindow.gBrowser;
|
||||||
|
|
||||||
@@ -119,56 +142,56 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
|
|
||||||
TAB_EVENTS.forEach(function (aEvent) {
|
TAB_EVENTS.forEach(function (aEvent) {
|
||||||
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
|
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
|
||||||
@@ -2531,7 +2548,7 @@ var SessionStoreInternal = {
|
@@ -1755,7 +1788,7 @@ class _SessionStore {
|
||||||
|
|
||||||
let isLastRegularWindow =
|
let isLastRegularWindow =
|
||||||
Object.values(this._windows).filter(
|
Object.values(this.#windows).filter(
|
||||||
- wData => !wData.isPrivate && !wData.isTaskbarTab
|
- wData => !wData.isPrivate && !wData.isTaskbarTab
|
||||||
+ wData => !wData.isPrivate && !wData.isTaskbarTab && !wData.isZenUnsynced
|
+ wData => !wData.isPrivate && !wData.isTaskbarTab && !wData.isZenUnsynced
|
||||||
).length == 1;
|
).length == 1;
|
||||||
this._log.debug(
|
this.#log.debug(
|
||||||
`onClose, closing window isLastRegularWindow? ${isLastRegularWindow}`
|
`onClose, closing window isLastRegularWindow? ${isLastRegularWindow}`
|
||||||
@@ -2588,8 +2605,8 @@ var SessionStoreInternal = {
|
@@ -1812,8 +1845,8 @@ class _SessionStore {
|
||||||
// 2) Flush the window.
|
// 2) Flush the window.
|
||||||
// 3) When the flush is complete, revisit our decision to store the window
|
// 3) When the flush is complete, revisit our decision to store the window
|
||||||
// in _closedWindows, and add/remove as necessary.
|
// in #closedWindows, and add/remove as necessary.
|
||||||
- if (!winData.isPrivate && !winData.isTaskbarTab) {
|
- if (!winData.isPrivate && !winData.isTaskbarTab) {
|
||||||
- this.maybeSaveClosedWindow(winData, isLastWindow);
|
- this.#maybeSaveClosedWindow(winData, isLastWindow);
|
||||||
+ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) {
|
+ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) {
|
||||||
+ this.maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
+ this.#maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
completionPromise = lazy.TabStateFlusher.flushWindow(aWindow).then(() => {
|
completionPromise = lazy.TabStateFlusher.flushWindow(aWindow).then(() => {
|
||||||
@@ -2609,8 +2626,9 @@ var SessionStoreInternal = {
|
@@ -1833,8 +1866,9 @@ class _SessionStore {
|
||||||
|
|
||||||
// Save non-private windows if they have at
|
// Save non-private windows if they have at
|
||||||
// least one saveable tab or are the last window.
|
// least one saveable tab or are the last window.
|
||||||
- if (!winData.isPrivate && !winData.isTaskbarTab) {
|
- if (!winData.isPrivate && !winData.isTaskbarTab) {
|
||||||
- this.maybeSaveClosedWindow(winData, isLastWindow);
|
- this.#maybeSaveClosedWindow(winData, isLastWindow);
|
||||||
+ lazy.ZenWindowSync.on_WindowCloseAndBrowserFlushed(browsers);
|
+ lazy.ZenWindowSync.on_WindowCloseAndBrowserFlushed(browsers);
|
||||||
+ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) {
|
+ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) {
|
||||||
+ this.maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
+ this.#maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow);
|
||||||
|
|
||||||
if (!isLastWindow && winData.closedId > -1) {
|
if (!isLastWindow && winData.closedId > -1) {
|
||||||
this._addClosedAction(
|
this.#addClosedAction(
|
||||||
@@ -2686,7 +2704,7 @@ var SessionStoreInternal = {
|
@@ -1910,7 +1944,7 @@ class _SessionStore {
|
||||||
* to call this method again asynchronously (for example, after
|
* to call this method again asynchronously (for example, after
|
||||||
* a window flush).
|
* a window flush).
|
||||||
*/
|
*/
|
||||||
- maybeSaveClosedWindow(winData, isLastWindow) {
|
- #maybeSaveClosedWindow(winData, isLastWindow) {
|
||||||
+ maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow = false) {
|
+ #maybeSaveClosedWindow(winData, isLastWindow, isLastRegularWindow = false) {
|
||||||
// Make sure SessionStore is still running, and make sure that we
|
// Make sure SessionStore is still running, and make sure that we
|
||||||
// haven't chosen to forget this window.
|
// haven't chosen to forget this window.
|
||||||
if (
|
if (
|
||||||
@@ -2703,6 +2721,7 @@ var SessionStoreInternal = {
|
@@ -1927,6 +1961,7 @@ class _SessionStore {
|
||||||
// _closedWindows from a previous call to this function.
|
// #closedWindows from a previous call to this function.
|
||||||
let winIndex = this._closedWindows.indexOf(winData);
|
let winIndex = this.#closedWindows.indexOf(winData);
|
||||||
let alreadyStored = winIndex != -1;
|
let alreadyStored = winIndex != -1;
|
||||||
+ lazy.ZenSessionStore.maybeSaveClosedWindow(winData, isLastRegularWindow);
|
+ lazy.ZenSessionStore.maybeSaveClosedWindow(winData, isLastRegularWindow);
|
||||||
// If sidebar command is truthy, i.e. sidebar is open, store sidebar settings
|
// If sidebar command is truthy, i.e. sidebar is open, store sidebar settings
|
||||||
let shouldStore = hasSaveableTabs || isLastWindow;
|
let shouldStore = hasSaveableTabs || isLastWindow;
|
||||||
|
|
||||||
@@ -3525,7 +3544,7 @@ var SessionStoreInternal = {
|
@@ -2744,7 +2779,7 @@ class _SessionStore {
|
||||||
if (!isPrivateWindow && tabState.isPrivate) {
|
if (!isPrivateWindow && tabState.isPrivate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -177,10 +200,14 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4264,6 +4283,12 @@ var SessionStoreInternal = {
|
@@ -3511,7 +3546,15 @@ class _SessionStore {
|
||||||
|
1,
|
||||||
Math.min(tabState.index, tabState.entries.length)
|
Math.min(tabState.index, tabState.entries.length)
|
||||||
);
|
);
|
||||||
tabState.pinned = false;
|
- tabState.pinned = false;
|
||||||
|
+ tabState.pinned =
|
||||||
|
+ newTab.group?.isZenFolder === true &&
|
||||||
|
+ Services.prefs.getBoolPref("zen.folders.owned-tabs-in-folder");
|
||||||
+ tabState.zenEssential = false;
|
+ tabState.zenEssential = false;
|
||||||
+ tabState.zenSyncId = null;
|
+ tabState.zenSyncId = null;
|
||||||
+ tabState.zenIsGlance = false;
|
+ tabState.zenIsGlance = false;
|
||||||
@@ -190,7 +217,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
|
|
||||||
if (inBackground === false) {
|
if (inBackground === false) {
|
||||||
aWindow.gBrowser.selectedTab = newTab;
|
aWindow.gBrowser.selectedTab = newTab;
|
||||||
@@ -4697,6 +4722,8 @@ var SessionStoreInternal = {
|
@@ -4036,6 +4079,8 @@ class _SessionStore {
|
||||||
// Append the tab if we're opening into a different window,
|
// Append the tab if we're opening into a different window,
|
||||||
tabIndex: aSource == aTargetWindow ? pos : Infinity,
|
tabIndex: aSource == aTargetWindow ? pos : Infinity,
|
||||||
pinned: state.pinned,
|
pinned: state.pinned,
|
||||||
@@ -199,7 +226,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
userContextId: state.userContextId,
|
userContextId: state.userContextId,
|
||||||
skipLoad: true,
|
skipLoad: true,
|
||||||
preferredRemoteType,
|
preferredRemoteType,
|
||||||
@@ -5194,9 +5221,10 @@ var SessionStoreInternal = {
|
@@ -4608,9 +4653,10 @@ class _SessionStore {
|
||||||
if (activePageData.title && activePageData.title != activePageData.url) {
|
if (activePageData.title && activePageData.title != activePageData.url) {
|
||||||
win.gBrowser.setInitialTabTitle(tab, activePageData.title, {
|
win.gBrowser.setInitialTabTitle(tab, activePageData.title, {
|
||||||
isContentTitle: true,
|
isContentTitle: true,
|
||||||
@@ -211,7 +238,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5561,7 +5589,7 @@ var SessionStoreInternal = {
|
@@ -4982,7 +5028,7 @@ class _SessionStore {
|
||||||
|
|
||||||
for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
|
for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
|
||||||
let tab = tabbrowser.tabs[i];
|
let tab = tabbrowser.tabs[i];
|
||||||
@@ -220,30 +247,30 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
removableTabs.push(tab);
|
removableTabs.push(tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5674,7 +5702,7 @@ var SessionStoreInternal = {
|
@@ -5095,7 +5141,7 @@ class _SessionStore {
|
||||||
|
|
||||||
// collect the data for all windows
|
// collect the data for all windows
|
||||||
for (ix in this._windows) {
|
for (ix in this.#windows) {
|
||||||
- if (this._windows[ix]._restoring || this._windows[ix].isTaskbarTab) {
|
- if (this.#windows[ix]._restoring || this.#windows[ix].isTaskbarTab) {
|
||||||
+ if (this._windows[ix]._restoring || this._windows[ix].isTaskbarTab && !this._windows[ix].isZenUnsynced) {
|
+ if (this.#windows[ix]._restoring || this.#windows[ix].isTaskbarTab && !this.#windows[ix].isZenUnsynced) {
|
||||||
// window data is still in _statesToRestore
|
// window data is still in #statesToRestore
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -5818,11 +5846,12 @@ var SessionStoreInternal = {
|
@@ -5239,11 +5285,12 @@ class _SessionStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tabbrowser = aWindow.gBrowser;
|
let tabbrowser = aWindow.gBrowser;
|
||||||
- let tabs = tabbrowser.tabs;
|
- let tabs = tabbrowser.tabs;
|
||||||
+ let tabs = aWindow.gZenWorkspaces.allStoredTabs;
|
+ let tabs = aWindow.gZenWorkspaces.allStoredTabs;
|
||||||
/** @type {WindowStateData} */
|
/** @type {WindowStateData} */
|
||||||
let winData = this._windows[aWindow.__SSi];
|
let winData = this.#windows[aWindow.__SSi];
|
||||||
let tabsData = (winData.tabs = []);
|
let tabsData = (winData.tabs = []);
|
||||||
|
|
||||||
+ winData.splitViewData = aWindow.gZenViewSplitter?.storeDataForSessionStore();
|
+ winData.splitViewData = aWindow.gZenViewSplitter?.storeDataForSessionStore();
|
||||||
// update the internal state data for this window
|
// update the internal state data for this window
|
||||||
for (let tab of tabs) {
|
for (let tab of tabs) {
|
||||||
if (tab == aWindow.FirefoxViewHandler.tab) {
|
if (tab == aWindow.FirefoxViewHandler.tab) {
|
||||||
@@ -5833,6 +5862,9 @@ var SessionStoreInternal = {
|
@@ -5254,6 +5301,9 @@ class _SessionStore {
|
||||||
tabsData.push(tabData);
|
tabsData.push(tabData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,7 +280,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
// update tab group state for this window
|
// update tab group state for this window
|
||||||
winData.groups = [];
|
winData.groups = [];
|
||||||
for (let tabGroup of aWindow.gBrowser.tabGroups) {
|
for (let tabGroup of aWindow.gBrowser.tabGroups) {
|
||||||
@@ -5849,7 +5881,7 @@ var SessionStoreInternal = {
|
@@ -5270,7 +5320,7 @@ class _SessionStore {
|
||||||
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
|
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
|
||||||
// since it's only inserted into the tab strip after it's selected).
|
// since it's only inserted into the tab strip after it's selected).
|
||||||
if (aWindow.FirefoxViewHandler.tab?.selected) {
|
if (aWindow.FirefoxViewHandler.tab?.selected) {
|
||||||
@@ -262,7 +289,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
winData.title = tabbrowser.tabs[0].label;
|
winData.title = tabbrowser.tabs[0].label;
|
||||||
}
|
}
|
||||||
winData.selected = selectedIndex;
|
winData.selected = selectedIndex;
|
||||||
@@ -6051,8 +6083,8 @@ var SessionStoreInternal = {
|
@@ -5472,8 +5522,8 @@ class _SessionStore {
|
||||||
// selectTab represents.
|
// selectTab represents.
|
||||||
let selectTab = 0;
|
let selectTab = 0;
|
||||||
if (overwriteTabs) {
|
if (overwriteTabs) {
|
||||||
@@ -273,7 +300,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
selectTab = Math.min(selectTab, winData.tabs.length);
|
selectTab = Math.min(selectTab, winData.tabs.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6074,6 +6106,7 @@ var SessionStoreInternal = {
|
@@ -5495,6 +5545,7 @@ class _SessionStore {
|
||||||
if (overwriteTabs) {
|
if (overwriteTabs) {
|
||||||
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
|
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
|
||||||
if (!tabbrowser.tabs[i].selected) {
|
if (!tabbrowser.tabs[i].selected) {
|
||||||
@@ -281,7 +308,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
tabbrowser.removeTab(tabbrowser.tabs[i]);
|
tabbrowser.removeTab(tabbrowser.tabs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6108,6 +6141,12 @@ var SessionStoreInternal = {
|
@@ -5529,6 +5580,12 @@ class _SessionStore {
|
||||||
savedTabGroup => !openTabGroupIdsInWindow.has(savedTabGroup.id)
|
savedTabGroup => !openTabGroupIdsInWindow.has(savedTabGroup.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -294,7 +321,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
|
|
||||||
// Move the originally open tabs to the end.
|
// Move the originally open tabs to the end.
|
||||||
if (initialTabs) {
|
if (initialTabs) {
|
||||||
@@ -6674,6 +6713,25 @@ var SessionStoreInternal = {
|
@@ -6098,6 +6155,25 @@ class _SessionStore {
|
||||||
|
|
||||||
// Most of tabData has been restored, now continue with restoring
|
// Most of tabData has been restored, now continue with restoring
|
||||||
// attributes that may trigger external events.
|
// attributes that may trigger external events.
|
||||||
@@ -320,17 +347,25 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
|
|
||||||
if (tabData.pinned) {
|
if (tabData.pinned) {
|
||||||
tabbrowser.pinTab(tab);
|
tabbrowser.pinTab(tab);
|
||||||
@@ -6859,6 +6917,9 @@ var SessionStoreInternal = {
|
@@ -6272,6 +6348,9 @@ class _SessionStore {
|
||||||
aWindow.gURLBar.readOnly = false;
|
aWindow.gURLBar.readOnly = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+ if (aWinData.isZenUnsynced) {
|
+ if (aWinData.isZenUnsynced) {
|
||||||
+ this._windows[aWindow.__SSi].isZenUnsynced = true;
|
+ this.#windows[aWindow.__SSi].isZenUnsynced = true;
|
||||||
+ }
|
+ }
|
||||||
|
|
||||||
let promiseParts = Promise.withResolvers();
|
let promiseParts = Promise.withResolvers();
|
||||||
aWindow.setTimeout(() => {
|
const wasMinimized = aWindow.windowState == aWindow.STATE_MINIMIZED;
|
||||||
@@ -7654,7 +7715,7 @@ var SessionStoreInternal = {
|
@@ -6774,6 +6853,7 @@ class _SessionStore {
|
||||||
|
*/
|
||||||
|
#isCmdLineEmpty(aWindow, aState) {
|
||||||
|
var pinnedOnly =
|
||||||
|
+ !Services.prefs.getBoolPref("zen.workspaces.continue-where-left-off") &&
|
||||||
|
aState.windows &&
|
||||||
|
aState.windows.every(win => win.tabs.every(tab => tab.pinned));
|
||||||
|
|
||||||
|
@@ -7116,7 +7196,7 @@ class _SessionStore {
|
||||||
|
|
||||||
let groupsToSave = new Map();
|
let groupsToSave = new Map();
|
||||||
for (let tIndex = 0; tIndex < window.tabs.length; ) {
|
for (let tIndex = 0; tIndex < window.tabs.length; ) {
|
||||||
@@ -339,7 +374,7 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
// Adjust window.selected
|
// Adjust window.selected
|
||||||
if (tIndex + 1 < window.selected) {
|
if (tIndex + 1 < window.selected) {
|
||||||
window.selected -= 1;
|
window.selected -= 1;
|
||||||
@@ -7669,7 +7730,7 @@ var SessionStoreInternal = {
|
@@ -7131,7 +7211,7 @@ class _SessionStore {
|
||||||
);
|
);
|
||||||
// We don't want to increment tIndex here.
|
// We don't want to increment tIndex here.
|
||||||
continue;
|
continue;
|
||||||
@@ -348,15 +383,15 @@ index 536e06eec9f35bad3b8366733b23b5a8697df9c8..631a16bc7518108641993836f0c52e2a
|
|||||||
// Convert any open groups into saved groups.
|
// Convert any open groups into saved groups.
|
||||||
let groupStateToSave = window.groups.find(
|
let groupStateToSave = window.groups.find(
|
||||||
groupState => groupState.id == window.tabs[tIndex].groupId
|
groupState => groupState.id == window.tabs[tIndex].groupId
|
||||||
@@ -8233,7 +8294,6 @@ var SessionStoreInternal = {
|
@@ -7691,7 +7771,6 @@ class _SessionStore {
|
||||||
timer.initWithCallback(
|
timer.initWithCallback(
|
||||||
function () {
|
() => {
|
||||||
if (beats <= 0) {
|
if (beats <= 0) {
|
||||||
- this._log.debug(`looseTimer of ${delay} timed out`);
|
- this.#log.debug(`looseTimer of ${delay} timed out`);
|
||||||
Glean.sessionRestore.shutdownFlushAllOutcomes.timed_out.add(1);
|
Glean.sessionRestore.shutdownFlushAllOutcomes.timed_out.add(1);
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
}
|
}
|
||||||
@@ -8711,6 +8771,7 @@ var SessionStoreInternal = {
|
@@ -8174,6 +8253,7 @@ class _SessionStore {
|
||||||
if (
|
if (
|
||||||
!savedTabGroupState.tabs.length ||
|
!savedTabGroupState.tabs.length ||
|
||||||
this.getSavedTabGroup(savedTabGroupState.id)
|
this.getSavedTabGroup(savedTabGroupState.id)
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
diff --git a/browser/components/sessionstore/TabState.sys.mjs b/browser/components/sessionstore/TabState.sys.mjs
|
diff --git a/browser/components/sessionstore/TabState.sys.mjs b/browser/components/sessionstore/TabState.sys.mjs
|
||||||
index a33deeb5b587d6a950960a1a4781176e4e730ad7..e96cfb9a5ffbe4feccdffa8b6d18ececb48d4c52 100644
|
index bb7bd8c7ca88f776188fce64e0c85beb5ceb27a5..bdec77ba26172fe1b41369b1d45d5a6f9d52ae25 100644
|
||||||
--- a/browser/components/sessionstore/TabState.sys.mjs
|
--- a/browser/components/sessionstore/TabState.sys.mjs
|
||||||
+++ b/browser/components/sessionstore/TabState.sys.mjs
|
+++ b/browser/components/sessionstore/TabState.sys.mjs
|
||||||
@@ -8,6 +8,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
@@ -10,6 +10,7 @@ const lazy = XPCOMUtils.declareLazy({
|
||||||
PrivacyFilter: "resource://gre/modules/sessionstore/PrivacyFilter.sys.mjs",
|
"moz-src:///browser/components/sessionstore/TabAttributes.sys.mjs",
|
||||||
TabAttributes: "resource:///modules/sessionstore/TabAttributes.sys.mjs",
|
TabStateCache:
|
||||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||||
+ UrlbarShared: "chrome://browser/content/urlbar/UrlbarShared.mjs",
|
+ UrlbarShared: "chrome://browser/content/urlbar/UrlbarShared.mjs",
|
||||||
sessionStoreLogger: "resource:///modules/sessionstore/SessionLogger.sys.mjs",
|
sessionStoreLogger:
|
||||||
|
"moz-src:///browser/components/sessionstore/SessionLogger.sys.mjs",
|
||||||
});
|
});
|
||||||
|
@@ -106,10 +107,28 @@ class _TabState {
|
||||||
@@ -103,10 +104,28 @@ class _TabState {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,3 +39,14 @@ index a33deeb5b587d6a950960a1a4781176e4e730ad7..e96cfb9a5ffbe4feccdffa8b6d18ecec
|
|||||||
|
|
||||||
tabData.userContextId = tab.userContextId || 0;
|
tabData.userContextId = tab.userContextId || 0;
|
||||||
|
|
||||||
|
@@ -135,6 +154,10 @@ class _TabState {
|
||||||
|
tabData.image = tabbrowser.getIcon(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (tab.zenStaticIcon) {
|
||||||
|
+ tabData.image = tab.zenStaticIcon;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// If there is a userTypedValue set, then either the user has typed something
|
||||||
|
// in the URL bar, or a new tab was opened with a URI to load.
|
||||||
|
// If so, we also track whether we were still in the process of loading something.
|
||||||
|
|||||||
1202
src/browser/components/tabbrowser/Tabbrowser-sys-mjs.patch
Normal file
1202
src/browser/components/tabbrowser/Tabbrowser-sys-mjs.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/browser/components/tabbrowser/content/drag-and-drop.js b/browser/components/tabbrowser/content/drag-and-drop.js
|
diff --git a/browser/components/tabbrowser/content/drag-and-drop.js b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||||
index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8edf9bcf4 100644
|
index f9623f82499e516050d523068e70ebaa4fe9a66a..95bcc078a86b4ec4b35f5916b7e4a5e305afba9e 100644
|
||||||
--- a/browser/components/tabbrowser/content/drag-and-drop.js
|
--- a/browser/components/tabbrowser/content/drag-and-drop.js
|
||||||
+++ b/browser/components/tabbrowser/content/drag-and-drop.js
|
+++ b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||||
@@ -35,6 +35,9 @@
|
@@ -42,6 +42,9 @@
|
||||||
* @returns {MozTabbrowserTab|vbox}
|
* @returns {MozTabbrowserTab|vbox}
|
||||||
*/
|
*/
|
||||||
const elementToMove = element => {
|
const elementToMove = element => {
|
||||||
@@ -12,7 +12,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
if (isTab(element) || isSplitViewWrapper(element)) {
|
if (isTab(element) || isSplitViewWrapper(element)) {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
@@ -128,6 +131,9 @@
|
@@ -140,6 +143,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||||
@@ -22,15 +22,15 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
if (
|
if (
|
||||||
(dropEffect == "move" || dropEffect == "copy") &&
|
(dropEffect == "move" || dropEffect == "copy") &&
|
||||||
document == draggedTab.ownerDocument &&
|
document == draggedTab.ownerDocument &&
|
||||||
@@ -148,6 +154,7 @@
|
@@ -161,6 +167,7 @@
|
||||||
!draggedTab.group.collapsed
|
|
||||||
) {
|
) {
|
||||||
|
draggedTab.group.collapsedByDrag = true;
|
||||||
draggedTab.group.collapsed = true;
|
draggedTab.group.collapsed = true;
|
||||||
+ gZenFolders.animateGroupMove(draggedTab.group);
|
+ gZenFolders.animateGroupMove(draggedTab.group);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dropEffect == "move") {
|
if (dropEffect == "move") {
|
||||||
@@ -155,10 +162,6 @@
|
@@ -168,10 +175,6 @@
|
||||||
|
|
||||||
// Pinned tabs in expanded vertical mode are on a grid format and require
|
// Pinned tabs in expanded vertical mode are on a grid format and require
|
||||||
// different logic to drag and drop.
|
// different logic to drag and drop.
|
||||||
@@ -41,7 +41,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
this._animateTabMove(event);
|
this._animateTabMove(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -297,6 +300,10 @@
|
@@ -310,6 +313,10 @@
|
||||||
|
|
||||||
this._tabDropIndicator.hidden = true;
|
this._tabDropIndicator.hidden = true;
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
@@ -52,7 +52,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
if (draggedTab && dropEffect == "copy") {
|
if (draggedTab && dropEffect == "copy") {
|
||||||
let duplicatedDraggedTab;
|
let duplicatedDraggedTab;
|
||||||
let duplicatedTabs = [];
|
let duplicatedTabs = [];
|
||||||
@@ -324,12 +331,16 @@
|
@@ -337,12 +344,16 @@
|
||||||
let translateOffsetY = oldTranslateY % tabHeight;
|
let translateOffsetY = oldTranslateY % tabHeight;
|
||||||
let newTranslateX = oldTranslateX - translateOffsetX;
|
let newTranslateX = oldTranslateX - translateOffsetX;
|
||||||
let newTranslateY = oldTranslateY - translateOffsetY;
|
let newTranslateY = oldTranslateY - translateOffsetY;
|
||||||
@@ -73,7 +73,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
|
|
||||||
if (this._tabbrowserTabs.isContainerVerticalPinnedGrid(draggedTab)) {
|
if (this._tabbrowserTabs.isContainerVerticalPinnedGrid(draggedTab)) {
|
||||||
// Update both translate axis for pinned vertical expanded tabs
|
// Update both translate axis for pinned vertical expanded tabs
|
||||||
@@ -404,11 +415,13 @@
|
@@ -417,11 +428,13 @@
|
||||||
this._dragToPinPromoCard,
|
this._dragToPinPromoCard,
|
||||||
];
|
];
|
||||||
let shouldPin =
|
let shouldPin =
|
||||||
@@ -87,7 +87,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
isTab(draggedTab) &&
|
isTab(draggedTab) &&
|
||||||
draggedTab.pinned &&
|
draggedTab.pinned &&
|
||||||
this._tabbrowserTabs.arrowScrollbox.contains(event.target);
|
this._tabbrowserTabs.arrowScrollbox.contains(event.target);
|
||||||
@@ -484,6 +497,7 @@
|
@@ -492,6 +505,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
if (shouldTranslate) {
|
if (shouldTranslate) {
|
||||||
this.#dropAnimationEndTime = Date.now() + DROP_ANIMATION_GRACE_MS;
|
this.#dropAnimationEndTime = Date.now() + DROP_ANIMATION_GRACE_MS;
|
||||||
let translationPromises = [];
|
let translationPromises = [];
|
||||||
@@ -496,7 +510,7 @@
|
@@ -504,7 +518,7 @@
|
||||||
item.removeAttribute("tabdrop-samewindow");
|
item.removeAttribute("tabdrop-samewindow");
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
@@ -104,7 +104,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
postTransitionCleanup();
|
postTransitionCleanup();
|
||||||
} else {
|
} else {
|
||||||
let onTransitionEnd = transitionendEvent => {
|
let onTransitionEnd = transitionendEvent => {
|
||||||
@@ -580,7 +594,7 @@
|
@@ -595,7 +609,7 @@
|
||||||
if (tab.selected) {
|
if (tab.selected) {
|
||||||
selectedTab = tab;
|
selectedTab = tab;
|
||||||
indexForSelectedTab = newIndex;
|
indexForSelectedTab = newIndex;
|
||||||
@@ -113,7 +113,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
const droppedIntoPinnedArea = dropIndex < gBrowser.pinnedTabCount;
|
const droppedIntoPinnedArea = dropIndex < gBrowser.pinnedTabCount;
|
||||||
const newSplitView = gBrowser.adoptSplitView(tab, {
|
const newSplitView = gBrowser.adoptSplitView(tab, {
|
||||||
elementIndex: droppedIntoPinnedArea
|
elementIndex: droppedIntoPinnedArea
|
||||||
@@ -605,7 +619,7 @@
|
@@ -620,7 +634,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
const newTab = gBrowser.adoptTab(selectedTab, {
|
const newTab = gBrowser.adoptTab(selectedTab, {
|
||||||
elementIndex: indexForSelectedTab,
|
elementIndex: indexForSelectedTab,
|
||||||
selectTab: selectedTab == draggedTab,
|
selectTab: selectedTab == draggedTab,
|
||||||
@@ -639,10 +653,6 @@
|
@@ -654,10 +668,6 @@
|
||||||
this._tabbrowserTabs.dragAndDropElements[
|
this._tabbrowserTabs.dragAndDropElements[
|
||||||
gBrowser.pinnedTabCount + unpinnedSplitViews.length - 1
|
gBrowser.pinnedTabCount + unpinnedSplitViews.length - 1
|
||||||
];
|
];
|
||||||
@@ -133,7 +133,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -703,6 +713,7 @@
|
@@ -717,6 +727,7 @@
|
||||||
|
|
||||||
let nextItem = this._tabbrowserTabs.dragAndDropElements[newIndex];
|
let nextItem = this._tabbrowserTabs.dragAndDropElements[newIndex];
|
||||||
let tabGroup = isTab(nextItem) && nextItem.group;
|
let tabGroup = isTab(nextItem) && nextItem.group;
|
||||||
@@ -141,7 +141,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
gBrowser.loadTabs(urls, {
|
gBrowser.loadTabs(urls, {
|
||||||
inBackground,
|
inBackground,
|
||||||
replace,
|
replace,
|
||||||
@@ -744,6 +755,22 @@
|
@@ -758,6 +769,22 @@
|
||||||
this._expandGroupOnDrop(draggedTab);
|
this._expandGroupOnDrop(draggedTab);
|
||||||
}
|
}
|
||||||
this._resetTabsAfterDrop(draggedTab);
|
this._resetTabsAfterDrop(draggedTab);
|
||||||
@@ -164,7 +164,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
dt.mozUserCancelled ||
|
dt.mozUserCancelled ||
|
||||||
@@ -1074,11 +1101,10 @@
|
@@ -1088,11 +1115,10 @@
|
||||||
return this.#getHorizontalScrollboxDragTarget(event, ignoreSides);
|
return this.#getHorizontalScrollboxDragTarget(event, ignoreSides);
|
||||||
}
|
}
|
||||||
while (target) {
|
while (target) {
|
||||||
@@ -180,7 +180,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
target = target.parentNode;
|
target = target.parentNode;
|
||||||
@@ -1108,6 +1134,9 @@
|
@@ -1122,6 +1148,9 @@
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,36 +190,43 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1170,14 +1199,20 @@
|
@@ -1188,17 +1217,24 @@
|
||||||
let releaseReservedSpace = () =>
|
let periphery = draggedTab.ownerDocument.getElementById(
|
||||||
this.#releaseSpaceInScrolledContent(periphery);
|
"tabbrowser-arrowscrollbox-periphery"
|
||||||
if (group.collapsed) {
|
);
|
||||||
- // The group's tabs animate back to their full size, so hold on to the
|
- // The group's tabs animate back to their full size, so hold on to the
|
||||||
- // space reserved for them until they get there.
|
- // space reserved for them until they get there.
|
||||||
- group.addEventListener(
|
- group.addEventListener(
|
||||||
- "TabGroupAnimationComplete",
|
- "TabGroupAnimationComplete",
|
||||||
- releaseReservedSpace,
|
- () => {
|
||||||
- { once: true }
|
- group.collapsedByDrag = false;
|
||||||
- );
|
- this.#releaseSpaceInScrolledContent(periphery);
|
||||||
- group.collapsed = false;
|
- },
|
||||||
+ const expand = !group.hasAttribute("has-active");
|
- { once: true }
|
||||||
+ if (expand) {
|
- );
|
||||||
+ // The group's tabs animate back to their full size, so hold on to the
|
- group.collapsed = false;
|
||||||
+ // space reserved for them until they get there.
|
+ const expand = !group.hasAttribute("has-active");
|
||||||
+ group.addEventListener(
|
+ if (expand) {
|
||||||
+ "TabGroupAnimationComplete",
|
+ // The group's tabs animate back to their full size, so hold on to the
|
||||||
+ releaseReservedSpace,
|
+ // space reserved for them until they get there.
|
||||||
+ { once: true }
|
+ group.addEventListener(
|
||||||
+ );
|
+ "TabGroupAnimationComplete",
|
||||||
+ } else {
|
+ () => {
|
||||||
+ releaseReservedSpace();
|
+ group.collapsedByDrag = false;
|
||||||
+ }
|
+ this.#releaseSpaceInScrolledContent(periphery);
|
||||||
+ group.collapsed = !expand;
|
+ },
|
||||||
+ gZenFolders.animateGroupMove(group, true);
|
+ { once: true }
|
||||||
} else {
|
+ );
|
||||||
releaseReservedSpace();
|
+ } else {
|
||||||
}
|
+ group.collapsedByDrag = false;
|
||||||
@@ -1362,7 +1397,6 @@
|
+ this.#releaseSpaceInScrolledContent(periphery);
|
||||||
|
+ }
|
||||||
|
+ group.collapsed = !expand;
|
||||||
|
+ gZenFolders.animateGroupMove(group, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -1380,7 +1416,6 @@
|
||||||
// using updateDragImage. On Linux, we can use a panel.
|
// using updateDragImage. On Linux, we can use a panel.
|
||||||
if (platform == "win" || platform == "macosx") {
|
if (platform == "win" || platform == "macosx") {
|
||||||
captureListener = function () {
|
captureListener = function () {
|
||||||
@@ -227,7 +234,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// Create a panel to use it in setDragImage
|
// Create a panel to use it in setDragImage
|
||||||
@@ -1400,7 +1434,6 @@
|
@@ -1418,7 +1453,6 @@
|
||||||
);
|
);
|
||||||
dragImageOffset = dragImageOffset * scale;
|
dragImageOffset = dragImageOffset * scale;
|
||||||
}
|
}
|
||||||
@@ -235,7 +242,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
|
|
||||||
// _dragData.offsetX/Y give the coordinates that the mouse should be
|
// _dragData.offsetX/Y give the coordinates that the mouse should be
|
||||||
// positioned relative to the corner of the new window created upon
|
// positioned relative to the corner of the new window created upon
|
||||||
@@ -1419,7 +1452,7 @@
|
@@ -1437,7 +1471,7 @@
|
||||||
let dropEffect = this.getDropEffectForTabDrag(event);
|
let dropEffect = this.getDropEffectForTabDrag(event);
|
||||||
let isMovingInTabStrip = !fromTabList && dropEffect == "move";
|
let isMovingInTabStrip = !fromTabList && dropEffect == "move";
|
||||||
let collapseTabGroupDuringDrag =
|
let collapseTabGroupDuringDrag =
|
||||||
@@ -244,7 +251,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
|
|
||||||
tab._dragData = {
|
tab._dragData = {
|
||||||
offsetX: this._tabbrowserTabs.verticalMode
|
offsetX: this._tabbrowserTabs.verticalMode
|
||||||
@@ -1429,7 +1462,7 @@
|
@@ -1447,7 +1481,7 @@
|
||||||
? event.screenY - window.screenY - tabOffset
|
? event.screenY - window.screenY - tabOffset
|
||||||
: event.screenY - window.screenY,
|
: event.screenY - window.screenY,
|
||||||
scrollPos:
|
scrollPos:
|
||||||
@@ -253,7 +260,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
? this._tabbrowserTabs.pinnedTabsContainer.scrollPosition
|
? this._tabbrowserTabs.pinnedTabsContainer.scrollPosition
|
||||||
: this._tabbrowserTabs.arrowScrollbox.scrollPosition,
|
: this._tabbrowserTabs.arrowScrollbox.scrollPosition,
|
||||||
screenX: event.screenX,
|
screenX: event.screenX,
|
||||||
@@ -1522,6 +1555,7 @@
|
@@ -1540,6 +1574,7 @@
|
||||||
if (tabStripItemElement.hasAttribute("dragtarget")) {
|
if (tabStripItemElement.hasAttribute("dragtarget")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -261,7 +268,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
let isPinned = tab.pinned;
|
let isPinned = tab.pinned;
|
||||||
let dragAndDropElements = this._tabbrowserTabs.dragAndDropElements;
|
let dragAndDropElements = this._tabbrowserTabs.dragAndDropElements;
|
||||||
let isGrid = this._tabbrowserTabs.isContainerVerticalPinnedGrid(tab);
|
let isGrid = this._tabbrowserTabs.isContainerVerticalPinnedGrid(tab);
|
||||||
@@ -1895,23 +1929,6 @@
|
@@ -1913,23 +1948,6 @@
|
||||||
|
|
||||||
// Slide the relevant tabs to their new position.
|
// Slide the relevant tabs to their new position.
|
||||||
// non-moving tabs adjust for RTL
|
// non-moving tabs adjust for RTL
|
||||||
@@ -285,7 +292,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
// moving tabs don't adjust for RTL
|
// moving tabs don't adjust for RTL
|
||||||
for (let item of selectedElements) {
|
for (let item of selectedElements) {
|
||||||
if (
|
if (
|
||||||
@@ -1960,7 +1977,6 @@
|
@@ -1978,7 +1996,6 @@
|
||||||
for (let item of this._tabbrowserTabs.dragAndDropElements) {
|
for (let item of this._tabbrowserTabs.dragAndDropElements) {
|
||||||
delete item._moveTogetherSelectedTabsData;
|
delete item._moveTogetherSelectedTabsData;
|
||||||
item = elementToMove(item);
|
item = elementToMove(item);
|
||||||
@@ -293,7 +300,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
item.removeAttribute("multiselected-move-together");
|
item.removeAttribute("multiselected-move-together");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2812,7 +2828,6 @@
|
@@ -2830,7 +2847,6 @@
|
||||||
tab.style.top = "";
|
tab.style.top = "";
|
||||||
tab.style.maxWidth = "";
|
tab.style.maxWidth = "";
|
||||||
tab.style.pointerEvents = "";
|
tab.style.pointerEvents = "";
|
||||||
@@ -301,7 +308,7 @@ index 70b37f93c4e8ff4ad9a2452681e468d23914c1b5..dbf2d9c83dafbe0e0b4e6caf3835edc8
|
|||||||
tab.removeAttribute("small-stack");
|
tab.removeAttribute("small-stack");
|
||||||
tab.removeAttribute("big-stack");
|
tab.removeAttribute("big-stack");
|
||||||
}
|
}
|
||||||
@@ -2821,11 +2836,9 @@
|
@@ -2839,11 +2855,9 @@
|
||||||
)) {
|
)) {
|
||||||
label.style.width = "";
|
label.style.width = "";
|
||||||
label.style.maxWidth = "";
|
label.style.maxWidth = "";
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
|||||||
diff --git a/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs b/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
diff --git a/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs b/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
||||||
index cfc232f038cd491db32e0c0ca35622360dd9dec5..4806a725ddefa9d0709020d537eae5464249a294 100644
|
index e32b02941a6019703212cede4660a24b88845120..5cb363ed20d49c1ae8abedecc3b08540406b7a1b 100644
|
||||||
--- a/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
--- a/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
||||||
+++ b/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
+++ b/browser/components/urlbar/UrlbarProviderHeuristicFallback.sys.mjs
|
||||||
@@ -77,22 +77,26 @@ export class UrlbarProviderHeuristicFallback extends UrlbarProvider {
|
@@ -76,22 +76,26 @@ export class UrlbarProviderHeuristicFallback extends UrlbarProvider {
|
||||||
// Since we can't tell if this is a real URL and whether the user wants
|
// Since we can't tell if this is a real URL and whether the user wants
|
||||||
// to visit or search for it, we provide an alternative searchengine
|
// to visit or search for it, we provide an alternative searchengine
|
||||||
// match if the string looks like an alphanumeric origin or an e-mail.
|
// match if the string looks like an alphanumeric origin or an e-mail.
|
||||||
- let str = queryContext.searchString;
|
- let str = queryContext.searchString;
|
||||||
- if (!URL.canParse(str)) {
|
- if (!URL.canParse(str)) {
|
||||||
- if (
|
- if (
|
||||||
- lazy.UrlbarPrefs.get("keyword.enabled") &&
|
- queryContext.keywordEnabled &&
|
||||||
- (lazy.UrlUtils.looksLikeOrigin(str, {
|
- (lazy.UrlUtils.looksLikeOrigin(str, {
|
||||||
- noIp: true,
|
- noIp: true,
|
||||||
- noPort: true,
|
- noPort: true,
|
||||||
@@ -24,7 +24,7 @@ index cfc232f038cd491db32e0c0ca35622360dd9dec5..4806a725ddefa9d0709020d537eae546
|
|||||||
+ }
|
+ }
|
||||||
+ );
|
+ );
|
||||||
+ if (
|
+ if (
|
||||||
+ lazy.UrlbarPrefs.get("keyword.enabled") &&
|
+ queryContext.keywordEnabled &&
|
||||||
+ (lazy.UrlUtils.looksLikeUrl(searchCandidate) ||
|
+ (lazy.UrlUtils.looksLikeUrl(searchCandidate) ||
|
||||||
+ lazy.UrlUtils.looksLikeOrigin(searchCandidate, {
|
+ lazy.UrlUtils.looksLikeOrigin(searchCandidate, {
|
||||||
+ allowPartialNumericalTLDs: true,
|
+ allowPartialNumericalTLDs: true,
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
diff --git a/browser/components/urlbar/UrlbarUtils.sys.mjs b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
|
||||||
index 178cd5e84fda74a28b2de59b671b3399cc28fac4..b03c6e06de4ee9a95dcb4d33d7ac9f0b053be4e1 100644
|
|
||||||
--- a/browser/components/urlbar/UrlbarUtils.sys.mjs
|
|
||||||
+++ b/browser/components/urlbar/UrlbarUtils.sys.mjs
|
|
||||||
@@ -214,6 +214,11 @@ export var UrlbarUtils = {
|
|
||||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_FALLBACK;
|
|
||||||
case "UrlbarProviderHistoryUrlHeuristic":
|
|
||||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_HISTORY_URL;
|
|
||||||
+ case "ZenUrlbarProviderGlobalActions":
|
|
||||||
+ if (result.source == UrlbarShared.RESULT_SOURCE.WORKSPACES) {
|
|
||||||
+ return UrlbarShared.RESULT_GROUP.ZEN_WORKSPACE;
|
|
||||||
+ }
|
|
||||||
+ return UrlbarShared.RESULT_GROUP.ZEN_ACTION;
|
|
||||||
case "UrlbarProviderOmnibox":
|
|
||||||
return UrlbarShared.RESULT_GROUP.HEURISTIC_OMNIBOX;
|
|
||||||
case "UrlbarProviderRestrictKeywordsAutofill":
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
diff --git a/browser/components/urlbar/content/UrlbarChildController.mjs b/browser/components/urlbar/content/UrlbarChildController.mjs
|
diff --git a/browser/components/urlbar/content/UrlbarChildController.mjs b/browser/components/urlbar/content/UrlbarChildController.mjs
|
||||||
index a17a4de079b69d2818388b33a2c1746cc6148c73..4fee63a22919972af08716db2d2de1c7549ff100 100644
|
index 52ed36deac35d3de9f7f537313159fb4debe98a6..3bbc612a2e10eedafdabdaa8e17cf36831a6a27c 100644
|
||||||
--- a/browser/components/urlbar/content/UrlbarChildController.mjs
|
--- a/browser/components/urlbar/content/UrlbarChildController.mjs
|
||||||
+++ b/browser/components/urlbar/content/UrlbarChildController.mjs
|
+++ b/browser/components/urlbar/content/UrlbarChildController.mjs
|
||||||
@@ -438,7 +438,6 @@ export class UrlbarChildController {
|
@@ -446,7 +446,6 @@ export class UrlbarChildController {
|
||||||
const isMac = AppConstants.platform == "macosx";
|
const isMac = UrlbarContentUtils.getPlatform() == "macosx";
|
||||||
// Handle readline/emacs-style navigation bindings on Mac.
|
// Handle readline/emacs-style navigation bindings on Mac.
|
||||||
if (
|
if (
|
||||||
- isMac &&
|
- isMac &&
|
||||||
this.view.isOpen &&
|
this.view.isOpen &&
|
||||||
event.ctrlKey &&
|
event.ctrlKey &&
|
||||||
(event.key == "n" || event.key == "p")
|
(event.key == "n" || event.key == "p")
|
||||||
@@ -630,6 +629,8 @@ export class UrlbarChildController {
|
@@ -644,6 +643,8 @@ export class UrlbarChildController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -19,7 +19,7 @@ index a17a4de079b69d2818388b33a2c1746cc6148c73..4fee63a22919972af08716db2d2de1c7
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -934,6 +935,10 @@ export class UrlbarChildController {
|
@@ -905,6 +906,10 @@ export class UrlbarChildController {
|
||||||
}
|
}
|
||||||
reuseEmpty = true;
|
reuseEmpty = true;
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ index a17a4de079b69d2818388b33a2c1746cc6148c73..4fee63a22919972af08716db2d2de1c7
|
|||||||
// The browser window exists only in chrome; a content-process input has no
|
// The browser window exists only in chrome; a content-process input has no
|
||||||
// tab to reuse, so `gBrowser` is absent and the reuse is skipped.
|
// tab to reuse, so `gBrowser` is absent and the reuse is skipped.
|
||||||
if (
|
if (
|
||||||
@@ -943,6 +948,10 @@ export class UrlbarChildController {
|
@@ -914,6 +919,10 @@ export class UrlbarChildController {
|
||||||
) {
|
) {
|
||||||
where = "current";
|
where = "current";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
|
diff --git a/browser/components/urlbar/content/UrlbarInputBase.mjs b/browser/components/urlbar/content/UrlbarInputBase.mjs
|
||||||
index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1a95e28b8 100644
|
index 8be35b58c5369e123ca69426e852e3849bf75513..170cffbdd12a72dab15976cdab9207dc4292d4e6 100644
|
||||||
--- a/browser/components/urlbar/content/UrlbarInput.mjs
|
--- a/browser/components/urlbar/content/UrlbarInputBase.mjs
|
||||||
+++ b/browser/components/urlbar/content/UrlbarInput.mjs
|
+++ b/browser/components/urlbar/content/UrlbarInputBase.mjs
|
||||||
@@ -88,6 +88,13 @@ const lazy = XPCOMUtils.declareLazy({
|
@@ -83,6 +83,12 @@ if (lazy) {
|
||||||
logger: () => UrlbarShared.getLogger({ prefix: "Input" }),
|
Ci.nsIURLQueryStringStripper,
|
||||||
});
|
],
|
||||||
|
});
|
||||||
|
+ XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
|
+ lazy,
|
||||||
|
+ "ZEN_URLBAR_BEHAVIOR",
|
||||||
|
+ "zen.urlbar.behavior",
|
||||||
|
+ 'default'
|
||||||
|
+ );
|
||||||
|
}
|
||||||
|
|
||||||
+XPCOMUtils.defineLazyPreferenceGetter(
|
const logger = () => UrlbarShared.getLogger({ prefix: "Input" });
|
||||||
+ lazy,
|
@@ -917,7 +923,16 @@ ${
|
||||||
+ "ZEN_URLBAR_BEHAVIOR",
|
|
||||||
+ "zen.urlbar.behavior",
|
|
||||||
+ 'default'
|
|
||||||
+);
|
|
||||||
+
|
|
||||||
const UNLIMITED_MAX_RESULTS = 99;
|
|
||||||
|
|
||||||
let getBoundsWithoutFlushing = element =>
|
|
||||||
@@ -771,7 +778,16 @@ ${
|
|
||||||
// See _on_select(). HTMLInputElement.select() dispatches a "select"
|
// See _on_select(). HTMLInputElement.select() dispatches a "select"
|
||||||
// event but does not set the primary selection.
|
// event but does not set the primary selection.
|
||||||
this._suppressPrimaryAdjustment = true;
|
this._suppressPrimaryAdjustment = true;
|
||||||
@@ -33,7 +32,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
this._suppressPrimaryAdjustment = false;
|
this._suppressPrimaryAdjustment = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,6 +862,10 @@ ${
|
@@ -992,6 +1007,10 @@ ${
|
||||||
hideSearchTerms = false,
|
hideSearchTerms = false,
|
||||||
isSameDocument = false,
|
isSameDocument = false,
|
||||||
} = {}) {
|
} = {}) {
|
||||||
@@ -44,7 +43,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
if (!this.#isAddressbar) {
|
if (!this.#isAddressbar) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Cannot set URI for UrlbarInput that is not an address bar"
|
"Cannot set URI for UrlbarInput that is not an address bar"
|
||||||
@@ -1143,7 +1163,16 @@ ${
|
@@ -1289,7 +1308,16 @@ ${
|
||||||
this.searchModeSwitcher?.updateSearchIcon();
|
this.searchModeSwitcher?.updateSearchIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +60,17 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1726,7 +1755,11 @@ ${
|
@@ -1401,6 +1429,9 @@ ${
|
||||||
|
where,
|
||||||
|
query: searchString,
|
||||||
|
});
|
||||||
|
+ if (where != "current" && this.sapName != "searchbar") {
|
||||||
|
+ this.handleRevert();
|
||||||
|
+ }
|
||||||
|
this.controller.openSERP(
|
||||||
|
engine.id,
|
||||||
|
searchString,
|
||||||
|
@@ -1884,7 +1915,11 @@ ${
|
||||||
openParams.avoidBrowserFocus = keepViewOpen;
|
openParams.avoidBrowserFocus = keepViewOpen;
|
||||||
|
|
||||||
if (!this.#providesSearchMode(result) && !keepViewOpen) {
|
if (!this.#providesSearchMode(result) && !keepViewOpen) {
|
||||||
@@ -74,12 +83,12 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isCanonized) {
|
if (isCanonized) {
|
||||||
@@ -3016,6 +3049,42 @@ ${
|
@@ -3181,6 +3216,42 @@ ${
|
||||||
await this.#updateLayoutBreakoutDimensions();
|
await this.#updateLayoutBreakoutDimensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
+ zenFormatURLValue() {
|
+ zenFormatURLValue() {
|
||||||
+ return this.#lazy.valueFormatter._formatURL();
|
+ return this.#getValueFormatter().update();
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ get zenUrlbarBehavior() {
|
+ get zenUrlbarBehavior() {
|
||||||
@@ -117,7 +126,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
startLayoutExtend() {
|
startLayoutExtend() {
|
||||||
if (!this.#allowBreakout || this.hasAttribute("breakout-extend")) {
|
if (!this.#allowBreakout || this.hasAttribute("breakout-extend")) {
|
||||||
// Do not expand if the Urlbar does not support being expanded or it is
|
// Do not expand if the Urlbar does not support being expanded or it is
|
||||||
@@ -3030,6 +3099,13 @@ ${
|
@@ -3195,6 +3266,13 @@ ${
|
||||||
this.toggleAttribute("breakout-extend", true);
|
this.toggleAttribute("breakout-extend", true);
|
||||||
this.#updateTextboxPosition();
|
this.#updateTextboxPosition();
|
||||||
|
|
||||||
@@ -131,7 +140,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
// Enable the animation only after the first extend call to ensure it
|
// Enable the animation only after the first extend call to ensure it
|
||||||
// doesn't run when opening a new window.
|
// doesn't run when opening a new window.
|
||||||
if (!this.hasAttribute("breakout-extend-animate")) {
|
if (!this.hasAttribute("breakout-extend-animate")) {
|
||||||
@@ -3053,6 +3129,29 @@ ${
|
@@ -3218,6 +3296,29 @@ ${
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +170,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
this.toggleAttribute("breakout-extend", false);
|
this.toggleAttribute("breakout-extend", false);
|
||||||
this.#updateTextboxPosition();
|
this.#updateTextboxPosition();
|
||||||
}
|
}
|
||||||
@@ -3091,7 +3190,7 @@ ${
|
@@ -3256,7 +3357,7 @@ ${
|
||||||
forceUnifiedSearchButtonAvailable = false
|
forceUnifiedSearchButtonAvailable = false
|
||||||
) {
|
) {
|
||||||
let prevState = this.getAttribute("pageproxystate");
|
let prevState = this.getAttribute("pageproxystate");
|
||||||
@@ -170,20 +179,20 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
this.setAttribute("pageproxystate", state);
|
this.setAttribute("pageproxystate", state);
|
||||||
this._inputContainer.setAttribute("pageproxystate", state);
|
this._inputContainer.setAttribute("pageproxystate", state);
|
||||||
this._identityBox?.setAttribute("pageproxystate", state);
|
this._identityBox?.setAttribute("pageproxystate", state);
|
||||||
@@ -3355,10 +3454,12 @@ ${
|
@@ -3533,7 +3634,11 @@ ${
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.style.top = px(
|
- this.style.top = px(getUntransformedTop(this.parentNode));
|
||||||
|
+ this.style.top = px(
|
||||||
+ this.window.gZenVerticalTabsManager._hasSetSingleToolbar ?
|
+ this.window.gZenVerticalTabsManager._hasSetSingleToolbar ?
|
||||||
this.parentNode.getBoxQuads({
|
+ getUntransformedTop(this.parentNode)
|
||||||
ignoreTransforms: true,
|
+ : (UrlbarContentUtils.getPlatform() == "macosx" ? -2 : -5)
|
||||||
flush: false,
|
+ );
|
||||||
})[0].p1.y
|
|
||||||
+ : (AppConstants.platform == "macosx" ? -2 : -5)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3417,9 +3518,10 @@ ${
|
#updateTextboxPositionNextFrame() {
|
||||||
|
@@ -3591,9 +3696,10 @@ ${
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +204,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (this.#breakoutBlockerCount) {
|
if (this.#breakoutBlockerCount) {
|
||||||
@@ -3929,6 +4031,7 @@ ${
|
@@ -4108,6 +4214,7 @@ ${
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggleActionOverride(event) {
|
_toggleActionOverride(event) {
|
||||||
@@ -203,7 +212,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
if (
|
if (
|
||||||
event.keyCode == KeyEvent.DOM_VK_SHIFT ||
|
event.keyCode == KeyEvent.DOM_VK_SHIFT ||
|
||||||
event.keyCode == KeyEvent.DOM_VK_ALT ||
|
event.keyCode == KeyEvent.DOM_VK_ALT ||
|
||||||
@@ -4027,9 +4130,10 @@ ${
|
@@ -4206,9 +4313,10 @@ ${
|
||||||
if (!this.#isAddressbar) {
|
if (!this.#isAddressbar) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@@ -216,36 +225,36 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
+ : val;
|
+ : val;
|
||||||
// Only trim value if the directionality doesn't change to RTL and we're not
|
// Only trim value if the directionality doesn't change to RTL and we're not
|
||||||
// showing a strikeout https protocol.
|
// showing a strikeout https protocol.
|
||||||
return this.controller.isTextDirectionRTL(trimmedValue) ||
|
return UrlbarContentUtils.isTextDirectionRTL(trimmedValue, window) ||
|
||||||
@@ -4235,6 +4339,11 @@ ${
|
@@ -4410,6 +4518,11 @@ ${
|
||||||
keepViewOpen = false,
|
keepViewOpen = false,
|
||||||
browserId = null,
|
browserId = null,
|
||||||
}) {
|
}) {
|
||||||
+ where = this.window.gZenUIManager.getOpenUILinkWhere(
|
+ where = this.window.gZenUIManager.getOpenUILinkWhere(
|
||||||
+ url,
|
+ loadRequest.urlLoad?.url ?? "",
|
||||||
+ this.window.gBrowser.selectedBrowser,
|
+ this.window.gBrowser.selectedBrowser,
|
||||||
+ where
|
+ where
|
||||||
+ );
|
+ );
|
||||||
let userTypedValue;
|
let keyDownEnterDeferred;
|
||||||
if (this.#isAddressbar && where == "current") {
|
if (
|
||||||
// Make sure URL is formatted properly (don't show punycode).
|
this._keyDownEnterDeferred &&
|
||||||
@@ -4576,6 +4685,7 @@ ${
|
@@ -4731,6 +4844,7 @@ ${
|
||||||
this.setResultForCurrentValue(null);
|
this.setResultForCurrentValue(null);
|
||||||
this.handleCommand();
|
this.handleCommand();
|
||||||
this.controller.clearLastQueryContextCache();
|
this.controller.clearLastQueryContextCache();
|
||||||
+ this.view.close();
|
+ this.view.close();
|
||||||
|
|
||||||
this._suppressStartQuery = false;
|
this._suppressStartQuery = false;
|
||||||
});
|
});
|
||||||
@@ -4583,7 +4693,6 @@ ${
|
@@ -4742,7 +4856,6 @@ ${
|
||||||
contextMenu.addEventListener("popupshowing", () => {
|
// Close the results pane, because paste and go doesn't want a result
|
||||||
// Close the results pane when the input field contextual menu is open,
|
// selection. This has to happen before the menu opens: ending
|
||||||
// because paste and go doesn't want a result selection.
|
// breakout-extend once it's open keeps it from showing (bug 2037468).
|
||||||
- this.view.close();
|
- this.view.close();
|
||||||
|
|
||||||
let controller =
|
let controller =
|
||||||
this.document.commandDispatcher.getControllerForCommand("cmd_paste");
|
this.document.commandDispatcher.getControllerForCommand("cmd_paste");
|
||||||
@@ -4850,7 +4959,11 @@ ${
|
@@ -5025,7 +5138,11 @@ ${
|
||||||
if (!engineName && !source && !this.hasAttribute("searchmode")) {
|
if (!engineName && !source && !this.hasAttribute("searchmode")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -258,7 +267,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
if (this._searchModeIndicatorTitle) {
|
if (this._searchModeIndicatorTitle) {
|
||||||
this._searchModeIndicatorTitle.textContent = "";
|
this._searchModeIndicatorTitle.textContent = "";
|
||||||
this._searchModeIndicatorTitle.removeAttribute("data-l10n-id");
|
this._searchModeIndicatorTitle.removeAttribute("data-l10n-id");
|
||||||
@@ -5149,6 +5262,7 @@ ${
|
@@ -5335,6 +5452,7 @@ ${
|
||||||
|
|
||||||
this.document.l10n.setAttributes(
|
this.document.l10n.setAttributes(
|
||||||
this.inputField,
|
this.inputField,
|
||||||
@@ -266,10 +275,10 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
l10nId,
|
l10nId,
|
||||||
l10nId == "urlbar-placeholder-with-name"
|
l10nId == "urlbar-placeholder-with-name"
|
||||||
? { name: engineName }
|
? { name: engineName }
|
||||||
@@ -5199,6 +5313,12 @@ ${
|
@@ -5385,6 +5503,12 @@ ${
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy.logger.debug("Blur Event");
|
logger().debug("Blur Event");
|
||||||
+ if (
|
+ if (
|
||||||
+ this.document.commandDispatcher.focusedElement == this.inputField &&
|
+ this.document.commandDispatcher.focusedElement == this.inputField &&
|
||||||
+ !UrlbarPrefs.get("closeOnWindowBlur")
|
+ !UrlbarPrefs.get("closeOnWindowBlur")
|
||||||
@@ -279,7 +288,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
// We cannot count every blur events after a missed engagement as abandoment
|
// We cannot count every blur events after a missed engagement as abandoment
|
||||||
// because the user may have clicked on some view element that executes
|
// because the user may have clicked on some view element that executes
|
||||||
// a command causing a focus change. For example opening preferences from
|
// a command causing a focus change. For example opening preferences from
|
||||||
@@ -5276,6 +5396,11 @@ ${
|
@@ -5464,6 +5588,11 @@ ${
|
||||||
}
|
}
|
||||||
|
|
||||||
_on_click(event) {
|
_on_click(event) {
|
||||||
@@ -291,7 +300,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
switch (event.target) {
|
switch (event.target) {
|
||||||
case this.inputField:
|
case this.inputField:
|
||||||
case this._inputContainer:
|
case this._inputContainer:
|
||||||
@@ -5371,10 +5496,11 @@ ${
|
@@ -5558,10 +5687,11 @@ ${
|
||||||
}
|
}
|
||||||
if (untrim) {
|
if (untrim) {
|
||||||
this.setValue(this._untrimmedValue);
|
this.setValue(this._untrimmedValue);
|
||||||
@@ -304,7 +313,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
this.view.autoOpen({ event });
|
this.view.autoOpen({ event });
|
||||||
} else {
|
} else {
|
||||||
if (this._untrimOnFocusAfterKeydown) {
|
if (this._untrimOnFocusAfterKeydown) {
|
||||||
@@ -5414,9 +5540,16 @@ ${
|
@@ -5605,9 +5735,16 @@ ${
|
||||||
}
|
}
|
||||||
|
|
||||||
_on_mousedown(event) {
|
_on_mousedown(event) {
|
||||||
@@ -322,7 +331,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
if (
|
if (
|
||||||
event.composedTarget != this.inputField &&
|
event.composedTarget != this.inputField &&
|
||||||
event.composedTarget != this._inputContainer
|
event.composedTarget != this._inputContainer
|
||||||
@@ -5426,6 +5559,10 @@ ${
|
@@ -5617,6 +5754,10 @@ ${
|
||||||
|
|
||||||
this.focusedViaMousedown = !this.focused;
|
this.focusedViaMousedown = !this.focused;
|
||||||
this.#preventClickSelectsAll = this.focused;
|
this.#preventClickSelectsAll = this.focused;
|
||||||
@@ -333,7 +342,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
|
|
||||||
// Keep the focus status, since the attribute may be changed
|
// Keep the focus status, since the attribute may be changed
|
||||||
// upon calling this.focus().
|
// upon calling this.focus().
|
||||||
@@ -5463,7 +5600,7 @@ ${
|
@@ -5654,7 +5795,7 @@ ${
|
||||||
// view open on tab switch, and the TabSelect event arrived earlier.
|
// view open on tab switch, and the TabSelect event arrived earlier.
|
||||||
// Also ignore mousedown on the urlbarView context menu: opening/closing the
|
// Also ignore mousedown on the urlbarView context menu: opening/closing the
|
||||||
// view is already handled by the result opening flow.
|
// view is already handled by the result opening flow.
|
||||||
@@ -342,7 +351,7 @@ index 319fb6870ec18d87b9f1263bd960edaa39b0447c..554cc90fb2307450ddc68033968cefd1
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5754,7 +5891,7 @@ ${
|
@@ -5948,7 +6089,7 @@ ${
|
||||||
// When we are in actions search mode we can show more results so
|
// When we are in actions search mode we can show more results so
|
||||||
// increase the limit.
|
// increase the limit.
|
||||||
let maxResults =
|
let maxResults =
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/browser/components/urlbar/content/UrlbarShared.mjs b/browser/components/urlbar/content/UrlbarShared.mjs
|
diff --git a/browser/components/urlbar/content/UrlbarShared.mjs b/browser/components/urlbar/content/UrlbarShared.mjs
|
||||||
index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36119ae73e 100644
|
index 0ac5330223c84fbb98880a5c2d83ae58a8f3079e..f9d3d27333f5552404bd8a1138fb1e5d6150a3d8 100644
|
||||||
--- a/browser/components/urlbar/content/UrlbarShared.mjs
|
--- a/browser/components/urlbar/content/UrlbarShared.mjs
|
||||||
+++ b/browser/components/urlbar/content/UrlbarShared.mjs
|
+++ b/browser/components/urlbar/content/UrlbarShared.mjs
|
||||||
@@ -100,6 +100,7 @@ export const UrlbarShared = {
|
@@ -158,6 +158,7 @@ export const UrlbarShared = {
|
||||||
// `looksLikeOrigin()` returned `LOOKS_LIKE_ORIGIN.OTHER` for this token.
|
// `looksLikeOrigin()` returned `LOOKS_LIKE_ORIGIN.OTHER` for this token.
|
||||||
// It may or may not be an origin.
|
// It may or may not be an origin.
|
||||||
POSSIBLE_ORIGIN_BUT_SEARCH_ALLOWED: 12,
|
POSSIBLE_ORIGIN_BUT_SEARCH_ALLOWED: 12,
|
||||||
@@ -10,7 +10,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,6 +121,7 @@ export const UrlbarShared = {
|
@@ -178,6 +179,7 @@ export const UrlbarShared = {
|
||||||
TITLE: "#",
|
TITLE: "#",
|
||||||
URL: "$",
|
URL: "$",
|
||||||
ACTION: ">",
|
ACTION: ">",
|
||||||
@@ -18,7 +18,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
// Defines UrlbarResult types.
|
// Defines UrlbarResult types.
|
||||||
@@ -165,6 +167,8 @@ export const UrlbarShared = {
|
@@ -223,6 +225,8 @@ export const UrlbarShared = {
|
||||||
OTHER_NETWORK: 6,
|
OTHER_NETWORK: 6,
|
||||||
ADDON: 7,
|
ADDON: 7,
|
||||||
ACTIONS: 8,
|
ACTIONS: 8,
|
||||||
@@ -27,7 +27,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
// Results are categorized into groups to help the muxer compose them. See
|
// Results are categorized into groups to help the muxer compose them. See
|
||||||
@@ -200,6 +204,8 @@ export const UrlbarShared = {
|
@@ -258,6 +262,8 @@ export const UrlbarShared = {
|
||||||
SEMANTIC_HISTORY: "semanticHistory",
|
SEMANTIC_HISTORY: "semanticHistory",
|
||||||
SUGGESTED_INDEX: "suggestedIndex",
|
SUGGESTED_INDEX: "suggestedIndex",
|
||||||
TAIL_SUGGESTION: "tailSuggestion",
|
TAIL_SUGGESTION: "tailSuggestion",
|
||||||
@@ -36,7 +36,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
// Defines provider types.
|
// Defines provider types.
|
||||||
@@ -385,6 +391,14 @@ export const UrlbarShared = {
|
@@ -443,6 +449,14 @@ export const UrlbarShared = {
|
||||||
telemetryLabel: "actions",
|
telemetryLabel: "actions",
|
||||||
uiLabel: "urlbar-searchmode-actions3",
|
uiLabel: "urlbar-searchmode-actions3",
|
||||||
},
|
},
|
||||||
@@ -51,7 +51,7 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
|||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -402,6 +416,7 @@ export const UrlbarShared = {
|
@@ -460,6 +474,7 @@ export const UrlbarShared = {
|
||||||
if (UrlbarPrefs.get("scotchBonnet.enableOverride")) {
|
if (UrlbarPrefs.get("scotchBonnet.enableOverride")) {
|
||||||
keys.push(this.RESTRICT_TOKENS.ACTION);
|
keys.push(this.RESTRICT_TOKENS.ACTION);
|
||||||
}
|
}
|
||||||
@@ -59,3 +59,15 @@ index 4e67dad66ae006842abc6eed547e4a244320d57a..393b61b4d2543c73e60afd334a353f36
|
|||||||
return new Set(keys);
|
return new Set(keys);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@@ -1032,6 +1047,11 @@ export const UrlbarShared = {
|
||||||
|
return UrlbarShared.RESULT_GROUP.HEURISTIC_FALLBACK;
|
||||||
|
case "UrlbarProviderHistoryUrlHeuristic":
|
||||||
|
return UrlbarShared.RESULT_GROUP.HEURISTIC_HISTORY_URL;
|
||||||
|
+ case "ZenUrlbarProviderGlobalActions":
|
||||||
|
+ if (result.source == UrlbarShared.RESULT_SOURCE.WORKSPACES) {
|
||||||
|
+ return UrlbarShared.RESULT_GROUP.ZEN_WORKSPACE;
|
||||||
|
+ }
|
||||||
|
+ return UrlbarShared.RESULT_GROUP.ZEN_ACTION;
|
||||||
|
case "UrlbarProviderOmnibox":
|
||||||
|
return UrlbarShared.RESULT_GROUP.HEURISTIC_OMNIBOX;
|
||||||
|
case "UrlbarProviderRestrictKeywordsAutofill":
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/browser/extensions/newtab/lib/AboutPreferences.sys.mjs b/browser/extensions/newtab/lib/AboutPreferences.sys.mjs
|
||||||
|
index 4562efc05b76d5dddd35bda79bd7d5d98a51ffc9..ad9b6f55f5e77065ce74535daf6457a5c4b44058 100644
|
||||||
|
--- a/browser/extensions/newtab/lib/AboutPreferences.sys.mjs
|
||||||
|
+++ b/browser/extensions/newtab/lib/AboutPreferences.sys.mjs
|
||||||
|
@@ -355,7 +355,7 @@ export class AboutPreferences {
|
||||||
|
// Firefox 155+ registers `homepage` and `customHomepage` in
|
||||||
|
// components/preferences. They can't be registered twice, so skip them
|
||||||
|
// on 155+. Drop this condition once 155 reaches Release.
|
||||||
|
- if (Services.vc.compare(AppConstants.MOZ_APP_VERSION, "155.0a1") < 0) {
|
||||||
|
+ if (false) {
|
||||||
|
groups.homepage = this._setupHomepageGroup(window);
|
||||||
|
groups.customHomepage = this._setupCustomHomepageGroup(window);
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
diff --git a/browser/modules/ExtensionsUI.sys.mjs b/browser/modules/ExtensionsUI.sys.mjs
|
diff --git a/browser/modules/ExtensionsUI.sys.mjs b/browser/modules/ExtensionsUI.sys.mjs
|
||||||
index 95a4b6e40bd568c3ea5003b648b0acbf96bbb725..6ab8a658721aa6470d482dc958e4b3ac78f49f44 100644
|
index 73ef024602cb4554a024de4ddef83f492adc33ef..959c3403a48a3e4294ad5d2f72bad0e5d4fbfd75 100644
|
||||||
--- a/browser/modules/ExtensionsUI.sys.mjs
|
--- a/browser/modules/ExtensionsUI.sys.mjs
|
||||||
+++ b/browser/modules/ExtensionsUI.sys.mjs
|
+++ b/browser/modules/ExtensionsUI.sys.mjs
|
||||||
@@ -502,7 +502,7 @@ export var ExtensionsUI = {
|
@@ -507,7 +507,7 @@ export var ExtensionsUI = {
|
||||||
eventCallback,
|
// right after the panel opens can't accidentally grant permissions).
|
||||||
removeOnDismissal: true,
|
autofocus: true,
|
||||||
popupOptions: {
|
popupOptions: {
|
||||||
- position: "bottomright topright",
|
- position: "bottomright topright",
|
||||||
+ position: window.gZenUIManager.panelUIPosition(),
|
+ position: window.gZenUIManager.panelUIPosition(),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/browser/themes/shared/tabbrowser/content-area.css b/browser/themes/shared/tabbrowser/content-area.css
|
diff --git a/browser/themes/shared/tabbrowser/content-area.css b/browser/themes/shared/tabbrowser/content-area.css
|
||||||
index 2374ed38bd9361d6c7e1886117099c6761e403b8..72f1f52a13096f19ca4009037ad0cdc880775ff7 100644
|
index 86400b643c8b2af4207d226fbd6d91e5e74548b9..3044e4ab87b7ebcfaa2ac624680da1cc5653c861 100644
|
||||||
--- a/browser/themes/shared/tabbrowser/content-area.css
|
--- a/browser/themes/shared/tabbrowser/content-area.css
|
||||||
+++ b/browser/themes/shared/tabbrowser/content-area.css
|
+++ b/browser/themes/shared/tabbrowser/content-area.css
|
||||||
@@ -239,7 +239,6 @@
|
@@ -166,7 +166,6 @@
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
/* We want to be able to show the frame color behind the clipped radiused corner */
|
/* We want to be able to show the frame color behind the clipped radiused corner */
|
||||||
@@ -10,7 +10,7 @@ index 2374ed38bd9361d6c7e1886117099c6761e403b8..72f1f52a13096f19ca4009037ad0cdc8
|
|||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
/**
|
/**
|
||||||
@@ -425,7 +424,6 @@
|
@@ -355,7 +354,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
browser:is([blank], [pendingpaint]) {
|
browser:is([blank], [pendingpaint]) {
|
||||||
@@ -18,21 +18,21 @@ index 2374ed38bd9361d6c7e1886117099c6761e403b8..72f1f52a13096f19ca4009037ad0cdc8
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Exclude browsers with smartwindow-content attribute which inherit
|
/* Exclude browsers with smartwindow-content attribute which inherit
|
||||||
@@ -865,7 +863,7 @@ split-view-footer {
|
@@ -735,7 +733,7 @@ split-view-footer {
|
||||||
|
|
||||||
.dialogStack {
|
.dialogStack {
|
||||||
z-index: var(--browser-stack-z-index-dialog-stack);
|
z-index: var(--browser-stack-z-index-dialog-stack);
|
||||||
- position: absolute;
|
- position: absolute;
|
||||||
+ position: fixed;
|
+ position: fixed;
|
||||||
inset: 0;
|
|
||||||
/* --browser-with-dialog set on browser[tabDialogShowing], we want to position the overlay
|
/* --browser-with-dialog set on browser[tabDialogShowing], we want to position the overlay
|
||||||
only on the top of the <browser> element so it doesn't overlap the DevTools toolbox */
|
only on the top of the <browser> element so it doesn't overlap the DevTools toolbox */
|
||||||
@@ -1034,7 +1032,7 @@ split-view-footer {
|
@@ -909,7 +907,7 @@ split-view-footer {
|
||||||
|
|
||||||
.dialogOverlay[topmost="true"],
|
.dialogOverlay[topmost="true"],
|
||||||
#window-modal-dialog::backdrop {
|
#window-modal-dialog::backdrop {
|
||||||
- background-color: var(--background-color-overlay);
|
- background-color: var(--background-color-overlay);
|
||||||
+ background-color: light-dark(rgba(255, 255, 255, .3), rgba(0, 0, 0, .3));
|
+ background-color: light-dark(rgba(255, 255, 255, .3), rgba(0, 0, 0, .3));
|
||||||
border-radius: var(--chrome-block-radius);
|
}
|
||||||
|
|
||||||
.browserSidebarContainer.responsive-mode & {
|
.dialogOverlay[hideContent="true"][topmost="true"] {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/themes/shared/toolbarbuttons.css b/browser/themes/shared/toolbarbuttons.css
|
diff --git a/browser/themes/shared/toolbarbuttons.css b/browser/themes/shared/toolbarbuttons.css
|
||||||
index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391fc5fcc79b 100644
|
index bbf906c7bf1d6f0d71744953aeeb750c5181639a..dd116e22c38dc376c9c6b34dfa569bf4661a8971 100644
|
||||||
--- a/browser/themes/shared/toolbarbuttons.css
|
--- a/browser/themes/shared/toolbarbuttons.css
|
||||||
+++ b/browser/themes/shared/toolbarbuttons.css
|
+++ b/browser/themes/shared/toolbarbuttons.css
|
||||||
@@ -13,20 +13,6 @@
|
@@ -13,20 +13,6 @@
|
||||||
@@ -23,7 +23,7 @@ index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391f
|
|||||||
&:where([uidensity="compact"]) {
|
&:where([uidensity="compact"]) {
|
||||||
--toolbarbutton-padding-inner: var(--toolbarbutton-padding-inner-compact);
|
--toolbarbutton-padding-inner: var(--toolbarbutton-padding-inner-compact);
|
||||||
--bookmark-block-padding: 1px;
|
--bookmark-block-padding: 1px;
|
||||||
@@ -123,9 +109,7 @@
|
@@ -119,9 +105,7 @@
|
||||||
#TabsToolbar {
|
#TabsToolbar {
|
||||||
/* Override the inner padding to ensure the dimensions match the tabs, but also making sure
|
/* Override the inner padding to ensure the dimensions match the tabs, but also making sure
|
||||||
different types of buttons (combined-buttons-dropmarker or text) still look correct. */
|
different types of buttons (combined-buttons-dropmarker or text) still look correct. */
|
||||||
@@ -33,18 +33,16 @@ index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391f
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Primary toolbar buttons */
|
/* Primary toolbar buttons */
|
||||||
@@ -205,8 +189,8 @@ toolbar .toolbarbutton-1 {
|
@@ -174,7 +158,7 @@
|
||||||
|
|
||||||
> .toolbarbutton-icon {
|
toolbar .toolbarbutton-1 {
|
||||||
/* horizontal padding + actual icon width */
|
/* horizontal padding + actual icon width */
|
||||||
- width: calc(2 * var(--toolbarbutton-padding-inner) + 16px);
|
- --toolbarbutton-icon-size: calc(2 * var(--toolbarbutton-padding-inner) + 16px);
|
||||||
- height: calc(2 * var(--toolbarbutton-padding-inner) + 16px);
|
+ --toolbarbutton-icon-size: calc(2 * var(--toolbarbutton-padding-inner) + var(--zen-toolbar-button-size, 16px));
|
||||||
+ width: calc(2 * var(--toolbarbutton-padding-inner) + var(--zen-toolbar-button-size, 16px));
|
|
||||||
+ height: calc(2 * var(--toolbarbutton-padding-inner) + var(--zen-toolbar-button-size, 16px));
|
|
||||||
}
|
|
||||||
|
|
||||||
> .toolbarbutton-text {
|
appearance: none;
|
||||||
@@ -216,7 +200,7 @@ toolbar .toolbarbutton-1 {
|
margin: 0;
|
||||||
|
@@ -214,7 +198,7 @@ toolbar .toolbarbutton-1 {
|
||||||
* height as the button icons and the same vertical padding, but as a minimum,
|
* height as the button icons and the same vertical padding, but as a minimum,
|
||||||
* because otherwise an increase in text sizes would break things.
|
* because otherwise an increase in text sizes would break things.
|
||||||
*/
|
*/
|
||||||
@@ -62,7 +60,7 @@ index 94b1a2a841d8fd47a491616d52e5bf544f0c0bf9..9e98266b98c6b66fed26fec12fa3391f
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +520,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton) {
|
@@ -427,7 +411,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton) {
|
||||||
*/
|
*/
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
> .toolbarbutton-icon {
|
> .toolbarbutton-icon {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css
|
diff --git a/browser/themes/shared/urlbar.css b/browser/themes/shared/urlbar.css
|
||||||
index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d2078419659065 100644
|
index 06183c82e2869290a5fb476c47fb7db92bbef57f..c64cde1eef50d3457fb1c540d95fe3b8aa087294 100644
|
||||||
--- a/browser/themes/shared/urlbar-searchbar.css
|
--- a/browser/themes/shared/urlbar.css
|
||||||
+++ b/browser/themes/shared/urlbar-searchbar.css
|
+++ b/browser/themes/shared/urlbar.css
|
||||||
@@ -19,8 +19,8 @@
|
@@ -24,8 +24,8 @@
|
||||||
|
|
||||||
@media not -moz-pref("browser.nova.enabled") {
|
@media not -moz-pref("browser.nova.enabled") {
|
||||||
--urlbar-basic-component-size: calc(var(--urlbar-height) - 2 * (var(--urlbar-input-container-border-width) + var(--urlbar-input-container-padding)));
|
--urlbar-basic-component-size: calc(var(--urlbar-height) - 2 * (var(--urlbar-input-container-border-width) + var(--urlbar-input-container-padding)));
|
||||||
@@ -13,7 +13,7 @@ index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d20784
|
|||||||
}
|
}
|
||||||
@media (max-width: 770px) {
|
@media (max-width: 770px) {
|
||||||
--urlbar-container-min-width: 240px;
|
--urlbar-container-min-width: 240px;
|
||||||
@@ -127,7 +127,7 @@ toolbar[inactive="true"] .urlbar,
|
@@ -143,7 +143,7 @@ toolbar[inactive="true"] .urlbar,
|
||||||
.urlbar:not([usertyping]) > .urlbar-input-container > .urlbar-go-button,
|
.urlbar:not([usertyping]) > .urlbar-input-container > .urlbar-go-button,
|
||||||
.urlbar:not(#searchbar-new, [focused]) > .urlbar-input-container > .urlbar-go-button,
|
.urlbar:not(#searchbar-new, [focused]) > .urlbar-input-container > .urlbar-go-button,
|
||||||
#urlbar-revert-button-container {
|
#urlbar-revert-button-container {
|
||||||
@@ -22,7 +22,7 @@ index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d20784
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Document Picture-in-Picture API window */
|
/* Document Picture-in-Picture API window */
|
||||||
@@ -405,6 +405,10 @@ toolbar[inactive="true"] .urlbar,
|
@@ -434,6 +434,10 @@ toolbar[inactive="true"] .urlbar,
|
||||||
.urlbar:not([focused])[textoverflow="left"][domaindir="rtl"] > .urlbar-input-container > .urlbar-input-box > & {
|
.urlbar:not([focused])[textoverflow="left"][domaindir="rtl"] > .urlbar-input-container > .urlbar-input-box > & {
|
||||||
mask-image: linear-gradient(to right, transparent var(--urlbar-scheme-size), black calc(var(--urlbar-scheme-size) + 3ch));
|
mask-image: linear-gradient(to right, transparent var(--urlbar-scheme-size), black calc(var(--urlbar-scheme-size) + 3ch));
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ index 149f123e26cd79e89432dfeb504ca7218ee04810..7e0e6d981d6c2aa53bc2a76d82d20784
|
|||||||
}
|
}
|
||||||
|
|
||||||
#urlbar-scheme {
|
#urlbar-scheme {
|
||||||
@@ -476,10 +480,15 @@ toolbar[inactive="true"] .urlbar,
|
@@ -505,10 +509,15 @@ toolbar[inactive="true"] .urlbar,
|
||||||
}
|
}
|
||||||
|
|
||||||
.urlbar[breakout][breakout-extend] {
|
.urlbar[breakout][breakout-extend] {
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/build/moz.configure/lto-pgo.configure b/build/moz.configure/lto-pgo.configure
|
diff --git a/build/moz.configure/lto-pgo.configure b/build/moz.configure/lto-pgo.configure
|
||||||
index df2b0bf0081edfdc2c7bccaefc780d2b0c6555ff..53a3b55de7650799e3730372e72ad7b4bb2eea03 100644
|
index c72af5ed5f88fc80c810ef626e57a8b991dee514..53a3b55de7650799e3730372e72ad7b4bb2eea03 100644
|
||||||
--- a/build/moz.configure/lto-pgo.configure
|
--- a/build/moz.configure/lto-pgo.configure
|
||||||
+++ b/build/moz.configure/lto-pgo.configure
|
+++ b/build/moz.configure/lto-pgo.configure
|
||||||
@@ -234,6 +234,7 @@ def moz_pgo_rust(pgo, profile_use, profile_generate, c_compiler):
|
@@ -234,6 +234,7 @@ def moz_pgo_rust(pgo, profile_use, profile_generate, c_compiler):
|
||||||
@@ -14,7 +14,7 @@ index df2b0bf0081edfdc2c7bccaefc780d2b0c6555ff..53a3b55de7650799e3730372e72ad7b4
|
|||||||
help="Indicate that ld64 is free of symbol aliasing bugs",
|
help="Indicate that ld64 is free of symbol aliasing bugs",
|
||||||
)
|
)
|
||||||
|
|
||||||
-imply_option("MOZ_LD64_KNOWN_GOOD", moz_automation)
|
-imply_option("MOZ_LD64_KNOWN_GOOD", True, when=moz_automation)
|
||||||
|
|
||||||
use_fat_lto = cxx_compiler.try_link(
|
use_fat_lto = cxx_compiler.try_link(
|
||||||
ldflags=depends(stlport_libs)(
|
ldflags=depends(stlport_libs)(
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
diff --git a/browser/components/sessionstore/test/browser.toml b/browser/components/sessionstore/test/browser.toml
|
|
||||||
--- a/browser/components/sessionstore/test/browser.toml
|
|
||||||
+++ b/browser/components/sessionstore/test/browser.toml
|
|
||||||
@@ -14,10 +14,12 @@
|
|
||||||
"browser_frame_history_c.html",
|
|
||||||
"browser_frame_history_c1.html",
|
|
||||||
"browser_frame_history_c2.html",
|
|
||||||
"browser_formdata_format_sample.html",
|
|
||||||
"browser_sessionHistory_slow.sjs",
|
|
||||||
+ "browser_policy_container_sample.html",
|
|
||||||
+ "browser_policy_container_sample_frame.html",
|
|
||||||
"browser_scrollPositions_sample.html",
|
|
||||||
"browser_scrollPositions_sample2.html",
|
|
||||||
"browser_scrollPositions_sample_frameset.html",
|
|
||||||
"browser_scrollPositions_readerModeArticle.html",
|
|
||||||
"browser_sessionStorage.html",
|
|
||||||
@@ -226,10 +228,12 @@
|
|
||||||
["browser_pinned_tabs.js"]
|
|
||||||
skip-if = [
|
|
||||||
"ccov", # Bug 1625525
|
|
||||||
]
|
|
||||||
|
|
||||||
+["browser_policy_container_not_stored.js"]
|
|
||||||
+
|
|
||||||
["browser_privatetabs.js"]
|
|
||||||
|
|
||||||
["browser_purge_domaindata.js"]
|
|
||||||
|
|
||||||
["browser_purge_shistory.js"]
|
|
||||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_not_stored.js b/browser/components/sessionstore/test/browser_policy_container_not_stored.js
|
|
||||||
new file mode 100644
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/browser/components/sessionstore/test/browser_policy_container_not_stored.js
|
|
||||||
@@ -0,0 +1,51 @@
|
|
||||||
+/* 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/. */
|
|
||||||
+
|
|
||||||
+"use strict";
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * A session history entry only needs to retain the policy container for loads
|
|
||||||
+ * that inherit their policies (about:blank, about:srcdoc, blob:, data:, ...).
|
|
||||||
+ * Anything fetched over the network gets its policies from the response again,
|
|
||||||
+ * so storing them would only bloat the session store (bug 2011236).
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+const TEST_ROOT = getRootDirectory(gTestPath).replace(
|
|
||||||
+ "chrome://mochitests/content",
|
|
||||||
+ "https://example.com"
|
|
||||||
+);
|
|
||||||
+const PARENT_URL = TEST_ROOT + "browser_policy_container_sample.html";
|
|
||||||
+const FRAME_URL = TEST_ROOT + "browser_policy_container_sample_frame.html";
|
|
||||||
+
|
|
||||||
+add_task(async function test_policy_container_only_for_inheriting_loads() {
|
|
||||||
+ const tab = BrowserTestUtils.addTab(gBrowser, PARENT_URL);
|
|
||||||
+ gBrowser.selectedTab = tab;
|
|
||||||
+ await promiseBrowserLoaded(tab.linkedBrowser, true, PARENT_URL);
|
|
||||||
+ await TabStateFlusher.flush(tab.linkedBrowser);
|
|
||||||
+
|
|
||||||
+ const state = JSON.parse(ss.getTabState(tab));
|
|
||||||
+ const topEntry = state.entries.at(-1);
|
|
||||||
+ is(topEntry.url, PARENT_URL, "collected the parent entry");
|
|
||||||
+
|
|
||||||
+ const children = topEntry.children ?? [];
|
|
||||||
+ const networkFrame = children.find(child => child.url === FRAME_URL);
|
|
||||||
+ const blankFrame = children.find(child => child.url === "about:blank");
|
|
||||||
+
|
|
||||||
+ ok(networkFrame, "collected the network-scheme subframe entry");
|
|
||||||
+ ok(blankFrame, "collected the about:blank subframe entry");
|
|
||||||
+
|
|
||||||
+ // The parent has a CSP, so both subframes inherit a policy container onto
|
|
||||||
+ // their load state. Only the one that cannot recover it from a response
|
|
||||||
+ // should keep it in session history.
|
|
||||||
+ ok(
|
|
||||||
+ !("policyContainer" in networkFrame),
|
|
||||||
+ "https subframe entry does not store a policyContainer"
|
|
||||||
+ );
|
|
||||||
+ ok(
|
|
||||||
+ "policyContainer" in blankFrame,
|
|
||||||
+ "about:blank subframe entry still stores its inherited policyContainer"
|
|
||||||
+ );
|
|
||||||
+
|
|
||||||
+ await BrowserTestUtils.removeTab(tab);
|
|
||||||
+});
|
|
||||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_sample.html b/browser/components/sessionstore/test/browser_policy_container_sample.html
|
|
||||||
new file mode 100644
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/browser/components/sessionstore/test/browser_policy_container_sample.html
|
|
||||||
@@ -0,0 +1,12 @@
|
|
||||||
+<!DOCTYPE html>
|
|
||||||
+<html>
|
|
||||||
+<head>
|
|
||||||
+ <meta charset="utf-8">
|
|
||||||
+ <meta http-equiv="Content-Security-Policy" content="default-src * data: blob: 'unsafe-inline'">
|
|
||||||
+ <title>policyContainer session store sample</title>
|
|
||||||
+</head>
|
|
||||||
+<body>
|
|
||||||
+ <iframe id="network" src="browser_policy_container_sample_frame.html"></iframe>
|
|
||||||
+ <iframe id="blank" src="about:blank"></iframe>
|
|
||||||
+</body>
|
|
||||||
+</html>
|
|
||||||
diff --git a/browser/components/sessionstore/test/browser_policy_container_sample_frame.html b/browser/components/sessionstore/test/browser_policy_container_sample_frame.html
|
|
||||||
new file mode 100644
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/browser/components/sessionstore/test/browser_policy_container_sample_frame.html
|
|
||||||
@@ -0,0 +1,10 @@
|
|
||||||
+<!DOCTYPE html>
|
|
||||||
+<html>
|
|
||||||
+<head>
|
|
||||||
+ <meta charset="utf-8">
|
|
||||||
+ <title>policyContainer session store sample frame</title>
|
|
||||||
+</head>
|
|
||||||
+<body>
|
|
||||||
+ frame
|
|
||||||
+</body>
|
|
||||||
+</html>
|
|
||||||
diff --git a/docshell/shistory/SessionHistoryEntry.cpp b/docshell/shistory/SessionHistoryEntry.cpp
|
|
||||||
--- a/docshell/shistory/SessionHistoryEntry.cpp
|
|
||||||
+++ b/docshell/shistory/SessionHistoryEntry.cpp
|
|
||||||
@@ -41,10 +41,18 @@
|
|
||||||
extern mozilla::LazyLogModule gSHLog;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
+// Only store policy container for loads that can't carry it themselves
|
|
||||||
+// (about:blank, about:srcdoc, blob:, data:, ...)
|
|
||||||
+// bug 1867137, bug 2011236
|
|
||||||
+static nsIPolicyContainer* PolicyContainerToStore(
|
|
||||||
+ nsIURI* aURI, nsIPolicyContainer* aPolicyContainer) {
|
|
||||||
+ return CSP_ShouldURIInheritCSP(aURI) ? aPolicyContainer : nullptr;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
SessionHistoryInfo::SessionHistoryInfo(nsDocShellLoadState* aLoadState,
|
|
||||||
nsIChannel* aChannel)
|
|
||||||
: mURI(aLoadState->URI()),
|
|
||||||
mOriginalURI(aLoadState->OriginalURI()),
|
|
||||||
mResultPrincipalURI(aLoadState->ResultPrincipalURI()),
|
|
||||||
@@ -59,11 +67,12 @@
|
|
||||||
mLoadReplace(aLoadState->LoadReplace()),
|
|
||||||
mHasUserActivation(aLoadState->HasValidUserGestureActivation()),
|
|
||||||
mSharedState(SharedState::Create(
|
|
||||||
aLoadState->TriggeringPrincipal(), aLoadState->PrincipalToInherit(),
|
|
||||||
aLoadState->PartitionedPrincipalToInherit(),
|
|
||||||
- aLoadState->PolicyContainer(),
|
|
||||||
+ PolicyContainerToStore(aLoadState->URI(),
|
|
||||||
+ aLoadState->PolicyContainer()),
|
|
||||||
/* FIXME Is this correct? */
|
|
||||||
aLoadState->TypeHint())) {
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!mURI->SchemeIs("javascript"));
|
|
||||||
|
|
||||||
// Pull the upload stream off of the channel instead of the load state, as
|
|
||||||
@@ -124,11 +133,12 @@
|
|
||||||
loadInfo->GetPrincipalToInherit(
|
|
||||||
getter_AddRefs(mSharedState.Get()->mPrincipalToInherit));
|
|
||||||
|
|
||||||
mSharedState.Get()->mPartitionedPrincipalToInherit =
|
|
||||||
aPartitionedPrincipalToInherit;
|
|
||||||
- mSharedState.Get()->mPolicyContainer = aPolicyContainer;
|
|
||||||
+ mSharedState.Get()->mPolicyContainer =
|
|
||||||
+ PolicyContainerToStore(mURI, aPolicyContainer);
|
|
||||||
aChannel->GetContentType(mSharedState.Get()->mContentType);
|
|
||||||
aChannel->GetOriginalURI(getter_AddRefs(mOriginalURI));
|
|
||||||
|
|
||||||
uint32_t loadFlags;
|
|
||||||
aChannel->GetLoadFlags(&loadFlags);
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
131
src/external-patches/firefox/issue_15123.patch
Normal file
131
src/external-patches/firefox/issue_15123.patch
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
diff --git a/toolkit/modules/subprocess/subprocess_shared_unix.js b/toolkit/modules/subprocess/subprocess_shared_unix.js
|
||||||
|
--- a/toolkit/modules/subprocess/subprocess_shared_unix.js
|
||||||
|
+++ b/toolkit/modules/subprocess/subprocess_shared_unix.js
|
||||||
|
@@ -57,11 +57,11 @@
|
||||||
|
fcntl: [
|
||||||
|
ctypes.default_abi,
|
||||||
|
ctypes.int,
|
||||||
|
ctypes.int /* fildes */,
|
||||||
|
ctypes.int /* cmd */,
|
||||||
|
- ctypes.int /* ... */,
|
||||||
|
+ "...",
|
||||||
|
],
|
||||||
|
|
||||||
|
getcwd: [
|
||||||
|
ctypes.default_abi,
|
||||||
|
ctypes.char.ptr,
|
||||||
|
diff --git a/toolkit/modules/subprocess/subprocess_unix.sys.mjs b/toolkit/modules/subprocess/subprocess_unix.sys.mjs
|
||||||
|
--- a/toolkit/modules/subprocess/subprocess_unix.sys.mjs
|
||||||
|
+++ b/toolkit/modules/subprocess/subprocess_unix.sys.mjs
|
||||||
|
@@ -34,13 +34,13 @@
|
||||||
|
throw new Error("Unable to create pipe");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.signalFd = fds[1];
|
||||||
|
|
||||||
|
- libc.fcntl(fds[0], LIBC.F_SETFL, LIBC.O_NONBLOCK);
|
||||||
|
- libc.fcntl(fds[0], LIBC.F_SETFD, LIBC.FD_CLOEXEC);
|
||||||
|
- libc.fcntl(fds[1], LIBC.F_SETFD, LIBC.FD_CLOEXEC);
|
||||||
|
+ libc.fcntl(fds[0], LIBC.F_SETFL, ctypes.int(LIBC.O_NONBLOCK));
|
||||||
|
+ libc.fcntl(fds[0], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));
|
||||||
|
+ libc.fcntl(fds[1], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));
|
||||||
|
|
||||||
|
this.call("init", [{ signalFd: fds[0] }]);
|
||||||
|
}
|
||||||
|
|
||||||
|
closePipe() {
|
||||||
|
diff --git a/toolkit/modules/subprocess/subprocess_unix.worker.js b/toolkit/modules/subprocess/subprocess_unix.worker.js
|
||||||
|
--- a/toolkit/modules/subprocess/subprocess_unix.worker.js
|
||||||
|
+++ b/toolkit/modules/subprocess/subprocess_unix.worker.js
|
||||||
|
@@ -349,13 +349,13 @@
|
||||||
|
our_pipes.push(new InputPipe(this, fds[1]));
|
||||||
|
} else {
|
||||||
|
our_pipes.push(new OutputPipe(this, fds[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
- libc.fcntl(fds[0], LIBC.F_SETFD, LIBC.FD_CLOEXEC);
|
||||||
|
- libc.fcntl(fds[1], LIBC.F_SETFD, LIBC.FD_CLOEXEC);
|
||||||
|
- libc.fcntl(fds[1], LIBC.F_SETFL, LIBC.O_NONBLOCK);
|
||||||
|
+ libc.fcntl(fds[0], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));
|
||||||
|
+ libc.fcntl(fds[1], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));
|
||||||
|
+ libc.fcntl(fds[1], LIBC.F_SETFL, ctypes.int(LIBC.O_NONBLOCK));
|
||||||
|
|
||||||
|
return fds[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
their_pipes.set(0, pipe(false));
|
||||||
|
diff --git a/toolkit/modules/subprocess/test/xpcshell/test_subprocess_pipe_flags.js b/toolkit/modules/subprocess/test/xpcshell/test_subprocess_pipe_flags.js
|
||||||
|
new file mode 100644
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/toolkit/modules/subprocess/test/xpcshell/test_subprocess_pipe_flags.js
|
||||||
|
@@ -0,0 +1,56 @@
|
||||||
|
+/* 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/. */
|
||||||
|
+
|
||||||
|
+"use strict";
|
||||||
|
+
|
||||||
|
+// fcntl commands for reading the flags set by the subprocess modules. The
|
||||||
|
+// values are the same on Linux and macOS but are not exposed by
|
||||||
|
+// ChromeUtils.getLibcConstants().
|
||||||
|
+const F_GETFD = 1;
|
||||||
|
+const F_GETFL = 3;
|
||||||
|
+
|
||||||
|
+add_task(async function test_subprocess_pipe_flags() {
|
||||||
|
+ const { getSubprocessImplForTest } = ChromeUtils.importESModule(
|
||||||
|
+ "resource://gre/modules/Subprocess.sys.mjs"
|
||||||
|
+ );
|
||||||
|
+ const { libc } = ChromeUtils.importESModule(
|
||||||
|
+ "resource://gre/modules/subprocess/subprocess_unix.sys.mjs"
|
||||||
|
+ );
|
||||||
|
+ const { FD_CLOEXEC, O_NONBLOCK } = ChromeUtils.getLibcConstants();
|
||||||
|
+
|
||||||
|
+ const worker = getSubprocessImplForTest().Process.getWorker();
|
||||||
|
+ equal(
|
||||||
|
+ libc.fcntl(worker.signalFd, F_GETFD),
|
||||||
|
+ FD_CLOEXEC,
|
||||||
|
+ "The main-thread signal pipe has exactly FD_CLOEXEC set"
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+ const proc = await Subprocess.call({
|
||||||
|
+ command: await Subprocess.pathSearch("cat"),
|
||||||
|
+ stderr: "pipe",
|
||||||
|
+ });
|
||||||
|
+ const fds = await worker.call("getFds", [proc.id]);
|
||||||
|
+ ok(
|
||||||
|
+ fds.every(Number.isInteger),
|
||||||
|
+ "The worker owns the stdin, stdout and stderr pipes"
|
||||||
|
+ );
|
||||||
|
+ for (const fd of fds) {
|
||||||
|
+ equal(
|
||||||
|
+ libc.fcntl(fd, F_GETFD),
|
||||||
|
+ FD_CLOEXEC,
|
||||||
|
+ "Worker pipes have exactly FD_CLOEXEC set"
|
||||||
|
+ );
|
||||||
|
+ equal(
|
||||||
|
+ libc.fcntl(fd, F_GETFL) & O_NONBLOCK,
|
||||||
|
+ O_NONBLOCK,
|
||||||
|
+ "Worker pipes are nonblocking"
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ const output = proc.stdout.readString(5);
|
||||||
|
+ await proc.stdin.write("hello");
|
||||||
|
+ equal(await output, "hello", "The subprocess pipes transfer data");
|
||||||
|
+ await proc.stdin.close();
|
||||||
|
+ equal((await proc.wait()).exitCode, 0, "The subprocess exits cleanly");
|
||||||
|
+});
|
||||||
|
diff --git a/toolkit/modules/subprocess/test/xpcshell/xpcshell.toml b/toolkit/modules/subprocess/test/xpcshell/xpcshell.toml
|
||||||
|
--- a/toolkit/modules/subprocess/test/xpcshell/xpcshell.toml
|
||||||
|
+++ b/toolkit/modules/subprocess/test/xpcshell/xpcshell.toml
|
||||||
|
@@ -25,6 +25,9 @@
|
||||||
|
["test_subprocess_pathSearch.js"]
|
||||||
|
|
||||||
|
["test_subprocess_perf.js"]
|
||||||
|
requesttimeoutfactor = 2 # Slow on Windows
|
||||||
|
|
||||||
|
+["test_subprocess_pipe_flags.js"]
|
||||||
|
+skip-if = ["os == 'win'"]
|
||||||
|
+
|
||||||
|
["test_subprocess_polling.js"]
|
||||||
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
diff --git a/toolkit/themes/shared/global-shared.css b/toolkit/themes/shared/global-shared.css
|
diff --git a/toolkit/themes/shared/global-shared.css b/toolkit/themes/shared/global-shared.css
|
||||||
--- a/toolkit/themes/shared/global-shared.css
|
--- a/toolkit/themes/shared/global-shared.css
|
||||||
+++ b/toolkit/themes/shared/global-shared.css
|
+++ b/toolkit/themes/shared/global-shared.css
|
||||||
@@ -80,11 +80,10 @@
|
@@ -80,10 +80,9 @@
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
--panel-background: transparent;
|
|
||||||
--panel-box-shadow: none;
|
--panel-box-shadow: none;
|
||||||
--panel-border-color: transparent;
|
--panel-border-color: transparent;
|
||||||
--panel-box-shadow-margin: 0px;
|
--panel-box-shadow-margin: 0px;
|
||||||
|
|||||||
@@ -7,6 +7,11 @@
|
|||||||
"id": "D299584",
|
"id": "D299584",
|
||||||
"name": "Native MacOS popovers fix"
|
"name": "Native MacOS popovers fix"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "phabricator",
|
||||||
|
"id": "D323933",
|
||||||
|
"name": "Issue 15123"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "local",
|
"type": "local",
|
||||||
// TODO: Convert into https://phabricator.services.mozilla.com/D298079
|
// TODO: Convert into https://phabricator.services.mozilla.com/D298079
|
||||||
@@ -41,20 +46,11 @@
|
|||||||
" jsonLengthHint,": " lengthHint: jsonLengthHint,"
|
" jsonLengthHint,": " lengthHint: jsonLengthHint,"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "phabricator",
|
|
||||||
"id": "D320897",
|
|
||||||
"name": "Bug 2011236"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "phabricator",
|
"type": "phabricator",
|
||||||
"id": "D321446",
|
"id": "D321446",
|
||||||
"name": "Issue 14710"
|
"name": "Issue 14710"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "local",
|
|
||||||
"path": "firefox/css_corner_shape_rendering.patch"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"path": "firefox/override_cert_checks_temp.patch"
|
"path": "firefox/override_cert_checks_temp.patch"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp
|
diff --git a/layout/painting/nsImageRenderer.cpp b/layout/painting/nsImageRenderer.cpp
|
||||||
index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d24fb106ce 100644
|
index 7ddc4f7e259272e7b905f44aff7316c1ba540c22..277a92e5d10e6a04b12373854ffe6791d562215e 100644
|
||||||
--- a/layout/painting/nsImageRenderer.cpp
|
--- a/layout/painting/nsImageRenderer.cpp
|
||||||
+++ b/layout/painting/nsImageRenderer.cpp
|
+++ b/layout/painting/nsImageRenderer.cpp
|
||||||
@@ -90,7 +90,7 @@ static already_AddRefed<imgIContainer> GetSymbolicIconImage(nsAtom* aName,
|
@@ -95,7 +95,7 @@ static already_AddRefed<imgIContainer> GetSymbolicIconImage(nsAtom* aName,
|
||||||
if (NS_WARN_IF(!XRE_IsParentProcess())) {
|
if (NS_WARN_IF(!XRE_IsParentProcess())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d2
|
|||||||
auto key = std::make_tuple(aName, aScale, fg);
|
auto key = std::make_tuple(aName, aScale, fg);
|
||||||
auto* cache = aFrame->GetOrCreateDeletableProperty(SymbolicImageCacheProp());
|
auto* cache = aFrame->GetOrCreateDeletableProperty(SymbolicImageCacheProp());
|
||||||
auto lookup = cache->Lookup(key);
|
auto lookup = cache->Lookup(key);
|
||||||
@@ -575,7 +575,7 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
|
@@ -580,7 +580,7 @@ ImgDrawResult nsImageRenderer::Draw(nsPresContext* aPresContext,
|
||||||
}
|
}
|
||||||
case StyleImage::Tag::Gradient: {
|
case StyleImage::Tag::Gradient: {
|
||||||
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
||||||
@@ -20,7 +20,7 @@ index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d2
|
|||||||
|
|
||||||
renderer.Paint(*ctx, aDest, aFill, aRepeatSize, aSrc, aDirtyRect,
|
renderer.Paint(*ctx, aDest, aFill, aRepeatSize, aSrc, aDirtyRect,
|
||||||
aOpacity);
|
aOpacity);
|
||||||
@@ -652,7 +652,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
@@ -657,7 +657,7 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
||||||
switch (mType) {
|
switch (mType) {
|
||||||
case StyleImage::Tag::Gradient: {
|
case StyleImage::Tag::Gradient: {
|
||||||
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
||||||
@@ -29,16 +29,16 @@ index 6e464b48c90174b8954aad8a79bae30a7a30cbc9..9ea9a4963ceae679f092e014ac24a0d2
|
|||||||
|
|
||||||
renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aDest, aFill,
|
renderer.BuildWebRenderDisplayItems(aBuilder, aSc, aDest, aFill,
|
||||||
aRepeatSize, aSrc,
|
aRepeatSize, aSrc,
|
||||||
@@ -678,6 +678,8 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
@@ -679,6 +679,8 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
|
||||||
nsPresContext::AppUnitsToIntCSSPixels(aDest.height)};
|
}
|
||||||
|
|
||||||
SVGImageContext svgContext(Some(destCSSSize));
|
SVGImageContext svgContext(Some(CSSSize::FromAppUnits(aDest.Size())));
|
||||||
+ SVGImageContext::MaybeStoreZenBoosts(svgContext,
|
+ SVGImageContext::MaybeStoreZenBoosts(svgContext,
|
||||||
+ *mForFrame->PresContext());
|
+ *mForFrame->PresContext());
|
||||||
Maybe<ImageIntRegion> region;
|
Maybe<ImageIntRegion> region;
|
||||||
|
|
||||||
const int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
|
const int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
|
||||||
@@ -1092,7 +1094,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
|
@@ -1098,7 +1100,7 @@ ImgDrawResult nsImageRenderer::DrawShapeImage(nsPresContext* aPresContext,
|
||||||
|
|
||||||
if (mImage->IsGradient()) {
|
if (mImage->IsGradient()) {
|
||||||
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
nsCSSGradientRenderer renderer = nsCSSGradientRenderer::Create(
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
diff --git a/layout/svg/SVGGradientFrame.cpp b/layout/svg/SVGGradientFrame.cpp
|
diff --git a/layout/svg/SVGGradientFrame.cpp b/layout/svg/SVGGradientFrame.cpp
|
||||||
index b0d38b0fab01797328af0b1f1f48af8fb5eebe4d..953feffdc96143dc2d8f8e57f8bb4a6aeb33f0c5 100644
|
index eebcced86ec1e9010b761d5df4a92684dde44009..4dc018a73a979f50ac7842e4a3f3fcf9d0071b56 100644
|
||||||
--- a/layout/svg/SVGGradientFrame.cpp
|
--- a/layout/svg/SVGGradientFrame.cpp
|
||||||
+++ b/layout/svg/SVGGradientFrame.cpp
|
+++ b/layout/svg/SVGGradientFrame.cpp
|
||||||
@@ -229,8 +229,9 @@ class MOZ_STACK_CLASS SVGColorStopInterpolator
|
@@ -228,8 +228,9 @@ class MOZ_STACK_CLASS SVGColorStopInterpolator
|
||||||
SVGColorStopInterpolator(
|
SVGColorStopInterpolator(
|
||||||
gfxPattern* aGradient, const nsTArray<ColorStop>& aStops,
|
gfxPattern* aGradient, const nsTArray<ColorStop>& aStops,
|
||||||
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
|
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
|
||||||
@@ -14,8 +14,8 @@ index b0d38b0fab01797328af0b1f1f48af8fb5eebe4d..953feffdc96143dc2d8f8e57f8bb4a6a
|
|||||||
mGradient(aGradient) {}
|
mGradient(aGradient) {}
|
||||||
|
|
||||||
void CreateStop(float aPosition, DeviceColor aColor) {
|
void CreateStop(float aPosition, DeviceColor aColor) {
|
||||||
@@ -270,7 +271,8 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
|
@@ -269,7 +270,8 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
|
||||||
if (nStops == 1 || GradientVectorLengthIsZero()) {
|
if (nStops == 1 || GradientVectorLengthIsZero(gradientUnits)) {
|
||||||
// The gradient paints a single colour, using the stop-color of the last
|
// The gradient paints a single colour, using the stop-color of the last
|
||||||
// gradient step if there are more than one.
|
// gradient step if there are more than one.
|
||||||
- return MakeAndAddRef<gfxPattern>(ToDeviceColor(stops.LastElement().mColor));
|
- return MakeAndAddRef<gfxPattern>(ToDeviceColor(stops.LastElement().mColor));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/layout/svg/SVGImageContext.h b/layout/svg/SVGImageContext.h
|
diff --git a/layout/svg/SVGImageContext.h b/layout/svg/SVGImageContext.h
|
||||||
index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd6178f9e3 100644
|
index 63f3c4926cfdb8b12e9e4a38016fc66f50cf3129..5ba3f2c07f521905a086ee6eea87975d5a3441ec 100644
|
||||||
--- a/layout/svg/SVGImageContext.h
|
--- a/layout/svg/SVGImageContext.h
|
||||||
+++ b/layout/svg/SVGImageContext.h
|
+++ b/layout/svg/SVGImageContext.h
|
||||||
@@ -6,6 +6,7 @@
|
@@ -6,6 +6,7 @@
|
||||||
@@ -7,10 +7,10 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
|||||||
|
|
||||||
#include "Units.h"
|
#include "Units.h"
|
||||||
+#include "nsColor.h"
|
+#include "nsColor.h"
|
||||||
|
#include "mozilla/Casting.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/SVGContextPaint.h"
|
#include "mozilla/SVGContextPaint.h"
|
||||||
#include "mozilla/SVGPreserveAspectRatio.h"
|
@@ -64,6 +65,11 @@ class SVGImageContext {
|
||||||
@@ -63,6 +64,11 @@ class SVGImageContext {
|
|
||||||
nsISVGPaintContext* aPaintContext,
|
nsISVGPaintContext* aPaintContext,
|
||||||
imgIContainer* aImgContainer);
|
imgIContainer* aImgContainer);
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
|||||||
+ static void MaybeStoreZenBoosts(SVGImageContext& aContext,
|
+ static void MaybeStoreZenBoosts(SVGImageContext& aContext,
|
||||||
+ const nsPresContext& aPresContext);
|
+ const nsPresContext& aPresContext);
|
||||||
+
|
+
|
||||||
const Maybe<CSSIntSize>& GetViewportSize() const { return mViewportSize; }
|
const Maybe<CSSSize>& GetViewportSize() const { return mViewportSize; }
|
||||||
|
|
||||||
void SetViewportSize(const Maybe<CSSIntSize>& aSize) {
|
void SetViewportSize(const Maybe<CSSSize>& aSize) { mViewportSize = aSize; }
|
||||||
@@ -75,6 +81,21 @@ class SVGImageContext {
|
@@ -74,6 +80,21 @@ class SVGImageContext {
|
||||||
mColorScheme = aScheme;
|
mColorScheme = aScheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
|||||||
const Maybe<SVGPreserveAspectRatio>& GetPreserveAspectRatio() const {
|
const Maybe<SVGPreserveAspectRatio>& GetPreserveAspectRatio() const {
|
||||||
return mPreserveAspectRatio;
|
return mPreserveAspectRatio;
|
||||||
}
|
}
|
||||||
@@ -110,7 +131,11 @@ class SVGImageContext {
|
@@ -109,7 +130,11 @@ class SVGImageContext {
|
||||||
return contextPaintIsEqual && mViewportSize == aOther.mViewportSize &&
|
return contextPaintIsEqual && mViewportSize == aOther.mViewportSize &&
|
||||||
mPreserveAspectRatio == aOther.mPreserveAspectRatio &&
|
mPreserveAspectRatio == aOther.mPreserveAspectRatio &&
|
||||||
mColorScheme == aOther.mColorScheme &&
|
mColorScheme == aOther.mColorScheme &&
|
||||||
@@ -56,8 +56,8 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
|||||||
+ mZenBoostsInverted == aOther.mZenBoostsInverted;
|
+ mZenBoostsInverted == aOther.mZenBoostsInverted;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const SVGImageContext&) const = default;
|
PLDHashNumber Hash() const {
|
||||||
@@ -123,7 +148,8 @@ class SVGImageContext {
|
@@ -120,7 +145,8 @@ class SVGImageContext {
|
||||||
return AddToHash(hash, mViewportSize.map(HashSize).valueOr(0),
|
return AddToHash(hash, mViewportSize.map(HashSize).valueOr(0),
|
||||||
mPreserveAspectRatio.map(HashPAR).valueOr(0),
|
mPreserveAspectRatio.map(HashPAR).valueOr(0),
|
||||||
mColorScheme.map(HashColorScheme).valueOr(0),
|
mColorScheme.map(HashColorScheme).valueOr(0),
|
||||||
@@ -67,7 +67,7 @@ index ad833c7c2ee6a4c4984efdb0d59e3576c2d1bc19..36864a34badc0cbfe44d6295798622fd
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -156,6 +182,9 @@ class SVGImageContext {
|
@@ -154,6 +180,9 @@ class SVGImageContext {
|
||||||
Maybe<SVGPreserveAspectRatio> mPreserveAspectRatio;
|
Maybe<SVGPreserveAspectRatio> mPreserveAspectRatio;
|
||||||
Maybe<ColorScheme> mColorScheme;
|
Maybe<ColorScheme> mColorScheme;
|
||||||
StyleLinkParameters mLinkParameters;
|
StyleLinkParameters mLinkParameters;
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
diff --git a/toolkit/content/widgets/panel-list/panel-list.mjs b/toolkit/content/widgets/panel-list/panel-list.mjs
|
|
||||||
index 68ad2fafc8b31dfff541cf8381d9b9533e376d1c..fa62fec6bfb33338091fc06d3736fb76fd5c47c4 100644
|
|
||||||
--- a/toolkit/content/widgets/panel-list/panel-list.mjs
|
|
||||||
+++ b/toolkit/content/widgets/panel-list/panel-list.mjs
|
|
||||||
@@ -223,7 +223,12 @@ export class PanelList extends HTMLElement {
|
|
||||||
this.setAttribute("showing", "true");
|
|
||||||
// Tell the host element to hide any overflow in case the panel extends off
|
|
||||||
// the page before the alignment is set.
|
|
||||||
- hostElement.style.overflow = "hidden";
|
|
||||||
+ const hostHidesOverflow = !getComputedStyle(hostElement)
|
|
||||||
+ .overflow.split(" ")
|
|
||||||
+ .includes("visible");
|
|
||||||
+ if (!hostHidesOverflow) {
|
|
||||||
+ hostElement.style.overflow = "hidden";
|
|
||||||
+ }
|
|
||||||
|
|
||||||
// Wait for a layout flush, then find the bounds.
|
|
||||||
let {
|
|
||||||
@@ -344,7 +349,9 @@ export class PanelList extends HTMLElement {
|
|
||||||
// Set the alignments and show the panel.
|
|
||||||
this.setAttribute("align", align);
|
|
||||||
this.setAttribute("valign", valign);
|
|
||||||
- hostElement.style.overflow = "";
|
|
||||||
+ if (!hostHidesOverflow) {
|
|
||||||
+ hostElement.style.overflow = "";
|
|
||||||
+ }
|
|
||||||
// Decide positioning based on where this panel will be rendered
|
|
||||||
const offsetParentIsBody =
|
|
||||||
this.supportsPopover() ||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/toolkit/themes/shared/design-system/dist/tokens-shared.css b/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
diff --git a/toolkit/themes/shared/design-system/dist/tokens-shared.css b/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
||||||
index 63c641f560d4c0ce06b40a652ca99d1c48cd6941..39c81e773a442870763396e68fb57bd336e3625a 100644
|
index b0f8fa146de335c53e73d46853f45dda9b15cc73..1b7592c0e9ca12fd9d1f8a555633fd39c2efb537 100644
|
||||||
--- a/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
--- a/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
||||||
+++ b/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
+++ b/toolkit/themes/shared/design-system/dist/tokens-shared.css
|
||||||
@@ -7,6 +7,8 @@
|
@@ -7,6 +7,8 @@
|
||||||
@@ -8,9 +8,9 @@ index 63c641f560d4c0ce06b40a652ca99d1c48cd6941..39c81e773a442870763396e68fb57bd3
|
|||||||
|
|
||||||
+@import url("chrome://browser/content/zen-styles/zen-theme.css");
|
+@import url("chrome://browser/content/zen-styles/zen-theme.css");
|
||||||
+
|
+
|
||||||
@layer tokens-foundation {
|
:root,
|
||||||
:root,
|
:host(.anonymous-content-host) {
|
||||||
:host(.anonymous-content-host) {
|
@layer tokens-foundation {
|
||||||
@@ -28,10 +30,10 @@
|
@@ -28,10 +30,10 @@
|
||||||
--border-color-selected: var(--color-accent-primary);
|
--border-color-selected: var(--color-accent-primary);
|
||||||
--border-color-transparent: transparent;
|
--border-color-transparent: transparent;
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||||
index 2efd02e4a92433fd29bbfdb707aa81cfec45031e..3b763c3927f07e529c826f8e4f62bc80a324b247 100644
|
index 887e4c052d5dd2b73d4c2059463529fb4b09dcab..36da18e19018b1b216576c299f938e75093546d3 100644
|
||||||
--- a/widget/cocoa/nsCocoaWindow.mm
|
--- a/widget/cocoa/nsCocoaWindow.mm
|
||||||
+++ b/widget/cocoa/nsCocoaWindow.mm
|
+++ b/widget/cocoa/nsCocoaWindow.mm
|
||||||
@@ -86,6 +86,7 @@
|
@@ -86,6 +86,8 @@
|
||||||
#include "mozilla/StaticPrefs_gfx.h"
|
#include "mozilla/StaticPrefs_gfx.h"
|
||||||
#include "mozilla/StaticPrefs_ui.h"
|
#include "mozilla/StaticPrefs_ui.h"
|
||||||
#include "mozilla/StaticPrefs_widget.h"
|
#include "mozilla/StaticPrefs_widget.h"
|
||||||
+#include "mozilla/StaticPrefs_zen.h"
|
+#include "mozilla/StaticPrefs_zen.h"
|
||||||
|
+#include "mozilla/nsZenDragAndDrop.h"
|
||||||
#include "mozilla/WritingModes.h"
|
#include "mozilla/WritingModes.h"
|
||||||
#include "mozilla/dom/Document.h"
|
#include "mozilla/dom/Document.h"
|
||||||
#include "mozilla/layers/CompositorBridgeChild.h"
|
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||||
@@ -1332,6 +1333,110 @@ - (NSRect)_opaqueRectForWindowMoveWhenInTitlebar {
|
@@ -1332,6 +1334,110 @@ - (NSRect)_opaqueRectForWindowMoveWhenInTitlebar {
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -121,7 +122,28 @@ index 2efd02e4a92433fd29bbfdb707aa81cfec45031e..3b763c3927f07e529c826f8e4f62bc80
|
|||||||
void nsCocoaWindow::UpdateWindowDraggingRegion(
|
void nsCocoaWindow::UpdateWindowDraggingRegion(
|
||||||
const LayoutDeviceIntRegion& aRegion) {
|
const LayoutDeviceIntRegion& aRegion) {
|
||||||
// mChildView returns YES from mouseDownCanMoveWindow, so we need to put
|
// mChildView returns YES from mouseDownCanMoveWindow, so we need to put
|
||||||
@@ -4919,6 +5024,10 @@ - (BOOL)wantsBestResolutionOpenGLSurface {
|
@@ -3858,7 +3964,9 @@ - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
|
||||||
|
// NSDraggingDestination
|
||||||
|
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
|
||||||
|
MOZ_LOG(sCocoaLog, LogLevel::Info, ("ChildView draggingUpdated: entered\n"));
|
||||||
|
- return [self doDragAction:eDragOver sender:sender];
|
||||||
|
+ NSDragOperation operation = [self doDragAction:eDragOver sender:sender];
|
||||||
|
+ zen::PrepareDropLanding(sender);
|
||||||
|
+ return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NSDraggingDestination
|
||||||
|
@@ -3874,6 +3982,9 @@ - (void)draggingExited:(id<NSDraggingInfo>)sender {
|
||||||
|
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
|
||||||
|
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||||
|
BOOL handled = [self doDragAction:eDrop sender:sender] != NSDragOperationNone;
|
||||||
|
+ if (handled) {
|
||||||
|
+ zen::LandDrop(sender);
|
||||||
|
+ }
|
||||||
|
NS_IF_RELEASE(mDragService);
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
@@ -4919,6 +5030,10 @@ - (BOOL)wantsBestResolutionOpenGLSurface {
|
||||||
nsCocoaWindow::~nsCocoaWindow() {
|
nsCocoaWindow::~nsCocoaWindow() {
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm
|
diff --git a/widget/cocoa/nsDragService.mm b/widget/cocoa/nsDragService.mm
|
||||||
index 340a9ad81c5cb23bb7e5f927d11d5cffdde7ce70..32fc707ccfa56fa8c307860868d092c4a9050419 100644
|
index 340a9ad81c5cb23bb7e5f927d11d5cffdde7ce70..ba597ba4373ba3ace7455ce0859f2339349ffc06 100644
|
||||||
--- a/widget/cocoa/nsDragService.mm
|
--- a/widget/cocoa/nsDragService.mm
|
||||||
+++ b/widget/cocoa/nsDragService.mm
|
+++ b/widget/cocoa/nsDragService.mm
|
||||||
@@ -10,6 +10,7 @@
|
@@ -10,6 +10,7 @@
|
||||||
@@ -45,3 +45,112 @@ index 340a9ad81c5cb23bb7e5f927d11d5cffdde7ce70..32fc707ccfa56fa8c307860868d092c4
|
|||||||
#endif
|
#endif
|
||||||
src += 4;
|
src += 4;
|
||||||
dest += 4;
|
dest += 4;
|
||||||
|
@@ -249,12 +254,44 @@
|
||||||
|
[[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem] autorelease];
|
||||||
|
[dragItem setDraggingFrame:localDragRect contents:image];
|
||||||
|
|
||||||
|
+ NSMutableArray* dragItems = [NSMutableArray arrayWithObject:dragItem];
|
||||||
|
+ auto zenDragAndDrop = zen::nsZenDragAndDrop::GetZenDragAndDropInstance();
|
||||||
|
+ const nsTArray<nsCOMPtr<nsINode>> noExtraImages;
|
||||||
|
+ @try {
|
||||||
|
+ for (const auto& extraImageNode :
|
||||||
|
+ zenDragAndDrop ? zenDragAndDrop->DragImages() : noExtraImages) {
|
||||||
|
+ nsCOMPtr<nsINode> mainImage = std::move(mImage);
|
||||||
|
+ mImage = extraImageNode;
|
||||||
|
+ NSPoint extraPoint;
|
||||||
|
+ NSImage* extraImage = ConstructDragImage(mSourceNode, aRegion, &extraPoint);
|
||||||
|
+ mImage = std::move(mainImage);
|
||||||
|
+ if (!extraImage) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ NSRect extraRect = extraImage.alignmentRect;
|
||||||
|
+ extraRect.origin.x = extraPoint.x;
|
||||||
|
+ extraRect.origin.y = extraPoint.y - extraRect.size.height;
|
||||||
|
+ NSPasteboardItem* extraPbItem = [[NSPasteboardItem new] autorelease];
|
||||||
|
+ [extraPbItem setData:[NSData data]
|
||||||
|
+ forType:[UTIHelper stringFromPboardType:kMozWildcardPboardType]];
|
||||||
|
+ NSDraggingItem* extraItem = [[[NSDraggingItem alloc]
|
||||||
|
+ initWithPasteboardWriter:extraPbItem] autorelease];
|
||||||
|
+ [extraItem setDraggingFrame:extraRect contents:extraImage];
|
||||||
|
+ [dragItems addObject:extraItem];
|
||||||
|
+ }
|
||||||
|
+ } @catch (NSException* e) {
|
||||||
|
+ dragItems = [NSMutableArray arrayWithObject:dragItem];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
OpenDragPopup();
|
||||||
|
|
||||||
|
mNSDraggingSession = [mNativeDragView
|
||||||
|
- beginDraggingSessionWithItems:[NSArray arrayWithObject:dragItem]
|
||||||
|
+ beginDraggingSessionWithItems:dragItems
|
||||||
|
event:mNativeDragEvent
|
||||||
|
source:mNativeDragView];
|
||||||
|
+ if (dragItems.count > 1) {
|
||||||
|
+ mNSDraggingSession.draggingFormation = NSDraggingFormationStack;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
mNSDraggingSession.animatesToStartingPositionsOnCancelOrFail =
|
||||||
|
!mDataTransfer || mDataTransfer->MozShowFailAnimation();
|
||||||
|
@@ -455,29 +492,44 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc) {
|
||||||
|
+ nsPoint pt = LayoutDevicePixel::ToAppUnits(
|
||||||
|
+ devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
||||||
|
+ CSSIntPoint screenPoint =
|
||||||
|
+ CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
||||||
|
+ nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
||||||
|
+
|
||||||
|
+ NSMutableArray* images = [NSMutableArray array];
|
||||||
|
+ NSMutableArray* rects = [NSMutableArray array];
|
||||||
|
+ auto render = [&]() {
|
||||||
|
+ LayoutDeviceIntRect newRect;
|
||||||
|
+ NSImage* image =
|
||||||
|
+ ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
||||||
|
+ [images addObject:image ? (id)image : (id)[NSNull null]];
|
||||||
|
+ [rects addObject:[NSValue valueWithRect:
|
||||||
|
+ image ? nsCocoaUtils::GeckoRectToCocoaRectDevPix(
|
||||||
|
+ newRect, scaleFactor)
|
||||||
|
+ : NSZeroRect]];
|
||||||
|
+ };
|
||||||
|
+ render();
|
||||||
|
+ if (auto zenDragAndDrop = zen::nsZenDragAndDrop::GetZenDragAndDropInstance()) {
|
||||||
|
+ for (const auto& extraImageNode : zenDragAndDrop->DragImages()) {
|
||||||
|
+ nsCOMPtr<nsINode> mainImage = std::move(mImage);
|
||||||
|
+ mImage = extraImageNode;
|
||||||
|
+ render();
|
||||||
|
+ mImage = std::move(mainImage);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
void (^changeImageBlock)(NSDraggingItem*, NSInteger, BOOL*) = ^(
|
||||||
|
NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
|
||||||
|
- // We never add more than one item right now, but check just in case.
|
||||||
|
- if (idx > 0) {
|
||||||
|
+ if ((NSUInteger)idx >= images.count || images[idx] == [NSNull null]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- nsPoint pt = LayoutDevicePixel::ToAppUnits(
|
||||||
|
- devPoint, pc->DeviceContext()->AppUnitsPerDevPixel());
|
||||||
|
- CSSIntPoint screenPoint =
|
||||||
|
- CSSIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
|
||||||
|
- nsPresContext::AppUnitsToIntCSSPixels(pt.y));
|
||||||
|
-
|
||||||
|
- // Create a new image; if one isn't returned don't change the current
|
||||||
|
- // one.
|
||||||
|
- LayoutDeviceIntRect newRect;
|
||||||
|
- NSImage* image =
|
||||||
|
- ConstructDragImage(mSourceNode, Nothing(), screenPoint, &newRect);
|
||||||
|
- if (image) {
|
||||||
|
- NSRect draggingRect =
|
||||||
|
- nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
|
||||||
|
- [draggingItem setDraggingFrame:draggingRect contents:image];
|
||||||
|
+ NSRect frame = [rects[idx] rectValue];
|
||||||
|
+ if (idx > 0) {
|
||||||
|
+ frame.origin = draggingItem.draggingFrame.origin;
|
||||||
|
}
|
||||||
|
+ [draggingItem setDraggingFrame:frame contents:images[idx]];
|
||||||
|
};
|
||||||
|
|
||||||
|
[mNSDraggingSession
|
||||||
|
|||||||
@@ -1521,7 +1521,7 @@ ${cssSelector} {
|
|||||||
shuffleBoost() {
|
shuffleBoost() {
|
||||||
const availFonts = this.fetchFontList();
|
const availFonts = this.fetchFontList();
|
||||||
const commonFonts = this.commonFonts;
|
const commonFonts = this.commonFonts;
|
||||||
let font = commonFonts[Math.round(Math.random() * commonFonts.length)];
|
let font = commonFonts[Math.floor(Math.random() * commonFonts.length)];
|
||||||
if (availFonts.includes(font)) {
|
if (availFonts.includes(font)) {
|
||||||
this.currentBoostData.fontFamily = font;
|
this.currentBoostData.fontFamily = font;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -649,9 +649,10 @@ class nsZenBoostsManager {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Close the editor if the tab is switched
|
// Close the editor if the tab is switched
|
||||||
|
const onTabSelect = editor.close.bind(editor);
|
||||||
parentWindow.gBrowser.tabContainer.addEventListener(
|
parentWindow.gBrowser.tabContainer.addEventListener(
|
||||||
"TabSelect",
|
"TabSelect",
|
||||||
editor.close.bind(editor),
|
onTabSelect,
|
||||||
{
|
{
|
||||||
once: true,
|
once: true,
|
||||||
}
|
}
|
||||||
@@ -661,13 +662,24 @@ class nsZenBoostsManager {
|
|||||||
onLocationChange: webProgress => {
|
onLocationChange: webProgress => {
|
||||||
if (webProgress.isTopLevel) {
|
if (webProgress.isTopLevel) {
|
||||||
editor.close();
|
editor.close();
|
||||||
parentWindow.gBrowser.removeTabsProgressListener(progressListener);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
parentWindow.gBrowser.addProgressListener(progressListener);
|
parentWindow.gBrowser.addProgressListener(progressListener);
|
||||||
|
|
||||||
|
editor.addEventListener(
|
||||||
|
"unload",
|
||||||
|
() => {
|
||||||
|
parentWindow.gBrowser.tabContainer.removeEventListener(
|
||||||
|
"TabSelect",
|
||||||
|
onTabSelect
|
||||||
|
);
|
||||||
|
parentWindow.gBrowser.removeProgressListener(progressListener);
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
|
||||||
// Give the domain
|
// Give the domain
|
||||||
editor.domain = domain;
|
editor.domain = domain;
|
||||||
editor.openerWindow = parentWindow;
|
editor.openerWindow = parentWindow;
|
||||||
|
|||||||
@@ -70,8 +70,10 @@ export class ZenBoostsChild extends JSWindowActorChild {
|
|||||||
|
|
||||||
static PREVENTABLE_SET = new Set(ZenBoostsChild.PREVENTABLE_EVENTS);
|
static PREVENTABLE_SET = new Set(ZenBoostsChild.PREVENTABLE_EVENTS);
|
||||||
|
|
||||||
actorCreated() {
|
handleEvent(event) {
|
||||||
this.#applyBoostForPageIfAvailable();
|
if (event.type === "DOMDocElementInserted") {
|
||||||
|
this.#applyBoostForPageIfAvailable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
didDestroy() {
|
didDestroy() {
|
||||||
@@ -330,6 +332,22 @@ export class ZenBoostsChild extends JSWindowActorChild {
|
|||||||
return this.sendQuery("ZenBoost:GetBoostForDomain", domain);
|
return this.sendQuery("ZenBoost:GetBoostForDomain", domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a synced BrowsingContext field only when its value changes. Every
|
||||||
|
* setter commits a transaction that is broadcast to the whole browsing
|
||||||
|
* context group, even when the value is unchanged, so this avoids three
|
||||||
|
* such broadcasts on every page load that has no boost.
|
||||||
|
*
|
||||||
|
* @param {BrowsingContext} browsingContext
|
||||||
|
* @param {string} field - The synced field name.
|
||||||
|
* @param {number | boolean} value
|
||||||
|
*/
|
||||||
|
#setSyncedField(browsingContext, field, value) {
|
||||||
|
if (browsingContext[field] !== value) {
|
||||||
|
browsingContext[field] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies the boost settings for the current page if available.
|
* Applies the boost settings for the current page if available.
|
||||||
*
|
*
|
||||||
@@ -360,7 +378,11 @@ export class ZenBoostsChild extends JSWindowActorChild {
|
|||||||
sizeOverride: boostData.sizeOverride,
|
sizeOverride: boostData.sizeOverride,
|
||||||
});
|
});
|
||||||
|
|
||||||
browsingContext.isZenBoostsInverted = boostData.smartInvert;
|
this.#setSyncedField(
|
||||||
|
browsingContext,
|
||||||
|
"isZenBoostsInverted",
|
||||||
|
!!boostData.smartInvert
|
||||||
|
);
|
||||||
if (boostData.enableColorBoost) {
|
if (boostData.enableColorBoost) {
|
||||||
let primaryColor;
|
let primaryColor;
|
||||||
if (boostData.autoTheme) {
|
if (boostData.autoTheme) {
|
||||||
@@ -396,18 +418,21 @@ export class ZenBoostsChild extends JSWindowActorChild {
|
|||||||
boostData
|
boostData
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
browsingContext.zenBoostsData = primaryColor;
|
this.#setSyncedField(browsingContext, "zenBoostsData", primaryColor);
|
||||||
// The complementary accent is derived in the backend by rotating the
|
// The complementary accent is derived in the backend by rotating the
|
||||||
// primary accent's hue by this delta (in degrees).
|
// primary accent's hue by this delta (in degrees).
|
||||||
browsingContext.zenBoostsComplementaryRotation =
|
this.#setSyncedField(
|
||||||
boostData.secondaryDotAngleDegDelta ?? 0;
|
browsingContext,
|
||||||
|
"zenBoostsComplementaryRotation",
|
||||||
|
boostData.secondaryDotAngleDegDelta ?? 0
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
browsingContext.isZenBoostsInverted = false;
|
this.#setSyncedField(browsingContext, "isZenBoostsInverted", false);
|
||||||
}
|
}
|
||||||
browsingContext.zenBoostsData = 0;
|
this.#setSyncedField(browsingContext, "zenBoostsData", 0);
|
||||||
browsingContext.zenBoostsComplementaryRotation = 0;
|
this.#setSyncedField(browsingContext, "zenBoostsComplementaryRotation", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
"chrome://browser/content/zen-components/ZenEmojiPicker.mjs",
|
"chrome://browser/content/zen-components/ZenEmojiPicker.mjs",
|
||||||
"chrome://browser/content/zen-components/ZenLiveFoldersUI.mjs",
|
"chrome://browser/content/zen-components/ZenLiveFoldersUI.mjs",
|
||||||
"chrome://browser/content/zen-components/ZenDownloadAnimation.mjs",
|
"chrome://browser/content/zen-components/ZenDownloadAnimation.mjs",
|
||||||
|
"resource:///modules/zen/share/ZenShareManager.mjs",
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let script of scripts) {
|
for (let script of scripts) {
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ window.gZenUIManager = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
updateTabsToolbar() {
|
updateTabsToolbar(fromResizeEvent = false) {
|
||||||
const kUrlbarHeight = 333;
|
const kUrlbarHeight = 333;
|
||||||
gURLBar.style.setProperty(
|
gURLBar.style.setProperty(
|
||||||
"--zen-urlbar-top",
|
"--zen-urlbar-top",
|
||||||
@@ -270,8 +270,8 @@ window.gZenUIManager = {
|
|||||||
gZenVerticalTabsManager.actualWindowButtons.removeAttribute(
|
gZenVerticalTabsManager.actualWindowButtons.removeAttribute(
|
||||||
"zen-has-hover"
|
"zen-has-hover"
|
||||||
);
|
);
|
||||||
gZenVerticalTabsManager.recalculateURLBarHeight(true);
|
gZenVerticalTabsManager.recalculateURLBarHeight(!fromResizeEvent);
|
||||||
if (!this._preventToolbarRebuild) {
|
if (!this._preventToolbarRebuild && !fromResizeEvent) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
gZenWorkspaces.updateTabsContainers();
|
gZenWorkspaces.updateTabsContainers();
|
||||||
}, 0);
|
}, 0);
|
||||||
@@ -990,14 +990,7 @@ window.gZenVerticalTabsManager = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ChromeUtils.defineLazyGetter(this, "hidesTabsToolbar", () => {
|
ChromeUtils.defineLazyGetter(this, "hidesTabsToolbar", () => {
|
||||||
return (
|
return document.documentElement.hasAttribute("popup-window");
|
||||||
document.documentElement
|
|
||||||
.getAttribute("chromehidden")
|
|
||||||
?.includes("toolbar") ||
|
|
||||||
document.documentElement
|
|
||||||
.getAttribute("chromehidden")
|
|
||||||
?.includes("menubar")
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
@@ -1278,8 +1271,16 @@ window.gZenVerticalTabsManager = {
|
|||||||
if (gZenWorkspaces._processingResize) {
|
if (gZenWorkspaces._processingResize) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this._pendingUrlbarFormatUpdate ||= updateFormat;
|
||||||
|
if (this._urlbarHeightRecalcScheduled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._urlbarHeightRecalcScheduled = true;
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
|
delete this._urlbarHeightRecalcScheduled;
|
||||||
|
const shouldUpdateFormat = this._pendingUrlbarFormatUpdate;
|
||||||
|
delete this._pendingUrlbarFormatUpdate;
|
||||||
gURLBar.removeAttribute("--urlbar-height");
|
gURLBar.removeAttribute("--urlbar-height");
|
||||||
let height;
|
let height;
|
||||||
if (!this._hasSetSingleToolbar) {
|
if (!this._hasSetSingleToolbar) {
|
||||||
@@ -1290,7 +1291,7 @@ window.gZenVerticalTabsManager = {
|
|||||||
if (typeof height !== "undefined") {
|
if (typeof height !== "undefined") {
|
||||||
gURLBar.style.setProperty("--urlbar-height", `${height}px`);
|
gURLBar.style.setProperty("--urlbar-height", `${height}px`);
|
||||||
}
|
}
|
||||||
if (updateFormat) {
|
if (shouldUpdateFormat) {
|
||||||
gURLBar.zenFormatURLValue();
|
gURLBar.zenFormatURLValue();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1579,9 +1580,7 @@ window.gZenVerticalTabsManager = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gURLBar._initCopyCutController();
|
gURLBar._initCopyCutController();
|
||||||
gURLBar._initPasteAndGo();
|
gURLBar.updatePlaceholder();
|
||||||
gURLBar._initStripOnShare();
|
|
||||||
gURLBar._updatePlaceholderFromDefaultEngine();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
rebuildAreas() {
|
rebuildAreas() {
|
||||||
|
|||||||
36
src/zen/common/styles/squircle-exclusions.inc.css
Normal file
36
src/zen/common/styles/squircle-exclusions.inc.css
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Upstream elements that take their radius from --border-radius-circle (9999px).
|
||||||
|
They are meant to read as circles or pills, so a superellipse only makes them
|
||||||
|
look lumpy. */
|
||||||
|
.tab-icon-overlay:not([crashed]):is([soundplaying], [muted], [activemedia-blocked]),
|
||||||
|
.tab-note-icon-overlay,
|
||||||
|
.tab-group-overflow-count,
|
||||||
|
.tab-group-editor-swatch,
|
||||||
|
.tab-preview-container-indicator,
|
||||||
|
#tabbrowser-tabs[orient='vertical']:not([expanded]) .tab-close-button,
|
||||||
|
.all-tabs-item > toolbarbutton.all-tabs-container-indicator::before,
|
||||||
|
.urlbarView-button,
|
||||||
|
.downloadButton,
|
||||||
|
.titlebar-button,
|
||||||
|
.titlebar-button .toolbarbutton-icon,
|
||||||
|
#downloads-indicator-progress-inner,
|
||||||
|
#smartwindow-ask-button-inner,
|
||||||
|
#PanelUI-fxa-menu-manage-account-button,
|
||||||
|
.fxa-menu-manage-account-avatar,
|
||||||
|
[fxastatus='signedin'] #fxa-avatar-image,
|
||||||
|
#profile-icon-image,
|
||||||
|
.appMenu-update-banner-pulse-ring,
|
||||||
|
.urlbarView-favicon,
|
||||||
|
:is(#appMenu-zoomReduce-button2, #appMenu-zoomEnlarge-button2) > .toolbarbutton-icon,
|
||||||
|
.color-swatches .userContext-icon,
|
||||||
|
.reusable-relay-masks > button,
|
||||||
|
.radio-check,
|
||||||
|
#zen-loading-progress-bar,
|
||||||
|
#statuspanel-label {
|
||||||
|
corner-shape: round;
|
||||||
|
}
|
||||||
@@ -3,13 +3,19 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
:root:not([inDOMFullscreen="true"]):not([chromehidden~="location"]):not([chromehidden~="toolbar"]) {
|
:root:not([inDOMFullscreen="true"]):not([popup-window]) {
|
||||||
& #tabbrowser-tabbox #tabbrowser-tabpanels .browserSidebarContainer {
|
& #tabbrowser-tabbox #tabbrowser-tabpanels .browserSidebarContainer {
|
||||||
|
--zen-transparent-browser-background: light-dark(rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.1));
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
|
|
||||||
:root:not([zen-no-padding="true"]) &:not(.zen-glance-overlay) {
|
:root:not([zen-no-padding="true"]) &:not(.zen-glance-overlay) {
|
||||||
border-radius: var(--zen-native-inner-radius);
|
border-radius: var(--zen-native-inner-radius);
|
||||||
box-shadow: var(--zen-big-shadow);
|
box-shadow: var(--zen-big-shadow);
|
||||||
|
@media not (-moz-pref("zen.theme.squircle-browser-view")) {
|
||||||
|
/* stylelint-disable-next-line property-no-unknown */
|
||||||
|
corner-shape: round;
|
||||||
|
border-radius: calc(var(--zen-native-inner-radius) / var(--zen-squircle-value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& browser[type="content"] {
|
& browser[type="content"] {
|
||||||
@@ -18,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&[transparent="true"] {
|
&[transparent="true"] {
|
||||||
background: light-dark(rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.1));
|
background: var(--zen-transparent-browser-background);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ body,
|
|||||||
position: inherit;
|
position: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root:is([inDOMFullscreen="true"], [chromehidden~="location"], [chromehidden~="toolbar"]) {
|
:root:is([inDOMFullscreen="true"], [popup-window]) {
|
||||||
#navigator-toolbox,
|
#navigator-toolbox,
|
||||||
#zen-sidebar-splitter {
|
#zen-sidebar-splitter {
|
||||||
visibility: collapse;
|
visibility: collapse;
|
||||||
@@ -61,7 +61,7 @@ body,
|
|||||||
background: var(--zen-main-browser-background);
|
background: var(--zen-main-browser-background);
|
||||||
opacity: var(--zen-background-opacity);
|
opacity: var(--zen-background-opacity);
|
||||||
transition: 0s;
|
transition: 0s;
|
||||||
background-blend-mode: screen;
|
background-blend-mode: lighten;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:is(.zen-toolbar-background) {
|
&:is(.zen-toolbar-background) {
|
||||||
@@ -74,7 +74,7 @@ body,
|
|||||||
background: var(--zen-main-browser-background-old);
|
background: var(--zen-main-browser-background-old);
|
||||||
opacity: calc(1 - var(--zen-background-opacity));
|
opacity: calc(1 - var(--zen-background-opacity));
|
||||||
transition: 0s;
|
transition: 0s;
|
||||||
background-blend-mode: screen;
|
background-blend-mode: lighten;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:is(.zen-toolbar-background) {
|
&:is(.zen-toolbar-background) {
|
||||||
@@ -170,7 +170,7 @@ body,
|
|||||||
min-width: 1px;
|
min-width: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root:not([inDOMFullscreen="true"]):not([chromehidden~="location"]):not([chromehidden~="toolbar"]) {
|
:root:not([inDOMFullscreen="true"]):not([popup-window]) {
|
||||||
& #zen-tabbox-wrapper {
|
& #zen-tabbox-wrapper {
|
||||||
margin: var(--zen-element-separation);
|
margin: var(--zen-element-separation);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|||||||
@@ -78,3 +78,52 @@ dialog::part(dialog-button) {
|
|||||||
scale: 0.98;
|
scale: 0.98;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--zen-accent-button-color: light-dark(
|
||||||
|
oklch(from var(--zen-primary-color) clamp(0.35, l, 0.6) c h),
|
||||||
|
oklch(from var(--zen-primary-color) clamp(0.7, l, 0.85) c h)
|
||||||
|
);
|
||||||
|
--zen-accent-button-background: light-dark(
|
||||||
|
oklch(from var(--zen-primary-color) clamp(0.35, l, 0.6) c h),
|
||||||
|
oklch(from var(--zen-primary-color) clamp(0.55, l, 0.7) c h)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.zen-big-accent-button {
|
||||||
|
appearance: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1.2rem 1rem;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--zen-accent-button-color);
|
||||||
|
font: inherit;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
will-change: transform;
|
||||||
|
transition: scale 0.15s ease-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
scale: 1.03;
|
||||||
|
filter: brightness(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:hover {
|
||||||
|
scale: 1;
|
||||||
|
color: color-mix(in srgb, var(--zen-accent-button-color) 80%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
background: var(--zen-accent-button-background);
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:hover {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.urlbar {
|
.urlbar {
|
||||||
--urlbarview-separator-color: light-dark(hsl(0, 0%, 80%), hsl(0, 0%, 20%));
|
--urlbarview-separator-color: light-dark(hsl(0, 0%, 85%), hsl(0, 0%, 15%));
|
||||||
--urlbarview-background-color-hover: var(--toolbarbutton-background-color-hover);
|
--urlbarview-background-color-hover: var(--toolbarbutton-background-color-hover);
|
||||||
border-radius: calc(var(--toolbarbutton-border-radius) - 2px);
|
border-radius: calc(var(--toolbarbutton-border-radius) - 2px);
|
||||||
--urlbarView-results-padding: 10px !important;
|
--urlbarView-results-padding: 10px !important;
|
||||||
@@ -284,7 +284,7 @@
|
|||||||
background-color: var(--zen-urlbar-background-transparent, var(--zen-urlbar-background-base)) !important;
|
background-color: var(--zen-urlbar-background-transparent, var(--zen-urlbar-background-base)) !important;
|
||||||
box-shadow: 0 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;
|
backdrop-filter: none !important;
|
||||||
outline: 0.5px solid light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2)) !important;
|
outline: 0.5px solid light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.1)) !important;
|
||||||
outline-offset: var(--zen-urlbar-outline-offset) !important;
|
outline-offset: var(--zen-urlbar-outline-offset) !important;
|
||||||
|
|
||||||
/* stylelint-disable-next-line media-query-no-invalid */
|
/* stylelint-disable-next-line media-query-no-invalid */
|
||||||
@@ -295,7 +295,7 @@
|
|||||||
|
|
||||||
&,
|
&,
|
||||||
.urlbar-background {
|
.urlbar-background {
|
||||||
border-radius: 12px !important;
|
border-radius: 14px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[breakout-extend][animate-searchmode="true"]::before {
|
&[breakout-extend][animate-searchmode="true"]::before {
|
||||||
|
|||||||
@@ -30,6 +30,14 @@ panel[type="arrow"]:not(#feature-callout) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (-moz-platform: linux) or ((-moz-platform: windows) and (not (-moz-windows-mica-popups))) {
|
||||||
|
&::part(content) {
|
||||||
|
/* stylelint-disable-next-line property-no-unknown */
|
||||||
|
corner-shape: round;
|
||||||
|
border-radius: calc(var(--panel-border-radius) / var(--zen-squircle-value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (-moz-platform: macos) {
|
@media (-moz-platform: macos) {
|
||||||
&:is([nonnative], :not([type="arrow"])) {
|
&:is([nonnative], :not([type="arrow"])) {
|
||||||
appearance: auto !important;
|
appearance: auto !important;
|
||||||
|
|||||||
@@ -64,6 +64,10 @@ hbox.editBMPanel_folderRow {
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#editBMPanel_workspaceSummary .workspace-trigger {
|
||||||
|
margin-inline-end: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Bookmarks in toolbar */
|
/* Bookmarks in toolbar */
|
||||||
#PersonalToolbar {
|
#PersonalToolbar {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|||||||
@@ -101,7 +101,7 @@
|
|||||||
) !important;
|
) !important;
|
||||||
--focus-outline-color: var(--color-accent-primary) !important;
|
--focus-outline-color: var(--color-accent-primary) !important;
|
||||||
|
|
||||||
--toolbarbutton-icon-fill-attention: var(--toolbar-color) !important;
|
--toolbarbutton-icon-fill-attention: var(--toolbar-color, currentColor) !important;
|
||||||
--toolbarbutton-icon-fill: currentColor !important;
|
--toolbarbutton-icon-fill: currentColor !important;
|
||||||
|
|
||||||
--button-background-color-primary: var(--in-content-primary-button-background) !important;
|
--button-background-color-primary: var(--in-content-primary-button-background) !important;
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
--zen-squircle-value: 1.3;
|
--zen-squircle-value: 1.3;
|
||||||
|
|
||||||
@media (-moz-platform: windows) {
|
@media (-moz-platform: windows) {
|
||||||
--zen-squircle-value: 2.1;
|
--zen-squircle-value: 2.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
--tab-icon-overlay-stroke: light-dark(white, black) !important;
|
--tab-icon-overlay-stroke: light-dark(white, black) !important;
|
||||||
@@ -303,7 +303,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-window[windowtype="navigator:browser"]:not([chromehidden~='toolbar']) {
|
#main-window[windowtype="navigator:browser"]:not([popup-window]) {
|
||||||
min-height: 495px !important;
|
min-height: 495px !important;
|
||||||
|
|
||||||
@media (-moz-windows-mica) or (-moz-platform: macos) or ((-moz-platform: linux) and
|
@media (-moz-windows-mica) or (-moz-platform: macos) or ((-moz-platform: linux) and
|
||||||
@@ -361,4 +361,6 @@
|
|||||||
.zen-squircle-after::after {
|
.zen-squircle-after::after {
|
||||||
corner-shape: superellipse(var(--zen-squircle-value));
|
corner-shape: superellipse(var(--zen-squircle-value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%include squircle-exclusions.inc.css
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ let JSWINDOWACTORS = {
|
|||||||
child: {
|
child: {
|
||||||
esModuleURI: "resource:///actors/ZenGlanceChild.sys.mjs",
|
esModuleURI: "resource:///actors/ZenGlanceChild.sys.mjs",
|
||||||
events: {
|
events: {
|
||||||
DOMContentLoaded: {},
|
|
||||||
mousedown: {
|
mousedown: {
|
||||||
capture: true,
|
capture: true,
|
||||||
},
|
},
|
||||||
@@ -86,9 +85,7 @@ if (!Services.appinfo.inSafeMode) {
|
|||||||
child: {
|
child: {
|
||||||
esModuleURI: "resource:///actors/ZenBoostsChild.sys.mjs",
|
esModuleURI: "resource:///actors/ZenBoostsChild.sys.mjs",
|
||||||
events: {
|
events: {
|
||||||
// Needed to let the actor be created, please don't remove
|
DOMDocElementInserted: {},
|
||||||
// without checking if boosts still work without it, thanks <3
|
|
||||||
DOMWindowCreated: {},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
safeForUntrustedWebProcess: true,
|
safeForUntrustedWebProcess: true,
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
|||||||
const lazy = {};
|
const lazy = {};
|
||||||
|
|
||||||
ChromeUtils.defineESModuleGetters(lazy, {
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
SessionStore:
|
||||||
|
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||||
});
|
});
|
||||||
|
|
||||||
class nsZenUIMigration {
|
class nsZenUIMigration {
|
||||||
PREF_NAME = "zen.ui.migration.version";
|
PREF_NAME = "zen.ui.migration.version";
|
||||||
MIGRATION_VERSION = 7;
|
MIGRATION_VERSION = 8;
|
||||||
|
|
||||||
init(isNewProfile) {
|
init(isNewProfile) {
|
||||||
if (!isNewProfile) {
|
if (!isNewProfile) {
|
||||||
@@ -164,6 +165,18 @@ class nsZenUIMigration {
|
|||||||
Services.prefs.setBoolPref("zen.widget.macos.window-vibrancy", false);
|
Services.prefs.setBoolPref("zen.widget.macos.window-vibrancy", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_migrateV8() {
|
||||||
|
// A version mismatch in the downloadable gfx blocklist wrongly blocked
|
||||||
|
// video overlays for every Windows user. The status pref persists in the
|
||||||
|
// profile and short-circuits the blocklist evaluation, so clear it (and
|
||||||
|
// its failure id) and restart, since gfx is already initialized by now.
|
||||||
|
if (Services.prefs.prefHasUserValue("gfx.blacklist.video-overlay")) {
|
||||||
|
Services.prefs.clearUserPref("gfx.blacklist.video-overlay");
|
||||||
|
Services.prefs.clearUserPref("gfx.blacklist.video-overlay.failureid");
|
||||||
|
this.shouldRestart = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export var gZenUIMigration = new nsZenUIMigration();
|
export var gZenUIMigration = new nsZenUIMigration();
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ document.addEventListener(
|
|||||||
case "cmd_zenSplitViewContextMenu":
|
case "cmd_zenSplitViewContextMenu":
|
||||||
gZenViewSplitter.contextSplitTabs();
|
gZenViewSplitter.contextSplitTabs();
|
||||||
break;
|
break;
|
||||||
|
case "cmd_zenCtxShareSplitView":
|
||||||
|
gZenViewSplitter.contextShareSplitView();
|
||||||
|
break;
|
||||||
case "cmd_zenCopyCurrentURLMarkdown":
|
case "cmd_zenCopyCurrentURLMarkdown":
|
||||||
gZenCommonActions.copyCurrentURLAsMarkdownToClipboard();
|
gZenCommonActions.copyCurrentURLAsMarkdownToClipboard();
|
||||||
break;
|
break;
|
||||||
@@ -90,6 +93,9 @@ document.addEventListener(
|
|||||||
case "cmd_zenCtxDeleteWorkspace":
|
case "cmd_zenCtxDeleteWorkspace":
|
||||||
gZenWorkspaces.contextDeleteWorkspace(event);
|
gZenWorkspaces.contextDeleteWorkspace(event);
|
||||||
break;
|
break;
|
||||||
|
case "cmd_zenCtxShareWorkspace":
|
||||||
|
gZenWorkspaces.contextShareWorkspace();
|
||||||
|
break;
|
||||||
case "cmd_zenChangeWorkspaceName":
|
case "cmd_zenChangeWorkspaceName":
|
||||||
gZenVerticalTabsManager.renameTabStart({
|
gZenVerticalTabsManager.renameTabStart({
|
||||||
target: gZenWorkspaces.activeWorkspaceIndicator.querySelector(
|
target: gZenWorkspaces.activeWorkspaceIndicator.querySelector(
|
||||||
@@ -154,7 +160,7 @@ document.addEventListener(
|
|||||||
}
|
}
|
||||||
case "cmd_zenDuplicateTab": {
|
case "cmd_zenDuplicateTab": {
|
||||||
const selectedTabs = gBrowser.selectedTabs;
|
const selectedTabs = gBrowser.selectedTabs;
|
||||||
let insertAt = selectedTabs.at(-1)._tPos + 1;
|
let insertAt = selectedTabs.at(-1).index + 1;
|
||||||
for (const tab of selectedTabs) {
|
for (const tab of selectedTabs) {
|
||||||
gBrowser.duplicateTab(tab, true, { tabIndex: insertAt++ });
|
gBrowser.duplicateTab(tab, true, { tabIndex: insertAt++ });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
if (AppConstants.platform == "macosx") {
|
if (AppConstants.platform == "macosx") {
|
||||||
const targetRadius = window.matchMedia("(-moz-mac-tahoe-theme)")
|
const targetRadius = window.matchMedia("(-moz-mac-tahoe-theme)")
|
||||||
.matches
|
.matches
|
||||||
? 12
|
? 11
|
||||||
: 10;
|
: 10;
|
||||||
document.documentElement.style.setProperty(
|
document.documentElement.style.setProperty(
|
||||||
"--zen-border-radius",
|
"--zen-border-radius",
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
// Windows defaults to 8px
|
// Windows defaults to 8px
|
||||||
document.documentElement.style.setProperty(
|
document.documentElement.style.setProperty(
|
||||||
"--zen-border-radius",
|
"--zen-border-radius",
|
||||||
"8px"
|
"9px"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -165,9 +165,7 @@ window.gZenCompactModeManager = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
get shouldBeCompact() {
|
get shouldBeCompact() {
|
||||||
return !document.documentElement
|
return !document.documentElement.hasAttribute("popup-window");
|
||||||
.getAttribute("chromehidden")
|
|
||||||
?.includes("toolbar");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
set preference(value) {
|
set preference(value) {
|
||||||
@@ -477,9 +475,9 @@ window.gZenCompactModeManager = {
|
|||||||
document.documentElement.setAttribute("zen-compact-animating", "true");
|
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
|
// We need to set the splitter width before hiding it
|
||||||
let splitterWidth = document
|
let splitterWidth = window.windowUtils.getBoundsWithoutFlushing(
|
||||||
.getElementById("zen-sidebar-splitter")
|
document.getElementById("zen-sidebar-splitter")
|
||||||
.getBoundingClientRect().width;
|
).width;
|
||||||
const isCompactMode = this.preference;
|
const isCompactMode = this.preference;
|
||||||
const canHideSidebar = this.canHideSidebar;
|
const canHideSidebar = this.canHideSidebar;
|
||||||
let canAnimate =
|
let canAnimate =
|
||||||
@@ -543,7 +541,7 @@ window.gZenCompactModeManager = {
|
|||||||
ease: "easeIn",
|
ease: "easeIn",
|
||||||
type: "spring",
|
type: "spring",
|
||||||
bounce: 0,
|
bounce: 0,
|
||||||
duration: 0.12,
|
duration: 0.1,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -599,7 +597,7 @@ window.gZenCompactModeManager = {
|
|||||||
ease: "easeOut",
|
ease: "easeOut",
|
||||||
type: "spring",
|
type: "spring",
|
||||||
bounce: 0,
|
bounce: 0,
|
||||||
duration: 0.12,
|
duration: 0.1,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -864,7 +862,6 @@ window.gZenCompactModeManager = {
|
|||||||
"supress-primary-adjustment"
|
"supress-primary-adjustment"
|
||||||
) === "true" &&
|
) === "true" &&
|
||||||
gZenVerticalTabsManager._hasSetSingleToolbar) ||
|
gZenVerticalTabsManager._hasSetSingleToolbar) ||
|
||||||
this._hasHoveredUrlbar ||
|
|
||||||
this._ignoreNextHover ||
|
this._ignoreNextHover ||
|
||||||
(event.type === "dragleave" &&
|
(event.type === "dragleave" &&
|
||||||
event.explicitOriginalTarget !== target &&
|
event.explicitOriginalTarget !== target &&
|
||||||
@@ -877,7 +874,10 @@ window.gZenCompactModeManager = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hoverableElements[i].keepHoverDuration) {
|
if (
|
||||||
|
this.hoverableElements[i].keepHoverDuration &&
|
||||||
|
!this._hasHoveredUrlbar
|
||||||
|
) {
|
||||||
this.flashElement(
|
this.flashElement(
|
||||||
target,
|
target,
|
||||||
this.hoverableElements[i].keepHoverDuration,
|
this.hoverableElements[i].keepHoverDuration,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
--zen-compact-float: var(--zen-element-separation);
|
--zen-compact-float: var(--zen-element-separation);
|
||||||
|
|
||||||
@media (-moz-mac-tahoe-theme) {
|
@media (-moz-mac-tahoe-theme) {
|
||||||
--zen-compact-mode-no-padding-radius-fix: -2px;
|
--zen-compact-mode-no-padding-radius-fix: -4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[zen-no-padding='true'] & {
|
:root[zen-no-padding='true'] & {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
&,
|
&,
|
||||||
&::before,
|
&::before,
|
||||||
&::after {
|
&::after {
|
||||||
border-radius: calc((var(--zen-native-inner-radius) - var(--zen-compact-mode-no-padding-radius-fix, 0px)) * var(--zen-squircle-value));
|
border-radius: calc((var(--zen-native-inner-radius) - var(--zen-compact-mode-no-padding-radius-fix, 0px)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
* - <tab-group> label element wrapper (.tab-group-label-container)
|
* - <tab-group> label element wrapper (.tab-group-label-container)
|
||||||
*
|
*
|
||||||
* When working with tab strip items, if you need logical information, you
|
* When working with tab strip items, if you need logical information, you
|
||||||
* can get it directly, e.g. `element.elementIndex` or `element._tPos`. If
|
* can get it directly, e.g. `element.elementIndex` or `element._index`. If
|
||||||
* you need spatial information like position or dimensions, then you should
|
* you need spatial information like position or dimensions, then you should
|
||||||
* call this function. For example, `elementToMove(element).getBoundingClientRect()`
|
* call this function. For example, `elementToMove(element).getBoundingClientRect()`
|
||||||
* or `elementToMove(element).style.top`.
|
* or `elementToMove(element).style.top`.
|
||||||
@@ -69,6 +69,7 @@
|
|||||||
#changeSpaceTimer = null;
|
#changeSpaceTimer = null;
|
||||||
#isAnimatingTabMove = false;
|
#isAnimatingTabMove = false;
|
||||||
#firstHapticFeedbackPlayed = false;
|
#firstHapticFeedbackPlayed = false;
|
||||||
|
#dragImageEssential = false;
|
||||||
|
|
||||||
#dragOverSplit = {};
|
#dragOverSplit = {};
|
||||||
|
|
||||||
@@ -152,10 +153,14 @@
|
|||||||
);
|
);
|
||||||
const dragImage = this.#createDragImageForTabs(draggingTabs);
|
const dragImage = this.#createDragImageForTabs(draggingTabs);
|
||||||
this.originalDragImageArgs = [dragImage, offsetX, offsetY];
|
this.originalDragImageArgs = [dragImage, offsetX, offsetY];
|
||||||
|
this.#dragImageEssential = tab.hasAttribute("zen-essential");
|
||||||
dt.setDragImage(...this.originalDragImageArgs);
|
dt.setDragImage(...this.originalDragImageArgs);
|
||||||
if (tab.hasAttribute("zen-essential")) {
|
if (tab.hasAttribute("zen-essential")) {
|
||||||
tab.style.visibility = "hidden";
|
tab.style.visibility = "hidden";
|
||||||
}
|
}
|
||||||
|
this._dropLandingArmed =
|
||||||
|
!args[0]?.fromTabList && this.getDropEffectForTabDrag(event) == "move";
|
||||||
|
this.ZenDragAndDropService.armDropLanding(this._dropLandingArmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#createDragImageForTabs(movingTabs) {
|
#createDragImageForTabs(movingTabs) {
|
||||||
@@ -165,62 +170,79 @@
|
|||||||
const tabRect = window.windowUtils.getBoundsWithoutFlushing(
|
const tabRect = window.windowUtils.getBoundsWithoutFlushing(
|
||||||
movingTabs[0]
|
movingTabs[0]
|
||||||
);
|
);
|
||||||
|
const native = AppConstants.platform == "macosx";
|
||||||
|
const stacked = native ? 1 : Math.min(movingTabs.length, 3);
|
||||||
|
const wrapper = this.#createDragImageWrapper(periphery, tabRect, stacked);
|
||||||
|
for (let i = 0; i < stacked; i++) {
|
||||||
|
this.#appendDragImageClone(wrapper, movingTabs[i], tabRect, i);
|
||||||
|
}
|
||||||
|
this._dragImageTabs = native ? [...movingTabs] : [movingTabs[0]];
|
||||||
|
this._extraDragImages = [];
|
||||||
|
if (native) {
|
||||||
|
for (const tab of movingTabs.slice(1)) {
|
||||||
|
const extra = this.#createDragImageWrapper(periphery, tabRect, 1);
|
||||||
|
this.#appendDragImageClone(extra, tab, tabRect, 0);
|
||||||
|
this.ZenDragAndDropService.addDragImage(extra);
|
||||||
|
this._extraDragImages.push(extra);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.#maybeCreateDragImageDot(movingTabs, wrapper);
|
||||||
|
}
|
||||||
|
this._tempDragImageParent = wrapper;
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
#createDragImageWrapper(periphery, tabRect, count) {
|
||||||
const wrapper = document.createElement("div");
|
const wrapper = document.createElement("div");
|
||||||
let movingTabsCount = Math.min(movingTabs.length, 3);
|
|
||||||
wrapper.style.width = tabRect.width + "px";
|
wrapper.style.width = tabRect.width + "px";
|
||||||
wrapper.style.height = tabRect.height * movingTabsCount + "px";
|
wrapper.style.height = tabRect.height * count + "px";
|
||||||
wrapper.style.position = "fixed";
|
wrapper.style.position = "fixed";
|
||||||
wrapper.style.top = "-9999px";
|
wrapper.style.top = "-9999px";
|
||||||
periphery.appendChild(wrapper);
|
periphery.appendChild(wrapper);
|
||||||
for (let i = 0; i < movingTabsCount; i++) {
|
return wrapper;
|
||||||
const tab = movingTabs[i];
|
}
|
||||||
const tabClone = tab.cloneNode(true);
|
|
||||||
if (tab.hasAttribute("zen-essential")) {
|
#appendDragImageClone(wrapper, tab, tabRect, i) {
|
||||||
const rect = tab.getBoundingClientRect();
|
const tabClone = tab.cloneNode(true);
|
||||||
tabClone.style.minWidth = tabClone.style.maxWidth = `${rect.width}px`;
|
if (tab.hasAttribute("zen-essential")) {
|
||||||
tabClone.style.minHeight =
|
const rect = tab.getBoundingClientRect();
|
||||||
tabClone.style.maxHeight = `${rect.height}px`;
|
tabClone.style.minWidth = tabClone.style.maxWidth = `${rect.width}px`;
|
||||||
if (tabClone.hasAttribute("visuallyselected")) {
|
tabClone.style.minHeight =
|
||||||
tabClone.style.transform = "translate(-50%, -50%)";
|
tabClone.style.maxHeight = `${rect.height}px`;
|
||||||
}
|
if (tabClone.hasAttribute("visuallyselected")) {
|
||||||
} else if (AppConstants.platform == "win" && !tab.isZenFolder) {
|
tabClone.style.transform = "translate(-50%, -50%)";
|
||||||
// On windows, the shell applies its own translucency to the drag
|
|
||||||
// image which we can't control, so force some extra contrast for
|
|
||||||
// the tab to be more visible. This is a hacky workaround.
|
|
||||||
tabClone.style.colorScheme = "light";
|
|
||||||
tabClone.style.setProperty("--tab-selected-textcolor", "black");
|
|
||||||
}
|
}
|
||||||
if (i > 0) {
|
} else if (AppConstants.platform == "win" && !tab.isZenFolder) {
|
||||||
tabClone.style.transform = `translate(${i * 4}px, -${i * (tabRect.height - 4)}px)`;
|
// On windows, the shell applies its own translucency to the drag
|
||||||
tabClone.style.opacity = "0.2";
|
// image which we can't control, so force some extra contrast for
|
||||||
tabClone.style.zIndex = `${-i}`;
|
// the tab to be more visible. This is a hacky workaround.
|
||||||
}
|
tabClone.style.colorScheme = "light";
|
||||||
tabClone.setAttribute("drag-image", "true");
|
tabClone.style.setProperty("--tab-selected-textcolor", "black");
|
||||||
wrapper.appendChild(tabClone);
|
}
|
||||||
if (isTab(tabClone)) {
|
if (i > 0) {
|
||||||
// We need to limit the label content so the drag image doesn't grow too big.
|
tabClone.style.transform = `translate(${i * 4}px, -${i * (tabRect.height - 4)}px)`;
|
||||||
const label = tabClone.textLabel;
|
tabClone.style.opacity = "0.2";
|
||||||
const tabLabelParentWidth =
|
tabClone.style.zIndex = `${-i}`;
|
||||||
label.parentElement.getBoundingClientRect().width;
|
}
|
||||||
label.textContent = label.textContent.slice(
|
tabClone.setAttribute("drag-image", "true");
|
||||||
0,
|
wrapper.appendChild(tabClone);
|
||||||
Math.floor(tabLabelParentWidth / 6)
|
if (isTab(tabClone)) {
|
||||||
);
|
// We need to limit the label content so the drag image doesn't grow too big.
|
||||||
} else if (
|
const label = tabClone.textLabel;
|
||||||
gBrowser.isTabGroup(tabClone) &&
|
const tabLabelParentWidth =
|
||||||
tabClone.hasAttribute("split-view-group")
|
label.parentElement.getBoundingClientRect().width;
|
||||||
) {
|
label.textContent = label.textContent.slice(
|
||||||
let tabs = tab.tabs;
|
0,
|
||||||
for (let j = 0; j < tabs.length; j++) {
|
Math.floor(tabLabelParentWidth / 6)
|
||||||
const tabInGroup = tabs[j];
|
);
|
||||||
const tabInGroupClone = tabInGroup.cloneNode(true);
|
} else if (
|
||||||
tabClone.appendChild(tabInGroupClone);
|
gBrowser.isTabGroup(tabClone) &&
|
||||||
}
|
tabClone.hasAttribute("split-view-group")
|
||||||
|
) {
|
||||||
|
for (const tabInGroup of tab.tabs) {
|
||||||
|
tabClone.appendChild(tabInGroup.cloneNode(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.#maybeCreateDragImageDot(movingTabs, wrapper);
|
|
||||||
this._tempDragImageParent = wrapper;
|
|
||||||
return wrapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#maybeCreateDragImageDot(movingTabs, wrapper) {
|
#maybeCreateDragImageDot(movingTabs, wrapper) {
|
||||||
@@ -255,7 +277,10 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.#animateVerticalPinnedGridDragOver(event);
|
return this.#animateVerticalPinnedGridDragOver(event);
|
||||||
} else if (this._fakeEssentialTab) {
|
} else if (
|
||||||
|
this.#dragImageEssential &&
|
||||||
|
!event.target.closest("zen-essentials-promo")
|
||||||
|
) {
|
||||||
this.#makeDragImageNonEssential(event);
|
this.#makeDragImageNonEssential(event);
|
||||||
}
|
}
|
||||||
let dragData = draggedTab._dragData;
|
let dragData = draggedTab._dragData;
|
||||||
@@ -557,7 +582,7 @@
|
|||||||
dropElementSize
|
dropElementSize
|
||||||
);
|
);
|
||||||
|
|
||||||
moveOverThreshold = gBrowser._tabGroupsEnabled
|
moveOverThreshold = gBrowser.tabGroupsEnabled
|
||||||
? Services.prefs.getIntPref(
|
? Services.prefs.getIntPref(
|
||||||
"browser.tabs.dragDrop.moveOverThresholdPercent"
|
"browser.tabs.dragDrop.moveOverThresholdPercent"
|
||||||
) / 100
|
) / 100
|
||||||
@@ -882,6 +907,8 @@
|
|||||||
|
|
||||||
this.#dragOverSplit.fakeTab = element;
|
this.#dragOverSplit.fakeTab = element;
|
||||||
this.#dragOverSplit.canDrop = true;
|
this.#dragOverSplit.canDrop = true;
|
||||||
|
// A drop into the split takes the drag image away at once.
|
||||||
|
this.ZenDragAndDropService.armDropLanding(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearDragOverSplit() {
|
_clearDragOverSplit() {
|
||||||
@@ -889,6 +916,9 @@
|
|||||||
clearTimeout(this.#dragOverSplit.timer);
|
clearTimeout(this.#dragOverSplit.timer);
|
||||||
}
|
}
|
||||||
this.#dragOverSplit.fakeTab?.remove();
|
this.#dragOverSplit.fakeTab?.remove();
|
||||||
|
if (this.#dragOverSplit.canDrop && this._dropLandingArmed) {
|
||||||
|
this.ZenDragAndDropService.armDropLanding(true);
|
||||||
|
}
|
||||||
|
|
||||||
this.#dragOverSplit.timer = null;
|
this.#dragOverSplit.timer = null;
|
||||||
this.#dragOverSplit.fakeTab = null;
|
this.#dragOverSplit.fakeTab = null;
|
||||||
@@ -902,9 +932,54 @@
|
|||||||
}
|
}
|
||||||
this.#isOutOfWindow = false;
|
this.#isOutOfWindow = false;
|
||||||
const dt = event.dataTransfer;
|
const dt = event.dataTransfer;
|
||||||
|
for (const extra of this._extraDragImages ?? []) {
|
||||||
|
this.#restoreExtraDragImage(extra);
|
||||||
|
}
|
||||||
dt.updateDragImage(...this.originalDragImageArgs);
|
dt.updateDragImage(...this.originalDragImageArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Out of the window, every dragged tab becomes the window. Each further
|
||||||
|
* drag item gets a copy of the preview the drag image shows.
|
||||||
|
*
|
||||||
|
* @param {Element} extra - The image of a further tab
|
||||||
|
* @param {HTMLCanvasElement} canvas - The window preview
|
||||||
|
*/
|
||||||
|
#previewExtraDragImage(extra, canvas) {
|
||||||
|
if (extra._tabContents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extra._tabContents = {
|
||||||
|
nodes: [...extra.childNodes],
|
||||||
|
width: extra.style.width,
|
||||||
|
height: extra.style.height,
|
||||||
|
};
|
||||||
|
const copy = document.createElementNS(
|
||||||
|
"http://www.w3.org/1999/xhtml",
|
||||||
|
"canvas"
|
||||||
|
);
|
||||||
|
copy.width = canvas.width;
|
||||||
|
copy.height = canvas.height;
|
||||||
|
copy.getContext("2d").drawImage(canvas, 0, 0);
|
||||||
|
copy.style.width = copy.style.height = "100%";
|
||||||
|
copy.style.borderRadius = canvas.style.borderRadius;
|
||||||
|
copy.style.border = canvas.style.border;
|
||||||
|
extra.style.width = this._browserDragImageWrapper.style.width;
|
||||||
|
extra.style.height = this._browserDragImageWrapper.style.height;
|
||||||
|
extra.replaceChildren(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
#restoreExtraDragImage(extra) {
|
||||||
|
const contents = extra._tabContents;
|
||||||
|
if (!contents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete extra._tabContents;
|
||||||
|
extra.style.width = contents.width;
|
||||||
|
extra.style.height = contents.height;
|
||||||
|
extra.replaceChildren(...contents.nodes);
|
||||||
|
}
|
||||||
|
|
||||||
handle_windowDragLeave(event) {
|
handle_windowDragLeave(event) {
|
||||||
// If relatedTarget exists, then we are still in the window
|
// If relatedTarget exists, then we are still in the window
|
||||||
if (
|
if (
|
||||||
@@ -930,8 +1005,6 @@
|
|||||||
this.clearDragOverVisuals();
|
this.clearDragOverVisuals();
|
||||||
this.clearSpaceSwitchTimer();
|
this.clearSpaceSwitchTimer();
|
||||||
const dt = event.dataTransfer;
|
const dt = event.dataTransfer;
|
||||||
let dragData = draggedTab._dragData;
|
|
||||||
let movingTabs = dragData.movingTabs;
|
|
||||||
if (!this._browserDragImageWrapper) {
|
if (!this._browserDragImageWrapper) {
|
||||||
const wrappingDiv = document.createXULElement("vbox");
|
const wrappingDiv = document.createXULElement("vbox");
|
||||||
canvas.style.borderRadius = "8px";
|
canvas.style.borderRadius = "8px";
|
||||||
@@ -939,11 +1012,13 @@
|
|||||||
wrappingDiv.style.width = 200 + "px";
|
wrappingDiv.style.width = 200 + "px";
|
||||||
wrappingDiv.style.height = 130 + "px";
|
wrappingDiv.style.height = 130 + "px";
|
||||||
wrappingDiv.style.position = "relative";
|
wrappingDiv.style.position = "relative";
|
||||||
this.#maybeCreateDragImageDot(movingTabs, wrappingDiv);
|
|
||||||
wrappingDiv.appendChild(canvas);
|
wrappingDiv.appendChild(canvas);
|
||||||
this._browserDragImageWrapper = wrappingDiv;
|
this._browserDragImageWrapper = wrappingDiv;
|
||||||
document.documentElement.appendChild(wrappingDiv);
|
document.documentElement.appendChild(wrappingDiv);
|
||||||
}
|
}
|
||||||
|
for (const extra of this._extraDragImages ?? []) {
|
||||||
|
this.#previewExtraDragImage(extra, canvas);
|
||||||
|
}
|
||||||
dt.updateDragImage(
|
dt.updateDragImage(
|
||||||
this._browserDragImageWrapper,
|
this._browserDragImageWrapper,
|
||||||
this.originalDragImageArgs[1],
|
this.originalDragImageArgs[1],
|
||||||
@@ -970,11 +1045,70 @@
|
|||||||
}
|
}
|
||||||
this.clearSpaceSwitchTimer();
|
this.clearSpaceSwitchTimer();
|
||||||
gZenFolders.highlightGroupOnDragOver(null);
|
gZenFolders.highlightGroupOnDragOver(null);
|
||||||
|
const toSplit = !!this.#dragOverSplit.canDrop;
|
||||||
|
const placesBefore = new Map(
|
||||||
|
this.#draggedElements(event).map(element => [
|
||||||
|
element,
|
||||||
|
this.#placeOf(element),
|
||||||
|
])
|
||||||
|
);
|
||||||
super.handle_drop(event);
|
super.handle_drop(event);
|
||||||
this.#maybeClearVerticalPinnedGridDragOver();
|
this.#maybeClearVerticalPinnedGridDragOver();
|
||||||
this.#handle_dropSwitchSpace(event);
|
this.#handle_dropSwitchSpace(event);
|
||||||
this.#handle_dropCreateSplit(event);
|
this.#handle_dropCreateSplit(event);
|
||||||
this._clearDragOverSplit();
|
this._clearDragOverSplit();
|
||||||
|
if (!toSplit) {
|
||||||
|
this.#landDragImage(event, placesBefore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {DragEvent} event
|
||||||
|
* @returns {Element[]} The elements of the dragged tabs, in the order of
|
||||||
|
* their drag images, when they are this window's
|
||||||
|
*/
|
||||||
|
#draggedElements(event) {
|
||||||
|
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||||
|
if (draggedTab?.documentGlobal !== window) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return (this._dragImageTabs ?? [draggedTab]).map(elementToMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
#placeOf(element) {
|
||||||
|
return `${element.screenX},${element.screenY}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the drag image land on the dropped tab rather than vanish. The OS
|
||||||
|
* slides it onto the tab's new place and ends the drag once it is there,
|
||||||
|
* which is when the tab shows again. Only macOS does so.
|
||||||
|
*
|
||||||
|
* @param {DragEvent} event - The drop
|
||||||
|
* @param {Map<Element, string>} placesBefore - Where each dragged element
|
||||||
|
* was before the drop.
|
||||||
|
*/
|
||||||
|
#landDragImage(event, placesBefore) {
|
||||||
|
// The drop is done, so its indicator goes before the image lands.
|
||||||
|
this.clearDragOverVisuals();
|
||||||
|
if (gReduceMotion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const landing = [];
|
||||||
|
for (const element of this.#draggedElements(event)) {
|
||||||
|
const { width, height } = element.getBoundingClientRect();
|
||||||
|
this.ZenDragAndDropService.addDropLandingRect(
|
||||||
|
Math.round(element.screenX),
|
||||||
|
Math.round(element.screenY),
|
||||||
|
Math.round(width),
|
||||||
|
Math.round(height)
|
||||||
|
);
|
||||||
|
if (placesBefore.get(element) !== this.#placeOf(element)) {
|
||||||
|
element.style.visibility = "hidden";
|
||||||
|
landing.push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._landingElements = landing;
|
||||||
}
|
}
|
||||||
|
|
||||||
#handle_dropSwitchSpace(event) {
|
#handle_dropSwitchSpace(event) {
|
||||||
@@ -1031,6 +1165,7 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line complexity
|
||||||
handle_drop_transition(dropElement, draggedTab, movingTabs, dropBefore) {
|
handle_drop_transition(dropElement, draggedTab, movingTabs, dropBefore) {
|
||||||
if (
|
if (
|
||||||
dropElement?.hasAttribute("zen-empty-tab") &&
|
dropElement?.hasAttribute("zen-empty-tab") &&
|
||||||
@@ -1056,6 +1191,7 @@
|
|||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
this.#isAnimatingTabMove ||
|
this.#isAnimatingTabMove ||
|
||||||
|
this.#dragOverSplit.canDrop ||
|
||||||
!gZenStartup.isReady ||
|
!gZenStartup.isReady ||
|
||||||
gReduceMotion ||
|
gReduceMotion ||
|
||||||
!dropElement ||
|
!dropElement ||
|
||||||
@@ -1175,6 +1311,10 @@
|
|||||||
let ownerGlobal = draggedTab?.documentGlobal;
|
let ownerGlobal = draggedTab?.documentGlobal;
|
||||||
draggedTab.style.visibility = "";
|
draggedTab.style.visibility = "";
|
||||||
let thisFromGlobal = ownerGlobal?.gBrowser.tabContainer.tabDragAndDrop;
|
let thisFromGlobal = ownerGlobal?.gBrowser.tabContainer.tabDragAndDrop;
|
||||||
|
for (const element of thisFromGlobal._landingElements ?? []) {
|
||||||
|
element.style.visibility = "";
|
||||||
|
}
|
||||||
|
delete thisFromGlobal._landingElements;
|
||||||
let currentEssenialContainer =
|
let currentEssenialContainer =
|
||||||
ownerGlobal.gZenWorkspaces.getCurrentEssentialsContainer();
|
ownerGlobal.gZenWorkspaces.getCurrentEssentialsContainer();
|
||||||
if (currentEssenialContainer?.essentialsPromo) {
|
if (currentEssenialContainer?.essentialsPromo) {
|
||||||
@@ -1194,6 +1334,7 @@
|
|||||||
thisFromGlobal._clearDragOverSplit();
|
thisFromGlobal._clearDragOverSplit();
|
||||||
this.#maybeClearVerticalPinnedGridDragOver();
|
this.#maybeClearVerticalPinnedGridDragOver();
|
||||||
thisFromGlobal.originalDragImageArgs = [];
|
thisFromGlobal.originalDragImageArgs = [];
|
||||||
|
thisFromGlobal._dropLandingArmed = false;
|
||||||
this.#firstHapticFeedbackPlayed = false;
|
this.#firstHapticFeedbackPlayed = false;
|
||||||
window.removeEventListener(
|
window.removeEventListener(
|
||||||
"dragenter",
|
"dragenter",
|
||||||
@@ -1211,6 +1352,11 @@
|
|||||||
thisFromGlobal._tempDragImageParent.remove();
|
thisFromGlobal._tempDragImageParent.remove();
|
||||||
delete thisFromGlobal._tempDragImageParent;
|
delete thisFromGlobal._tempDragImageParent;
|
||||||
}
|
}
|
||||||
|
for (const extra of thisFromGlobal._extraDragImages ?? []) {
|
||||||
|
extra.remove();
|
||||||
|
}
|
||||||
|
delete thisFromGlobal._extraDragImages;
|
||||||
|
delete thisFromGlobal._dragImageTabs;
|
||||||
delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged;
|
delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged;
|
||||||
if (dt.dropEffect !== "move") {
|
if (dt.dropEffect !== "move") {
|
||||||
ownerGlobal.gZenCompactModeManager._clearAllHoverStates();
|
ownerGlobal.gZenCompactModeManager._clearAllHoverStates();
|
||||||
@@ -1334,10 +1480,14 @@
|
|||||||
dropElement = dragData.dropElement;
|
dropElement = dragData.dropElement;
|
||||||
dropBefore = dragData.dropBefore;
|
dropBefore = dragData.dropBefore;
|
||||||
}
|
}
|
||||||
// Essentials should be properly handled by ::animateVerticalPinnedGridDragOver
|
if (!dropElement) {
|
||||||
if (!dropElement || dropElement.hasAttribute("zen-essential")) {
|
|
||||||
this.clearDragOverVisuals();
|
this.clearDragOverVisuals();
|
||||||
// If dropElement is null or essential, dropElement should be the empty tab
|
return [undefined, null];
|
||||||
|
}
|
||||||
|
// Essentials should be properly handled by ::animateVerticalPinnedGridDragOver
|
||||||
|
if (dropElement.hasAttribute("zen-essential")) {
|
||||||
|
this.clearDragOverVisuals();
|
||||||
|
// If dropElement is essential, dropElement should be the empty tab
|
||||||
return [dropBefore, gZenWorkspaces._emptyTab];
|
return [dropBefore, gZenWorkspaces._emptyTab];
|
||||||
}
|
}
|
||||||
if (dropElement.hasAttribute("zen-empty-tab") && dropElement.group) {
|
if (dropElement.hasAttribute("zen-empty-tab") && dropElement.group) {
|
||||||
@@ -1490,6 +1640,7 @@
|
|||||||
switch (essentialsPromoStatus) {
|
switch (essentialsPromoStatus) {
|
||||||
case "shown":
|
case "shown":
|
||||||
case "created":
|
case "created":
|
||||||
|
this.#makeDragImageEssential(event);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1777,53 +1928,131 @@
|
|||||||
#makeDragImageEssential(event) {
|
#makeDragImageEssential(event) {
|
||||||
const dt = event.dataTransfer;
|
const dt = event.dataTransfer;
|
||||||
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||||
if (draggedTab.hasAttribute("zen-essential")) {
|
if (this.#dragImageEssential) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.#dragImageEssential = true;
|
||||||
const dragData = draggedTab._dragData;
|
const dragData = draggedTab._dragData;
|
||||||
const [wrapper] = this.originalDragImageArgs;
|
const wasEssential = draggedTab.hasAttribute("zen-essential");
|
||||||
const tab = wrapper.firstElementChild;
|
const draggedTabRect = this.#essentialTileRect(event, draggedTab);
|
||||||
tab.setAttribute("zen-essential", "true");
|
for (const { wrapper, tab } of this.#dragImageClones(draggedTab)) {
|
||||||
tab.setAttribute("pinned", "true");
|
tab.setAttribute("zen-essential", "true");
|
||||||
tab.setAttribute("selected", "true");
|
tab.setAttribute("pinned", "true");
|
||||||
const draggedTabRect = window.windowUtils.getBoundsWithoutFlushing(
|
tab.setAttribute("selected", "true");
|
||||||
this._fakeEssentialTab
|
tab.style.minWidth =
|
||||||
|
tab.style.maxWidth =
|
||||||
|
wrapper.style.width =
|
||||||
|
draggedTabRect.width + "px";
|
||||||
|
tab.style.minHeight =
|
||||||
|
tab.style.maxHeight =
|
||||||
|
wrapper.style.height =
|
||||||
|
draggedTabRect.height + "px";
|
||||||
|
if (wasEssential) {
|
||||||
|
// Back to how the drag began.
|
||||||
|
tab.style.transform = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const offsetY = dragData.offsetY;
|
||||||
|
const offsetX = dragData.offsetX;
|
||||||
|
// Apply a transform translate to the tab in order to center it within the drag image
|
||||||
|
tab.style.transform = `translate(${(54 - offsetX) / 2}px, ${(50 - offsetY) / 2}px)`;
|
||||||
|
gZenPinnedTabManager.setEssentialTabIcon(tab);
|
||||||
|
}
|
||||||
|
if (wasEssential) {
|
||||||
|
dt.updateDragImage(...this.originalDragImageArgs);
|
||||||
|
} else {
|
||||||
|
dt.updateDragImage(this.originalDragImageArgs[0], -16, -16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every drag image with the tab it shows. The drag image itself and,
|
||||||
|
* on macOS, one for each further dragged tab.
|
||||||
|
*
|
||||||
|
* @param {Element} draggedTab
|
||||||
|
* @returns {{wrapper: Element, tab: Element, source: Element}[]} Each
|
||||||
|
* image's wrapper, the clone in it, and the tab it was cloned from
|
||||||
|
*/
|
||||||
|
#dragImageClones(draggedTab) {
|
||||||
|
const wrappers = [
|
||||||
|
this.originalDragImageArgs[0],
|
||||||
|
...(this._extraDragImages ?? []),
|
||||||
|
];
|
||||||
|
const sources = this._dragImageTabs ?? [draggedTab];
|
||||||
|
return wrappers.map((wrapper, i) => ({
|
||||||
|
wrapper,
|
||||||
|
tab: wrapper.firstElementChild,
|
||||||
|
source: sources[i] ?? draggedTab,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size the dragged tab takes as an essential. Its own when it is
|
||||||
|
* one, the tile made for it in the grid, or, with only the promo shown,
|
||||||
|
* a tile as the grid would lay it out.
|
||||||
|
*
|
||||||
|
* @param {DragEvent} event
|
||||||
|
* @param {Element} draggedTab
|
||||||
|
* @returns {{width: number, height: number}}
|
||||||
|
*/
|
||||||
|
#essentialTileRect(event, draggedTab) {
|
||||||
|
const bounds = element =>
|
||||||
|
window.windowUtils.getBoundsWithoutFlushing(element);
|
||||||
|
if (draggedTab.hasAttribute("zen-essential")) {
|
||||||
|
return bounds(draggedTab);
|
||||||
|
}
|
||||||
|
if (this._fakeEssentialTab?.isConnected) {
|
||||||
|
return bounds(this._fakeEssentialTab);
|
||||||
|
}
|
||||||
|
const container =
|
||||||
|
event.target.closest(".zen-essentials-container") ??
|
||||||
|
gZenWorkspaces.getCurrentEssentialsContainer();
|
||||||
|
const height = parseFloat(
|
||||||
|
getComputedStyle(container).getPropertyValue("--tab-min-height")
|
||||||
);
|
);
|
||||||
tab.style.minWidth =
|
return {
|
||||||
tab.style.maxWidth =
|
width: Math.max(bounds(container).width * 0.237, height + 4),
|
||||||
wrapper.style.width =
|
height,
|
||||||
draggedTabRect.width + "px";
|
};
|
||||||
tab.style.minHeight =
|
|
||||||
tab.style.maxHeight =
|
|
||||||
wrapper.style.height =
|
|
||||||
draggedTabRect.height + "px";
|
|
||||||
const offsetY = dragData.offsetY;
|
|
||||||
const offsetX = dragData.offsetX;
|
|
||||||
// Apply a transform translate to the tab in order to center it within the drag image
|
|
||||||
tab.style.transform = `translate(${(54 - offsetX) / 2}px, ${(50 - offsetY) / 2}px)`;
|
|
||||||
gZenPinnedTabManager.setEssentialTabIcon(tab);
|
|
||||||
dt.updateDragImage(wrapper, -16, -16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#makeDragImageNonEssential(event) {
|
#makeDragImageNonEssential(event) {
|
||||||
const dt = event.dataTransfer;
|
const dt = event.dataTransfer;
|
||||||
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
const draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||||
if (draggedTab.hasAttribute("zen-essential")) {
|
if (!this.#dragImageEssential) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const wrapper = this.originalDragImageArgs[0];
|
this.#dragImageEssential = false;
|
||||||
const tab = wrapper.firstElementChild;
|
// An essential takes the size of a row in the strip, as any tab there.
|
||||||
tab.style.setProperty("transition", "none", "important");
|
let model = draggedTab;
|
||||||
tab.removeAttribute("zen-essential");
|
if (draggedTab.hasAttribute("zen-essential")) {
|
||||||
tab.removeAttribute("pinned");
|
model =
|
||||||
tab.style.minWidth = tab.style.maxWidth = "";
|
this._tabbrowserTabs.ariaFocusableItems.find(
|
||||||
tab.style.minHeight = tab.style.maxHeight = "";
|
item => isTab(item) && !item.hasAttribute("zen-essential")
|
||||||
tab.style.transform = "";
|
) ?? draggedTab;
|
||||||
const rect = window.windowUtils.getBoundsWithoutFlushing(draggedTab);
|
}
|
||||||
wrapper.style.width = rect.width + "px";
|
const rect = window.windowUtils.getBoundsWithoutFlushing(model);
|
||||||
wrapper.style.height = rect.height + "px";
|
const clones = this.#dragImageClones(draggedTab);
|
||||||
|
for (const { wrapper, tab, source } of clones) {
|
||||||
|
tab.style.setProperty("transition", "none", "important");
|
||||||
|
tab.removeAttribute("zen-essential");
|
||||||
|
tab.removeAttribute("pinned");
|
||||||
|
tab.style.minWidth = tab.style.maxWidth = "";
|
||||||
|
tab.style.minHeight = tab.style.maxHeight = "";
|
||||||
|
tab.style.transform = "";
|
||||||
|
wrapper.style.width = rect.width + "px";
|
||||||
|
wrapper.style.height = rect.height + "px";
|
||||||
|
if (source.hasAttribute("zen-essential") && tab.textLabel) {
|
||||||
|
tab.textLabel.textContent = source.label.slice(
|
||||||
|
0,
|
||||||
|
Math.floor(rect.width / 6)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
tab.style.transition = "";
|
for (const { tab } of clones) {
|
||||||
|
tab.style.transition = "";
|
||||||
|
}
|
||||||
dt.updateDragImage(...this.originalDragImageArgs);
|
dt.updateDragImage(...this.originalDragImageArgs);
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ SOURCES += [
|
|||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
||||||
SOURCES += ["nsZenNativeWindowMove.mm"]
|
SOURCES += [
|
||||||
|
"nsZenDropLandingCocoa.mm",
|
||||||
|
"nsZenNativeWindowMove.mm",
|
||||||
|
]
|
||||||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk":
|
||||||
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
|
CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"]
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface mozIDOMWindowProxy;
|
interface mozIDOMWindowProxy;
|
||||||
|
webidl Node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Interface for Zen's drag and drop functionality.
|
* @brief Interface for Zen's drag and drop functionality.
|
||||||
@@ -33,4 +34,24 @@ interface nsIZenDragAndDrop : nsISupports {
|
|||||||
* @param window The chrome window to move.
|
* @param window The chrome window to move.
|
||||||
*/
|
*/
|
||||||
void beginNativeWindowMove(in mozIDOMWindowProxy window);
|
void beginNativeWindowMove(in mozIDOMWindowProxy window);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Slide the drag image onto the drop instead of removing it.
|
||||||
|
* macOS only, the drag ends once it lands.
|
||||||
|
* @param arm Whether this drag's drops land the image.
|
||||||
|
*/
|
||||||
|
void armDropLanding(in boolean arm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Drag an extra image along as its own item, one per further tab.
|
||||||
|
* macOS stacks and counts them. Add before the drag starts.
|
||||||
|
* @param image The element to render.
|
||||||
|
*/
|
||||||
|
void addDragImage(in Node image);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Where a drag item lands, in screen CSS pixels. One call per
|
||||||
|
* item in order, from within the drop event.
|
||||||
|
*/
|
||||||
|
void addDropLandingRect(in long x, in long y, in long width, in long height);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -91,9 +91,37 @@ nsZenDragAndDrop::OnDragStart(float opacity) {
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsZenDragAndDrop::OnDragEnd() {
|
nsZenDragAndDrop::OnDragEnd() {
|
||||||
mDragImageOpacity = kZenDefaultDragImageOpacity;
|
mDragImageOpacity = kZenDefaultDragImageOpacity;
|
||||||
|
mDropLandingArmed = false;
|
||||||
|
mDragImages.Clear();
|
||||||
|
mDropLandingRects.Clear();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsZenDragAndDrop::ArmDropLanding(bool aArm) {
|
||||||
|
mDropLandingArmed = aArm;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsZenDragAndDrop::AddDragImage(nsINode* aImage) {
|
||||||
|
NS_ENSURE_ARG_POINTER(aImage);
|
||||||
|
mDragImages.AppendElement(aImage);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsZenDragAndDrop::AddDropLandingRect(int32_t aX, int32_t aY, int32_t aWidth,
|
||||||
|
int32_t aHeight) {
|
||||||
|
mDropLandingRects.AppendElement(
|
||||||
|
mozilla::DesktopIntRect(aX, aY, aWidth, aHeight));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<mozilla::DesktopIntRect> nsZenDragAndDrop::TakeDropLandingRects() {
|
||||||
|
return std::move(mDropLandingRects);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsZenDragAndDrop::BeginNativeWindowMove(mozIDOMWindowProxy* aWindow) {
|
nsZenDragAndDrop::BeginNativeWindowMove(mozIDOMWindowProxy* aWindow) {
|
||||||
NS_ENSURE_ARG_POINTER(aWindow);
|
NS_ENSURE_ARG_POINTER(aWindow);
|
||||||
|
|||||||
@@ -7,6 +7,13 @@
|
|||||||
|
|
||||||
#include "nsIZenDragAndDrop.h"
|
#include "nsIZenDragAndDrop.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
#include "Units.h"
|
||||||
|
#include "nsINode.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(__OBJC__)
|
||||||
|
@protocol NSDraggingInfo;
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ZEN_DND_MANAGER_CONTRACTID "@mozilla.org/zen/drag-and-drop;1"
|
#define ZEN_DND_MANAGER_CONTRACTID "@mozilla.org/zen/drag-and-drop;1"
|
||||||
|
|
||||||
@@ -26,6 +33,15 @@ class nsZenDragAndDrop final : public nsIZenDragAndDrop {
|
|||||||
public:
|
public:
|
||||||
explicit nsZenDragAndDrop();
|
explicit nsZenDragAndDrop();
|
||||||
auto GetDragImageOpacity() const { return mDragImageOpacity; }
|
auto GetDragImageOpacity() const { return mDragImageOpacity; }
|
||||||
|
auto DropLandingArmed() const { return mDropLandingArmed; }
|
||||||
|
const auto& DragImages() const { return mDragImages; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Take the rects the drag items are to land on after the drop
|
||||||
|
* being handled, as the drop added them, in screen CSS pixels and item
|
||||||
|
* order. Empty when the drop added none.
|
||||||
|
*/
|
||||||
|
nsTArray<mozilla::DesktopIntRect> TakeDropLandingRects();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the singleton instance of nsZenDragAndDrop. There may be
|
* @brief Get the singleton instance of nsZenDragAndDrop. There may be
|
||||||
@@ -39,8 +55,25 @@ class nsZenDragAndDrop final : public nsIZenDragAndDrop {
|
|||||||
private:
|
private:
|
||||||
~nsZenDragAndDrop() = default;
|
~nsZenDragAndDrop() = default;
|
||||||
float mDragImageOpacity{};
|
float mDragImageOpacity{};
|
||||||
|
bool mDropLandingArmed{};
|
||||||
|
nsTArray<nsCOMPtr<nsINode>> mDragImages;
|
||||||
|
nsTArray<mozilla::DesktopIntRect> mDropLandingRects;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(XP_MACOSX) && defined(__OBJC__)
|
||||||
|
/**
|
||||||
|
* @brief From the drag destination view, once a dragover is handled, ask
|
||||||
|
* the OS to land the drag image on the drop, if the drag wants that.
|
||||||
|
*/
|
||||||
|
void PrepareDropLanding(id<NSDraggingInfo> aInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief From the drag destination view, once a drop is handled, send the
|
||||||
|
* drag image to the rect the drop set, if it set one.
|
||||||
|
*/
|
||||||
|
void LandDrop(id<NSDraggingInfo> aInfo);
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace zen
|
} // namespace zen
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
54
src/zen/drag-and-drop/nsZenDropLandingCocoa.mm
Normal file
54
src/zen/drag-and-drop/nsZenDropLandingCocoa.mm
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
#include "nsCocoaUtils.h"
|
||||||
|
#include "nsObjCExceptions.h"
|
||||||
|
#include "nsZenDragAndDrop.h"
|
||||||
|
|
||||||
|
namespace zen {
|
||||||
|
|
||||||
|
void PrepareDropLanding(id<NSDraggingInfo> aInfo) {
|
||||||
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
|
auto zen = nsZenDragAndDrop::GetZenDragAndDropInstance();
|
||||||
|
aInfo.animatesToDestination = zen && zen->DropLandingArmed();
|
||||||
|
|
||||||
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LandDrop(id<NSDraggingInfo> aInfo) {
|
||||||
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
|
auto zen = nsZenDragAndDrop::GetZenDragAndDropInstance();
|
||||||
|
if (!zen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSMutableArray* targets = [NSMutableArray array];
|
||||||
|
for (const auto& landing : zen->TakeDropLandingRects()) {
|
||||||
|
[targets
|
||||||
|
addObject:[NSValue valueWithRect:nsCocoaUtils::GeckoRectToCocoaRect(
|
||||||
|
landing)]];
|
||||||
|
}
|
||||||
|
if (!targets.count) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[aInfo enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
|
||||||
|
forView:nil
|
||||||
|
classes:@[ [NSPasteboardItem class] ]
|
||||||
|
searchOptions:@{}
|
||||||
|
usingBlock:^(NSDraggingItem* item, NSInteger idx, BOOL* stop) {
|
||||||
|
NSRect target =
|
||||||
|
[targets[MIN((NSUInteger)idx, targets.count - 1)] rectValue];
|
||||||
|
NSRect frame = item.draggingFrame;
|
||||||
|
frame.origin.x = target.origin.x;
|
||||||
|
frame.origin.y = NSMaxY(target) - frame.size.height;
|
||||||
|
item.draggingFrame = frame;
|
||||||
|
}];
|
||||||
|
|
||||||
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace zen
|
||||||
@@ -183,6 +183,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
case "context_zenFolderChangeIcon":
|
case "context_zenFolderChangeIcon":
|
||||||
this.changeFolderUserIcon(this.#lastFolderContextMenu);
|
this.changeFolderUserIcon(this.#lastFolderContextMenu);
|
||||||
break;
|
break;
|
||||||
|
case "context_zenShareFolder":
|
||||||
|
gZenShareManager.shareFolder(this.#lastFolderContextMenu);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -324,7 +327,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
if (isActiveFolder) {
|
if (isActiveFolder) {
|
||||||
for (const folder of group.activeGroups) {
|
for (const folder of group.activeGroups) {
|
||||||
folder.activeTabs = [...new Set([...folder.activeTabs, tab])].sort(
|
folder.activeTabs = [...new Set([...folder.activeTabs, tab])].sort(
|
||||||
(a, b) => a._tPos > b._tPos
|
(a, b) => a.index - b.index
|
||||||
);
|
);
|
||||||
this.setFolderIndentation([tab], folder, /* for collapse = */ true);
|
this.setFolderIndentation([tab], folder, /* for collapse = */ true);
|
||||||
}
|
}
|
||||||
@@ -375,7 +378,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
if (isActiveFolder && isSplitView) {
|
if (isActiveFolder && isSplitView) {
|
||||||
parentFolder.activeTabs = [
|
parentFolder.activeTabs = [
|
||||||
...new Set([...parentFolder.activeTabs, ...folder.tabs]),
|
...new Set([...parentFolder.activeTabs, ...folder.tabs]),
|
||||||
].sort((a, b) => a._tPos > b._tPos);
|
].sort((a, b) => a.index - b.index);
|
||||||
}
|
}
|
||||||
parentFolder.collapsed = isActiveFolder;
|
parentFolder.collapsed = isActiveFolder;
|
||||||
}
|
}
|
||||||
@@ -1502,10 +1505,78 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
#createAnimation(items, targetState, opts, callback = () => {}) {
|
#createAnimation(items, targetState, opts, callback = () => {}) {
|
||||||
items = Array.isArray(items) ? items : [items];
|
items = Array.isArray(items) ? items : [items];
|
||||||
return items.map(item =>
|
return items.map(item =>
|
||||||
gZenUIManager.motion.animate(item, targetState, opts).then(callback)
|
this.#animateItem(item, targetState, opts).then(callback)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animates an element to the given target state. An array value is a
|
||||||
|
* [from, to] pair, "auto" endpoints are resolved by measuring and an
|
||||||
|
* empty string animates back to the element's natural value. The final
|
||||||
|
* values are left applied as inline styles.
|
||||||
|
*
|
||||||
|
* @param {Element} item - The element to animate.
|
||||||
|
* @param {object} targetState - Property to value (or [from, to]) map.
|
||||||
|
* @param {object} opts - The animation options.
|
||||||
|
* @param {number} opts.duration - The duration in seconds.
|
||||||
|
* @param {string} opts.ease - The easing name.
|
||||||
|
* @returns {Promise} Resolves when the animation has finished.
|
||||||
|
*/
|
||||||
|
async #animateItem(item, targetState, { duration = 0.18, ease } = {}) {
|
||||||
|
const computed = window.getComputedStyle(item);
|
||||||
|
const toCssValue = (prop, value) =>
|
||||||
|
typeof value === "number" && prop !== "opacity"
|
||||||
|
? `${value}px`
|
||||||
|
: String(value);
|
||||||
|
const measure = prop => {
|
||||||
|
const value = computed[prop];
|
||||||
|
if (value === "auto") {
|
||||||
|
return `${item.getBoundingClientRect()[prop] ?? 0}px`;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
const from = {};
|
||||||
|
const to = {};
|
||||||
|
const finalStyles = new Map();
|
||||||
|
for (const [prop, value] of Object.entries(targetState)) {
|
||||||
|
let [start, end] = Array.isArray(value) ? value : [undefined, value];
|
||||||
|
const cssProp = prop.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
|
||||||
|
if (start === undefined || start === "auto") {
|
||||||
|
start = measure(prop);
|
||||||
|
} else {
|
||||||
|
start = toCssValue(prop, start);
|
||||||
|
}
|
||||||
|
if (end === "" || end === "auto") {
|
||||||
|
// Resolve the natural value by clearing any inline override.
|
||||||
|
item.style.removeProperty(cssProp);
|
||||||
|
end = measure(prop);
|
||||||
|
finalStyles.set(cssProp, null);
|
||||||
|
} else {
|
||||||
|
end = toCssValue(prop, end);
|
||||||
|
finalStyles.set(cssProp, end);
|
||||||
|
}
|
||||||
|
from[prop] = start;
|
||||||
|
to[prop] = end;
|
||||||
|
}
|
||||||
|
const animation = item.animate([from, to], {
|
||||||
|
duration: duration * 1000,
|
||||||
|
easing: ease === "easeInOut" ? "ease-in-out" : "ease",
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await animation.finished;
|
||||||
|
} catch (e) {
|
||||||
|
// The animation was cancelled, leave the element as-is.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const [cssProp, value] of finalStyles) {
|
||||||
|
if (value === null) {
|
||||||
|
item.style.removeProperty(cssProp);
|
||||||
|
} else {
|
||||||
|
item.style.setProperty(cssProp, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#calculateHeightShift(tabsContainer, selectedTabs) {
|
#calculateHeightShift(tabsContainer, selectedTabs) {
|
||||||
let heightShift = 0;
|
let heightShift = 0;
|
||||||
if (selectedTabs.length) {
|
if (selectedTabs.length) {
|
||||||
@@ -1523,7 +1594,11 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get #folderAnimationDuration() {
|
get #folderAnimationDuration() {
|
||||||
return this._dontAnimateFolder ? 0 : 0.12;
|
return this._dontAnimateFolder ? 0 : 0.18;
|
||||||
|
}
|
||||||
|
|
||||||
|
get #folderRevealDuration() {
|
||||||
|
return this._dontAnimateFolder ? 0 : 0.22;
|
||||||
}
|
}
|
||||||
|
|
||||||
async animateCollapse(group) {
|
async animateCollapse(group) {
|
||||||
@@ -1543,6 +1618,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
splitViewIds,
|
splitViewIds,
|
||||||
activeFoldersIds,
|
activeFoldersIds,
|
||||||
});
|
});
|
||||||
|
if (selectedTabs.length) {
|
||||||
|
tabsContainer.removeAttribute("hidden");
|
||||||
|
}
|
||||||
const collapsedHeight = this.#calculateHeightShift(
|
const collapsedHeight = this.#calculateHeightShift(
|
||||||
tabsContainer,
|
tabsContainer,
|
||||||
selectedTabs
|
selectedTabs
|
||||||
@@ -1761,6 +1839,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
|
|
||||||
// Set correct margin-top after animation
|
// Set correct margin-top after animation
|
||||||
const afterAnimate = () => {
|
const afterAnimate = () => {
|
||||||
|
if (folder.hasAttribute("has-active")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
groupStart.style.removeProperty("margin-top");
|
groupStart.style.removeProperty("margin-top");
|
||||||
this.styleCleanup(groupItems);
|
this.styleCleanup(groupItems);
|
||||||
// Trigger the recalculation so that zen returns
|
// Trigger the recalculation so that zen returns
|
||||||
@@ -1782,7 +1863,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
{
|
{
|
||||||
marginTop: -(collapsedHeight + 4),
|
marginTop: -(collapsedHeight + 4),
|
||||||
},
|
},
|
||||||
{ duration: 0.12, ease: "easeInOut" },
|
{ duration: this.#folderAnimationDuration, ease: "easeInOut" },
|
||||||
afterAnimate
|
afterAnimate
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -1818,6 +1899,9 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
|
|
||||||
// Set correct margin-top after animation
|
// Set correct margin-top after animation
|
||||||
const afterAnimate = () => {
|
const afterAnimate = () => {
|
||||||
|
if (folder.hasAttribute("has-active")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
groupStart.style.removeProperty("margin-top");
|
groupStart.style.removeProperty("margin-top");
|
||||||
this.styleCleanup(groupItems);
|
this.styleCleanup(groupItems);
|
||||||
// Trigger the recalculation so that zen returns
|
// Trigger the recalculation so that zen returns
|
||||||
@@ -1842,7 +1926,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
{
|
{
|
||||||
marginTop: -(collapsedHeight + 4),
|
marginTop: -(collapsedHeight + 4),
|
||||||
},
|
},
|
||||||
{ duration: 0.12, ease: "easeInOut" },
|
{ duration: this.#folderAnimationDuration, ease: "easeInOut" },
|
||||||
afterAnimate
|
afterAnimate
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -1867,7 +1951,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
height: 0,
|
height: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
duration: 0.12,
|
duration: this.#folderAnimationDuration,
|
||||||
ease: "easeInOut",
|
ease: "easeInOut",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -1896,12 +1980,31 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
const selectedTabs = [];
|
const selectedTabs = [];
|
||||||
const splitViewIds = new Set();
|
const splitViewIds = new Set();
|
||||||
const itemsToHide = [];
|
const itemsToHide = [];
|
||||||
|
const newlyActive = new Set();
|
||||||
|
|
||||||
const groupItems = this.#collectGroupItems(group, {
|
const groupItems = this.#collectGroupItems(group, {
|
||||||
selectedTabs,
|
selectedTabs,
|
||||||
splitViewIds,
|
splitViewIds,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (group.collapsed && selectedTabs.length) {
|
||||||
|
const active = new Set([...(group.activeTabs ?? []), ...selectedTabs]);
|
||||||
|
const tabs = group.tabs.filter(tab => !tab.hasAttribute("zen-empty-tab"));
|
||||||
|
if (
|
||||||
|
tabs.length &&
|
||||||
|
tabs.every(
|
||||||
|
tab =>
|
||||||
|
active.has(tab) ||
|
||||||
|
tab.selected ||
|
||||||
|
tab.multiselected ||
|
||||||
|
tab.hasAttribute("folder-active")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
group.collapsed = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const tab of selectedTabs) {
|
for (const tab of selectedTabs) {
|
||||||
let currentGroup = tab?.group?.hasAttribute("split-view-group")
|
let currentGroup = tab?.group?.hasAttribute("split-view-group")
|
||||||
? tab.group.group
|
? tab.group.group
|
||||||
@@ -1913,10 +2016,15 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
if (activeTabs.length) {
|
if (activeTabs.length) {
|
||||||
if (currentGroup.collapsed) {
|
if (currentGroup.collapsed) {
|
||||||
if (currentGroup.hasAttribute("has-active")) {
|
if (currentGroup.hasAttribute("has-active")) {
|
||||||
|
for (const activeTab of activeTabs) {
|
||||||
|
if (!currentGroup.activeTabs.includes(activeTab)) {
|
||||||
|
newlyActive.add(activeTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
// It is important to keep the sequence of elements as in the DOM
|
// It is important to keep the sequence of elements as in the DOM
|
||||||
currentGroup.activeTabs = [
|
currentGroup.activeTabs = [
|
||||||
...new Set([...currentGroup.activeTabs, ...activeTabs]),
|
...new Set([...currentGroup.activeTabs, ...activeTabs]),
|
||||||
].sort((a, b) => a._tPos > b._tPos);
|
].sort((a, b) => a.index - b.index);
|
||||||
} else {
|
} else {
|
||||||
currentGroup.setAttribute("has-active", "true");
|
currentGroup.setAttribute("has-active", "true");
|
||||||
currentGroup.activeTabs = activeTabs;
|
currentGroup.activeTabs = activeTabs;
|
||||||
@@ -1941,7 +2049,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
{
|
{
|
||||||
marginTop: 0,
|
marginTop: 0,
|
||||||
},
|
},
|
||||||
{ duration: 0.12, ease: "easeInOut" },
|
{ duration: this.#folderAnimationDuration, ease: "easeInOut" },
|
||||||
afterMarginTop
|
afterMarginTop
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -1960,13 +2068,14 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const itemsToShow = [];
|
const itemsToShow = [];
|
||||||
|
const itemsToReveal = [];
|
||||||
if (selectedTabs.length) {
|
if (selectedTabs.length) {
|
||||||
for (let i = 0; i < groupItems.length; i++) {
|
for (let i = 0; i < groupItems.length; i++) {
|
||||||
const { item, splitViewId } = groupItems[i];
|
const { item, splitViewId } = groupItems[i];
|
||||||
|
|
||||||
let itemVisible = item.visible;
|
let itemVisible = item.visible;
|
||||||
if (itemVisible) {
|
if (itemVisible) {
|
||||||
itemsToShow.push(item);
|
(newlyActive.has(item) ? itemsToReveal : itemsToShow).push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip selected items
|
// Skip selected items
|
||||||
@@ -2000,18 +2109,48 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
height: "",
|
height: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
duration: 0.12,
|
duration: this.#folderAnimationDuration,
|
||||||
ease: "easeInOut",
|
ease: "easeInOut",
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
...itemsToReveal.flatMap(item => {
|
||||||
|
const state = {
|
||||||
|
opacity: [0, ""],
|
||||||
|
height: [0, ""],
|
||||||
|
minHeight: [0, ""],
|
||||||
|
};
|
||||||
|
const folder = item.group?.hasAttribute("split-view-group")
|
||||||
|
? item.group.group
|
||||||
|
: item.group;
|
||||||
|
const slidesFromFolder = !(folder?.activeTabs ?? []).some(
|
||||||
|
active =>
|
||||||
|
!newlyActive.has(active) &&
|
||||||
|
active.compareDocumentPosition(item) &
|
||||||
|
Node.DOCUMENT_POSITION_FOLLOWING
|
||||||
|
);
|
||||||
|
if (slidesFromFolder) {
|
||||||
|
const height =
|
||||||
|
item.getBoundingClientRect().height ||
|
||||||
|
(folder?.activeTabs ?? []).reduce(
|
||||||
|
(found, active) => found || active.getBoundingClientRect().height,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
state.transform = [`translateY(-${height}px)`, ""];
|
||||||
|
}
|
||||||
|
return this.#createAnimation(item, state, {
|
||||||
|
duration: this.#folderRevealDuration,
|
||||||
|
ease: "easeInOut",
|
||||||
|
});
|
||||||
|
}),
|
||||||
...this.#createAnimation(
|
...this.#createAnimation(
|
||||||
itemsToHide,
|
itemsToHide,
|
||||||
{
|
{
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
|
minHeight: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
duration: 0.12,
|
duration: this.#folderAnimationDuration,
|
||||||
ease: "easeInOut",
|
ease: "easeInOut",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -2044,7 +2183,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
{
|
{
|
||||||
marginTop: expand ? 0 : -(heightContainer + 4),
|
marginTop: expand ? 0 : -(heightContainer + 4),
|
||||||
},
|
},
|
||||||
{ duration: 0.12, ease: "easeInOut" }
|
{ duration: this.#folderAnimationDuration, ease: "easeInOut" }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2052,6 +2191,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
|
|||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
item.style.removeProperty("opacity");
|
item.style.removeProperty("opacity");
|
||||||
item.style.removeProperty("height");
|
item.style.removeProperty("height");
|
||||||
|
item.style.removeProperty("min-height");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,4 @@
|
|||||||
|
|
||||||
content/browser/zen-components/ZenFolder.mjs (../../zen/folders/ZenFolder.mjs)
|
content/browser/zen-components/ZenFolder.mjs (../../zen/folders/ZenFolder.mjs)
|
||||||
content/browser/zen-components/ZenFolders.mjs (../../zen/folders/ZenFolders.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)
|
||||||
|
|||||||
19
src/zen/folders/zen-folder-icon.inc.css
Normal file
19
src/zen/folders/zen-folder-icon.inc.css
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
& g,
|
||||||
|
& rect,
|
||||||
|
& path {
|
||||||
|
transition:
|
||||||
|
transform 0.3s cubic-bezier(0.42, 0, 0, 1),
|
||||||
|
opacity 0.3s cubic-bezier(0.42, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[state="open"] .back {
|
||||||
|
transform: skewX(16deg) translate(-4px, 2px) scale(0.85);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[state="open"] :is(.front, .dots, .icon) {
|
||||||
|
transform: skewX(-16deg) translate(8px, 2px) scale(0.85);
|
||||||
|
}
|
||||||
@@ -8,15 +8,17 @@
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--zen-folder-behind-bgcolor: light-dark(color-mix(in srgb, var(--zen-primary-color) 60%, gray), color-mix(in srgb, var(--zen-primary-color) 60%, #c1c1c1));
|
||||||
|
--zen-folder-front-bgcolor: light-dark(color-mix(in srgb, var(--zen-primary-color), white 70%), color-mix(in srgb, var(--zen-primary-color), black 40%));
|
||||||
|
--zen-folder-stroke: light-dark(color-mix(in srgb, var(--zen-primary-color) 50%, black), color-mix(in srgb, var(--zen-colors-primary) 15%, #ebebeb));
|
||||||
|
}
|
||||||
|
|
||||||
zen-folder {
|
zen-folder {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
|
|
||||||
--zen-folder-behind-bgcolor: light-dark(color-mix(in srgb, var(--zen-primary-color) 60%, gray), color-mix(in srgb, var(--zen-primary-color) 60%, #c1c1c1));
|
|
||||||
--zen-folder-front-bgcolor: light-dark(color-mix(in srgb, var(--zen-primary-color), white 70%), color-mix(in srgb, var(--zen-primary-color), black 40%));
|
|
||||||
--zen-folder-stroke: light-dark(color-mix(in srgb, var(--zen-primary-color) 50%, black), color-mix(in srgb, var(--zen-colors-primary) 15%, #ebebeb));
|
|
||||||
|
|
||||||
-moz-window-dragging: no-drag;
|
-moz-window-dragging: no-drag;
|
||||||
transition: var(--zen-tabbox-element-indent-transition);
|
transition: var(--zen-tabbox-element-indent-transition);
|
||||||
|
|
||||||
@@ -114,21 +116,7 @@ zen-folder {
|
|||||||
transform: translate(8.5px, 10.5px);
|
transform: translate(8.5px, 10.5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
& g,
|
%include zen-folder-icon.inc.css
|
||||||
& rect,
|
|
||||||
& path {
|
|
||||||
transition:
|
|
||||||
transform 0.3s cubic-bezier(0.42, 0, 0, 1),
|
|
||||||
opacity 0.3s cubic-bezier(0.42, 0, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
&[state="open"] .back {
|
|
||||||
transform: skewX(16deg) translate(-4px, 2px) scale(0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
&[state="open"] :is(.front, .dots, .icon) {
|
|
||||||
transform: skewX(-16deg) translate(8px, 2px) scale(0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
& .icon {
|
& .icon {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -205,15 +193,8 @@ zen-folder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[zen-sidebar-expanded] &[has-active] > .tab-group-label-container {
|
:root[zen-sidebar-expanded] &[has-active] > .tab-group-label-container:hover .tab-reset-button {
|
||||||
& .tab-reset-button {
|
display: flex;
|
||||||
display: flex;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .tab-reset-button {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
|
|||||||
return Promise.resolve(this.#currentTab);
|
return Promise.resolve(this.#currentTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Existing-tab glances perform no navigation and are exempt; for fresh
|
// Existing-tab glances perform no navigation and are exempt. For fresh
|
||||||
// loads, refuse any URL the triggering principal isn't allowed to load
|
// loads, refuse any URL the triggering principal isn't allowed to load
|
||||||
// (e.g. a web page linking to file://).
|
// (e.g. a web page linking to file://).
|
||||||
if (!existingTab && !this.#isGlanceLoadAllowed(data)) {
|
if (!existingTab && !this.#isGlanceLoadAllowed(data)) {
|
||||||
|
|||||||
@@ -17,12 +17,18 @@ XPCOMUtils.defineLazyPreferenceGetter(
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
|
lazy,
|
||||||
|
"activationMethod",
|
||||||
|
"zen.glance.activation-method",
|
||||||
|
"ctrl"
|
||||||
|
);
|
||||||
|
|
||||||
// A small threshold to allow for minor mouse jitter during a normal click.
|
// A small threshold to allow for minor mouse jitter during a normal click.
|
||||||
// Anything beyond this is likely an intentional drag (like selecting text).
|
// Anything beyond this is likely an intentional drag (like selecting text).
|
||||||
const CLICK_DRAG_THRESHOLD_PX = 4;
|
const CLICK_DRAG_THRESHOLD_PX = 4;
|
||||||
|
|
||||||
export class ZenGlanceChild extends JSWindowActorChild {
|
export class ZenGlanceChild extends JSWindowActorChild {
|
||||||
#activationMethod;
|
|
||||||
#mouseDownX = null;
|
#mouseDownX = null;
|
||||||
#mouseDownY = null;
|
#mouseDownY = null;
|
||||||
|
|
||||||
@@ -37,12 +43,6 @@ export class ZenGlanceChild extends JSWindowActorChild {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async #initActivationMethod() {
|
|
||||||
this.#activationMethod = await this.sendQuery(
|
|
||||||
"ZenGlance:GetActivationMethod"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ensureOnlyKeyModifiers(event) {
|
#ensureOnlyKeyModifiers(event) {
|
||||||
return !(event.ctrlKey ^ event.altKey ^ event.shiftKey ^ event.metaKey);
|
return !(event.ctrlKey ^ event.altKey ^ event.shiftKey ^ event.metaKey);
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ export class ZenGlanceChild extends JSWindowActorChild {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const activationMethod = this.#activationMethod;
|
const activationMethod = lazy.activationMethod;
|
||||||
if (activationMethod === "ctrl" && !event.ctrlKey) {
|
if (activationMethod === "ctrl" && !event.ctrlKey) {
|
||||||
return;
|
return;
|
||||||
} else if (activationMethod === "alt" && !event.altKey) {
|
} else if (activationMethod === "alt" && !event.altKey) {
|
||||||
@@ -184,8 +184,4 @@ export class ZenGlanceChild extends JSWindowActorChild {
|
|||||||
this.contentWindow.document.body,
|
this.contentWindow.document.body,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async on_DOMContentLoaded() {
|
|
||||||
await this.#initActivationMethod();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,6 @@ export class ZenGlanceParent extends JSWindowActorParent {
|
|||||||
|
|
||||||
async receiveMessage(message) {
|
async receiveMessage(message) {
|
||||||
switch (message.name) {
|
switch (message.name) {
|
||||||
case "ZenGlance:GetActivationMethod": {
|
|
||||||
return Services.prefs.getStringPref(
|
|
||||||
"zen.glance.activation-method",
|
|
||||||
"ctrl"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case "ZenGlance:OpenGlance": {
|
case "ZenGlance:OpenGlance": {
|
||||||
this.openGlance(this.browsingContext.topChromeWindow, message.data);
|
this.openGlance(this.browsingContext.topChromeWindow, message.data);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -105,6 +105,11 @@
|
|||||||
.browserSidebarContainer.zen-glance-background,
|
.browserSidebarContainer.zen-glance-background,
|
||||||
.browserSidebarContainer.zen-glance-overlay .browserContainer:not([fade-out="true"]) {
|
.browserSidebarContainer.zen-glance-overlay .browserContainer:not([fade-out="true"]) {
|
||||||
border-radius: var(--zen-native-inner-radius);
|
border-radius: var(--zen-native-inner-radius);
|
||||||
|
@media not (-moz-pref("zen.theme.squircle-browser-view")) {
|
||||||
|
/* stylelint-disable-next-line property-no-unknown */
|
||||||
|
corner-shape: round;
|
||||||
|
border-radius: calc(var(--zen-native-inner-radius) / var(--zen-squircle-value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.browserSidebarContainer.zen-glance-overlay {
|
.browserSidebarContainer.zen-glance-overlay {
|
||||||
@@ -144,6 +149,11 @@
|
|||||||
border-radius: var(--zen-native-inner-radius);
|
border-radius: var(--zen-native-inner-radius);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: var(--zen-big-shadow);
|
box-shadow: var(--zen-big-shadow);
|
||||||
|
@media not (-moz-pref("zen.theme.squircle-browser-view")) {
|
||||||
|
/* stylelint-disable-next-line property-no-unknown */
|
||||||
|
corner-shape: round;
|
||||||
|
border-radius: calc(var(--zen-native-inner-radius) / var(--zen-squircle-value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
& browser {
|
& browser {
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ const lazy = {};
|
|||||||
ChromeUtils.defineESModuleGetters(lazy, {
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
JSONFile: "resource://gre/modules/JSONFile.sys.mjs",
|
JSONFile: "resource://gre/modules/JSONFile.sys.mjs",
|
||||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
TabStateCache:
|
||||||
|
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||||
ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||||
FeatureCallout: "resource:///modules/asrouter/FeatureCallout.sys.mjs",
|
FeatureCallout: "resource:///modules/asrouter/FeatureCallout.sys.mjs",
|
||||||
});
|
});
|
||||||
@@ -497,41 +498,51 @@ class nsZenLiveFoldersManager {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.map(item => {
|
.map(item => {
|
||||||
const tab = this.window.gBrowser.addTrustedTab(item.url, {
|
try {
|
||||||
createLazyBrowser: true,
|
const tab = this.window.gBrowser.addTrustedTab(item.url, {
|
||||||
inBackground: true,
|
createLazyBrowser: true,
|
||||||
skipAnimation: true,
|
inBackground: true,
|
||||||
noInitialLabel: true,
|
skipAnimation: true,
|
||||||
lazyTabTitle: item.title,
|
noInitialLabel: true,
|
||||||
userContextId,
|
lazyTabTitle: item.title,
|
||||||
});
|
userContextId,
|
||||||
// createLazyBrowser can't be pinned by default
|
});
|
||||||
this.window.gBrowser.pinTab(tab);
|
// createLazyBrowser can't be pinned by default
|
||||||
if (userContextId) {
|
this.window.gBrowser.pinTab(tab);
|
||||||
tab.setAttribute("zenDefaultUserContextId", "true");
|
if (userContextId) {
|
||||||
}
|
tab.setAttribute("zenDefaultUserContextId", "true");
|
||||||
if (item.icon) {
|
}
|
||||||
this.window.gBrowser.setIcon(tab, item.icon);
|
if (item.icon) {
|
||||||
if (tab.linkedBrowser) {
|
this.window.gBrowser.setIcon(tab, item.icon);
|
||||||
lazy.TabStateCache.update(tab.linkedBrowser.permanentKey, {
|
if (tab.linkedBrowser) {
|
||||||
image: null,
|
lazy.TabStateCache.update(tab.linkedBrowser.permanentKey, {
|
||||||
|
image: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
this.window.document.l10n.setArgs(tabLabel, {
|
||||||
|
tabSubtitle: item.subtitle,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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");
|
|
||||||
this.window.document.l10n.setArgs(tabLabel, {
|
|
||||||
tabSubtitle: item.subtitle,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return tab;
|
return tab;
|
||||||
});
|
} catch (e) {
|
||||||
|
console.error(
|
||||||
|
"ZenLiveFoldersManager: Failed to add tab for item",
|
||||||
|
item.url,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(tab => tab);
|
||||||
|
|
||||||
// Wait for tabs to (hopefully) be initialized on all windows
|
// Wait for tabs to (hopefully) be initialized on all windows
|
||||||
lazy.setTimeout(() => {
|
lazy.setTimeout(() => {
|
||||||
|
|||||||
@@ -242,6 +242,7 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
|
|||||||
const baseQuery = [
|
const baseQuery = [
|
||||||
this.state.type === "pull-requests" ? "is:pr" : "is:issue",
|
this.state.type === "pull-requests" ? "is:pr" : "is:issue",
|
||||||
"is:open",
|
"is:open",
|
||||||
|
"archived:false",
|
||||||
"sort:updated-desc",
|
"sort:updated-desc",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -182,15 +182,21 @@ class nsZenMods extends nsZenPreloadedFeature {
|
|||||||
({ enabled, preferences, name }) => ({
|
({ enabled, preferences, name }) => ({
|
||||||
enabled,
|
enabled,
|
||||||
sanitizedName: this.sanitizeModName(name),
|
sanitizedName: this.sanitizeModName(name),
|
||||||
prefs: preferences.map(({ property, type }) => ({
|
prefs: preferences.map(({ property, type }) => {
|
||||||
property,
|
const isEnabled = enabled === undefined || enabled;
|
||||||
type,
|
const getPref =
|
||||||
sanitizedProperty: property?.replaceAll(DOT_RE, "-"),
|
type === "checkbox"
|
||||||
value:
|
? Services.prefs.getBoolPref
|
||||||
enabled === undefined || enabled
|
: Services.prefs.getStringPref;
|
||||||
? Services.prefs.getStringPref(property, "")
|
const fallback = type === "checkbox" ? false : "";
|
||||||
: "",
|
|
||||||
})),
|
return {
|
||||||
|
property,
|
||||||
|
type,
|
||||||
|
sanitizedProperty: property?.replaceAll(DOT_RE, "-"),
|
||||||
|
value: isEnabled ? getPref(property, fallback) : fallback,
|
||||||
|
};
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -524,13 +530,20 @@ class nsZenMods extends nsZenPreloadedFeature {
|
|||||||
console.error("[ZenMods]: Error loading Zen Mods:", e);
|
console.error("[ZenMods]: Error loading Zen Mods:", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Services.prefs.addObserver(
|
const rebuildObserver = this.#rebuildModsStylesheet.bind(this);
|
||||||
this.updatePref,
|
const disableObserver = this.#handleDisableMods.bind(this);
|
||||||
this.#rebuildModsStylesheet.bind(this)
|
Services.prefs.addObserver(this.updatePref, rebuildObserver);
|
||||||
);
|
Services.prefs.addObserver("zen.themes.disable-all", disableObserver);
|
||||||
Services.prefs.addObserver(
|
window.addEventListener(
|
||||||
"zen.themes.disable-all",
|
"unload",
|
||||||
this.#handleDisableMods.bind(this)
|
() => {
|
||||||
|
Services.prefs.removeObserver(this.updatePref, rebuildObserver);
|
||||||
|
Services.prefs.removeObserver(
|
||||||
|
"zen.themes.disable-all",
|
||||||
|
disableObserver
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,12 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||||||
ZenLiveFoldersManager:
|
ZenLiveFoldersManager:
|
||||||
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
|
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
|
||||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
||||||
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
|
SessionStore:
|
||||||
SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs",
|
"moz-src:///browser/components/sessionstore/SessionStore.sys.mjs",
|
||||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
SessionStartup:
|
||||||
|
"moz-src:///browser/components/sessionstore/SessionStartup.sys.mjs",
|
||||||
|
TabStateFlusher:
|
||||||
|
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs",
|
||||||
gWindowSyncEnabled: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
gWindowSyncEnabled: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||||
gSyncOnlyPinnedTabs: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
gSyncOnlyPinnedTabs: "resource:///modules/zen/ZenWindowSync.sys.mjs",
|
||||||
DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs",
|
DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs",
|
||||||
|
|||||||
@@ -10,13 +10,15 @@ const lazy = {};
|
|||||||
|
|
||||||
ChromeUtils.defineESModuleGetters(lazy, {
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
|
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
|
||||||
TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
|
TabStateFlusher:
|
||||||
|
"moz-src:///browser/components/sessionstore/TabStateFlusher.sys.mjs",
|
||||||
// eslint-disable-next-line mozilla/valid-lazy
|
// eslint-disable-next-line mozilla/valid-lazy
|
||||||
ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
|
||||||
TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs",
|
TabStateCache:
|
||||||
|
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
||||||
RunState: "resource:///modules/sessionstore/RunState.sys.mjs",
|
RunState: "moz-src:///browser/components/sessionstore/RunState.sys.mjs",
|
||||||
});
|
});
|
||||||
|
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
@@ -328,7 +330,7 @@ class nsZenWindowSync {
|
|||||||
// browser/components/extensions/parent/ext-browser.js.
|
// browser/components/extensions/parent/ext-browser.js.
|
||||||
// See: Bug 1960104 - Improve tab group ID generation in addTabGroup
|
// See: Bug 1960104 - Improve tab group ID generation in addTabGroup
|
||||||
// This is implemented from gBrowser.addTabGroup.
|
// This is implemented from gBrowser.addTabGroup.
|
||||||
return `${Date.now()}-${Math.round(Math.random() * 100)}`;
|
return `${Date.now()}-${Services.uuid.generateUUID().toString().slice(1, -1)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
238
src/zen/share/ZenShareClient.sys.mjs
Normal file
238
src/zen/share/ZenShareClient.sys.mjs
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
||||||
|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||||
|
|
||||||
|
const lazy = {};
|
||||||
|
|
||||||
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
|
JsonSchema: "resource://gre/modules/JsonSchema.sys.mjs",
|
||||||
|
clearTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
|
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
|
lazy,
|
||||||
|
"gBaseUrl",
|
||||||
|
"zen.share.base-url",
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
value => value.trim().replace(/\/+$/, "")
|
||||||
|
);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
|
lazy,
|
||||||
|
"gSecretKey",
|
||||||
|
"zen.share.secret-key",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
const SCHEMA_URL = "resource:///modules/zen/share/share.schema.json";
|
||||||
|
|
||||||
|
// The server rejects bigger bodies at 25 MiB.
|
||||||
|
const MAX_SHARE_BYTES = 25 * 1024 * 1024;
|
||||||
|
const MAX_NAME_LENGTH = 200;
|
||||||
|
|
||||||
|
// Uploads can be tens of MiB, reads are small JSON.
|
||||||
|
const CREATE_TIMEOUT_MS = 120000;
|
||||||
|
const READ_TIMEOUT_MS = 30000;
|
||||||
|
|
||||||
|
// Public share page paths: /{slug}/{XXXX-XXXX-XXXX-XXXX id}.
|
||||||
|
const SHARE_PATH_RE =
|
||||||
|
/^\/(space|folder|split-view|split)\/([0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4}-[0-9A-Za-z]{4})\/?$/;
|
||||||
|
|
||||||
|
export class ZenShareError extends Error {
|
||||||
|
/**
|
||||||
|
* @param {string} code - One of "invalid-document", "auth", "too-large",
|
||||||
|
* "rate-limited", "not-found", "network", "server".
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
constructor(code, message) {
|
||||||
|
super(message);
|
||||||
|
this.name = "ZenShareError";
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class nsZenShareClient {
|
||||||
|
#validatorPromise = null;
|
||||||
|
|
||||||
|
get #baseUrl() {
|
||||||
|
return lazy.gBaseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#authHeaders() {
|
||||||
|
// A secret key authorizes on its own and makes the share permanent. Never
|
||||||
|
// send both keys.
|
||||||
|
if (lazy.gSecretKey) {
|
||||||
|
return { "x-secret-key": lazy.gSecretKey };
|
||||||
|
}
|
||||||
|
return { "x-api-key": AppConstants.MOZ_MOZILLA_API_KEY };
|
||||||
|
}
|
||||||
|
|
||||||
|
#getValidator() {
|
||||||
|
if (!this.#validatorPromise) {
|
||||||
|
this.#validatorPromise = fetch(SCHEMA_URL, { credentials: "omit" })
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(schema => new lazy.JsonSchema.Validator(schema));
|
||||||
|
}
|
||||||
|
return this.#validatorPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a share document against the schema.
|
||||||
|
*
|
||||||
|
* @param {object} doc
|
||||||
|
* @returns {Promise<{valid: boolean, errors: object[]}>}
|
||||||
|
*/
|
||||||
|
async validateDocument(doc) {
|
||||||
|
const validator = await this.#getValidator();
|
||||||
|
return validator.validate(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #assertValidDocument(doc) {
|
||||||
|
const result = await this.validateDocument(doc);
|
||||||
|
if (!result.valid) {
|
||||||
|
console.error("ZenShare: document fails the schema", result.errors);
|
||||||
|
throw new ZenShareError(
|
||||||
|
"invalid-document",
|
||||||
|
"share document fails the schema"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #request(url, options, timeoutMs = READ_TIMEOUT_MS) {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timer = lazy.setTimeout(() => controller.abort(), timeoutMs);
|
||||||
|
let response;
|
||||||
|
try {
|
||||||
|
response = await fetch(url, {
|
||||||
|
credentials: "omit",
|
||||||
|
signal: controller.signal,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
throw new ZenShareError(
|
||||||
|
"network",
|
||||||
|
`could not reach ${url}: ${e.message}`
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
lazy.clearTimeout(timer);
|
||||||
|
}
|
||||||
|
if (response.ok) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
let message = `${response.status}`;
|
||||||
|
try {
|
||||||
|
message = (await response.json()).error || message;
|
||||||
|
} catch (e) {}
|
||||||
|
switch (response.status) {
|
||||||
|
case 401:
|
||||||
|
case 403:
|
||||||
|
throw new ZenShareError("auth", message);
|
||||||
|
case 404:
|
||||||
|
throw new ZenShareError("not-found", message);
|
||||||
|
case 413:
|
||||||
|
throw new ZenShareError("too-large", message);
|
||||||
|
case 429:
|
||||||
|
throw new ZenShareError("rate-limited", message);
|
||||||
|
case 400:
|
||||||
|
case 422:
|
||||||
|
throw new ZenShareError("invalid-document", message);
|
||||||
|
default:
|
||||||
|
throw new ZenShareError("server", message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads a share document.
|
||||||
|
*
|
||||||
|
* @param {object} doc - A document conforming to share.schema.json.
|
||||||
|
* @param {{name?: string}} options - Optional sharer display name, shown on
|
||||||
|
* the share page as "A Space from {name}".
|
||||||
|
* @returns {Promise<object>} The create response, plus `link`: the absolute
|
||||||
|
* public page URL to hand to the user.
|
||||||
|
*/
|
||||||
|
async createShare(doc, { name } = {}) {
|
||||||
|
const base = this.#baseUrl;
|
||||||
|
const headers = this.#authHeaders();
|
||||||
|
await this.#assertValidDocument(doc);
|
||||||
|
const body = JSON.stringify(doc);
|
||||||
|
if (new TextEncoder().encode(body).length > MAX_SHARE_BYTES) {
|
||||||
|
throw new ZenShareError("too-large", "share document is over 25 MiB");
|
||||||
|
}
|
||||||
|
let url = `${base}/api/shares`;
|
||||||
|
if (name) {
|
||||||
|
url += `?name=${encodeURIComponent(name.slice(0, MAX_NAME_LENGTH))}`;
|
||||||
|
}
|
||||||
|
const response = await this.#request(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: { ...headers, "content-type": "application/json" },
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
CREATE_TIMEOUT_MS
|
||||||
|
);
|
||||||
|
const created = await response.json();
|
||||||
|
return { ...created, link: base + created.webUrl };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recognizes public share page URLs on the configured server.
|
||||||
|
*
|
||||||
|
* @param {string} spec
|
||||||
|
* @returns {?{type: string, id: string}} null when the URL is not a share
|
||||||
|
* page (or no server is configured).
|
||||||
|
*/
|
||||||
|
parseShareUrl(spec) {
|
||||||
|
let uri;
|
||||||
|
let baseUri;
|
||||||
|
try {
|
||||||
|
uri = Services.io.newURI(spec);
|
||||||
|
baseUri = Services.io.newURI(this.#baseUrl);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (uri.prePath !== baseUri.prePath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const match = uri.filePath.match(SHARE_PATH_RE);
|
||||||
|
if (!match) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const slug = match[1];
|
||||||
|
const type = slug === "split" ? "split-view" : slug;
|
||||||
|
return { type, id: match[2].toUpperCase() };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches everything needed to preview and import a share: the validated
|
||||||
|
* document, plus the sharer's display name.
|
||||||
|
*
|
||||||
|
* @param {{id: string}} share - As returned by parseShareUrl.
|
||||||
|
* @returns {Promise<{doc: object, name: ?string}>}
|
||||||
|
*/
|
||||||
|
async fetchSharePreview(share) {
|
||||||
|
const meta = await this.getShare(share.id);
|
||||||
|
await this.#assertValidDocument(meta.data);
|
||||||
|
return { doc: meta.data, name: meta.name || null };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches a share with its metadata (authed):
|
||||||
|
* { id, name, createdAt, expiresAt, size, data }.
|
||||||
|
*
|
||||||
|
* @param {string} id
|
||||||
|
*/
|
||||||
|
async getShare(id) {
|
||||||
|
const response = await this.#request(`${this.#baseUrl}/api/shares/${id}`, {
|
||||||
|
headers: this.#authHeaders(),
|
||||||
|
});
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ZenShareClient = new nsZenShareClient();
|
||||||
822
src/zen/share/ZenShareManager.mjs
Normal file
822
src/zen/share/ZenShareManager.mjs
Normal file
@@ -0,0 +1,822 @@
|
|||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
import { nsZenDOMOperatedFeature } from "chrome://browser/content/zen-components/ZenCommonUtils.mjs";
|
||||||
|
import { nsZenThemePicker } from "resource:///modules/zen/ZenGradientGenerator.mjs";
|
||||||
|
|
||||||
|
const lazy = {};
|
||||||
|
|
||||||
|
ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
|
TabStateCache:
|
||||||
|
"moz-src:///browser/components/sessionstore/TabStateCache.sys.mjs",
|
||||||
|
ZenShareClient: "resource:///modules/zen/share/ZenShareClient.sys.mjs",
|
||||||
|
ZenShareError: "resource:///modules/zen/share/ZenShareClient.sys.mjs",
|
||||||
|
});
|
||||||
|
|
||||||
|
const SHARE_DOCUMENT_VERSION = "1";
|
||||||
|
|
||||||
|
const SHAREABLE_ICON_RE = /^(data:|chrome:)/;
|
||||||
|
const FOLDER_ICON_RE = /^chrome:\/\//;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shares spaces, folders and split views through the share server, and
|
||||||
|
* imports them back from share links.
|
||||||
|
*/
|
||||||
|
class nsZenShareManager extends nsZenDOMOperatedFeature {
|
||||||
|
init() {
|
||||||
|
if (!this.enabled) {
|
||||||
|
for (const id of [
|
||||||
|
"context_zenShareWorkspace",
|
||||||
|
"context_zenShareFolder",
|
||||||
|
]) {
|
||||||
|
document.getElementById(id)?.setAttribute("hidden", "true");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delayedStartupPromise.then(() => {
|
||||||
|
gBrowser.addTabsProgressListener({
|
||||||
|
onLocationChange: (browser, webProgress, request, aLocation) => {
|
||||||
|
this.#onLocationChange(browser, webProgress, aLocation);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get enabled() {
|
||||||
|
return !gZenWorkspaces.privateWindowOrDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark: sharing
|
||||||
|
|
||||||
|
async shareSpace(workspaceId) {
|
||||||
|
const workspace = gZenWorkspaces.getWorkspaceFromId(workspaceId);
|
||||||
|
const element = gZenWorkspaces.workspaceElement(workspaceId);
|
||||||
|
if (!workspace || !element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const item = {
|
||||||
|
type: "space",
|
||||||
|
name: workspace.name || "Space",
|
||||||
|
items: [
|
||||||
|
...this.#serializeItems(element.pinnedTabsContainer.children, {
|
||||||
|
pinned: true,
|
||||||
|
}),
|
||||||
|
...this.#serializeItems(element.tabsContainer.children, {
|
||||||
|
pinned: false,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const theme = this.#serializeTheme(workspace.theme);
|
||||||
|
if (theme) {
|
||||||
|
item.theme = theme;
|
||||||
|
}
|
||||||
|
await this.#createAndCopyLink(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
async shareFolder(folder) {
|
||||||
|
if (!folder?.isZenFolder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.#createAndCopyLink(this.#serializeFolder(folder));
|
||||||
|
}
|
||||||
|
|
||||||
|
async shareSplitView(group) {
|
||||||
|
if (!group?.hasAttribute("split-view-group")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const item = this.#serializeSplitGroup(group);
|
||||||
|
if (!item) {
|
||||||
|
this.#showCreateError(
|
||||||
|
new lazy.ZenShareError("empty", "nothing to share")
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.#createAndCopyLink(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
#serializeSplitGroup(group) {
|
||||||
|
const tabs = group.tabs
|
||||||
|
.filter(tab => !tab.hasAttribute("zen-empty-tab"))
|
||||||
|
.map(tab => this.#serializeTab(tab, { pinned: tab.pinned }))
|
||||||
|
.filter(Boolean);
|
||||||
|
return tabs.length >= 2
|
||||||
|
? { type: "splitView", tabs: tabs.slice(0, gZenViewSplitter.MAX_TABS) }
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #createAndCopyLink(item) {
|
||||||
|
if (!this.enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(await this.#confirmShare())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const created = await lazy.ZenShareClient.createShare(
|
||||||
|
{ version: SHARE_DOCUMENT_VERSION, shared: item },
|
||||||
|
{ name: this.#displayName() }
|
||||||
|
);
|
||||||
|
Cc["@mozilla.org/widget/clipboardhelper;1"]
|
||||||
|
.getService(Ci.nsIClipboardHelper)
|
||||||
|
.copyString(created.link);
|
||||||
|
// The description's l10n args come from the whole options object.
|
||||||
|
gZenUIManager.showToast("zen-share-link-copied-toast", {
|
||||||
|
descriptionId: created.expiresAt
|
||||||
|
? "zen-share-link-expires-description"
|
||||||
|
: "zen-share-link-permanent-description",
|
||||||
|
date: created.expiresAt
|
||||||
|
? new Date(created.expiresAt).toLocaleDateString()
|
||||||
|
: "",
|
||||||
|
timeout: 6000,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this.#showCreateError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#displayName() {
|
||||||
|
return (
|
||||||
|
Services.prefs.getStringPref("zen.share.display-name", "") || undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #confirmShare() {
|
||||||
|
if (
|
||||||
|
Services.prefs.getBoolPref("zen.share.dont-ask-before-sharing", false)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const args = {
|
||||||
|
accepted: false,
|
||||||
|
name: Services.prefs.getStringPref("zen.share.display-name", ""),
|
||||||
|
};
|
||||||
|
await gDialogBox.open(
|
||||||
|
"chrome://browser/content/zen-components/windows/zen-share-confirm.xhtml",
|
||||||
|
args
|
||||||
|
);
|
||||||
|
if (args.accepted) {
|
||||||
|
Services.prefs.setStringPref("zen.share.display-name", args.name);
|
||||||
|
if (args.dontAsk) {
|
||||||
|
Services.prefs.setBoolPref("zen.share.dont-ask-before-sharing", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args.accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
#showCreateError(error) {
|
||||||
|
console.error("ZenShare: could not create share:", error);
|
||||||
|
const descriptions = {
|
||||||
|
auth: "zen-share-error-auth-description",
|
||||||
|
"too-large": "zen-share-error-too-large-description",
|
||||||
|
"rate-limited": "zen-share-error-rate-limited-description",
|
||||||
|
network: "zen-share-error-network-description",
|
||||||
|
empty: "zen-share-error-empty-description",
|
||||||
|
};
|
||||||
|
gZenUIManager.showToast("zen-share-error-toast", {
|
||||||
|
descriptionId:
|
||||||
|
descriptions[error.code] || "zen-share-error-server-description",
|
||||||
|
timeout: 6000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark: serialization
|
||||||
|
|
||||||
|
#serializeItems(children, { pinned }) {
|
||||||
|
const items = [];
|
||||||
|
for (const child of children) {
|
||||||
|
if (gBrowser.isTab(child)) {
|
||||||
|
if (
|
||||||
|
child.hasAttribute("zen-empty-tab") ||
|
||||||
|
child.hasAttribute("zen-glance-tab")
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const tab = this.#serializeTab(child, { pinned });
|
||||||
|
if (tab) {
|
||||||
|
items.push(tab);
|
||||||
|
}
|
||||||
|
} else if (child.isZenFolder) {
|
||||||
|
items.push(this.#serializeFolder(child));
|
||||||
|
} else if (gBrowser.isTabGroup(child)) {
|
||||||
|
const split = child.hasAttribute("split-view-group")
|
||||||
|
? this.#serializeSplitGroup(child)
|
||||||
|
: null;
|
||||||
|
if (split) {
|
||||||
|
items.push(split);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Plain tab groups (and degenerate splits) keep their member tabs.
|
||||||
|
for (const tab of child.tabs) {
|
||||||
|
if (tab.hasAttribute("zen-empty-tab")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const serialized = this.#serializeTab(tab, { pinned });
|
||||||
|
if (serialized) {
|
||||||
|
items.push(serialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
#serializeFolder(folder) {
|
||||||
|
const item = {
|
||||||
|
type: "folder",
|
||||||
|
name: folder.label || "Folder",
|
||||||
|
items: this.#serializeItems(folder.allItems, { pinned: false }),
|
||||||
|
};
|
||||||
|
const icon = folder.iconURL;
|
||||||
|
if (icon) {
|
||||||
|
item.icon = icon;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#serializeTab(tab, { pinned = false } = {}) {
|
||||||
|
const url = tab.linkedBrowser?.currentURI?.spec;
|
||||||
|
if (!url || !/^https?:\/\//.test(url)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const item = { type: "tab", url };
|
||||||
|
const label = tab.label;
|
||||||
|
if (label) {
|
||||||
|
item.label = label;
|
||||||
|
}
|
||||||
|
const image = this.#serializeIcon(tab);
|
||||||
|
if (image) {
|
||||||
|
item.image = image;
|
||||||
|
}
|
||||||
|
if (pinned) {
|
||||||
|
item.isPinned = true;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#serializeIcon(tab) {
|
||||||
|
let icon = tab.getAttribute("image") || "";
|
||||||
|
if (icon.startsWith("moz-remote-image:")) {
|
||||||
|
try {
|
||||||
|
icon =
|
||||||
|
new URLSearchParams(Services.io.newURI(icon).query).get("url") || "";
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SHAREABLE_ICON_RE.test(icon) ? icon : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
#serializeTheme(theme) {
|
||||||
|
if (theme?.type !== "gradient" || !Array.isArray(theme.gradientColors)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const gradientColors = theme.gradientColors
|
||||||
|
.map(color => this.#serializeGradientColor(color))
|
||||||
|
.filter(Boolean);
|
||||||
|
if (!gradientColors.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return { type: "gradient", gradientColors };
|
||||||
|
}
|
||||||
|
|
||||||
|
#serializeGradientColor(color) {
|
||||||
|
let c = color?.c;
|
||||||
|
if (typeof c === "string") {
|
||||||
|
c = this.#parseCssColor(c);
|
||||||
|
} else if (Array.isArray(c)) {
|
||||||
|
c = c.slice(0, 3).map(Number);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!Array.isArray(c) ||
|
||||||
|
c.length !== 3 ||
|
||||||
|
c.some(n => !Number.isFinite(n))
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const out = { c, type: typeof color.type === "string" ? color.type : "" };
|
||||||
|
if (typeof color.isCustom === "boolean") {
|
||||||
|
out.isCustom = color.isCustom;
|
||||||
|
}
|
||||||
|
if (typeof color.isPrimary === "boolean") {
|
||||||
|
out.isPrimary = color.isPrimary;
|
||||||
|
}
|
||||||
|
if (typeof color.algorithm === "string") {
|
||||||
|
out.algorithm = color.algorithm;
|
||||||
|
}
|
||||||
|
if (color.lightness !== undefined && color.lightness !== null) {
|
||||||
|
out.lightness = String(color.lightness);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
Number.isFinite(color.position?.x) &&
|
||||||
|
Number.isFinite(color.position?.y)
|
||||||
|
) {
|
||||||
|
out.position = { x: color.position.x, y: color.position.y };
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#parseCssColor(value) {
|
||||||
|
const hex = value.trim().match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i)?.[1];
|
||||||
|
if (hex) {
|
||||||
|
const full =
|
||||||
|
hex.length === 3 ? [...hex].map(ch => ch + ch).join("") : hex;
|
||||||
|
return [0, 2, 4].map(i => parseInt(full.slice(i, i + 2), 16));
|
||||||
|
}
|
||||||
|
const numbers = value
|
||||||
|
.match(/\d+(\.\d+)?/g)
|
||||||
|
?.slice(0, 3)
|
||||||
|
.map(Number);
|
||||||
|
return numbers?.length === 3 ? numbers : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark: importing
|
||||||
|
|
||||||
|
#stylesLoaded = false;
|
||||||
|
|
||||||
|
// The overlay styles are only needed once a share link is opened.
|
||||||
|
#ensureStyles() {
|
||||||
|
if (this.#stylesLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#stylesLoaded = true;
|
||||||
|
window.windowUtils.loadSheetUsingURIString(
|
||||||
|
"chrome://browser/content/zen-styles/zen-share.css",
|
||||||
|
window.windowUtils.AUTHOR_SHEET
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#setHostTabSubtitle(browser, subtitle) {
|
||||||
|
const tab = gBrowser.getTabForBrowser(browser);
|
||||||
|
if (!tab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tab.setAttribute("zen-show-sublabel", subtitle);
|
||||||
|
document.l10n.setArgs(tab.querySelector(".zen-tab-sublabel"), {
|
||||||
|
tabSubtitle: subtitle,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#clearHostTabSubtitle(browser) {
|
||||||
|
const tab = gBrowser.getTabForBrowser(browser);
|
||||||
|
if (!tab?.hasAttribute("zen-show-sublabel")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tab.removeAttribute("zen-show-sublabel");
|
||||||
|
document.l10n.setArgs(tab.querySelector(".zen-tab-sublabel"), {
|
||||||
|
tabSubtitle: "zen-default-pinned",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#onLocationChange(browser, webProgress, aLocation) {
|
||||||
|
if (!webProgress.isTopLevel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (browser._zenShareOverlay) {
|
||||||
|
browser._zenShareOverlay.remove();
|
||||||
|
delete browser._zenShareOverlay;
|
||||||
|
browser.removeAttribute("zen-share-overlay-showing");
|
||||||
|
this.#clearHostTabSubtitle(browser);
|
||||||
|
}
|
||||||
|
const share = lazy.ZenShareClient.parseShareUrl(aLocation.spec);
|
||||||
|
if (!share) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (share.type === "split-view") {
|
||||||
|
// Split views are light enough to open right away, no preview step.
|
||||||
|
this.#openSharedSplitView(browser, share);
|
||||||
|
} else {
|
||||||
|
this.#showImportOverlay(browser, share);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #openSharedSplitView(browser, share) {
|
||||||
|
let item;
|
||||||
|
const shareTab = gBrowser.getTabForBrowser(browser);
|
||||||
|
shareTab.style.display = "none";
|
||||||
|
const failure = () => {
|
||||||
|
shareTab.style.removeProperty("display");
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const { doc } = await lazy.ZenShareClient.fetchSharePreview(share);
|
||||||
|
item = doc.shared?.type === "splitView" ? doc.shared : null;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("ZenShare: could not load shared split view:", e);
|
||||||
|
const descriptions = {
|
||||||
|
"not-found": "zen-share-import-error-dead-description",
|
||||||
|
"invalid-document": "zen-share-import-error-invalid-description",
|
||||||
|
};
|
||||||
|
gZenUIManager.showToast("zen-share-import-error-toast", {
|
||||||
|
descriptionId:
|
||||||
|
descriptions[e.code] || "zen-share-error-network-description",
|
||||||
|
timeout: 6000,
|
||||||
|
});
|
||||||
|
failure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!item) {
|
||||||
|
failure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const workspaceId = gZenWorkspaces.activeWorkspace;
|
||||||
|
const pinned = item.tabs.every(child => child.isPinned);
|
||||||
|
const tabs = item.tabs.map(child => {
|
||||||
|
// Eager browsers so every pane renders as soon as the split shows.
|
||||||
|
const tab = this.#importTab(child, workspaceId, { lazyBrowser: false });
|
||||||
|
if (pinned) {
|
||||||
|
gBrowser.pinTab(tab);
|
||||||
|
}
|
||||||
|
this.#placeTab(tab, workspaceId, pinned);
|
||||||
|
return tab;
|
||||||
|
});
|
||||||
|
gZenViewSplitter.splitTabs(tabs, "grid", 0);
|
||||||
|
gBrowser.removeTab(shareTab, {
|
||||||
|
closeWindowWithLastTab: false,
|
||||||
|
skipSessionStore: true,
|
||||||
|
});
|
||||||
|
// Shake the new split group in the sidebar.
|
||||||
|
const group = tabs[0]?.group;
|
||||||
|
if (group?.hasAttribute("split-view-group")) {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
gZenUIManager.motion
|
||||||
|
.animate(
|
||||||
|
group,
|
||||||
|
{ x: [-32, 0] },
|
||||||
|
{ type: "spring", bounce: 0.5, duration: 1.5 }
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
group.style.removeProperty("transform");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #showImportOverlay(browser, share) {
|
||||||
|
const stack = browser.closest(".browserStack");
|
||||||
|
if (!stack) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#ensureStyles();
|
||||||
|
// Only the status text shows until the preview loads.
|
||||||
|
const overlay = window.MozXULElement.parseXULToFragment(`
|
||||||
|
<html:div class="zen-share-overlay">
|
||||||
|
<html:div class="zen-share-overlay-card">
|
||||||
|
<html:div class="zen-share-overlay-items"/>
|
||||||
|
<html:div class="zen-share-overlay-status"
|
||||||
|
data-l10n-id="zen-share-overlay-loading"/>
|
||||||
|
<html:div class="zen-share-overlay-footer" hidden="hidden">
|
||||||
|
<html:div class="zen-share-overlay-badge-stack">
|
||||||
|
<html:div class="zen-share-overlay-badge-sheet second"/>
|
||||||
|
<html:div class="zen-share-overlay-badge-sheet first"/>
|
||||||
|
<html:div class="zen-share-overlay-badge">
|
||||||
|
<html:img class="zen-share-overlay-badge-icon"
|
||||||
|
draggable="false"/>
|
||||||
|
<html:div class="zen-share-overlay-badge-text">
|
||||||
|
<html:div class="zen-share-overlay-badge-title"/>
|
||||||
|
<html:div class="zen-share-overlay-badge-subtitle"/>
|
||||||
|
</html:div>
|
||||||
|
</html:div>
|
||||||
|
</html:div>
|
||||||
|
</html:div>
|
||||||
|
</html:div>
|
||||||
|
<html:button class="zen-big-accent-button primary zen-share-overlay-add"
|
||||||
|
hidden="hidden" disabled="disabled"/>
|
||||||
|
</html:div>
|
||||||
|
`).firstElementChild;
|
||||||
|
const items = overlay.querySelector(".zen-share-overlay-items");
|
||||||
|
const statusEl = overlay.querySelector(".zen-share-overlay-status");
|
||||||
|
const footer = overlay.querySelector(".zen-share-overlay-footer");
|
||||||
|
const badgeIcon = overlay.querySelector(".zen-share-overlay-badge-icon");
|
||||||
|
const badgeTitle = overlay.querySelector(".zen-share-overlay-badge-title");
|
||||||
|
const badgeSubtitle = overlay.querySelector(
|
||||||
|
".zen-share-overlay-badge-subtitle"
|
||||||
|
);
|
||||||
|
const button = overlay.querySelector(".zen-share-overlay-add");
|
||||||
|
|
||||||
|
stack.appendChild(overlay);
|
||||||
|
browser._zenShareOverlay = overlay;
|
||||||
|
browser.setAttribute("zen-share-overlay-showing", "true");
|
||||||
|
|
||||||
|
let preview;
|
||||||
|
try {
|
||||||
|
preview = await lazy.ZenShareClient.fetchSharePreview(share);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("ZenShare: could not load share preview:", e);
|
||||||
|
const descriptions = {
|
||||||
|
"not-found": "zen-share-import-error-dead-description",
|
||||||
|
"invalid-document": "zen-share-import-error-invalid-description",
|
||||||
|
};
|
||||||
|
document.l10n.setAttributes(
|
||||||
|
statusEl,
|
||||||
|
descriptions[e.code] || "zen-share-error-network-description"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (browser._zenShareOverlay !== overlay) {
|
||||||
|
// Navigated away while loading.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { doc, name: sharerName } = preview;
|
||||||
|
const first = doc.shared;
|
||||||
|
const type = first.type;
|
||||||
|
|
||||||
|
badgeTitle.textContent = first.name;
|
||||||
|
this.#renderPreviewRows(items, first.items);
|
||||||
|
if (type === "folder") {
|
||||||
|
// The real zen folder icon, with the shared custom icon when set.
|
||||||
|
const folderIcon = this.#buildFolderIcon(first.icon);
|
||||||
|
folderIcon.classList.add("zen-share-overlay-badge-icon");
|
||||||
|
folderIcon.setAttribute("state", "open");
|
||||||
|
badgeIcon.replaceWith(folderIcon);
|
||||||
|
} else {
|
||||||
|
badgeIcon.src = "chrome://browser/skin/zen-icons/duplicate-tab.svg";
|
||||||
|
}
|
||||||
|
if (sharerName) {
|
||||||
|
document.l10n.setAttributes(
|
||||||
|
badgeSubtitle,
|
||||||
|
`zen-share-overlay-from-${type}`,
|
||||||
|
{ name: sharerName }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
document.l10n.setAttributes(
|
||||||
|
badgeSubtitle,
|
||||||
|
"zen-share-overlay-shared-with-you"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Mirror the badge subtitle under the tab's label, like live folders do.
|
||||||
|
const [tabSubtitle] = await document.l10n.formatValues([
|
||||||
|
sharerName
|
||||||
|
? { id: `zen-share-overlay-from-${type}`, args: { name: sharerName } }
|
||||||
|
: { id: "zen-share-overlay-shared-with-you" },
|
||||||
|
]);
|
||||||
|
this.#setHostTabSubtitle(browser, tabSubtitle);
|
||||||
|
statusEl.remove();
|
||||||
|
footer.hidden = false;
|
||||||
|
document.l10n.setAttributes(button, `zen-share-overlay-add-${type}`);
|
||||||
|
button.hidden = false;
|
||||||
|
button.disabled = false;
|
||||||
|
button.addEventListener("click", async () => {
|
||||||
|
button.disabled = true;
|
||||||
|
try {
|
||||||
|
await this.#importDocument(doc);
|
||||||
|
gZenUIManager.showToast("zen-share-imported-toast");
|
||||||
|
const tab = gBrowser.getTabForBrowser(browser);
|
||||||
|
if (tab) {
|
||||||
|
gBrowser.removeTab(tab, {
|
||||||
|
closeWindowWithLastTab: false,
|
||||||
|
skipSessionStore: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("ZenShare: could not import share:", e);
|
||||||
|
gZenUIManager.showToast("zen-share-import-error-toast", {
|
||||||
|
timeout: 6000,
|
||||||
|
});
|
||||||
|
button.disabled = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#renderPreviewRows(container, entries) {
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.type === "folder") {
|
||||||
|
container.appendChild(this.#buildFolderRow(entry));
|
||||||
|
} else if (entry.type === "splitView") {
|
||||||
|
const split = window.MozXULElement.parseXULToFragment(`
|
||||||
|
<html:div class="zen-share-overlay-split"/>
|
||||||
|
`).firstElementChild;
|
||||||
|
for (const tab of entry.tabs) {
|
||||||
|
split.appendChild(this.#buildTabRow(tab));
|
||||||
|
}
|
||||||
|
container.appendChild(split);
|
||||||
|
} else {
|
||||||
|
container.appendChild(this.#buildTabRow(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#buildTabRow(entry) {
|
||||||
|
const row = window.MozXULElement.parseXULToFragment(`
|
||||||
|
<html:div class="zen-share-overlay-row">
|
||||||
|
<html:img class="zen-share-overlay-row-icon" draggable="false"/>
|
||||||
|
<html:div class="zen-share-overlay-row-label"/>
|
||||||
|
</html:div>
|
||||||
|
`).firstElementChild;
|
||||||
|
row.title = entry.url;
|
||||||
|
row.querySelector(".zen-share-overlay-row-icon").src =
|
||||||
|
entry.image && SHAREABLE_ICON_RE.test(entry.image)
|
||||||
|
? entry.image
|
||||||
|
: `page-icon:${entry.url}`;
|
||||||
|
row.querySelector(".zen-share-overlay-row-label").textContent =
|
||||||
|
entry.label || entry.url;
|
||||||
|
row.addEventListener("click", () => {
|
||||||
|
const stackRect = row.closest(".browserStack").getBoundingClientRect();
|
||||||
|
const data = {
|
||||||
|
url: entry.url,
|
||||||
|
clientX: stackRect.width / 2,
|
||||||
|
clientY: stackRect.height / 2,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
triggeringPrincipal:
|
||||||
|
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||||
|
};
|
||||||
|
gZenGlanceManager.lastLinkClickData = data;
|
||||||
|
gZenGlanceManager.openGlance(data);
|
||||||
|
});
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buildFolderRow(entry) {
|
||||||
|
const wrapper = window.MozXULElement.parseXULToFragment(`
|
||||||
|
<html:div class="zen-share-overlay-folder" collapsed="true">
|
||||||
|
<html:div class="zen-share-overlay-row">
|
||||||
|
<html:div class="zen-share-overlay-row-label"/>
|
||||||
|
</html:div>
|
||||||
|
<html:div class="zen-share-overlay-children-clip">
|
||||||
|
<html:div class="zen-share-overlay-children"/>
|
||||||
|
</html:div>
|
||||||
|
</html:div>
|
||||||
|
`).firstElementChild;
|
||||||
|
const row = wrapper.querySelector(".zen-share-overlay-row");
|
||||||
|
const label = row.querySelector(".zen-share-overlay-row-label");
|
||||||
|
label.textContent = entry.name;
|
||||||
|
const icon = this.#buildFolderIcon(entry.icon);
|
||||||
|
row.insertBefore(icon, label);
|
||||||
|
this.#renderPreviewRows(
|
||||||
|
wrapper.querySelector(".zen-share-overlay-children"),
|
||||||
|
entry.items
|
||||||
|
);
|
||||||
|
row.addEventListener("click", () => {
|
||||||
|
const collapsed = wrapper.toggleAttribute("collapsed");
|
||||||
|
if (collapsed) {
|
||||||
|
icon.removeAttribute("state");
|
||||||
|
} else {
|
||||||
|
icon.setAttribute("state", "open");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buildFolderIcon(customIcon) {
|
||||||
|
const { nsZenFolder } = ChromeUtils.importESModule(
|
||||||
|
"chrome://browser/content/zen-components/ZenFolder.mjs",
|
||||||
|
{ global: "current" }
|
||||||
|
);
|
||||||
|
const svg = nsZenFolder.rawIcon.cloneNode(true);
|
||||||
|
svg.classList.add("zen-share-overlay-folder-icon");
|
||||||
|
if (customIcon && FOLDER_ICON_RE.test(customIcon)) {
|
||||||
|
svg.querySelector(".icon image").setAttribute("href", customIcon);
|
||||||
|
}
|
||||||
|
return svg;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #importDocument(doc) {
|
||||||
|
const item = doc.shared;
|
||||||
|
switch (item.type) {
|
||||||
|
case "space":
|
||||||
|
await this.#importSpace(item);
|
||||||
|
break;
|
||||||
|
case "folder":
|
||||||
|
this.#importFolder(item, gZenWorkspaces.activeWorkspace);
|
||||||
|
break;
|
||||||
|
case "splitView":
|
||||||
|
this.#importSplitView(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async #importSpace(item) {
|
||||||
|
const workspace = await gZenWorkspaces.createAndSaveWorkspace(
|
||||||
|
item.name,
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
beforeChangeCallback: async newWorkspace => {
|
||||||
|
for (const child of item.items) {
|
||||||
|
if (child.type === "tab") {
|
||||||
|
const tab = this.#importTab(child, newWorkspace.uuid);
|
||||||
|
if (child.isPinned) {
|
||||||
|
gBrowser.pinTab(tab);
|
||||||
|
}
|
||||||
|
this.#placeTab(tab, newWorkspace.uuid, !!child.isPinned);
|
||||||
|
} else if (child.type === "folder") {
|
||||||
|
this.#importFolder(child, newWorkspace.uuid);
|
||||||
|
} else if (child.type === "splitView") {
|
||||||
|
this.#importSplitView(child, newWorkspace.uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!workspace) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
workspace.name = item.name;
|
||||||
|
const theme = item.theme;
|
||||||
|
if (theme) {
|
||||||
|
workspace.theme = nsZenThemePicker.getTheme(
|
||||||
|
theme.gradientColors.map(color => this.#importGradientColor(color))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
gZenWorkspaces.saveWorkspace(workspace);
|
||||||
|
gZenThemePicker.onWorkspaceChange(workspace);
|
||||||
|
gZenStartup.playWindowSweepAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
#importGradientColor(color) {
|
||||||
|
if (color.isCustom) {
|
||||||
|
const [r, g, b] = color.c;
|
||||||
|
return { ...color, c: `rgb(${r}, ${g}, ${b})` };
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#importFolder(item, workspaceId, parentFolder = null) {
|
||||||
|
const folder = gZenFolders.createFolder([], {
|
||||||
|
label: item.name,
|
||||||
|
collapsed: true,
|
||||||
|
workspaceId,
|
||||||
|
insertAfter: parentFolder
|
||||||
|
? parentFolder.groupContainer.lastElementChild
|
||||||
|
: null,
|
||||||
|
});
|
||||||
|
if (item.icon && FOLDER_ICON_RE.test(item.icon)) {
|
||||||
|
gZenFolders.setFolderUserIcon(folder, item.icon);
|
||||||
|
}
|
||||||
|
for (const child of item.items) {
|
||||||
|
if (child.type === "tab") {
|
||||||
|
const tab = this.#importTab(child, workspaceId);
|
||||||
|
gBrowser.pinTab(tab);
|
||||||
|
folder.addTabs([tab]);
|
||||||
|
} else if (child.type === "folder") {
|
||||||
|
this.#importFolder(child, workspaceId, folder);
|
||||||
|
} else if (child.type === "splitView") {
|
||||||
|
this.#importSplitView(child, workspaceId, folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
#importSplitView(item, workspaceId, folder = null) {
|
||||||
|
workspaceId ??= gZenWorkspaces.activeWorkspace;
|
||||||
|
const pinned = item.tabs.every(child => child.isPinned);
|
||||||
|
const tabs = item.tabs.map(child => {
|
||||||
|
const tab = this.#importTab(child, workspaceId);
|
||||||
|
if (folder) {
|
||||||
|
gBrowser.pinTab(tab);
|
||||||
|
folder.addTabs([tab]);
|
||||||
|
} else {
|
||||||
|
if (pinned) {
|
||||||
|
gBrowser.pinTab(tab);
|
||||||
|
}
|
||||||
|
this.#placeTab(tab, workspaceId, pinned);
|
||||||
|
}
|
||||||
|
return tab;
|
||||||
|
});
|
||||||
|
gZenViewSplitter.splitTabs(tabs, "grid", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deterministic placement at the end of the right section;
|
||||||
|
// moveTabToWorkspace's anchor follows the new-tab-button position pref.
|
||||||
|
#placeTab(tab, workspaceId, pinned) {
|
||||||
|
const element = gZenWorkspaces.workspaceElement(workspaceId);
|
||||||
|
const container = pinned
|
||||||
|
? element.pinnedTabsContainer
|
||||||
|
: element.tabsContainer;
|
||||||
|
const anchor = pinned
|
||||||
|
? container.querySelector(".pinned-tabs-container-separator")
|
||||||
|
: container.querySelector("#tabbrowser-arrowscrollbox-periphery");
|
||||||
|
gBrowser.zenHandleTabMove(tab, () => {
|
||||||
|
tab.setAttribute("zen-workspace-id", workspaceId);
|
||||||
|
container.insertBefore(tab, anchor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#importTab(item, workspaceId, { lazyBrowser = true } = {}) {
|
||||||
|
const tab = gBrowser.addTrustedTab(item.url, {
|
||||||
|
createLazyBrowser: lazyBrowser,
|
||||||
|
inBackground: true,
|
||||||
|
skipAnimation: true,
|
||||||
|
skipBackgroundNotify: true,
|
||||||
|
lazyTabTitle: item.label || undefined,
|
||||||
|
skipRoute: true,
|
||||||
|
});
|
||||||
|
if (workspaceId) {
|
||||||
|
tab.setAttribute("zen-workspace-id", workspaceId);
|
||||||
|
}
|
||||||
|
if (item.image && SHAREABLE_ICON_RE.test(item.image)) {
|
||||||
|
try {
|
||||||
|
gBrowser.setIcon(tab, item.image);
|
||||||
|
lazy.TabStateCache.update(tab.linkedBrowser.permanentKey, {
|
||||||
|
image: null,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("ZenShare: could not set imported tab icon:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.gZenShareManager = new nsZenShareManager();
|
||||||
7
src/zen/share/jar.inc.mn
Normal file
7
src/zen/share/jar.inc.mn
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
* content/browser/zen-styles/zen-share.css (../../zen/share/zen-share.css)
|
||||||
|
* content/browser/zen-components/windows/zen-share-confirm.xhtml (../../zen/share/zen-share-confirm.inc.xhtml)
|
||||||
|
content/browser/zen-components/windows/zen-share-confirm.js (../../zen/share/zen-share-confirm.js)
|
||||||
@@ -4,4 +4,6 @@
|
|||||||
|
|
||||||
EXTRA_JS_MODULES.zen.share += [
|
EXTRA_JS_MODULES.zen.share += [
|
||||||
"share.schema.json",
|
"share.schema.json",
|
||||||
|
"ZenShareClient.sys.mjs",
|
||||||
|
"ZenShareManager.mjs",
|
||||||
]
|
]
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user