mirror of
https://github.com/zen-browser/desktop.git
synced 2026-06-13 23:13:41 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4313bc8aa4 | ||
|
|
3773e66e3c | ||
|
|
8b0aab15b5 | ||
|
|
6bc560c876 | ||
|
|
7bf236fcf4 | ||
|
|
4797717353 | ||
|
|
88b294364f | ||
|
|
d5cbe55d2b | ||
|
|
7c885218f7 | ||
|
|
ccefb76168 | ||
|
|
bd3adba05e | ||
|
|
acc5837c13 | ||
|
|
6bde408c79 | ||
|
|
11a977e533 | ||
|
|
7844e04df2 | ||
|
|
5db8780f5d | ||
|
|
965bb9391d | ||
|
|
e7e4c5a452 | ||
|
|
880d61df16 | ||
|
|
b1be664f4d | ||
|
|
5383737b23 | ||
|
|
b812bff07e | ||
|
|
e04e910a6f | ||
|
|
bf365f8043 | ||
|
|
0a45b82a6c | ||
|
|
2311e183f1 | ||
|
|
8ea65cba48 | ||
|
|
45075e2fbc | ||
|
|
64e2e49a00 | ||
|
|
feca914821 | ||
|
|
c7818fe355 | ||
|
|
2c59265249 | ||
|
|
193d004a37 | ||
|
|
072d874f78 | ||
|
|
7aa0ca05ec | ||
|
|
d76fa13edd |
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
brew install watchman
|
||||
|
||||
cargo install apple-codesign
|
||||
cargo install apple-codesign --locked --force
|
||||
|
||||
- name: Force usage of gnu-tar
|
||||
run: |
|
||||
|
||||
2
.github/workflows/sync-upstream.yml
vendored
2
.github/workflows/sync-upstream.yml
vendored
@@ -129,7 +129,7 @@ jobs:
|
||||
token: ${{ secrets.DEPLOY_KEY }}
|
||||
commit-message: "chore: Sync upstream to `Firefox ${{ steps.build-data.outputs.version }}`"
|
||||
branch: "chore/upstream-sync"
|
||||
title: "no-bug: Sync upstream Firefox to version ${{ steps.build-data.outputs.version }}"
|
||||
title: "no-bug: Sync upstream Firefox to version `${{ steps.build-data.outputs.version }}`"
|
||||
body: |
|
||||
This PR syncs the upstream Firefox to version ${{ steps.build-data.outputs.version }}.
|
||||
|
||||
|
||||
2
.github/workflows/windows-release-build.yml
vendored
2
.github/workflows/windows-release-build.yml
vendored
@@ -154,7 +154,7 @@ jobs:
|
||||
zlib1g-dev \
|
||||
aria2
|
||||
echo Setup wine
|
||||
aria2c "https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/gecko.cache.level-1.toolchains.v3.linux64-wine.latest/artifacts/public%2Fbuild%2Fwine.tar.zst" -o wine.tar.zst
|
||||
aria2c "https://firefox-ci-tc.services.mozilla.com/api/queue/v1/task/dQz_aHy8Rl-Lt0xf2WlrMw/artifacts/public/build/wine.tar.zst" -o wine.tar.zst
|
||||
tar --zstd -xf wine.tar.zst -C ~/win-cross
|
||||
rm wine.tar.zst
|
||||
echo Setup Visual Studio
|
||||
|
||||
@@ -34,8 +34,8 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
|
||||
|
||||
### Firefox Versions
|
||||
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `151.0.2`! 🚀
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 151.0.2`!
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `151.0.4`! 🚀
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 151.0.4`!
|
||||
|
||||
### Contributing
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
05272df13c2e4f435b4e0a706715f302b09ef829
|
||||
9a6aa4c359d1fb6ac60decc82402f82d49a17cea
|
||||
@@ -16,9 +16,9 @@ if test "$ZEN_CROSS_COMPILING"; then
|
||||
CROSS_COMPILE=1
|
||||
|
||||
if test "$SURFER_COMPAT" = "aarch64"; then
|
||||
export WIN32_REDIST_DIR="$(echo ~)/win-cross/vs2026/VC/Redist/MSVC/14.50.35710/arm64/Microsoft.VC145.CRT"
|
||||
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.50.35710/arm64/Microsoft.VC145.CRT"
|
||||
else
|
||||
export WIN32_REDIST_DIR="$(echo ~)/win-cross/vs2026/VC/Redist/MSVC/14.50.35710/x64/Microsoft.VC145.CRT"
|
||||
export WIN32_REDIST_DIR="$WINSYSROOT/VC/Redist/MSVC/14.50.35710/x64/Microsoft.VC145.CRT"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -22,3 +22,5 @@ files:
|
||||
translation: browser/browser/zen-folders.ftl
|
||||
- source: en-US/browser/browser/zen-boosts.ftl
|
||||
translation: browser/browser/zen-boosts.ftl
|
||||
- source: en-US/browser/browser/zen-space-routing.ftl
|
||||
translation: browser/browser/zen-space-routing.ftl
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Trieu el selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Obre l'inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brillantor
|
||||
zen-bootst-color-original-saturation = Saturació original
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brillantor
|
||||
zen-boost-color-original-saturation = Saturació original
|
||||
zen-add-zap-helper = Feu clic als elements de la pàgina per <b>amagar-los</b>
|
||||
zen-remove-zap-helper = ← Feu clic per mostrar
|
||||
zen-select-this = Insereix un selector per a això
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Selektor auswählen
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Inspektor öffnen
|
||||
zen-bootst-color-contrast = Kontrast
|
||||
zen-bootst-color-brightness = Helligkeit
|
||||
zen-bootst-color-original-saturation = Ausgangssättigung
|
||||
zen-boost-color-contrast = Kontrast
|
||||
zen-boost-color-brightness = Helligkeit
|
||||
zen-boost-color-original-saturation = Ausgangssättigung
|
||||
zen-add-zap-helper = Klicke auf Elemente auf der Seite, um sie mit <b>Zap</b> zu markieren
|
||||
zen-remove-zap-helper = ← Erneut klicken zum Wiederherstellen
|
||||
zen-select-this = Selektor für dieses Element einfügen
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
25
locales/en-US/browser/browser/zen-space-routing.ftl
Normal file
25
locales/en-US/browser/browser/zen-space-routing.ftl
Normal file
@@ -0,0 +1,25 @@
|
||||
# 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-space-routing-settings =
|
||||
.label = Space Routing Settings
|
||||
zen-space-routing-rulepanel-placeholder = Routes let you choose where specific sites open inside Zen. For example, you can route YouTube links to always open inside your Personal space.
|
||||
zen-space-routing-dialog-title = Space Routing Settings
|
||||
zen-space-routing-external-default = Default route for external links
|
||||
zen-space-routing-new-route = New Route
|
||||
zen-space-routing-open-in-space = Open in Space
|
||||
zen-space-routing-most-recent-space = Most recent Space
|
||||
zen-space-routing-close-button =
|
||||
.aria-label = Close
|
||||
.tooltiptext = Close
|
||||
|
||||
zen-space-routing-contains =
|
||||
.label = Contains
|
||||
zen-space-routing-equal-to =
|
||||
.label = Is Equal To
|
||||
zen-space-routing-regex =
|
||||
.label = RegEx
|
||||
|
||||
zen-space-routing-open-in = Open In
|
||||
zen-space-routing-url = URL
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Escoger selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Abrir inspector
|
||||
zen-bootst-color-contrast = Contraste
|
||||
zen-bootst-color-brightness = Brillo
|
||||
zen-bootst-color-original-saturation = Saturación original
|
||||
zen-boost-color-contrast = Contraste
|
||||
zen-boost-color-brightness = Brillo
|
||||
zen-boost-color-original-saturation = Saturación original
|
||||
zen-add-zap-helper = Haga clic en los elementos de la página para <b>borrarlos</b>
|
||||
zen-remove-zap-helper = ← Clic para deshacer
|
||||
zen-select-this = Insertar selector para esto
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Choisir le sélecteur
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Ouvrir l'inspecteur
|
||||
zen-bootst-color-contrast = Contraste
|
||||
zen-bootst-color-brightness = Luminosité
|
||||
zen-bootst-color-original-saturation = Saturation originale
|
||||
zen-boost-color-contrast = Contraste
|
||||
zen-boost-color-brightness = Luminosité
|
||||
zen-boost-color-original-saturation = Saturation originale
|
||||
zen-add-zap-helper = Cliquez sur des éléments de la page pour les <b>zapper</b>
|
||||
zen-remove-zap-helper = ← Cliquez pour démasquer
|
||||
zen-select-this = Insérer un sélecteur pour ceci
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Roghnóir Roghnaigh
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Oscail an Cigire
|
||||
zen-bootst-color-contrast = Codarsnacht
|
||||
zen-bootst-color-brightness = Gile
|
||||
zen-bootst-color-original-saturation = Sáithiú Bunaidh
|
||||
zen-boost-color-contrast = Codarsnacht
|
||||
zen-boost-color-brightness = Gile
|
||||
zen-boost-color-original-saturation = Sáithiú Bunaidh
|
||||
zen-add-zap-helper = Cliceáil ar eilimintí ar an leathanach chun iad a <b>Zapáil</b>
|
||||
zen-remove-zap-helper = ← Cliceáil chun Dízipáil
|
||||
zen-select-this = Cuir roghnóir isteach don seo
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = ניגודיות
|
||||
zen-bootst-color-brightness = בהירות
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = ניגודיות
|
||||
zen-boost-color-brightness = בהירות
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Vizsgáló megnyitása
|
||||
zen-bootst-color-contrast = Kontraszt
|
||||
zen-bootst-color-brightness = Fényerő
|
||||
zen-bootst-color-original-saturation = Eredeti szaturáció
|
||||
zen-boost-color-contrast = Kontraszt
|
||||
zen-boost-color-brightness = Fényerő
|
||||
zen-boost-color-original-saturation = Eredeti szaturáció
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Veljari
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Opna rýni
|
||||
zen-bootst-color-contrast = Birtuskil
|
||||
zen-bootst-color-brightness = Birtustig
|
||||
zen-bootst-color-original-saturation = Upprunaleg litmettun
|
||||
zen-boost-color-contrast = Birtuskil
|
||||
zen-boost-color-brightness = Birtustig
|
||||
zen-boost-color-original-saturation = Upprunaleg litmettun
|
||||
zen-add-zap-helper = Smelltu á atriði á síðunni til að <b>einangra</b> þau (zap)
|
||||
zen-remove-zap-helper = ← Smelltu til að taka úr einangrun
|
||||
zen-select-this = Setja inn veljara fyrir þetta
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = セレクターを選択
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = インスペクタを開く
|
||||
zen-bootst-color-contrast = コントラスト
|
||||
zen-bootst-color-brightness = 明るさ
|
||||
zen-bootst-color-original-saturation = 元の彩度
|
||||
zen-boost-color-contrast = コントラスト
|
||||
zen-boost-color-brightness = 明るさ
|
||||
zen-boost-color-original-saturation = 元の彩度
|
||||
zen-add-zap-helper = <b>Zap</b> にページ上の要素をクリックします
|
||||
zen-remove-zap-helper = ←クリックして解除
|
||||
zen-select-this = このセレクターを挿入
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = 선택자 선택
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = 검사기 열기
|
||||
zen-bootst-color-contrast = 대비
|
||||
zen-bootst-color-brightness = 밝기
|
||||
zen-bootst-color-original-saturation = 원본 채도
|
||||
zen-boost-color-contrast = 대비
|
||||
zen-boost-color-brightness = 밝기
|
||||
zen-boost-color-original-saturation = 원본 채도
|
||||
zen-add-zap-helper = 페이지 내의 요소를 클릭해서 <b>날려</b>버리세요
|
||||
zen-remove-zap-helper = ← 클릭하여 되살리기
|
||||
zen-select-this = 이 요소의 선택자 삽입
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Kontrastas
|
||||
zen-bootst-color-brightness = Šviesumas
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Kontrastas
|
||||
zen-boost-color-brightness = Šviesumas
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Velgselektor
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Åpne inspektør
|
||||
zen-bootst-color-contrast = Kontrast
|
||||
zen-bootst-color-brightness = Lysstyrke
|
||||
zen-bootst-color-original-saturation = Opprinnelig fargemetning
|
||||
zen-boost-color-contrast = Kontrast
|
||||
zen-boost-color-brightness = Lysstyrke
|
||||
zen-boost-color-original-saturation = Opprinnelig fargemetning
|
||||
zen-add-zap-helper = Klikk elementer på siden for å <b>Zappe</b> dem
|
||||
zen-remove-zap-helper = ← Klikk for å avzappe
|
||||
zen-select-this = Sett inn slektor for dette
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Wybierz selektor
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Otwórz Inspektor
|
||||
zen-bootst-color-contrast = Kontrast
|
||||
zen-bootst-color-brightness = Jasność
|
||||
zen-bootst-color-original-saturation = Oryginalne nasycenie
|
||||
zen-boost-color-contrast = Kontrast
|
||||
zen-boost-color-brightness = Jasność
|
||||
zen-boost-color-original-saturation = Oryginalne nasycenie
|
||||
zen-add-zap-helper = Kliknij elementy na stronie, aby je <b>ukryć</b>
|
||||
zen-remove-zap-helper = ← Kliknij, aby cofnąć ukrycie
|
||||
zen-select-this = Wstaw selektor dla tego elementu
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Ferramenta de Seleção
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Abrir Inspetor
|
||||
zen-bootst-color-contrast = Contraste
|
||||
zen-bootst-color-brightness = Brilho
|
||||
zen-bootst-color-original-saturation = Saturação Original
|
||||
zen-boost-color-contrast = Contraste
|
||||
zen-boost-color-brightness = Brilho
|
||||
zen-boost-color-original-saturation = Saturação Original
|
||||
zen-add-zap-helper = Clique em elementos da página para dar um <b>Zap</b> neles
|
||||
zen-remove-zap-helper = Clique para Deszapar
|
||||
zen-select-this = Inserir seletor para isto
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Välj väljare
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Öppna inspektör
|
||||
zen-bootst-color-contrast = Kontrast
|
||||
zen-bootst-color-brightness = Ljusstyrka
|
||||
zen-bootst-color-original-saturation = Ursprunglig mättnad
|
||||
zen-boost-color-contrast = Kontrast
|
||||
zen-boost-color-brightness = Ljusstyrka
|
||||
zen-boost-color-original-saturation = Ursprunglig mättnad
|
||||
zen-add-zap-helper = Klicka på element på sidan för att <b>zappa</b> dem
|
||||
zen-remove-zap-helper = ← Klicka för att avzappa
|
||||
zen-select-this = Infoga väljare för detta
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Pick Selector
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Open Inspector
|
||||
zen-bootst-color-contrast = Contrast
|
||||
zen-bootst-color-brightness = Brightness
|
||||
zen-bootst-color-original-saturation = Original Saturation
|
||||
zen-boost-color-contrast = Contrast
|
||||
zen-boost-color-brightness = Brightness
|
||||
zen-boost-color-original-saturation = Original Saturation
|
||||
zen-add-zap-helper = Click elements on the page to <b>Zap</b> them
|
||||
zen-remove-zap-helper = ← Click to Unzap
|
||||
zen-select-this = Insert selector for this
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Seçici seç
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Denetleyiciyi aç
|
||||
zen-bootst-color-contrast = Kontrast
|
||||
zen-bootst-color-brightness = Parlaklık
|
||||
zen-bootst-color-original-saturation = Orijinal doygunluk
|
||||
zen-boost-color-contrast = Kontrast
|
||||
zen-boost-color-brightness = Parlaklık
|
||||
zen-boost-color-original-saturation = Orijinal doygunluk
|
||||
zen-add-zap-helper = Sayfadaki ögelere tıklayarak onları <b>Zap</b> ile kaldırın
|
||||
zen-remove-zap-helper = ← Unzap için tıklayın
|
||||
zen-select-this = Bu öge için seçici ekle
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Вибір селектора
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Відкрити інспектора
|
||||
zen-bootst-color-contrast = Контраст
|
||||
zen-bootst-color-brightness = Яскравість
|
||||
zen-bootst-color-original-saturation = Оригінальна насиченість
|
||||
zen-boost-color-contrast = Контраст
|
||||
zen-boost-color-brightness = Яскравість
|
||||
zen-boost-color-original-saturation = Оригінальна насиченість
|
||||
zen-add-zap-helper = Клацніть на елементи на сторінці, щоби <b>сховати</b> їх
|
||||
zen-remove-zap-helper = ← Клацніть, аби знову показати
|
||||
zen-select-this = Вставити селектор для цього
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = Chọn phần tử
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = Mở trình kiểm tra
|
||||
zen-bootst-color-contrast = Độ tương phản
|
||||
zen-bootst-color-brightness = Độ sáng
|
||||
zen-bootst-color-original-saturation = Độ bão hòa gốc
|
||||
zen-boost-color-contrast = Độ tương phản
|
||||
zen-boost-color-brightness = Độ sáng
|
||||
zen-boost-color-original-saturation = Độ bão hòa gốc
|
||||
zen-add-zap-helper = Nhấp vào các phần tử trên trang để <b>Khử</b> chúng
|
||||
zen-remove-zap-helper = ← Nhấp để khôi phục
|
||||
zen-select-this = Nhập bộ chọn cho phần tử này
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = 选取选择器
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = 打开查看器
|
||||
zen-bootst-color-contrast = 对比度
|
||||
zen-bootst-color-brightness = 亮度
|
||||
zen-bootst-color-original-saturation = 初始饱和度
|
||||
zen-boost-color-contrast = 对比度
|
||||
zen-boost-color-brightness = 亮度
|
||||
zen-boost-color-original-saturation = 初始饱和度
|
||||
zen-add-zap-helper = 点击页面上的元素以将其<b>屏蔽</b>
|
||||
zen-remove-zap-helper = ← 点击以取消屏蔽
|
||||
zen-select-this = 插入此元素的选择器
|
||||
|
||||
@@ -29,9 +29,9 @@ zen-boost-css-picker =
|
||||
.tooltiptext = 汲取選擇器
|
||||
zen-boost-css-inspector =
|
||||
.tooltiptext = 開啟檢測器
|
||||
zen-bootst-color-contrast = 對比
|
||||
zen-bootst-color-brightness = 亮度
|
||||
zen-bootst-color-original-saturation = 飽和度
|
||||
zen-boost-color-contrast = 對比
|
||||
zen-boost-color-brightness = 亮度
|
||||
zen-boost-color-original-saturation = 飽和度
|
||||
zen-add-zap-helper = 選擇要 <b>Zap</b>的元素
|
||||
zen-remove-zap-helper = ← 按此取消zap
|
||||
zen-select-this = 加入此元素的選擇器
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"surfer": "surfer",
|
||||
"test": "python3 scripts/run_tests.py",
|
||||
"test:dbg": "python3 scripts/run_tests.py --jsdebugger --debug-on-failure",
|
||||
"test:gtest": "cd engine && ./mach gtest",
|
||||
"test:gtest": "cd engine && ./mach gtest Zen*",
|
||||
"ffprefs": "cd tools/ffprefs && cargo run --bin ffprefs -- ../../",
|
||||
"lc": "surfer license-check",
|
||||
"lc:fix": "surfer license-check --fix",
|
||||
|
||||
@@ -94,3 +94,8 @@
|
||||
# See gh-12985 for details on the following preferences
|
||||
- name: browser.search.widget.new
|
||||
value: true
|
||||
|
||||
# Disabled from https://searchfox.org/firefox-main/rev/d6bfff43852356ca98af848b4705d37f8d41856f/modules/libpref/init/StaticPrefList.yaml#2008
|
||||
# Only enabled for windows, doesn't really fit inside Zen.
|
||||
- name: browser.startup.preXulSkeletonUI
|
||||
value: false
|
||||
|
||||
@@ -20,3 +20,4 @@
|
||||
#include ../../../zen/fonts/jar.inc.mn
|
||||
#include ../../../zen/boosts/jar.inc.mn
|
||||
#include ../../../zen/live-folders/jar.inc.mn
|
||||
#include ../../../zen/space-routing/jar.inc.mn
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<command id="cmd_zenCtxDeleteWorkspace" />
|
||||
<command id="cmd_zenUnloadWorkspace" />
|
||||
<command id="cmd_zenUnloadAllOtherWorkspace" />
|
||||
<command id="cmd_zenOpenSpaceRoutingSettings" />
|
||||
<command id="cmd_zenChangeWorkspaceName" />
|
||||
<command id="cmd_zenChangeWorkspaceIcon" />
|
||||
<command id="cmd_zenReorderWorkspaces" />
|
||||
|
||||
@@ -11,4 +11,5 @@
|
||||
<link rel="localization" href="browser/zen-folders.ftl"/>
|
||||
<link rel="localization" href="browser/zen-boosts.ftl"/>
|
||||
<link rel="localization" href="browser/zen-live-folders.ftl"/>
|
||||
<link rel="localization" href="browser/zen-space-routing.ftl"/>
|
||||
</linkset>
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
<menuseparator/>
|
||||
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation"/>
|
||||
<menuitem id="context_zenDeleteWorkspace" data-l10n-id="zen-workspaces-panel-context-delete" command="cmd_zenCtxDeleteWorkspace"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="context_zenSpaceRoutingSettings" data-l10n-id="zen-space-routing-settings" command="cmd_zenOpenSpaceRoutingSettings"/>
|
||||
</menupopup>
|
||||
|
||||
<menupopup id="zenFolderActions">
|
||||
|
||||
@@ -825,6 +825,7 @@ var zenIgnoreKeyboardShortcutIDs = [
|
||||
"key_enterFullScreen_compat",
|
||||
"key_exitFullScreen_old",
|
||||
"key_exitFullScreen_compat",
|
||||
"key_duplicateTab",
|
||||
];
|
||||
|
||||
var zenIgnoreKeyboardShortcutL10n = [
|
||||
@@ -944,6 +945,7 @@ var gZenCKSSettings = {
|
||||
});
|
||||
|
||||
input.addEventListener("blur", (event) => {
|
||||
this._currentActionID = null;
|
||||
const target = event.target;
|
||||
target.classList.remove(`${ZEN_CKS_INPUT_FIELD_CLASS}-editing`);
|
||||
if (!this._hasSafed) {
|
||||
@@ -1048,6 +1050,7 @@ var gZenCKSSettings = {
|
||||
input.classList.remove(`${ZEN_CKS_INPUT_FIELD_CLASS}-not-set`);
|
||||
input.classList.remove(`${ZEN_CKS_INPUT_FIELD_CLASS}-editing`);
|
||||
this._latestValidKey = null;
|
||||
this._currentActionID = null;
|
||||
return;
|
||||
} else if (shortcut == "Escape" && !modifiersActive) {
|
||||
const { hasConflicts, conflictShortcut } = gZenKeyboardShortcutsManager.checkForConflicts(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88f4eec282 100644
|
||||
index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008ede72076 100644
|
||||
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
||||
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
@@ -502,6 +502,7 @@
|
||||
@@ -79,7 +79,17 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
set selectedTab(val) {
|
||||
if (
|
||||
gSharedTabWarning.willShowSharedTabWarning(val) ||
|
||||
@@ -659,6 +711,10 @@
|
||||
@@ -592,6 +644,9 @@
|
||||
) {
|
||||
return;
|
||||
}
|
||||
+ if (gZenWorkspaces.onBeforeTabSelect(val)) {
|
||||
+ return;
|
||||
+ }
|
||||
// Update the tab
|
||||
this.tabbox.selectedTab = val;
|
||||
}
|
||||
@@ -659,6 +714,10 @@
|
||||
userContextId = parseInt(tabArgument.getAttribute("usercontextid"), 10);
|
||||
}
|
||||
|
||||
@@ -90,7 +100,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (tabArgument && tabArgument.linkedBrowser) {
|
||||
remoteType = tabArgument.linkedBrowser.remoteType;
|
||||
initialBrowsingContextGroupId =
|
||||
@@ -751,6 +807,8 @@
|
||||
@@ -751,6 +810,8 @@
|
||||
this.tabpanels.appendChild(panel);
|
||||
|
||||
let tab = this.tabs[0];
|
||||
@@ -99,7 +109,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
tab.linkedPanel = uniqueId;
|
||||
this._selectedTab = tab;
|
||||
this._selectedBrowser = browser;
|
||||
@@ -1121,13 +1179,18 @@
|
||||
@@ -1121,13 +1182,18 @@
|
||||
}
|
||||
|
||||
this.showTab(aTab);
|
||||
@@ -119,7 +129,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
aTab.setAttribute("pinned", "true");
|
||||
this._updateTabBarForPinnedTabs();
|
||||
@@ -1140,11 +1203,19 @@
|
||||
@@ -1140,11 +1206,19 @@
|
||||
}
|
||||
|
||||
this.#handleTabMove(aTab, () => {
|
||||
@@ -140,7 +150,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
});
|
||||
|
||||
aTab.style.marginInlineStart = "";
|
||||
@@ -1321,6 +1392,9 @@
|
||||
@@ -1321,6 +1395,9 @@
|
||||
|
||||
let LOCAL_PROTOCOLS = ["chrome:", "about:", "resource:", "data:"];
|
||||
|
||||
@@ -150,7 +160,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (
|
||||
aIconURL &&
|
||||
!LOCAL_PROTOCOLS.some(protocol => aIconURL.startsWith(protocol))
|
||||
@@ -1330,6 +1404,9 @@
|
||||
@@ -1330,6 +1407,9 @@
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -160,7 +170,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
let browser = this.getBrowserForTab(aTab);
|
||||
browser.mIconURL = aIconURL;
|
||||
@@ -1652,7 +1729,6 @@
|
||||
@@ -1652,7 +1732,6 @@
|
||||
|
||||
// Preview mode should not reset the owner
|
||||
if (!this._previewMode && !oldTab.selected) {
|
||||
@@ -168,7 +178,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
let lastRelatedTab = this._lastRelatedTabMap.get(oldTab);
|
||||
@@ -1743,6 +1819,7 @@
|
||||
@@ -1743,6 +1822,7 @@
|
||||
if (!this._previewMode) {
|
||||
newTab.recordTimeFromUnloadToReload();
|
||||
newTab.updateLastAccessed();
|
||||
@@ -176,7 +186,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
oldTab.updateLastAccessed();
|
||||
// if this is the foreground window, update the last-seen timestamps.
|
||||
if (this.ownerGlobal == BrowserWindowTracker.getTopWindow()) {
|
||||
@@ -1957,6 +2034,9 @@
|
||||
@@ -1957,6 +2037,9 @@
|
||||
}
|
||||
|
||||
let activeEl = document.activeElement;
|
||||
@@ -186,7 +196,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
// If focus is on the old tab, move it to the new tab.
|
||||
if (activeEl == oldTab) {
|
||||
newTab.focus();
|
||||
@@ -1995,7 +2075,7 @@
|
||||
@@ -1995,7 +2078,7 @@
|
||||
// Focus the location bar if it was previously focused for that tab.
|
||||
// In full screen mode, only bother making the location bar visible
|
||||
// if the tab is a blank one.
|
||||
@@ -195,7 +205,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
let selectURL = () => {
|
||||
if (this._asyncTabSwitching) {
|
||||
// Set _awaitingSetURI flag to suppress popup notification
|
||||
@@ -2283,7 +2363,12 @@
|
||||
@@ -2283,7 +2366,12 @@
|
||||
return this._setTabLabel(aTab, aLabel);
|
||||
}
|
||||
|
||||
@@ -209,7 +219,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (!aLabel || (isURL && /^about:reader\?url=/.test(aLabel))) {
|
||||
return false;
|
||||
}
|
||||
@@ -2408,7 +2493,7 @@
|
||||
@@ -2408,7 +2496,7 @@
|
||||
newIndex = this.selectedTab._tPos + 1;
|
||||
}
|
||||
|
||||
@@ -218,7 +228,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (this.isTabGroupLabel(targetTab)) {
|
||||
throw new Error(
|
||||
"Replacing a tab group label with a tab is not supported"
|
||||
@@ -2685,6 +2770,7 @@
|
||||
@@ -2685,6 +2773,7 @@
|
||||
uriIsAboutBlank,
|
||||
userContextId,
|
||||
skipLoad,
|
||||
@@ -226,7 +236,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} = {}) {
|
||||
let b = document.createXULElement("browser");
|
||||
// Use the JSM global to create the permanentKey, so that if the
|
||||
@@ -2758,8 +2844,7 @@
|
||||
@@ -2758,8 +2847,7 @@
|
||||
// we use a different attribute name for this?
|
||||
b.setAttribute("name", name);
|
||||
}
|
||||
@@ -236,7 +246,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
b.setAttribute("transparent", "true");
|
||||
}
|
||||
|
||||
@@ -2929,7 +3014,7 @@
|
||||
@@ -2929,7 +3017,7 @@
|
||||
|
||||
let panel = this.getPanel(browser);
|
||||
let uniqueId = this._generateUniquePanelID();
|
||||
@@ -245,7 +255,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
aTab.linkedPanel = uniqueId;
|
||||
|
||||
// Inject the <browser> into the DOM if necessary.
|
||||
@@ -2989,8 +3074,8 @@
|
||||
@@ -2989,8 +3077,8 @@
|
||||
// If we transitioned from one browser to two browsers, we need to set
|
||||
// hasSiblings=false on both the existing browser and the new browser.
|
||||
if (this.tabs.length == 2) {
|
||||
@@ -256,7 +266,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} else {
|
||||
aTab.linkedBrowser.browsingContext.hasSiblings = this.tabs.length > 1;
|
||||
}
|
||||
@@ -3175,7 +3260,6 @@
|
||||
@@ -3175,7 +3263,6 @@
|
||||
this.selectedTab = this.addTrustedTab(BROWSER_NEW_TAB_URL, {
|
||||
tabIndex: tab._tPos + 1,
|
||||
userContextId: tab.userContextId,
|
||||
@@ -264,24 +274,33 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
focusUrlBar: true,
|
||||
});
|
||||
resolve(this.selectedBrowser);
|
||||
@@ -3285,6 +3369,9 @@
|
||||
@@ -3285,6 +3372,10 @@
|
||||
schemelessInput,
|
||||
hasValidUserGestureActivation = false,
|
||||
textDirectiveUserActivation = false,
|
||||
+ _forZenEmptyTab,
|
||||
+ essential,
|
||||
+ zenWorkspaceId,
|
||||
+ skipRoute = false,
|
||||
} = {}
|
||||
) {
|
||||
// all callers of addTab that pass a params object need to pass
|
||||
@@ -3295,10 +3382,17 @@
|
||||
@@ -3295,10 +3386,25 @@
|
||||
);
|
||||
}
|
||||
|
||||
+ const beforeRouteResult = window.gZenSpaceRoutingManager.onBeforeAddTab(uriString, { skipRoute, pinned, tabGroup, fromExternal }, window);
|
||||
+ if (beforeRouteResult.shouldEarlyExit) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ let hasZenDefaultUserContextId = false;
|
||||
+ let zenForcedWorkspaceId = undefined;
|
||||
+ if (typeof gZenWorkspaces !== "undefined" && !_forZenEmptyTab) {
|
||||
+ [userContextId, hasZenDefaultUserContextId, zenForcedWorkspaceId] = gZenWorkspaces.getContextIdIfNeeded(userContextId, fromExternal);
|
||||
+ if (beforeRouteResult.isRouteFound) {
|
||||
+ userContextId = beforeRouteResult.userContextId;
|
||||
+ hasZenDefaultUserContextId = true;
|
||||
+ } else if (typeof gZenWorkspaces !== "undefined" && !_forZenEmptyTab) {
|
||||
+ [userContextId, hasZenDefaultUserContextId, zenForcedWorkspaceId] = gZenWorkspaces.getContextIdIfNeeded(userContextId, fromExternal, triggeringPrincipal);
|
||||
+ }
|
||||
+
|
||||
if (!UserInteraction.running("browser.tabs.opening", window)) {
|
||||
@@ -292,7 +311,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
// If we're opening a foreground tab, set the owner by default.
|
||||
ownerTab ??= inBackground ? null : this.selectedTab;
|
||||
|
||||
@@ -3306,6 +3400,7 @@
|
||||
@@ -3306,6 +3412,7 @@
|
||||
if (this.selectedTab.owner) {
|
||||
this.selectedTab.owner = null;
|
||||
}
|
||||
@@ -300,7 +319,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
// Find the tab that opened this one, if any. This is used for
|
||||
// determining positioning, and inherited attributes such as the
|
||||
@@ -3358,6 +3453,22 @@
|
||||
@@ -3358,6 +3465,22 @@
|
||||
noInitialLabel,
|
||||
skipBackgroundNotify,
|
||||
});
|
||||
@@ -323,7 +342,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (insertTab) {
|
||||
// Insert the tab into the tab container in the correct position.
|
||||
this.#insertTabAtIndex(t, {
|
||||
@@ -3366,6 +3477,7 @@
|
||||
@@ -3366,6 +3489,7 @@
|
||||
ownerTab,
|
||||
openerTab,
|
||||
pinned,
|
||||
@@ -331,7 +350,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
bulkOrderedOpen,
|
||||
tabGroup: tabGroup ?? openerTab?.group,
|
||||
});
|
||||
@@ -3384,6 +3496,7 @@
|
||||
@@ -3384,6 +3508,7 @@
|
||||
openWindowInfo,
|
||||
skipLoad,
|
||||
triggeringRemoteType,
|
||||
@@ -339,7 +358,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}));
|
||||
|
||||
if (focusUrlBar) {
|
||||
@@ -3508,6 +3621,12 @@
|
||||
@@ -3508,6 +3633,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,7 +371,17 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
// Additionally send pinned tab events
|
||||
if (pinned) {
|
||||
this.#notifyPinnedStatus(t);
|
||||
@@ -3750,6 +3869,7 @@
|
||||
@@ -3518,6 +3649,9 @@
|
||||
if (!inBackground) {
|
||||
this.selectedTab = t;
|
||||
}
|
||||
+
|
||||
+ window.gZenSpaceRoutingManager.onAfterAddTab(uriString, t, { skipRoute: skipRoute || _forZenEmptyTab, fromExternal, pinned, tabGroup }, window, beforeRouteResult);
|
||||
+
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -3750,6 +3884,7 @@
|
||||
isAdoptingGroup = false,
|
||||
isUserTriggered = false,
|
||||
telemetryUserCreateSource = "unknown",
|
||||
@@ -360,7 +389,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} = {}
|
||||
) {
|
||||
if (
|
||||
@@ -3760,9 +3880,6 @@
|
||||
@@ -3760,9 +3895,6 @@
|
||||
!this.isSplitViewWrapper(tabOrSplitView)
|
||||
)
|
||||
) {
|
||||
@@ -370,7 +399,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
if (!color) {
|
||||
@@ -3783,9 +3900,14 @@
|
||||
@@ -3783,9 +3915,14 @@
|
||||
label,
|
||||
isAdoptingGroup
|
||||
);
|
||||
@@ -387,7 +416,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
);
|
||||
group.addTabs(tabsAndSplitViews);
|
||||
|
||||
@@ -3906,7 +4028,7 @@
|
||||
@@ -3906,7 +4043,7 @@
|
||||
}
|
||||
|
||||
this.#handleTabMove(tab, () =>
|
||||
@@ -396,7 +425,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3990,6 +4112,7 @@
|
||||
@@ -3990,6 +4127,7 @@
|
||||
color: group.color,
|
||||
insertBefore: newTabs[0],
|
||||
isAdoptingGroup: true,
|
||||
@@ -404,7 +433,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4200,6 +4323,7 @@
|
||||
@@ -4200,6 +4338,7 @@
|
||||
openWindowInfo,
|
||||
skipLoad,
|
||||
triggeringRemoteType,
|
||||
@@ -412,7 +441,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
) {
|
||||
// If we don't have a preferred remote type (or it is `NOT_REMOTE`), and
|
||||
@@ -4269,6 +4393,7 @@
|
||||
@@ -4269,6 +4408,7 @@
|
||||
openWindowInfo,
|
||||
name,
|
||||
skipLoad,
|
||||
@@ -420,7 +449,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4482,9 +4607,9 @@
|
||||
@@ -4482,9 +4622,9 @@
|
||||
}
|
||||
|
||||
// Add a new tab if needed.
|
||||
@@ -432,7 +461,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
let url = "about:blank";
|
||||
if (tabData.entries?.length) {
|
||||
@@ -4521,8 +4646,10 @@
|
||||
@@ -4521,8 +4661,10 @@
|
||||
insertTab: false,
|
||||
skipLoad: true,
|
||||
preferredRemoteType,
|
||||
@@ -444,7 +473,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (select) {
|
||||
tabToSelect = tab;
|
||||
}
|
||||
@@ -4544,7 +4671,8 @@
|
||||
@@ -4544,7 +4686,8 @@
|
||||
this.pinTab(tab);
|
||||
// Then ensure all the tab open/pinning information is sent.
|
||||
this._fireTabOpen(tab, {});
|
||||
@@ -454,7 +483,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
let { groupId } = tabData;
|
||||
const tabGroup = tabGroupWorkingData.get(groupId);
|
||||
// if a tab refers to a tab group we don't know, skip any group
|
||||
@@ -4564,7 +4692,10 @@
|
||||
@@ -4564,7 +4707,10 @@
|
||||
tabGroup.stateData.id,
|
||||
tabGroup.stateData.color,
|
||||
tabGroup.stateData.collapsed,
|
||||
@@ -466,7 +495,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
);
|
||||
tabsFragment.appendChild(tabGroup.node);
|
||||
}
|
||||
@@ -4619,9 +4750,21 @@
|
||||
@@ -4619,9 +4765,21 @@
|
||||
// to remove the old selected tab.
|
||||
if (tabToSelect) {
|
||||
let leftoverTab = this.selectedTab;
|
||||
@@ -488,7 +517,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
if (tabs.length > 1 || !tabs[0].selected) {
|
||||
this._updateTabsAfterInsert();
|
||||
@@ -4812,11 +4955,14 @@
|
||||
@@ -4812,11 +4970,14 @@
|
||||
if (ownerTab) {
|
||||
tab.owner = ownerTab;
|
||||
}
|
||||
@@ -504,7 +533,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (
|
||||
!bulkOrderedOpen &&
|
||||
((openerTab &&
|
||||
@@ -4828,7 +4974,7 @@
|
||||
@@ -4828,7 +4989,7 @@
|
||||
let lastRelatedTab =
|
||||
openerTab && this._lastRelatedTabMap.get(openerTab);
|
||||
let previousTab = lastRelatedTab || openerTab || this.selectedTab;
|
||||
@@ -513,7 +542,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
tabGroup = previousTab.group;
|
||||
}
|
||||
if (
|
||||
@@ -4844,7 +4990,7 @@
|
||||
@@ -4844,7 +5005,7 @@
|
||||
previousTab.splitview
|
||||
) + 1;
|
||||
} else if (previousTab.visible) {
|
||||
@@ -522,7 +551,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} else if (previousTab == FirefoxViewHandler.tab) {
|
||||
elementIndex = 0;
|
||||
}
|
||||
@@ -4872,14 +5018,14 @@
|
||||
@@ -4872,14 +5033,14 @@
|
||||
}
|
||||
// Ensure index is within bounds.
|
||||
if (tab.pinned) {
|
||||
@@ -541,7 +570,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
if (pinned && !itemAfter?.pinned) {
|
||||
itemAfter = null;
|
||||
@@ -4896,7 +5042,7 @@
|
||||
@@ -4896,7 +5057,7 @@
|
||||
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
|
||||
@@ -550,7 +579,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (
|
||||
(this.isTab(itemAfter) && itemAfter.group == tabGroup) ||
|
||||
this.isSplitViewWrapper(itemAfter)
|
||||
@@ -4927,7 +5073,11 @@
|
||||
@@ -4927,7 +5088,11 @@
|
||||
const tabContainer = pinned
|
||||
? this.tabContainer.pinnedTabsContainer
|
||||
: this.tabContainer;
|
||||
@@ -562,7 +591,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
if (tab.group?.collapsed) {
|
||||
@@ -4942,6 +5092,7 @@
|
||||
@@ -4942,6 +5107,7 @@
|
||||
if (pinned) {
|
||||
this._updateTabBarForPinnedTabs();
|
||||
}
|
||||
@@ -570,7 +599,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
TabBarVisibility.update();
|
||||
}
|
||||
@@ -5490,6 +5641,7 @@
|
||||
@@ -5490,6 +5656,7 @@
|
||||
telemetrySource,
|
||||
} = {}
|
||||
) {
|
||||
@@ -578,7 +607,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
// When 'closeWindowWithLastTab' pref is enabled, closing all tabs
|
||||
// can be considered equivalent to closing the window.
|
||||
if (
|
||||
@@ -5579,6 +5731,7 @@
|
||||
@@ -5579,6 +5746,7 @@
|
||||
if (lastToClose) {
|
||||
this.removeTab(lastToClose, aParams);
|
||||
}
|
||||
@@ -586,7 +615,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -5624,6 +5777,14 @@
|
||||
@@ -5624,6 +5792,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -601,7 +630,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
let isVisibleTab = aTab.visible;
|
||||
// We have to sample the tab width now, since _beginRemoveTab might
|
||||
// end up modifying the DOM in such a way that aTab gets a new
|
||||
@@ -5631,6 +5792,9 @@
|
||||
@@ -5631,6 +5807,9 @@
|
||||
// state).
|
||||
let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width;
|
||||
let isLastTab = this.#isLastTabInWindow(aTab);
|
||||
@@ -611,7 +640,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (
|
||||
!this._beginRemoveTab(aTab, {
|
||||
closeWindowFastpath: true,
|
||||
@@ -5642,13 +5806,14 @@
|
||||
@@ -5642,13 +5821,14 @@
|
||||
telemetrySource,
|
||||
})
|
||||
) {
|
||||
@@ -627,7 +656,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
let lockTabSizing =
|
||||
!this.tabContainer.verticalMode &&
|
||||
!aTab.pinned &&
|
||||
@@ -5679,7 +5844,13 @@
|
||||
@@ -5679,7 +5859,13 @@
|
||||
// We're not animating, so we can cancel the animation stopwatch.
|
||||
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
|
||||
aTab._closeTimeAnimTimerId = null;
|
||||
@@ -642,7 +671,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5813,7 +5984,7 @@
|
||||
@@ -5813,7 +5999,7 @@
|
||||
closeWindowWithLastTab != null
|
||||
? closeWindowWithLastTab
|
||||
: !window.toolbar.visible ||
|
||||
@@ -651,7 +680,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
if (closeWindow) {
|
||||
// We've already called beforeunload on all the relevant tabs if we get here,
|
||||
@@ -5837,6 +6008,7 @@
|
||||
@@ -5837,6 +6023,7 @@
|
||||
|
||||
newTab = true;
|
||||
}
|
||||
@@ -659,7 +688,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
aTab._endRemoveArgs = [closeWindow, newTab];
|
||||
|
||||
// swapBrowsersAndCloseOther will take care of closing the window without animation.
|
||||
@@ -5877,13 +6049,7 @@
|
||||
@@ -5877,13 +6064,7 @@
|
||||
aTab._mouseleave();
|
||||
|
||||
if (newTab) {
|
||||
@@ -674,7 +703,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} else {
|
||||
TabBarVisibility.update();
|
||||
}
|
||||
@@ -6016,6 +6182,7 @@
|
||||
@@ -6016,6 +6197,7 @@
|
||||
this.tabs[i]._tPos = i;
|
||||
}
|
||||
|
||||
@@ -682,7 +711,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (!this._windowIsClosing) {
|
||||
// update tab close buttons state
|
||||
this.tabContainer._updateCloseButtons();
|
||||
@@ -6201,6 +6368,7 @@
|
||||
@@ -6201,6 +6383,7 @@
|
||||
memory_after: await getTotalMemoryUsage(),
|
||||
time_to_unload_in_ms: timeElapsed,
|
||||
});
|
||||
@@ -690,7 +719,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6246,6 +6414,7 @@
|
||||
@@ -6246,6 +6429,7 @@
|
||||
}
|
||||
|
||||
let excludeTabs = new Set(aExcludeTabs);
|
||||
@@ -698,7 +727,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
// If this tab has a successor, it should be selectable, since
|
||||
// hiding or closing a tab removes that tab as a successor.
|
||||
@@ -6258,15 +6427,22 @@
|
||||
@@ -6258,15 +6442,22 @@
|
||||
!excludeTabs.has(aTab.owner) &&
|
||||
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
|
||||
) {
|
||||
@@ -723,7 +752,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
let tab = this.tabContainer.findNextTab(aTab, {
|
||||
direction: 1,
|
||||
filter: _tab => remainingTabs.includes(_tab),
|
||||
@@ -6280,7 +6456,7 @@
|
||||
@@ -6280,7 +6471,7 @@
|
||||
}
|
||||
|
||||
if (tab) {
|
||||
@@ -732,7 +761,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
// If no qualifying visible tab was found, see if there is a tab in
|
||||
@@ -6301,7 +6477,7 @@
|
||||
@@ -6301,7 +6492,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
@@ -741,7 +770,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
_blurTab(aTab) {
|
||||
@@ -6312,7 +6488,7 @@
|
||||
@@ -6312,7 +6503,7 @@
|
||||
* @returns {boolean}
|
||||
* False if swapping isn't permitted, true otherwise.
|
||||
*/
|
||||
@@ -750,7 +779,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
// Do not allow transfering a private tab to a non-private window
|
||||
// and vice versa.
|
||||
if (
|
||||
@@ -6366,6 +6542,7 @@
|
||||
@@ -6366,6 +6557,7 @@
|
||||
// fire the beforeunload event in the process. Close the other
|
||||
// window if this was its last tab.
|
||||
if (
|
||||
@@ -758,7 +787,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
!remoteBrowser._beginRemoveTab(aOtherTab, {
|
||||
adoptedByTab: aOurTab,
|
||||
closeWindowWithLastTab: true,
|
||||
@@ -6377,7 +6554,7 @@
|
||||
@@ -6377,7 +6569,7 @@
|
||||
// If this is the last tab of the window, hide the window
|
||||
// immediately without animation before the docshell swap, to avoid
|
||||
// about:blank being painted.
|
||||
@@ -767,7 +796,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (closeWindow) {
|
||||
let win = aOtherTab.ownerGlobal;
|
||||
win.windowUtils.suppressAnimation(true);
|
||||
@@ -6511,11 +6688,13 @@
|
||||
@@ -6511,11 +6703,13 @@
|
||||
}
|
||||
|
||||
// Finish tearing down the tab that's going away.
|
||||
@@ -781,7 +810,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
this.setTabTitle(aOurTab);
|
||||
|
||||
@@ -6717,10 +6896,10 @@
|
||||
@@ -6717,10 +6911,10 @@
|
||||
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
|
||||
}
|
||||
|
||||
@@ -794,7 +823,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
aTab.selected ||
|
||||
aTab.closing ||
|
||||
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
|
||||
@@ -6780,7 +6959,8 @@
|
||||
@@ -6780,7 +6974,8 @@
|
||||
* @param {object} [aOptions={}]
|
||||
* Key-value pairs that will be serialized into the features string.
|
||||
*/
|
||||
@@ -804,7 +833,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
if (this.tabs.length == 1) {
|
||||
return null;
|
||||
}
|
||||
@@ -6797,7 +6977,7 @@
|
||||
@@ -6797,7 +6992,7 @@
|
||||
// tell a new window to take the "dropped" tab
|
||||
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
args.appendElement(aTab.splitview ?? aTab);
|
||||
@@ -813,7 +842,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
private: PrivateBrowsingUtils.isWindowPrivate(window),
|
||||
features: Object.entries(aOptions)
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
@@ -6805,6 +6985,8 @@
|
||||
@@ -6805,6 +7000,8 @@
|
||||
openerWindow: window,
|
||||
args,
|
||||
});
|
||||
@@ -822,7 +851,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6917,7 +7099,7 @@
|
||||
@@ -6917,7 +7114,7 @@
|
||||
* `true` if element is a `<tab-group>`
|
||||
*/
|
||||
isTabGroup(element) {
|
||||
@@ -831,7 +860,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7002,8 +7184,8 @@
|
||||
@@ -7002,8 +7199,8 @@
|
||||
}
|
||||
|
||||
// Don't allow mixing pinned and unpinned tabs.
|
||||
@@ -842,7 +871,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} else {
|
||||
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
|
||||
}
|
||||
@@ -7049,8 +7231,8 @@
|
||||
@@ -7049,8 +7246,8 @@
|
||||
this.#handleTabMove(
|
||||
element,
|
||||
() => {
|
||||
@@ -853,7 +882,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
neighbor = neighbor.group;
|
||||
}
|
||||
if (neighbor?.splitview) {
|
||||
@@ -7061,6 +7243,12 @@
|
||||
@@ -7061,6 +7258,12 @@
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -866,7 +895,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
if (movingForwards && neighbor) {
|
||||
neighbor.after(element);
|
||||
@@ -7119,23 +7307,31 @@
|
||||
@@ -7119,23 +7322,31 @@
|
||||
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
|
||||
if (this.isTabGroupLabel(targetElement)) {
|
||||
targetElement = targetElement.group;
|
||||
@@ -904,7 +933,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
} else if (!element.pinned && targetElement && targetElement.pinned) {
|
||||
// If the caller asks to move an unpinned element next to a pinned
|
||||
// tab, move the unpinned element to be the first unpinned element
|
||||
@@ -7148,12 +7344,35 @@
|
||||
@@ -7148,12 +7359,35 @@
|
||||
// move the tab group right before the first unpinned tab.
|
||||
// 4. Moving a tab group and the first unpinned tab is grouped:
|
||||
// move the tab group right before the first unpinned tab's tab group.
|
||||
@@ -941,7 +970,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
// We want to include the splitview wrapper if it's the targetElement, but
|
||||
// not in the case where we want to reverse tabs within the same splitview.
|
||||
@@ -7162,6 +7381,7 @@
|
||||
@@ -7162,6 +7396,7 @@
|
||||
}
|
||||
|
||||
let getContainer = () =>
|
||||
@@ -949,7 +978,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
element.pinned
|
||||
? this.tabContainer.pinnedTabsContainer
|
||||
: this.tabContainer;
|
||||
@@ -7170,11 +7390,15 @@
|
||||
@@ -7170,11 +7405,15 @@
|
||||
element,
|
||||
() => {
|
||||
if (moveBefore) {
|
||||
@@ -966,7 +995,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
},
|
||||
metricsContext
|
||||
@@ -7248,11 +7472,15 @@
|
||||
@@ -7248,11 +7487,15 @@
|
||||
* @param {TabMetricsContext} [metricsContext]
|
||||
*/
|
||||
moveTabToExistingGroup(aTab, aGroup, metricsContext) {
|
||||
@@ -985,7 +1014,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
if (aTab.group && aTab.group.id === aGroup.id) {
|
||||
return;
|
||||
@@ -7324,6 +7552,7 @@
|
||||
@@ -7324,6 +7567,7 @@
|
||||
|
||||
let state = {
|
||||
tabIndex: tab._tPos,
|
||||
@@ -993,7 +1022,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
};
|
||||
if (tab.visible) {
|
||||
state.elementIndex = tab.elementIndex;
|
||||
@@ -7355,7 +7584,7 @@
|
||||
@@ -7355,7 +7599,7 @@
|
||||
let changedSplitView =
|
||||
previousTabState.splitViewId != currentTabState.splitViewId;
|
||||
|
||||
@@ -1002,7 +1031,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
tab.dispatchEvent(
|
||||
new CustomEvent("TabMove", {
|
||||
bubbles: true,
|
||||
@@ -7402,6 +7631,10 @@
|
||||
@@ -7402,6 +7646,10 @@
|
||||
|
||||
moveActionCallback();
|
||||
|
||||
@@ -1013,7 +1042,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
// Clear tabs cache after moving nodes because the order of tabs may have
|
||||
// changed.
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
@@ -7452,7 +7685,22 @@
|
||||
@@ -7452,7 +7700,22 @@
|
||||
* @returns {object}
|
||||
* The new tab in the current window, null if the tab couldn't be adopted.
|
||||
*/
|
||||
@@ -1037,7 +1066,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
// Swap the dropped tab with a new one we create and then close
|
||||
// it in the other window (making it seem to have moved between
|
||||
// windows). We also ensure that the tab we create to swap into has
|
||||
@@ -7495,6 +7743,8 @@
|
||||
@@ -7495,6 +7758,8 @@
|
||||
}
|
||||
params.skipLoad = true;
|
||||
let newTab = this.addWebTab("about:blank", params);
|
||||
@@ -1046,7 +1075,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
aTab.container.tabDragAndDrop.finishAnimateTabMove();
|
||||
|
||||
@@ -8205,7 +8455,7 @@
|
||||
@@ -8205,7 +8470,7 @@
|
||||
// preventDefault(). It will still raise the window if appropriate.
|
||||
return;
|
||||
}
|
||||
@@ -1055,7 +1084,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
window.focus();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
@@ -8222,7 +8472,6 @@
|
||||
@@ -8222,7 +8487,6 @@
|
||||
|
||||
on_TabGroupCollapse(aEvent) {
|
||||
aEvent.target.tabs.forEach(tab => {
|
||||
@@ -1063,7 +1092,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8556,7 +8805,9 @@
|
||||
@@ -8556,7 +8820,9 @@
|
||||
|
||||
let filter = this._tabFilters.get(tab);
|
||||
if (filter) {
|
||||
@@ -1073,7 +1102,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
|
||||
let listener = this._tabListeners.get(tab);
|
||||
if (listener) {
|
||||
@@ -9359,6 +9610,7 @@
|
||||
@@ -9359,6 +9625,7 @@
|
||||
aWebProgress.isTopLevel
|
||||
) {
|
||||
this.mTab.setAttribute("busy", "true");
|
||||
@@ -1081,7 +1110,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
gBrowser._tabAttrModified(this.mTab, ["busy"]);
|
||||
this.mTab._notselectedsinceload = !this.mTab.selected;
|
||||
}
|
||||
@@ -9439,6 +9691,7 @@
|
||||
@@ -9439,6 +9706,7 @@
|
||||
// known defaults. Note we use the original URL since about:newtab
|
||||
// redirects to a prerendered page.
|
||||
const shouldRemoveFavicon =
|
||||
@@ -1089,7 +1118,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
!this.mBrowser.mIconURL &&
|
||||
!ignoreBlank &&
|
||||
!(originalLocation.spec in FAVICON_DEFAULTS);
|
||||
@@ -9613,13 +9866,6 @@
|
||||
@@ -9613,13 +9881,6 @@
|
||||
this.mBrowser.originalURI = aRequest.originalURI;
|
||||
}
|
||||
|
||||
@@ -1103,7 +1132,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..146b1559b8430773bd4ec173a8f4fe88
|
||||
}
|
||||
|
||||
let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
|
||||
@@ -10507,7 +10753,8 @@ var TabContextMenu = {
|
||||
@@ -10507,7 +10768,8 @@ var TabContextMenu = {
|
||||
);
|
||||
contextUnpinSelectedTabs.hidden =
|
||||
!this.contextTab.pinned || !this.multiselected;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e6463b45191 100644
|
||||
index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..c166b7de23c35716bf8c51b6b9c72f771f0a75a8 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
@@ -98,6 +98,13 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
@@ -132,15 +132,17 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
// Enable the animation only after the first extend call to ensure it
|
||||
// doesn't run when opening a new window.
|
||||
if (!this.hasAttribute("breakout-extend-animate")) {
|
||||
@@ -2891,6 +2966,27 @@ ${
|
||||
@@ -2891,6 +2966,29 @@ ${
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (this._zenHandleUrlbarClose) {
|
||||
+ this._zenHandleUrlbarClose();
|
||||
+ } else if (!this._untrimmedValue || this.searchMode) {
|
||||
+ } else if (!this._untrimmedValue || (this.#isAddressbar && (this.searchMode || this.window.gZenVerticalTabsManager._hasSetSingleToolbar))) {
|
||||
+ // Restore the current page URL when the urlbar is empty on blur
|
||||
+ this.handleRevert();
|
||||
+ this.window.requestAnimationFrame(() => {
|
||||
+ this.handleRevert();
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ // Arc like URLbar: Blur the input on exit
|
||||
@@ -160,7 +162,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
this.removeAttribute("breakout-extend");
|
||||
this.#updateTextboxPosition();
|
||||
}
|
||||
@@ -2921,7 +3017,7 @@ ${
|
||||
@@ -2921,7 +3019,7 @@ ${
|
||||
forceUnifiedSearchButtonAvailable = false
|
||||
) {
|
||||
let prevState = this.getAttribute("pageproxystate");
|
||||
@@ -169,7 +171,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
this.setAttribute("pageproxystate", state);
|
||||
this._inputContainer.setAttribute("pageproxystate", state);
|
||||
this._identityBox?.setAttribute("pageproxystate", state);
|
||||
@@ -3198,10 +3294,12 @@ ${
|
||||
@@ -3198,10 +3296,12 @@ ${
|
||||
return;
|
||||
}
|
||||
this.style.top = px(
|
||||
@@ -182,7 +184,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3260,9 +3358,10 @@ ${
|
||||
@@ -3260,9 +3360,10 @@ ${
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -194,7 +196,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
);
|
||||
this.style.setProperty(
|
||||
"--urlbar-height",
|
||||
@@ -3768,6 +3867,7 @@ ${
|
||||
@@ -3768,6 +3869,7 @@ ${
|
||||
}
|
||||
|
||||
_toggleActionOverride(event) {
|
||||
@@ -202,7 +204,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
if (
|
||||
event.keyCode == KeyEvent.DOM_VK_SHIFT ||
|
||||
event.keyCode == KeyEvent.DOM_VK_ALT ||
|
||||
@@ -3880,8 +3980,8 @@ ${
|
||||
@@ -3880,8 +3982,8 @@ ${
|
||||
if (!this.#isAddressbar) {
|
||||
return val;
|
||||
}
|
||||
@@ -213,7 +215,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
: val;
|
||||
// Only trim value if the directionality doesn't change to RTL and we're not
|
||||
// showing a strikeout https protocol.
|
||||
@@ -4180,6 +4280,7 @@ ${
|
||||
@@ -4180,6 +4282,7 @@ ${
|
||||
resultDetails = null,
|
||||
browser = this.window.gBrowser.selectedBrowser
|
||||
) {
|
||||
@@ -221,7 +223,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
if (this.#isAddressbar) {
|
||||
this.#prepareAddressbarLoad(
|
||||
url,
|
||||
@@ -4291,6 +4392,10 @@ ${
|
||||
@@ -4291,6 +4394,10 @@ ${
|
||||
}
|
||||
reuseEmpty = true;
|
||||
}
|
||||
@@ -232,7 +234,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
if (
|
||||
where == "tab" &&
|
||||
reuseEmpty &&
|
||||
@@ -4298,6 +4403,9 @@ ${
|
||||
@@ -4298,6 +4405,9 @@ ${
|
||||
) {
|
||||
where = "current";
|
||||
}
|
||||
@@ -242,7 +244,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
return where;
|
||||
}
|
||||
|
||||
@@ -4552,6 +4660,7 @@ ${
|
||||
@@ -4552,6 +4662,7 @@ ${
|
||||
this.setResultForCurrentValue(null);
|
||||
this.handleCommand();
|
||||
this.controller.clearLastQueryContextCache();
|
||||
@@ -250,7 +252,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
|
||||
this._suppressStartQuery = false;
|
||||
});
|
||||
@@ -4559,7 +4668,6 @@ ${
|
||||
@@ -4559,7 +4670,6 @@ ${
|
||||
contextMenu.addEventListener("popupshowing", () => {
|
||||
// Close the results pane when the input field contextual menu is open,
|
||||
// because paste and go doesn't want a result selection.
|
||||
@@ -258,7 +260,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
|
||||
let controller =
|
||||
this.document.commandDispatcher.getControllerForCommand("cmd_paste");
|
||||
@@ -4715,7 +4823,11 @@ ${
|
||||
@@ -4715,7 +4825,11 @@ ${
|
||||
if (!engineName && !source && !this.hasAttribute("searchmode")) {
|
||||
return;
|
||||
}
|
||||
@@ -271,7 +273,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
if (this._searchModeIndicatorTitle) {
|
||||
this._searchModeIndicatorTitle.textContent = "";
|
||||
this._searchModeIndicatorTitle.removeAttribute("data-l10n-id");
|
||||
@@ -5031,6 +5143,7 @@ ${
|
||||
@@ -5031,6 +5145,7 @@ ${
|
||||
|
||||
this.document.l10n.setAttributes(
|
||||
this.inputField,
|
||||
@@ -279,7 +281,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
l10nId,
|
||||
l10nId == "urlbar-placeholder-with-name"
|
||||
? { name: engineName }
|
||||
@@ -5156,6 +5269,11 @@ ${
|
||||
@@ -5156,6 +5271,11 @@ ${
|
||||
}
|
||||
|
||||
_on_click(event) {
|
||||
@@ -291,7 +293,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
switch (event.target) {
|
||||
case this.inputField:
|
||||
case this._inputContainer:
|
||||
@@ -5242,7 +5360,7 @@ ${
|
||||
@@ -5242,7 +5362,7 @@ ${
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +302,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
this.view.autoOpen({ event });
|
||||
} else {
|
||||
if (this._untrimOnFocusAfterKeydown) {
|
||||
@@ -5282,9 +5400,16 @@ ${
|
||||
@@ -5282,9 +5402,16 @@ ${
|
||||
}
|
||||
|
||||
_on_mousedown(event) {
|
||||
@@ -318,7 +320,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
if (
|
||||
event.composedTarget != this.inputField &&
|
||||
event.composedTarget != this._inputContainer
|
||||
@@ -5294,6 +5419,10 @@ ${
|
||||
@@ -5294,6 +5421,10 @@ ${
|
||||
|
||||
this.focusedViaMousedown = !this.focused;
|
||||
this.#preventClickSelectsAll = this.focused;
|
||||
@@ -329,7 +331,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
|
||||
// Keep the focus status, since the attribute may be changed
|
||||
// upon calling this.focus().
|
||||
@@ -5329,7 +5458,7 @@ ${
|
||||
@@ -5329,7 +5460,7 @@ ${
|
||||
}
|
||||
// Don't close the view when clicking on a tab; we may want to keep the
|
||||
// view open on tab switch, and the TabSelect event arrived earlier.
|
||||
@@ -338,7 +340,7 @@ index d6615ec5a29f3e3327ac4171f3fc5d9a69bd09fe..e1128b0d7f5accfd48af27f99e3b2e64
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5636,7 +5765,7 @@ ${
|
||||
@@ -5636,7 +5767,7 @@ ${
|
||||
// When we are in actions search mode we can show more results so
|
||||
// increase the limit.
|
||||
let maxResults =
|
||||
|
||||
@@ -51,7 +51,8 @@
|
||||
}
|
||||
|
||||
#PanelUI-zen-gradient-generator-color-remove,
|
||||
#zen-gradient-generator-color-remove {
|
||||
#zen-gradient-generator-color-remove,
|
||||
.sr-remove {
|
||||
list-style-image: url("unpin.svg") !important;
|
||||
}
|
||||
|
||||
@@ -134,6 +135,10 @@
|
||||
list-style-image: url("arrow-right.svg");
|
||||
}
|
||||
|
||||
.sr-open-in-icon {
|
||||
list-style-image: url("arrow-corner-down-right.svg");
|
||||
}
|
||||
|
||||
#PanelUI-menu-button,
|
||||
#appMenu-more-button2,
|
||||
.zen-workspaces-actions,
|
||||
@@ -520,7 +525,8 @@
|
||||
list-style-image: url("permissions-fill.svg");
|
||||
}
|
||||
&[boosting] image {
|
||||
color: var(--color-accent-primary);
|
||||
fill-opacity: 1 !important;
|
||||
color: var(--zen-sidebar-themed-icon-fill);
|
||||
list-style-image: url("permissions-fill.svg");
|
||||
}
|
||||
|
||||
@@ -537,7 +543,9 @@
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: var(--color-accent-primary);
|
||||
color: var(--zen-sidebar-themed-icon-fill);
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
list-style-image: url("chrome://browser/content/zen-images/boost-indicator.svg");
|
||||
transform: translateX(-20%);
|
||||
z-index: 0;
|
||||
@@ -1003,7 +1011,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
#zen-copy-url-button image {
|
||||
#zen-copy-url-button image,
|
||||
.sr-url-icon {
|
||||
list-style-image: url("link.svg");
|
||||
fill-opacity: 0.65;
|
||||
}
|
||||
@@ -1087,3 +1096,7 @@
|
||||
#zen-boost-load {
|
||||
list-style-image: url("open.svg");
|
||||
}
|
||||
|
||||
.sr-airplane {
|
||||
list-style-image: url("selectable/airplane.svg");
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#ifdef XP_WIN
|
||||
* skin/classic/browser/zen-icons/algorithm.svg (../shared/zen-icons/nucleo/algorithm.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-corner-down-right.svg (../shared/zen-icons/nucleo/arrow-corner-down-right.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-down.svg (../shared/zen-icons/nucleo/arrow-down.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-left.svg (../shared/zen-icons/nucleo/arrow-left.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-right.svg (../shared/zen-icons/nucleo/arrow-right.svg)
|
||||
@@ -153,6 +154,7 @@
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
* skin/classic/browser/zen-icons/algorithm.svg (../shared/zen-icons/nucleo/algorithm.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-corner-down-right.svg (../shared/zen-icons/nucleo/arrow-corner-down-right.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-down.svg (../shared/zen-icons/nucleo/arrow-down.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-left.svg (../shared/zen-icons/nucleo/arrow-left.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-right.svg (../shared/zen-icons/nucleo/arrow-right.svg)
|
||||
@@ -302,6 +304,7 @@
|
||||
#endif
|
||||
#ifdef XP_LINUX
|
||||
* skin/classic/browser/zen-icons/algorithm.svg (../shared/zen-icons/nucleo/algorithm.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-corner-down-right.svg (../shared/zen-icons/nucleo/arrow-corner-down-right.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-down.svg (../shared/zen-icons/nucleo/arrow-down.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-left.svg (../shared/zen-icons/nucleo/arrow-left.svg)
|
||||
* skin/classic/browser/zen-icons/arrow-right.svg (../shared/zen-icons/nucleo/arrow-right.svg)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#filter dumbComments emptyLines substitution
|
||||
# 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/.
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="context-fill" fill-opacity="context-fill-opacity" viewBox="0 0 18 18"><path d="M2.75 3a.75.75 0 0 1 .75.75v4C3.5 8.44 4.06 9 4.75 9h8.69l-2.97-2.97a.75.75 0 1 1 1.06-1.06l4.25 4.25a.8.8 0 0 1 .118.16q.025.04.044.083a.75.75 0 0 1-.078.715 1 1 0 0 1-.084.102l-4.25 4.25a.75.75 0 0 1-1.06-1.06l2.97-2.97H4.75A2.75 2.75 0 0 1 2 7.75v-4A.75.75 0 0 1 2.75 3"/></svg>
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/toolkit/moz.configure b/toolkit/moz.configure
|
||||
index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d232f392d47 100644
|
||||
index 0f5dab192533aa42df97ee3bd4176a9f44d4d568..d45ad2409f6d36106fce5a380545aaae9397ae84 100644
|
||||
--- a/toolkit/moz.configure
|
||||
+++ b/toolkit/moz.configure
|
||||
@@ -22,6 +22,7 @@ def check_moz_app_id(moz_app_id, build_project):
|
||||
@@ -20,6 +20,7 @@ def check_moz_app_id(moz_app_id, build_project):
|
||||
|
||||
project_flag(
|
||||
env="MOZ_APP_VENDOR",
|
||||
@@ -10,7 +10,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
|
||||
nargs=1,
|
||||
help='Used for application.ini\'s "Vendor" field, which also impacts profile location and user-visible fields',
|
||||
)
|
||||
@@ -35,6 +36,7 @@ project_flag(
|
||||
@@ -33,6 +34,7 @@ project_flag(
|
||||
|
||||
project_flag(
|
||||
"MOZ_APP_PROFILE",
|
||||
@@ -18,7 +18,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
|
||||
nargs=1,
|
||||
help='Used for application.ini\'s "Profile" field, which controls profile location',
|
||||
)
|
||||
@@ -86,10 +88,13 @@ option(
|
||||
@@ -84,10 +86,13 @@ option(
|
||||
)
|
||||
set_config("MOZ_INCLUDE_SOURCE_INFO", True, when="MOZ_INCLUDE_SOURCE_INFO")
|
||||
|
||||
@@ -33,7 +33,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
|
||||
help="Set distribution-specific id",
|
||||
)
|
||||
set_config("MOZ_DISTRIBUTION_ID", depends("--with-distribution-id")(lambda v: v[0]))
|
||||
@@ -931,9 +936,9 @@ set_config("MOZ_SYSTEM_AV1", True, when="--with-system-av1")
|
||||
@@ -874,9 +879,9 @@ set_config("MOZ_SYSTEM_AV1", True, when="--with-system-av1")
|
||||
option("--disable-jxl", help="Disable jxl image support")
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
|
||||
return True
|
||||
|
||||
|
||||
@@ -2070,7 +2075,7 @@ set_define("A11Y_LOG", True, when=a11y_log)
|
||||
@@ -2028,7 +2033,7 @@ set_define("A11Y_LOG", True, when=a11y_log)
|
||||
# ==============================================================
|
||||
@depends(milestone)
|
||||
def require_signing(milestone):
|
||||
@@ -55,7 +55,7 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
|
||||
|
||||
|
||||
option(
|
||||
@@ -3903,7 +3908,7 @@ with only_when(compile_environment):
|
||||
@@ -3912,7 +3917,7 @@ with only_when(compile_environment):
|
||||
return "Mozilla"
|
||||
elif target.os == "Android":
|
||||
return ".mozilla"
|
||||
@@ -64,3 +64,12 @@ index 226d0c5a93a9a2404e1974001da4e34b7b670067..b73277448f7d2706d316df2505e17d23
|
||||
|
||||
option(
|
||||
"--with-user-appdir",
|
||||
@@ -4325,7 +4330,7 @@ with only_when(target_is_windows):
|
||||
|
||||
@depends(target.abi)
|
||||
def desktop_launcher_enabled(abi):
|
||||
- return abi == "msvc"
|
||||
+ return False # See gh-13745
|
||||
|
||||
set_config("DESKTOP_LAUNCHER_ENABLED", True, when=desktop_launcher_enabled)
|
||||
set_define("DESKTOP_LAUNCHER_ENABLED", True, when=desktop_launcher_enabled)
|
||||
|
||||
@@ -82,7 +82,7 @@ export class nsZenBoostStyles {
|
||||
|
||||
if (fontCase != "" || fontFamily != "") {
|
||||
style += `/* Text Format */\n`;
|
||||
style += `body * {\n`;
|
||||
style += `body *:not(.google-symbols, gf-load-icon-font, mat-icon, .google-material-icons) {\n`;
|
||||
style += `${fontFamily}\n`;
|
||||
style += `${fontCase}\n`;
|
||||
style += `}\n`;
|
||||
|
||||
@@ -18,6 +18,7 @@ export class nsZenBoostEditor {
|
||||
"zap-state-update",
|
||||
"selector-picker-state-update",
|
||||
"zen-boosts-active-change",
|
||||
"zen-theme-change",
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -55,6 +56,23 @@ export class nsZenBoostEditor {
|
||||
this.initColorPicker();
|
||||
this.initFonts();
|
||||
this.loadBoost(domain);
|
||||
this.updateColorScheme();
|
||||
}
|
||||
|
||||
get isDarkMode() {
|
||||
return this.openerWindow.gZenThemePicker.isDarkMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ZenBoosts JSWindowActor child for the currently selected tab.
|
||||
*
|
||||
* @returns {ZenBoostsChild} zenBoostsChild Boost JSActor child
|
||||
*/
|
||||
get zenBoostsChild() {
|
||||
const linkedBrowser = this.openerWindow.gBrowser.selectedTab.linkedBrowser;
|
||||
const actor =
|
||||
linkedBrowser.browsingContext.currentWindowGlobal.getActor("ZenBoosts");
|
||||
return actor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,6 +199,24 @@ export class nsZenBoostEditor {
|
||||
case "zen-boosts-active-change":
|
||||
this.editorWindow.close();
|
||||
break;
|
||||
case "zen-theme-change":
|
||||
this.updateColorScheme();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the color scheme of the editor window based on the current theme (dark or light mode)
|
||||
*/
|
||||
updateColorScheme() {
|
||||
const colorScheme = this.isDarkMode ? "dark" : "light";
|
||||
this.doc.documentElement.style.colorScheme = colorScheme;
|
||||
|
||||
if (this.codeEditorReady) {
|
||||
const container = this.doc.getElementById("zen-boost-code-editor");
|
||||
const editorEl =
|
||||
container.querySelector("iframe").contentDocument.documentElement;
|
||||
editorEl.className = "theme-" + colorScheme;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +241,7 @@ export class nsZenBoostEditor {
|
||||
const editor = new Editor({
|
||||
mode: Editor.modes.css,
|
||||
lineNumbers: true,
|
||||
theme: "default", // default is light theme
|
||||
theme: "mozilla",
|
||||
readOnly: false,
|
||||
gutters: ["CodeMirror-linenumbers"],
|
||||
});
|
||||
@@ -216,6 +252,8 @@ export class nsZenBoostEditor {
|
||||
|
||||
this.editorWindow._editor = editor;
|
||||
this.codeEditorReady = true;
|
||||
|
||||
this.updateColorScheme();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,12 +399,6 @@ export class nsZenBoostEditor {
|
||||
}
|
||||
windowElem.setAttribute("editor", "code");
|
||||
|
||||
// Store the old boost editor width.
|
||||
// The window needs the outer width which includes
|
||||
// window chrome. This results in the window
|
||||
// being smaller than it should be
|
||||
this._boostEditorWidth = this.editorWindow.outerWidth;
|
||||
|
||||
this.editorWindow.requestAnimationFrame(() => {
|
||||
this.editorWindow.resizeTo(
|
||||
this._codeEditorWidth,
|
||||
@@ -400,7 +432,11 @@ export class nsZenBoostEditor {
|
||||
}
|
||||
windowElem.setAttribute("editor", "boost");
|
||||
|
||||
this.editorWindow.requestAnimationFrame(() => {
|
||||
this.doc.getElementById("zen-boost-editor-root").style.display = "flex";
|
||||
this.doc.getElementById("zen-boost-code-editor-root").style.display =
|
||||
"none";
|
||||
|
||||
this.editorWindow.promiseDocumentFlushed(() => {
|
||||
this.editorWindow.resizeTo(
|
||||
this._boostEditorWidth,
|
||||
this.editorWindow.outerHeight
|
||||
@@ -411,10 +447,6 @@ export class nsZenBoostEditor {
|
||||
this.editorWindow.screenY
|
||||
);
|
||||
}
|
||||
|
||||
this.doc.getElementById("zen-boost-editor-root").style.display = "flex";
|
||||
this.doc.getElementById("zen-boost-code-editor-root").style.display =
|
||||
"none";
|
||||
});
|
||||
|
||||
// Disable picker mode
|
||||
@@ -422,20 +454,13 @@ export class nsZenBoostEditor {
|
||||
}
|
||||
|
||||
async onZapButtonPressed() {
|
||||
const linkedBrowser = this.openerWindow.gBrowser.selectedTab.linkedBrowser;
|
||||
const actor =
|
||||
linkedBrowser.browsingContext.currentWindowGlobal.getActor("ZenBoosts");
|
||||
actor.sendQuery("ZenBoost:ToggleZapMode");
|
||||
|
||||
this.zenBoostsChild.sendQuery("ZenBoost:ToggleZapMode");
|
||||
// Focus the parent browser window
|
||||
this.openerWindow.focus();
|
||||
}
|
||||
|
||||
async onPickerButtonPressed() {
|
||||
const linkedBrowser = this.openerWindow.gBrowser.selectedTab.linkedBrowser;
|
||||
const actor =
|
||||
linkedBrowser.browsingContext.currentWindowGlobal.getActor("ZenBoosts");
|
||||
actor.sendQuery("ZenBoost:TogglePickerMode");
|
||||
this.zenBoostsChild.sendQuery("ZenBoost:TogglePickerMode");
|
||||
this.openerWindow.focus();
|
||||
}
|
||||
|
||||
@@ -460,16 +485,11 @@ ${cssSelector} {
|
||||
}
|
||||
|
||||
onInspectorButtonPressed() {
|
||||
const linkedBrowser = this.openerWindow.gBrowser.selectedTab.linkedBrowser;
|
||||
const actor =
|
||||
linkedBrowser.browsingContext.currentWindowGlobal.getActor("ZenBoosts");
|
||||
actor.sendQuery("ZenBoost:OpenInspector");
|
||||
this.zenBoostsChild.sendQuery("ZenBoost:OpenInspector");
|
||||
}
|
||||
|
||||
async onUpdateZapButtonVisual() {
|
||||
const linkedBrowser = this.openerWindow.gBrowser.selectedTab.linkedBrowser;
|
||||
const actor =
|
||||
linkedBrowser.browsingContext.currentWindowGlobal.getActor("ZenBoosts");
|
||||
const actor = this.zenBoostsChild;
|
||||
const zapButton = this.doc.getElementById("zen-boost-zap");
|
||||
|
||||
const zapEnabled = await actor.sendQuery("ZenBoost:ZapModeEnabled");
|
||||
@@ -480,12 +500,8 @@ ${cssSelector} {
|
||||
}
|
||||
|
||||
async onUpdatePickerButtonVisual() {
|
||||
const linkedBrowser = this.openerWindow.gBrowser.selectedTab.linkedBrowser;
|
||||
const actor =
|
||||
linkedBrowser.browsingContext.currentWindowGlobal.getActor("ZenBoosts");
|
||||
|
||||
const pickerButton = this.doc.getElementById("zen-boost-css-picker");
|
||||
const selectEnabled = await actor.sendQuery(
|
||||
const selectEnabled = await this.zenBoostsChild.sendQuery(
|
||||
"ZenBoost:SelectorPickerModeEnabled"
|
||||
);
|
||||
|
||||
@@ -624,6 +640,7 @@ ${cssSelector} {
|
||||
this.currentBoostData.textCaseOverride = "uppercase";
|
||||
}
|
||||
|
||||
this.currentBoostData.changeWasMade = true;
|
||||
this.updateCaseButtonVisuals();
|
||||
this.updateCurrentBoost();
|
||||
}
|
||||
@@ -631,7 +648,7 @@ ${cssSelector} {
|
||||
/**
|
||||
* Handles the size toggle button press, cycling through size override options
|
||||
*/
|
||||
onBoostSizePressed() {
|
||||
async onBoostSizePressed() {
|
||||
if (this.currentBoostData.sizeOverride == 1) {
|
||||
this.currentBoostData.sizeOverride = 1.1;
|
||||
} else if (this.currentBoostData.sizeOverride == 1.1) {
|
||||
@@ -642,8 +659,10 @@ ${cssSelector} {
|
||||
this.currentBoostData.sizeOverride = 0.9;
|
||||
} else if (this.currentBoostData.sizeOverride == 0.9) {
|
||||
this.currentBoostData.sizeOverride = 1;
|
||||
await this.zenBoostsChild.sendQuery("ZenBoost:DisableSizeOverride");
|
||||
}
|
||||
|
||||
this.currentBoostData.changeWasMade = true;
|
||||
this.updateSizeButtonVisuals();
|
||||
this.updateCurrentBoost();
|
||||
}
|
||||
@@ -824,13 +843,19 @@ ${cssSelector} {
|
||||
const dotSec = this.doc.querySelector(
|
||||
"#zen-boost-color-picker-dot-secondary"
|
||||
);
|
||||
|
||||
const dotDistance = this.currentBoostData.dotDistance;
|
||||
const dotAngleDeg = this.currentBoostData.dotAngleDeg;
|
||||
const secondaryDotAngleDelta =
|
||||
this.currentBoostData.secondaryDotAngleDegDelta ?? 0;
|
||||
|
||||
dot.style.setProperty(
|
||||
"--zen-theme-picker-dot-color",
|
||||
`hsl(${this.currentBoostData.dotAngleDeg}deg, ${this.currentBoostData.dotDistance * 100}%, 55%)`
|
||||
`hsl(${dotAngleDeg}deg, ${dotDistance * 100}%, 55%)`
|
||||
);
|
||||
dotSec.style.setProperty(
|
||||
"--zen-theme-picker-dot-color",
|
||||
`hsl(${this.currentBoostData.dotAngleDeg + this.currentBoostData.secondaryDotAngleDegDelta}deg, ${this.currentBoostData.dotDistance * 100}%, 20%)`
|
||||
`hsl(${dotAngleDeg + secondaryDotAngleDelta}deg, ${dotDistance * 100}%, 20%)`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -854,22 +879,23 @@ ${cssSelector} {
|
||||
const centerY = rect.top + rect.height / 2;
|
||||
const radius = (rect.width - padding) / 2;
|
||||
|
||||
const dotDistance = this.currentBoostData.dotDistance;
|
||||
const primaryDotAngleDeg = this.currentBoostData.dotAngleDeg;
|
||||
|
||||
let angle = null;
|
||||
if (!pixelX || !pixelY) {
|
||||
if (pixelX == null || pixelY == null) {
|
||||
pixelX = centerX;
|
||||
pixelY = centerY;
|
||||
angle = this.currentBoostData.secondaryDotAngleDegDelta;
|
||||
} else {
|
||||
angle = Math.atan2(pixelY - centerY, pixelX - centerX);
|
||||
pixelX =
|
||||
centerX + Math.cos(angle) * this.currentBoostData.dotDistance * radius;
|
||||
pixelY =
|
||||
centerY + Math.sin(angle) * this.currentBoostData.dotDistance * radius;
|
||||
pixelX = centerX + Math.cos(angle) * dotDistance * radius;
|
||||
pixelY = centerY + Math.sin(angle) * dotDistance * radius;
|
||||
}
|
||||
|
||||
// Rad to degree
|
||||
this.currentBoostData.secondaryDotAngleDegDelta =
|
||||
((angle * 180) / Math.PI + 100 - this.currentBoostData.dotAngleDeg) % 360;
|
||||
((angle * 180) / Math.PI + 100 - primaryDotAngleDeg) % 360;
|
||||
if (this.currentBoostData.secondaryDotAngleDegDelta < 0) {
|
||||
this.currentBoostData.secondaryDotAngleDegDelta += 360;
|
||||
}
|
||||
@@ -902,14 +928,19 @@ ${cssSelector} {
|
||||
const cx = rect.width / 2;
|
||||
const cy = rect.height / 2;
|
||||
|
||||
const dotDistance = this.currentBoostData.dotDistance;
|
||||
const dotAngleDeg = this.currentBoostData.dotAngleDeg;
|
||||
const secondaryDotAngleDelta =
|
||||
this.currentBoostData.secondaryDotAngleDegDelta ?? 0;
|
||||
|
||||
// Updating the circle size to match the distance of the point
|
||||
const circle = this.doc.querySelector(".zen-boost-color-picker-circle");
|
||||
circle.setAttribute("animated", "false");
|
||||
circle.style.width = `${this.currentBoostData.dotDistance * radius * 2}px`;
|
||||
circle.style.height = `${this.currentBoostData.dotDistance * radius * 2}px`;
|
||||
circle.style.width = `${dotDistance * radius * 2}px`;
|
||||
circle.style.height = `${dotDistance * radius * 2}px`;
|
||||
|
||||
const dotColor = `hsl(${this.currentBoostData.dotAngleDeg}deg, ${this.currentBoostData.dotDistance * 100}%, 55%)`;
|
||||
const dotColorSec = `hsl(${this.currentBoostData.dotAngleDeg + this.currentBoostData.secondaryDotAngleDegDelta}deg, ${this.currentBoostData.dotDistance * 100}%, 20%)`;
|
||||
const dotColor = `hsl(${dotAngleDeg}deg, ${dotDistance * 100}%, 55%)`;
|
||||
const dotColorSec = `hsl(${dotAngleDeg + secondaryDotAngleDelta}deg, ${dotDistance * 100}%, 20%)`;
|
||||
|
||||
this.updateArcFill(cx, cy, radius, dotColor, dotColorSec);
|
||||
}
|
||||
@@ -1154,12 +1185,6 @@ ${cssSelector} {
|
||||
invertButton.classList.remove("zen-boost-button-active");
|
||||
}
|
||||
|
||||
if (this.currentBoostData.smartInvert) {
|
||||
invertButton.classList.add("zen-boost-button-active");
|
||||
} else {
|
||||
invertButton.classList.remove("zen-boost-button-active");
|
||||
}
|
||||
|
||||
if (!this.currentBoostData.enableColorBoost) {
|
||||
disableButton.classList.add("zen-boost-button-active-transparent");
|
||||
} else {
|
||||
|
||||
@@ -114,9 +114,12 @@ class nsZenBoostsManager {
|
||||
boostData: {
|
||||
boostName: "My Boost",
|
||||
|
||||
dotAngleDeg: 0,
|
||||
/* These initial values depend on
|
||||
each other. Changing one means having to
|
||||
recalculate all of them manually. */
|
||||
dotAngleDeg: 131.61,
|
||||
dotPos: { x: 0.76, y: 0.66 },
|
||||
dotDistance: 0,
|
||||
dotDistance: 0.91,
|
||||
|
||||
secondaryDotAngleDegDelta: 55,
|
||||
secondaryDotPos: { x: 0.5, y: 0.81 },
|
||||
|
||||
@@ -280,6 +280,9 @@ export class ZenBoostsChild extends JSWindowActorChild {
|
||||
case "ZenBoost:OpenInspector":
|
||||
this.sendAsyncMessage("ZenBoost:OpenInspector");
|
||||
break;
|
||||
case "ZenBoost:DisableSizeOverride":
|
||||
this.disableSizeOverride();
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -549,6 +552,14 @@ export class ZenBoostsChild extends JSWindowActorChild {
|
||||
this.sendNotify("selector-picker-state-update", "ondisable");
|
||||
}
|
||||
|
||||
disableSizeOverride() {
|
||||
const browsingContext = this.browsingContext;
|
||||
if (!browsingContext || browsingContext.parent !== null) {
|
||||
return;
|
||||
}
|
||||
browsingContext.fullZoom = 1;
|
||||
}
|
||||
|
||||
sendNotify(topic, msg = null) {
|
||||
this.sendAsyncMessage("ZenBoost:Notify", { topic, msg });
|
||||
}
|
||||
|
||||
104
src/zen/boosts/gtest/TestZenBoostsAccentCache.cpp
Normal file
104
src/zen/boosts/gtest/TestZenBoostsAccentCache.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/nsZenBoostsBackend.h"
|
||||
|
||||
using zen::detail::AccentCacheSize;
|
||||
using zen::detail::EnsureCachedAccent;
|
||||
using zen::detail::IsAccentCached;
|
||||
using zen::detail::ResetAccentCache;
|
||||
|
||||
namespace {
|
||||
|
||||
class ZenBoostsAccentCache : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override { ResetAccentCache(); }
|
||||
void TearDown() override { ResetAccentCache(); }
|
||||
};
|
||||
|
||||
constexpr nscolor kAccentA = NS_RGBA(80, 120, 200, 200);
|
||||
constexpr nscolor kAccentB = NS_RGBA(200, 80, 80, 200);
|
||||
constexpr nscolor kAccentC = NS_RGBA(80, 200, 120, 200);
|
||||
constexpr nscolor kAccentD = NS_RGBA(200, 200, 80, 200);
|
||||
constexpr nscolor kAccentE = NS_RGBA(120, 80, 200, 200);
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(ZenBoostsAccentCache, SizeIsAtLeastFour) {
|
||||
EXPECT_GE(AccentCacheSize(), 4u);
|
||||
}
|
||||
|
||||
TEST_F(ZenBoostsAccentCache, EmptyAfterReset) {
|
||||
EnsureCachedAccent(kAccentA, 0.0f);
|
||||
ResetAccentCache();
|
||||
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
|
||||
}
|
||||
|
||||
TEST_F(ZenBoostsAccentCache, SameKeyIsCachedAfterEnsure) {
|
||||
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
|
||||
EnsureCachedAccent(kAccentA, 0.0f);
|
||||
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
|
||||
}
|
||||
|
||||
// Keying on accent alone would silently serve a stale complementary accent
|
||||
// when the rotation changes.
|
||||
TEST_F(ZenBoostsAccentCache, DifferentRotationOccupiesDistinctEntry) {
|
||||
EnsureCachedAccent(kAccentA, 0.0f);
|
||||
EnsureCachedAccent(kAccentA, 90.0f);
|
||||
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentA, 90.0f));
|
||||
}
|
||||
|
||||
TEST_F(ZenBoostsAccentCache, DifferentAccentOccupiesDistinctEntry) {
|
||||
EnsureCachedAccent(kAccentA, 30.0f);
|
||||
EnsureCachedAccent(kAccentB, 30.0f);
|
||||
EXPECT_TRUE(IsAccentCached(kAccentA, 30.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentB, 30.0f));
|
||||
}
|
||||
|
||||
TEST_F(ZenBoostsAccentCache, RoundRobinEvictsOldestEntry) {
|
||||
ASSERT_EQ(AccentCacheSize(), 4u);
|
||||
|
||||
EnsureCachedAccent(kAccentA, 0.0f);
|
||||
EnsureCachedAccent(kAccentB, 0.0f);
|
||||
EnsureCachedAccent(kAccentC, 0.0f);
|
||||
EnsureCachedAccent(kAccentD, 0.0f);
|
||||
|
||||
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentB, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentC, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentD, 0.0f));
|
||||
|
||||
EnsureCachedAccent(kAccentE, 0.0f);
|
||||
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentB, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentC, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentD, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentE, 0.0f));
|
||||
}
|
||||
|
||||
// A cache hit must not consume a fresh slot, otherwise repeated paints with
|
||||
// the same accent would evict their own neighbours.
|
||||
TEST_F(ZenBoostsAccentCache, RepeatEnsureDoesNotChurnTheCache) {
|
||||
ASSERT_EQ(AccentCacheSize(), 4u);
|
||||
|
||||
EnsureCachedAccent(kAccentA, 0.0f);
|
||||
EnsureCachedAccent(kAccentB, 0.0f);
|
||||
EnsureCachedAccent(kAccentC, 0.0f);
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
EnsureCachedAccent(kAccentA, 0.0f);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(IsAccentCached(kAccentA, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentB, 0.0f));
|
||||
EXPECT_TRUE(IsAccentCached(kAccentC, 0.0f));
|
||||
|
||||
EnsureCachedAccent(kAccentD, 0.0f);
|
||||
EnsureCachedAccent(kAccentE, 0.0f);
|
||||
|
||||
EXPECT_FALSE(IsAccentCached(kAccentA, 0.0f));
|
||||
}
|
||||
42
src/zen/boosts/gtest/TestZenBoostsResolveStyleColor.cpp
Normal file
42
src/zen/boosts/gtest/TestZenBoostsResolveStyleColor.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/nsZenBoostsBackend.h"
|
||||
|
||||
using zen::nsZenBoostsBackend;
|
||||
|
||||
namespace {
|
||||
|
||||
const nscolor kResolveColors[] = {
|
||||
NS_RGBA(0, 0, 0, 255), NS_RGBA(255, 255, 255, 255),
|
||||
NS_RGBA(128, 128, 128, 255), NS_RGBA(255, 0, 0, 255),
|
||||
NS_RGBA(0, 255, 0, 255), NS_RGBA(0, 0, 255, 255),
|
||||
NS_RGBA(40, 44, 52, 255), NS_RGBA(248, 248, 248, 255),
|
||||
NS_RGBA(20, 22, 28, 255), NS_RGBA(80, 80, 80, 200),
|
||||
NS_RGBA(240, 17, 99, 1), NS_RGBA(0, 0, 0, 0),
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Removing the null-frame guard would crash chrome-process callers that
|
||||
// legitimately pass nullptr (canvas getComputedStyle, font-palette binding,
|
||||
// the StyleColor(nscolor)/StyleColor(StyleAbsoluteColor) overloads).
|
||||
TEST(ZenBoostsResolveStyleColor, NullFrameIsIdentity)
|
||||
{
|
||||
for (nscolor c : kResolveColors) {
|
||||
EXPECT_EQ(nsZenBoostsBackend::ResolveStyleColor(c, nullptr), c);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ZenBoostsResolveStyleColor, NullFrameIsIdempotent)
|
||||
{
|
||||
for (nscolor c : kResolveColors) {
|
||||
nscolor once = nsZenBoostsBackend::ResolveStyleColor(c, nullptr);
|
||||
nscolor twice = nsZenBoostsBackend::ResolveStyleColor(once, nullptr);
|
||||
EXPECT_EQ(once, c);
|
||||
EXPECT_EQ(twice, c);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"TestZenBoostsAccentCache.cpp",
|
||||
"TestZenBoostsColorFilter.cpp",
|
||||
"TestZenBoostsResolveStyleColor.cpp",
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = "xul-gtest"
|
||||
|
||||
@@ -450,11 +450,9 @@ inline static void GetZenBoostsDataForFrame(const nsIFrame* aFrame,
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
namespace detail {
|
||||
|
||||
// Thin forwarders that give unit tests access to the pure color math without
|
||||
// pulling in the singleton / BrowsingContext. They are defined here, after the
|
||||
// anonymous namespace, so they can reach those file-local implementations.
|
||||
nsZenAccentOklab PrecomputeAccent(nscolor aAccentColor) {
|
||||
return zenPrecomputeAccent(aAccentColor);
|
||||
}
|
||||
@@ -474,7 +472,33 @@ nscolor InvertColorChannel(nscolor aColor) {
|
||||
return zenInvertColorChannel(aColor);
|
||||
}
|
||||
|
||||
size_t AccentCacheSize() { return kAccentCacheSize; }
|
||||
|
||||
void ResetAccentCache() {
|
||||
for (auto& entry : sAccentCache) {
|
||||
entry.valid = false;
|
||||
entry.accentNS = 0;
|
||||
entry.rotationDeg = 0.0f;
|
||||
}
|
||||
sAccentCacheNext = 0;
|
||||
}
|
||||
|
||||
bool IsAccentCached(nscolor aAccentNS, float aRotationDeg) {
|
||||
for (const auto& entry : sAccentCache) {
|
||||
if (entry.valid && entry.accentNS == aAccentNS &&
|
||||
entry.rotationDeg == aRotationDeg) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EnsureCachedAccent(nscolor aAccentNS, float aRotationDeg) {
|
||||
(void)GetCachedAccent(aAccentNS, aRotationDeg);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
#endif // ENABLE_TESTS
|
||||
|
||||
static mozilla::StaticRefPtr<nsZenBoostsBackend> sZenBoostsBackend;
|
||||
|
||||
|
||||
@@ -27,10 +27,9 @@ struct nsZenAccentOklab {
|
||||
float contrastFactor;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
// Test-only forwarders into the file-local color math and accent cache.
|
||||
namespace detail {
|
||||
// Pure color-math primitives, exposed for unit testing. These have no
|
||||
// dependency on the singleton, the BrowsingContext, or the process type, so
|
||||
// they can be exercised directly from gtest.
|
||||
nsZenAccentOklab PrecomputeAccent(nscolor aAccentColor);
|
||||
nsZenAccentOklab RotateAccent(const nsZenAccentOklab& aBase,
|
||||
float aRotationDeg);
|
||||
@@ -38,7 +37,13 @@ nscolor FilterColorChannel(nscolor aOriginalColor,
|
||||
const nsZenAccentOklab& aAccent,
|
||||
const nsZenAccentOklab& aComplementary);
|
||||
nscolor InvertColorChannel(nscolor aColor);
|
||||
|
||||
size_t AccentCacheSize();
|
||||
void ResetAccentCache();
|
||||
bool IsAccentCached(nscolor aAccentNS, float aRotationDeg);
|
||||
void EnsureCachedAccent(nscolor aAccentNS, float aRotationDeg);
|
||||
} // namespace detail
|
||||
#endif // ENABLE_TESTS
|
||||
|
||||
class nsZenBoostsBackend final : public nsISupports {
|
||||
public:
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
*/
|
||||
|
||||
#zen-boost-advanced-color-options-panel {
|
||||
color-scheme: light;
|
||||
--panel-padding: 15px;
|
||||
|
||||
& p {
|
||||
color: #3a3a3b;
|
||||
color: var(--zen-boosts-primary-color);
|
||||
}
|
||||
|
||||
& input {
|
||||
|
||||
@@ -34,14 +34,6 @@
|
||||
<link rel="stylesheet" href="chrome://browser/content/zen-styles/zen-advanced-color-options.css" />
|
||||
|
||||
<link rel="localization" href="browser/zen-boosts.ftl"/>
|
||||
|
||||
<!-- Loading in the window module -->
|
||||
<script>
|
||||
const { nsZenBoostEditor } = ChromeUtils.importESModule( "resource:///modules/zen/boosts/ZenBoostsEditor.mjs" );
|
||||
window.addEventListener("load", () => {
|
||||
window.boostEditor = new nsZenBoostEditor(document, window.domain, window, window.openerWindow);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<html:body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<vbox flex="1" id="zen-boost-editor-root">
|
||||
@@ -120,15 +112,15 @@
|
||||
<popupset id="mainPopupSet">
|
||||
<panel type="arrow" popupalign="topmiddle" id="zen-boost-advanced-color-options-panel">
|
||||
<vbox>
|
||||
<p data-l10n-id="zen-bootst-color-contrast"></p>
|
||||
<p data-l10n-id="zen-boost-color-contrast"></p>
|
||||
<html:input id="zen-boost-color-contrast" type="range" min="0.05" max="0.9" value="0.75" step="0.01"/>
|
||||
</vbox>
|
||||
<vbox>
|
||||
<p data-l10n-id="zen-bootst-color-brightness"></p>
|
||||
<p data-l10n-id="zen-boost-color-brightness"></p>
|
||||
<html:input id="zen-boost-color-brightness" type="range" min="0" max="1" value="0.5" step="0.01"/>
|
||||
</vbox>
|
||||
<vbox>
|
||||
<p data-l10n-id="zen-bootst-color-original-saturation"></p>
|
||||
<p data-l10n-id="zen-boost-color-original-saturation"></p>
|
||||
<html:input id="zen-boost-color-saturation" type="range" min="0" max="1" value="0.5" step="0.01"/>
|
||||
</vbox>
|
||||
</panel>
|
||||
@@ -164,5 +156,10 @@
|
||||
<command id="cmd_zenBoostDelete"
|
||||
oncommand="window.boostEditor.deleteBoost();" />
|
||||
</commandset>
|
||||
|
||||
<script>
|
||||
const { nsZenBoostEditor } = ChromeUtils.importESModule( "resource:///modules/zen/boosts/ZenBoostsEditor.mjs" );
|
||||
window.boostEditor = new nsZenBoostEditor(document, window.domain, window, window.openerWindow);
|
||||
</script>
|
||||
</html:body>
|
||||
</html>
|
||||
|
||||
@@ -5,10 +5,33 @@
|
||||
*/
|
||||
|
||||
#zenBoostWindow {
|
||||
/* For the mica effect we want a white tint */
|
||||
@media not (-moz-platform: linux) {
|
||||
color-scheme: light;
|
||||
}
|
||||
--zen-boosts-primary-background: light-dark(#fcfcfe, #171717);
|
||||
--zen-boosts-secondary-background: light-dark(#f6f6f8, #1c1c1e);
|
||||
--zen-boosts-mica-background: light-dark(#f6f6f8c0, #1c1c1ec0);
|
||||
|
||||
--zen-boosts-primary-color: light-dark(#3a3a3b, #f3f3f3);
|
||||
--zen-boosts-secondary-color: light-dark(#727272, #b1b1b1);
|
||||
|
||||
--zen-boosts-button-background: light-dark(#ebebed, #262626);
|
||||
|
||||
--mod-button-c1: light-dark(#ebebed, #262626);
|
||||
--mod-button-c2: light-dark(#ebebed, #262626);
|
||||
|
||||
--zen-boosts-active-button-background: light-dark(#3a3a3a, #cccccc);
|
||||
--zen-boosts-active-button-hover-background: light-dark(#5b5b5c, #c9c9c9);
|
||||
--zen-boosts-active-button-color: light-dark(#fcfcfe, #1c1c1e);
|
||||
--zen-boosts-back-button-hover-background: light-dark(#e3e3e6, #3a3a3a);
|
||||
|
||||
--zen-boosts-magic-theme-background: light-dark(white, #3a3a3a);
|
||||
--zen-boosts-magic-theme-active-background: light-dark(#3a3a3a, white);
|
||||
|
||||
--zen-boosts-font-wrapper-background: light-dark(white, #262626);
|
||||
|
||||
--zen-boosts-primary-border-color: light-dark(#ededef, #3a3a3a);
|
||||
|
||||
--zen-boosts-color-picker-background: light-dark(#fbfbfdea, #1c1c1eea);
|
||||
--zen-boosts-color-picker-pattern-color: light-dark(#e3e9e4, #3a3a3a);
|
||||
|
||||
appearance: none;
|
||||
border: none;
|
||||
|
||||
@@ -40,12 +63,12 @@
|
||||
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: #f6f6f8;
|
||||
background-color: var(--zen-boosts-secondary-background);
|
||||
@media (-moz-windows-mica) {
|
||||
background-color: #f6f6f8c0;
|
||||
background-color: var(--zen-boosts-mica-background);
|
||||
}
|
||||
|
||||
border: solid 0 #ededef;
|
||||
border: solid 0 var(--zen-boosts-primary-border-color);
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
@@ -58,6 +81,9 @@
|
||||
margin-left: 4px;
|
||||
border-radius: 8px;
|
||||
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--zen-boosts-primary-color);
|
||||
|
||||
opacity: 0.75;
|
||||
background-color: transparent;
|
||||
|
||||
@@ -79,12 +105,12 @@
|
||||
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background-color: #f6f6f8;
|
||||
background-color: var(--zen-boosts-secondary-background);
|
||||
@media (-moz-windows-mica) {
|
||||
background-color: #f6f6f8c0;
|
||||
background-color: var(--zen-boosts-mica-background);
|
||||
}
|
||||
|
||||
border: solid 0 #ededef;
|
||||
border: solid 0 var(--zen-boosts-primary-border-color);
|
||||
border-top-width: 1px;
|
||||
|
||||
display: flex;
|
||||
@@ -113,6 +139,7 @@ body {
|
||||
user-select: none;
|
||||
|
||||
width: 100%;
|
||||
min-height: 582px;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@@ -148,7 +175,7 @@ body {
|
||||
}
|
||||
|
||||
.subviewbutton {
|
||||
color: #3a3a3b;
|
||||
color: var(--zen-boosts-primary-color);
|
||||
}
|
||||
|
||||
#zen-boost-editor-view {
|
||||
@@ -166,11 +193,11 @@ body {
|
||||
min-height: 40px;
|
||||
max-height: 40px;
|
||||
align-items: center;
|
||||
background-color: #f6f6f8;
|
||||
border: solid 1px #e7e7e7ab;
|
||||
background-color: var(--zen-boosts-secondary-background);
|
||||
border: solid 1px var(--zen-boosts-primary-border-color);
|
||||
|
||||
@media (-moz-windows-mica) {
|
||||
background-color: #f6f6f8c0;
|
||||
background-color: var(--zen-boosts-mica-background);
|
||||
border: none;
|
||||
}
|
||||
|
||||
@@ -232,6 +259,7 @@ body {
|
||||
padding: 2px;
|
||||
|
||||
& button {
|
||||
color: var(--zen-boosts-primary-color) !important;
|
||||
padding: auto;
|
||||
margin: auto;
|
||||
background-color: transparent;
|
||||
@@ -243,7 +271,7 @@ body {
|
||||
gap: 14px;
|
||||
padding-top: 6px;
|
||||
|
||||
background-color: #fcfcfe;
|
||||
background-color: var(--zen-boosts-primary-background);
|
||||
|
||||
-moz-window-dragging: drag;
|
||||
& > * {
|
||||
@@ -328,7 +356,7 @@ body {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
background-color: #ebebed;
|
||||
background-color: var(--zen-boosts-button-background);
|
||||
|
||||
transition:
|
||||
0.4s background-color cubic-bezier(0.075, 0.82, 0.165, 1),
|
||||
@@ -348,7 +376,7 @@ body {
|
||||
}
|
||||
|
||||
#zen-boost-case:not([case-mode="none"]) {
|
||||
background-color: #ebebed;
|
||||
background-color: var(--zen-boosts-button-background);
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
@@ -373,7 +401,7 @@ body {
|
||||
font-size: 8pt;
|
||||
text-indent: 2px;
|
||||
vertical-align: middle;
|
||||
color: #3a3a3b;
|
||||
color: var(--zen-boosts-primary-color);
|
||||
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -397,12 +425,16 @@ body {
|
||||
}
|
||||
|
||||
.zen-boost-button-active {
|
||||
background-color: #3a3a3a;
|
||||
color: #fcfcfe;
|
||||
background-color: var(--zen-boosts-active-button-background);
|
||||
color: var(--zen-boosts-active-button-color);
|
||||
|
||||
&#zen-boost-magic-theme {
|
||||
background-color: var(--zen-boosts-magic-theme-active-background);
|
||||
}
|
||||
}
|
||||
|
||||
.zen-boost-button-active:hover {
|
||||
background-color: #5b5b5c;
|
||||
background-color: var(--zen-boosts-active-button-hover-background);
|
||||
}
|
||||
|
||||
.zen-boost-button-active-transparent {
|
||||
@@ -430,12 +462,13 @@ body {
|
||||
}
|
||||
|
||||
&:not(.zen-boost-button-active) {
|
||||
background: white;
|
||||
background: var(--zen-boosts-magic-theme-background);
|
||||
color: var(--zen-boosts-primary-color);
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: #F6F6F8;
|
||||
background-color: var(--zen-boosts-secondary-background);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -471,7 +504,7 @@ body {
|
||||
|
||||
transition: 0.2s opacity ease-in-out;
|
||||
|
||||
color: #727272;
|
||||
color: var(--zen-boosts-secondary-color);
|
||||
background: none;
|
||||
|
||||
font-size: 9pt;
|
||||
@@ -490,7 +523,7 @@ body {
|
||||
|
||||
&[has-selection="true"] {
|
||||
opacity: 1;
|
||||
background-color: #ebebed;
|
||||
background-color: var(--zen-boosts-button-background);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,7 +546,7 @@ body {
|
||||
|
||||
#zen-boost-font-wrapper {
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,.15);
|
||||
background-color: #ffffff;
|
||||
background-color: var(--zen-boosts-font-wrapper-background);
|
||||
|
||||
border-radius: 6px;
|
||||
@media (-moz-platform: macos) {
|
||||
@@ -564,35 +597,35 @@ body {
|
||||
|
||||
@property --mod-button-c1 {
|
||||
syntax: "<color>";
|
||||
inherits: false;
|
||||
initial-value: #ebebed;
|
||||
inherits: true;
|
||||
initial-value: transparent;
|
||||
}
|
||||
|
||||
@property --mod-button-c2 {
|
||||
syntax: "<color>";
|
||||
inherits: false;
|
||||
initial-value: #ebebed;
|
||||
inherits: true;
|
||||
initial-value: transparent;
|
||||
}
|
||||
|
||||
.mod-button[mode="orange"] {
|
||||
color: #e3e9e4;
|
||||
--mod-button-c1: #ffbb5d;
|
||||
--mod-button-c2: #ffa01d;
|
||||
--mod-button-c1: light-dark(#ffbb5d, #c37a3f);
|
||||
--mod-button-c2: light-dark(#ffa01d, #9f5a2a);
|
||||
}
|
||||
.mod-button[mode="orange-red"] {
|
||||
color: #e3e9e4;
|
||||
--mod-button-c1: #ff8758;
|
||||
--mod-button-c2: #ff5b1b;
|
||||
--mod-button-c1: light-dark(#ff8758, #bd6048);
|
||||
--mod-button-c2: light-dark(#ff5b1b, #9b422b);
|
||||
}
|
||||
.mod-button[mode="red"] {
|
||||
color: #e3e9e4;
|
||||
--mod-button-c1: #ff595f;
|
||||
--mod-button-c2: #ff121b;
|
||||
--mod-button-c1: light-dark(#ff595f, #b94a50);
|
||||
--mod-button-c2: light-dark(#ff121b, #95272e);
|
||||
}
|
||||
.mod-button[mode="blue"] {
|
||||
color: #e3e9e4;
|
||||
--mod-button-c1: #6650fc;
|
||||
--mod-button-c2: #4125ff;
|
||||
--mod-button-c1: light-dark(#6650fc, #5d56ca);
|
||||
--mod-button-c2: light-dark(#4125ff, #453aa9);
|
||||
}
|
||||
.mod-button[mode] {
|
||||
background: linear-gradient(180deg, var(--mod-button-c1) 0%, var(--mod-button-c2) 100%) border-box;
|
||||
@@ -608,7 +641,7 @@ body {
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: #e3e3e6;
|
||||
background-color: var(--zen-boosts-back-button-hover-background);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,17 +668,17 @@ body {
|
||||
|
||||
z-index: 2;
|
||||
|
||||
background: #fbfbfdea;
|
||||
background: var(--zen-boosts-color-picker-background);
|
||||
|
||||
background-position: -23px -23px;
|
||||
backdrop-filter: saturate(2) blur(15px);
|
||||
|
||||
background-size: 6px 6px;
|
||||
background-image: radial-gradient(#e3e9e4, 1px, transparent 0);
|
||||
background-image: radial-gradient(var(--zen-boosts-color-picker-pattern-color), 1px, transparent 0);
|
||||
|
||||
@media (-moz-platform: macos) {
|
||||
background-size: 4px 4px;
|
||||
background-image: radial-gradient(#e3e9e4 0.5px, transparent 0);
|
||||
background-image: radial-gradient(var(--zen-boosts-color-picker-pattern-color) 0.5px, transparent 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
}
|
||||
|
||||
#select-component {
|
||||
--zen-boosts-selector-background: light-dark(#f5f7fb, #27272a);
|
||||
--zen-boosts-selector-preview-background: light-dark(#e0e2e63d, #27272a3d);
|
||||
--zen-boosts-selector-preview-color: light-dark(rgb(76, 78, 80), rgb(207, 200, 200));
|
||||
--zen-boosts-selector-button-color: light-dark(#dadada, #f1f1f1);
|
||||
--zen-boosts-selector-outline-color: light-dark(#e0e2e6ae, #474749);
|
||||
|
||||
width: min-content;
|
||||
font-family: system-ui;
|
||||
|
||||
@@ -29,7 +35,7 @@
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
|
||||
background-color: #f5f7fb;
|
||||
background-color: var(--zen-boosts-selector-background);
|
||||
margin: 4px;
|
||||
|
||||
border-radius: 12px;
|
||||
@@ -126,17 +132,29 @@
|
||||
|
||||
width: 250px !important;
|
||||
--related-elements-value: 100%;
|
||||
background: linear-gradient(to top, rgb(247, 66, 0), rgb(245, 134, 86));
|
||||
background: linear-gradient(
|
||||
to top,
|
||||
light-dark(#ff5b1b, #9b422b),
|
||||
light-dark(#ff8758, #bd6048)
|
||||
);
|
||||
|
||||
border: none;
|
||||
color: #dadada;
|
||||
color: var(--zen-boosts-selector-button-color);
|
||||
box-shadow: 0 0 15px #00000052;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 14px #00000066;
|
||||
background:
|
||||
linear-gradient(to right, transparent var(--related-elements-value), gray var(--related-elements-value)),
|
||||
linear-gradient(to top, rgb(247, 66, 0), rgb(245, 134, 86));
|
||||
linear-gradient(
|
||||
to right,
|
||||
transparent var(--related-elements-value),
|
||||
light-dark(gray, #363636) var(--related-elements-value)
|
||||
),
|
||||
linear-gradient(
|
||||
to top,
|
||||
light-dark(#ff5b1b, #9b422b),
|
||||
light-dark(#ff8758, #bd6048)
|
||||
);
|
||||
|
||||
@media not (-moz-platform: windows) {
|
||||
box-shadow: 0 0 20px #00000077;
|
||||
@@ -147,30 +165,34 @@
|
||||
#select-this {
|
||||
appearance: none;
|
||||
|
||||
background: linear-gradient(0deg, rgba(246, 27, 25, 1) 0%, rgba(254, 67, 59, 1) 100%);
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
light-dark(#ff121b, #95272e),
|
||||
light-dark(#ff595f, #b94a50)
|
||||
);
|
||||
border: none;
|
||||
color: #dadada;
|
||||
color: var(--zen-boosts-selector-button-color);
|
||||
|
||||
box-shadow: 0 0 15px #00000052;
|
||||
}
|
||||
|
||||
#select-cancel {
|
||||
appearance: none;
|
||||
|
||||
background: rgb(90, 94, 100);
|
||||
@media (-moz-platform: macos) {
|
||||
background: linear-gradient(0deg, rgba(81, 83, 85, 1) 0%, rgba(108, 110, 112, 1) 100%);
|
||||
}
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
light-dark(#525355, #373739) 0%,
|
||||
light-dark(#6c6e70, #4b4c4e) 100%
|
||||
);
|
||||
|
||||
border: none;
|
||||
color: #dadada;
|
||||
color: var(--zen-boosts-selector-button-color);
|
||||
|
||||
box-shadow: 0 0 15px #00000052;
|
||||
}
|
||||
|
||||
#selector-preview {
|
||||
background-color: #e0e2e63d;
|
||||
outline: 1px solid #e0e2e6ae;
|
||||
background-color: var(--zen-boosts-selector-preview-background);
|
||||
outline: 1px solid var(--zen-boosts-selector-outline-color);
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
text-indent: 18px;
|
||||
@@ -182,7 +204,7 @@
|
||||
#selector-element-preview-text {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 9pt;
|
||||
color: rgb(76, 78, 80);
|
||||
color: var(--zen-boosts-selector-preview-color);
|
||||
}
|
||||
|
||||
#hover-div {
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
// prettier-ignore
|
||||
// eslint-disable-next-line no-lone-blocks
|
||||
{
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
gZenSpaceRoutingManager:
|
||||
"resource:///modules/zen/spacerouting/ZenSpaceRoutingManager.sys.mjs",
|
||||
});
|
||||
|
||||
Services.scriptloader.loadSubScript("chrome://browser/content/zen-components/ZenSpaceBookmarksStorage.js", this);
|
||||
|
||||
let scripts = [
|
||||
|
||||
@@ -100,7 +100,16 @@ class ZenStartup {
|
||||
delete this.promiseInitializedResolve;
|
||||
|
||||
setTimeout(() => {
|
||||
gZenWorkspaces._invalidateBookmarkContainers();
|
||||
// Wait for the natural PlacesToolbar rebuild before invalidating, so
|
||||
// the two async rebuilds don't interleave and duplicate bookmarks.
|
||||
// promiseRebuilt() returns undefined when no rebuild is in flight.
|
||||
const rebuilt =
|
||||
document
|
||||
.getElementById("PlacesToolbar")
|
||||
?._placesView?.promiseRebuilt() ?? Promise.resolve();
|
||||
rebuilt
|
||||
.catch(console.error)
|
||||
.then(() => gZenWorkspaces._invalidateBookmarkContainers());
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -147,7 +156,7 @@ class ZenStartup {
|
||||
}
|
||||
|
||||
#initUIComponents() {
|
||||
const kUIComponents = ["ZenProgressBar"];
|
||||
const kUIComponents = ["ZenProgressBar", "ZenSpaceRoutingNavigation"];
|
||||
for (let component of kUIComponents) {
|
||||
const module = ChromeUtils.importESModule(
|
||||
"resource:///modules/zen/ui/" + component + ".sys.mjs"
|
||||
|
||||
@@ -10,5 +10,6 @@ EXTRA_JS_MODULES += [
|
||||
|
||||
EXTRA_JS_MODULES.zen.ui += [
|
||||
"sys/ui/ZenProgressBar.sys.mjs",
|
||||
"sys/ui/ZenSpaceRoutingNavigation.sys.mjs",
|
||||
"sys/ui/ZenUIComponent.sys.mjs",
|
||||
]
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
*/
|
||||
.dialogBox {
|
||||
border-radius: 12px !important;
|
||||
border: 1px solid light-dark(rgba(168, 168, 169, 0.50), var(--zen-dialog-background)) !important;
|
||||
border: 0.5px solid light-dark(rgba(0, 0, 0, 0.4), var(--zen-dialog-background)) !important;
|
||||
outline: 1px solid light-dark(transparent, rgba(168, 168, 169, 0.50)) !important;
|
||||
box-shadow: 0 10px 8px rgba(0, 0 , 0, 0.15) !important;
|
||||
outline-offset: -1.5px;
|
||||
outline-offset: -2px;
|
||||
|
||||
@media not (prefers-reduced-motion: reduce) {
|
||||
animation: zen-dialog-fade-in 0.3s ease-out;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding: 8px;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,12 @@
|
||||
white-space: nowrap;
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
transform: translateY(-50%);
|
||||
width: calc(100% - 40px);
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.zen-sidebar-notification-close-button {
|
||||
|
||||
@@ -495,7 +495,7 @@
|
||||
border-radius: 99px;
|
||||
width: var(--size-item-large);
|
||||
height: var(--size-item-large);
|
||||
background: var(--button-background-color-primary);
|
||||
background: var(--zen-sidebar-themed-icon-fill);
|
||||
opacity: 0.6;
|
||||
transition:
|
||||
transform 0.12s ease-in-out,
|
||||
@@ -540,6 +540,10 @@
|
||||
|
||||
& toolbarbutton {
|
||||
margin: 0;
|
||||
|
||||
&[disabled] {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,7 +625,7 @@
|
||||
color: var(--button-primary-color);
|
||||
|
||||
&::before {
|
||||
background: var(--button-background-color-primary);
|
||||
background: var(--zen-sidebar-themed-icon-fill);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,4 +790,8 @@
|
||||
@media not -moz-pref("zen.view.enable-loading-indicator") {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root[inDOMFullscreen="true"] & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
123
src/zen/common/sys/ui/ZenSpaceRoutingNavigation.sys.mjs
Normal file
123
src/zen/common/sys/ui/ZenSpaceRoutingNavigation.sys.mjs
Normal file
@@ -0,0 +1,123 @@
|
||||
// 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 { ZenUIComponent } from "resource:///modules/zen/ui/ZenUIComponent.sys.mjs";
|
||||
|
||||
/**
|
||||
* Per-window listener that re-routes in-place navigations for Space Routing.
|
||||
*
|
||||
* When any top-level navigation (link click, address bar, JS redirect, form
|
||||
* submit, ...) targets a URL whose rule points at a *different* space than the
|
||||
* one the tab currently lives in, the load is cancelled and re-opened in a new
|
||||
* tab. The new tab flows through tabbrowser's addTab() routing, which moves it
|
||||
* into the matching space.
|
||||
*/
|
||||
export class ZenSpaceRoutingNavigation extends ZenUIComponent {
|
||||
init() {
|
||||
this.listenBrowserTabsProgress();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MozBrowser} aBrowser - The browser the state change happened in
|
||||
* @param {nsIWebProgress} aWebProgress - The web progress
|
||||
* @param {nsIRequest} aRequest - The request driving the state change
|
||||
* @param {number} aStateFlags - The nsIWebProgressListener state flags
|
||||
*/
|
||||
onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags) {
|
||||
const wpl = Ci.nsIWebProgressListener;
|
||||
if (
|
||||
!aWebProgress?.isTopLevel ||
|
||||
!(aStateFlags & wpl.STATE_START) ||
|
||||
!(aStateFlags & wpl.STATE_IS_DOCUMENT) ||
|
||||
aStateFlags & wpl.STATE_RESTORING
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The tab we spawn for a route must be allowed to load once without being
|
||||
// redirected again, regardless of when its workspace attribute lands.
|
||||
if (aBrowser._zenSkipNavRouteOnce) {
|
||||
aBrowser._zenSkipNavRouteOnce = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let uri;
|
||||
try {
|
||||
uri = aRequest.QueryInterface(Ci.nsIChannel).URI;
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
if (!uri || !(uri.schemeIs("http") || uri.schemeIs("https"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't disturb a tab that is merely (re)loading the page it already shows:
|
||||
// a reload, a session restore, or a tab that was already sitting on this URL
|
||||
// before the rule was set. At STATE_START the browser's currentURI still
|
||||
// points at the existing document, so an equal target means this isn't a
|
||||
// new navigation worth routing.
|
||||
let currentURI = null;
|
||||
try {
|
||||
currentURI = aBrowser.currentURI;
|
||||
} catch (e) {
|
||||
currentURI = null;
|
||||
}
|
||||
if (currentURI?.equals(uri)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const win = this.window;
|
||||
const gBrowser = win.gBrowser;
|
||||
const tab = gBrowser.getTabForBrowser(aBrowser);
|
||||
if (
|
||||
!tab ||
|
||||
tab.pinned ||
|
||||
tab.hasAttribute("zen-empty-tab") ||
|
||||
tab.hasAttribute("zen-glance-tab")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentWorkspaceId = tab.getAttribute("zen-workspace-id");
|
||||
if (
|
||||
!win.gZenSpaceRoutingManager.shouldRedirectNavigation(
|
||||
uri.spec,
|
||||
currentWorkspaceId,
|
||||
win
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Under Fission the parent-side aRequest is a RemoteWebProgress stand-in
|
||||
// whose cancel()/loadInfo throw NS_ERROR_NOT_IMPLEMENTED (the real channel
|
||||
// lives in the content process). Stop the in-place load through the browser,
|
||||
// which proxies the request to the content process.
|
||||
try {
|
||||
aBrowser.stop();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
const urlToOpen = uri.spec;
|
||||
|
||||
// loadInfo isn't reachable on the remote request, so use the navigating
|
||||
// page as the triggering principal (correct for link clicks), with a null
|
||||
// principal as the safe last resort.
|
||||
const principal =
|
||||
aBrowser.contentPrincipal ||
|
||||
Services.scriptSecurityManager.createNullPrincipal({});
|
||||
|
||||
// Defer so we don't mutate the tab strip from inside a progress notification.
|
||||
win.setTimeout(() => {
|
||||
const newTab = gBrowser.addTab(urlToOpen, {
|
||||
triggeringPrincipal: principal,
|
||||
ownerTab: tab.isConnected ? tab : null,
|
||||
});
|
||||
if (newTab?.linkedBrowser) {
|
||||
newTab.linkedBrowser._zenSkipNavRouteOnce = true;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
@@ -133,6 +133,10 @@ document.addEventListener(
|
||||
gZenWorkspaces.unloadAllOtherWorkspaces();
|
||||
break;
|
||||
}
|
||||
case "cmd_zenOpenSpaceRoutingSettings": {
|
||||
gZenSpaceRoutingManager.openSpaceRoutingDialog(window);
|
||||
break;
|
||||
}
|
||||
case "cmd_zenNewNavigatorUnsynced":
|
||||
OpenBrowserWindow({ zenSyncedWindow: false });
|
||||
break;
|
||||
|
||||
@@ -168,17 +168,17 @@
|
||||
document.documentElement.setAttribute("zen-no-padding", true);
|
||||
} else {
|
||||
document.documentElement.removeAttribute("zen-no-padding");
|
||||
if (domFullscreen) {
|
||||
const selectedBrowser = gBrowser.selectedBrowser;
|
||||
selectedBrowser.style.paddingRight = "0.5px";
|
||||
window.addEventListener(
|
||||
"MozAfterPaint",
|
||||
() => {
|
||||
selectedBrowser.style.paddingRight = "";
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (domFullscreen) {
|
||||
const selectedBrowser = gBrowser.selectedBrowser;
|
||||
selectedBrowser.style.paddingRight = "0.5px";
|
||||
window.addEventListener(
|
||||
"MozAfterPaint",
|
||||
() => {
|
||||
selectedBrowser.style.paddingRight = "";
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -214,6 +214,7 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
|
||||
skipAnimation: true,
|
||||
ownerTab: currentTab,
|
||||
triggeringPrincipal: data.triggeringPrincipal,
|
||||
skipRoute: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,4 +19,5 @@ DIRS += [
|
||||
"sessionstore",
|
||||
"share",
|
||||
"spaces",
|
||||
"space-routing",
|
||||
]
|
||||
|
||||
@@ -521,10 +521,13 @@ class nsZenWindowSync {
|
||||
if (flags & SYNC_FLAG_ICON) {
|
||||
aTargetItem.zenStaticIcon = aOriginalItem.zenStaticIcon;
|
||||
if (gBrowser.isTab(aOriginalItem)) {
|
||||
gBrowser.setIcon(
|
||||
aTargetItem,
|
||||
aOriginalItem.getAttribute("image") || gBrowser.getIcon(aOriginalItem)
|
||||
);
|
||||
try {
|
||||
gBrowser.setIcon(
|
||||
aTargetItem,
|
||||
aOriginalItem.getAttribute("image") ||
|
||||
gBrowser.getIcon(aOriginalItem)
|
||||
);
|
||||
} catch {}
|
||||
} else if (aOriginalItem.isZenFolder) {
|
||||
// Icons are a zen-only feature for tab groups.
|
||||
gZenFolders.setFolderUserIcon(aTargetItem, aOriginalItem.iconURL);
|
||||
@@ -1542,6 +1545,7 @@ class nsZenWindowSync {
|
||||
console.error(`Error moving active tabs to other windows on close:`, e);
|
||||
}
|
||||
resolve();
|
||||
this.#docShellSwitchPromise = null;
|
||||
}
|
||||
|
||||
on_WindowCloseAndBrowserFlushed(aBrowsers) {
|
||||
|
||||
462
src/zen/space-routing/ZenSpaceRoutingDialog.mjs
Normal file
462
src/zen/space-routing/ZenSpaceRoutingDialog.mjs
Normal file
@@ -0,0 +1,462 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
const { gZenSpaceRoutingManager } = ChromeUtils.importESModule(
|
||||
"resource:///modules/zen/spacerouting/ZenSpaceRoutingManager.sys.mjs"
|
||||
);
|
||||
|
||||
export class nsZenSpaceRoutingDialog {
|
||||
doc = null;
|
||||
editorWindow = null;
|
||||
openerWindow = null;
|
||||
|
||||
static OBSERVERS = ["zen-space-routing-kill"];
|
||||
|
||||
/**
|
||||
* Creates a new Space Routing dialog controller.
|
||||
*
|
||||
* @param {Document} doc - The document object for the dialog window.
|
||||
* @param {Window} editorWindow - The Space Routing dialog window.
|
||||
* @param {Window} openerWindow - The browser window that opened the dialog.
|
||||
*/
|
||||
constructor(doc, editorWindow, openerWindow) {
|
||||
this.doc = doc;
|
||||
this.editorWindow = editorWindow;
|
||||
this.openerWindow = openerWindow;
|
||||
|
||||
this.killOtherShareInstances();
|
||||
|
||||
nsZenSpaceRoutingDialog.OBSERVERS.forEach(observe => {
|
||||
Services.obs.addObserver(this, observe);
|
||||
});
|
||||
|
||||
this.init();
|
||||
this.editorWindow.addEventListener("unload", () => this.uninit(), {
|
||||
once: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the boost share instance by setting up event listeners for all UI controls.
|
||||
*/
|
||||
init() {
|
||||
this.editorWindow.addEventListener("unload", () => this.handleClose(), {
|
||||
once: true,
|
||||
});
|
||||
|
||||
this.doc
|
||||
.getElementById("sr-close")
|
||||
.addEventListener("click", this.onClosePressed.bind(this));
|
||||
this.doc
|
||||
.getElementById("sr-new-route")
|
||||
.addEventListener("click", this.onNewRoutePressed.bind(this));
|
||||
|
||||
const defaultRouteSelect = this.doc.getElementById(
|
||||
"sr-default-external-open-in"
|
||||
);
|
||||
this.createOpenInList(
|
||||
defaultRouteSelect,
|
||||
gZenSpaceRoutingManager.getDefaultExternalRoute()
|
||||
);
|
||||
|
||||
defaultRouteSelect.addEventListener("command", e =>
|
||||
this.onRouteDefaultExternalChange(e.target.value)
|
||||
);
|
||||
|
||||
this.doc.addEventListener("keydown", event => {
|
||||
if (
|
||||
event.key === "Escape" ||
|
||||
(event.key === "w" && (event.ctrlKey || event.metaKey))
|
||||
) {
|
||||
this.onClosePressed();
|
||||
}
|
||||
});
|
||||
|
||||
this.initRouteList();
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the routes list and loads all current routes from the disk
|
||||
*/
|
||||
initRouteList() {
|
||||
const allRoutes = gZenSpaceRoutingManager.getAllRoutes();
|
||||
allRoutes.forEach(r => this.createRouteElement(r));
|
||||
}
|
||||
|
||||
/**
|
||||
* Will create a new route and update the route list
|
||||
*/
|
||||
onNewRoutePressed() {
|
||||
const newRoute = gZenSpaceRoutingManager.createNewRoute();
|
||||
this.createRouteElement(newRoute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will remove a route and update the list
|
||||
*
|
||||
* @param {string} routeId - The unique ID of the affected route
|
||||
* @param {string} containerElement - The container element of the route in the list
|
||||
*/
|
||||
onRemoveRoutePressed(routeId, containerElement) {
|
||||
gZenSpaceRoutingManager.removeRoute(routeId);
|
||||
containerElement.remove();
|
||||
|
||||
this.updateShowNoRouteText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will create the rule element content and inject it into the ui
|
||||
*
|
||||
* @param {object} route - The target route
|
||||
* @returns {Element} The created element for the route
|
||||
*/
|
||||
createRouteElement(route) {
|
||||
const container = this.doc.getElementById("sr-content");
|
||||
|
||||
const root = this.doc.createXULElement("vbox");
|
||||
root.setAttribute("routeId", route.id);
|
||||
root.className = "sr-rule-container";
|
||||
|
||||
// ---- Top row
|
||||
|
||||
const topRow = this.doc.createXULElement("hbox");
|
||||
topRow.className = "sr-rule-row sr-rule-top";
|
||||
|
||||
const topLabelContainer = this.doc.createXULElement("hbox");
|
||||
topLabelContainer.className = "sr-label-container";
|
||||
|
||||
const urlIcon = this.doc.createXULElement("image");
|
||||
urlIcon.className = "sr-url-icon";
|
||||
|
||||
const urlLabel = this.doc.createXULElement("label");
|
||||
urlLabel.className = "sr-label";
|
||||
urlLabel.setAttribute("data-l10n-id", "zen-space-routing-url");
|
||||
|
||||
topLabelContainer.append(urlIcon, urlLabel);
|
||||
|
||||
// Match type
|
||||
|
||||
const matchTypeMenulist = this.doc.createXULElement("menulist");
|
||||
matchTypeMenulist.className = "select match-type-select";
|
||||
|
||||
const matchTypePopup = this.doc.createXULElement("menupopup");
|
||||
matchTypeMenulist.appendChild(matchTypePopup);
|
||||
|
||||
["contains", "equal-to", "regex"].forEach(id => {
|
||||
const menuItem = this.doc.createXULElement("menuitem");
|
||||
menuItem.setAttribute("data-l10n-id", `zen-space-routing-${id}`);
|
||||
menuItem.setAttribute("value", id);
|
||||
matchTypePopup.appendChild(menuItem);
|
||||
});
|
||||
|
||||
matchTypeMenulist.value = route.matchType;
|
||||
|
||||
// Input domain
|
||||
|
||||
const input = this.doc.createElement("input");
|
||||
input.className = "input";
|
||||
input.value = route.reference;
|
||||
this.updateInputPlaceholder(route.matchType, input);
|
||||
|
||||
const removeButton = this.doc.createXULElement("button");
|
||||
removeButton.className = "sr-remove";
|
||||
|
||||
topRow.append(topLabelContainer, matchTypeMenulist, input, removeButton);
|
||||
|
||||
// ---- Bottom row
|
||||
|
||||
const bottomRow = this.doc.createXULElement("hbox");
|
||||
bottomRow.className = "sr-rule-row sr-rule-bottom";
|
||||
|
||||
const bottomLabelContainer = this.doc.createXULElement("hbox");
|
||||
bottomLabelContainer.className = "sr-label-container";
|
||||
|
||||
const openInIcon = this.doc.createXULElement("image");
|
||||
openInIcon.className = "sr-open-in-icon";
|
||||
|
||||
const openInLabel = this.doc.createXULElement("label");
|
||||
openInLabel.className = "sr-label";
|
||||
openInLabel.setAttribute("data-l10n-id", "zen-space-routing-open-in");
|
||||
|
||||
bottomLabelContainer.append(openInIcon, openInLabel);
|
||||
|
||||
// Open in
|
||||
|
||||
const openInMenulist = this.doc.createXULElement("menulist");
|
||||
openInMenulist.className = "select open-in-select";
|
||||
|
||||
const openInMenupopup = this.doc.createXULElement("menupopup");
|
||||
openInMenulist.appendChild(openInMenupopup);
|
||||
|
||||
this.createOpenInList(openInMenulist, route.openIn);
|
||||
|
||||
bottomRow.append(bottomLabelContainer, openInMenulist);
|
||||
|
||||
root.append(topRow, bottomRow);
|
||||
|
||||
root.style.display = "none";
|
||||
container.appendChild(root);
|
||||
|
||||
// Wait for l10n to catch up and then show the element to avoid flickering.
|
||||
this.editorWindow.promiseDocumentFlushed(() =>
|
||||
this.editorWindow.requestAnimationFrame(() => {
|
||||
root.style.display = "";
|
||||
input.focus();
|
||||
})
|
||||
);
|
||||
|
||||
removeButton.addEventListener("click", () => {
|
||||
this.onRemoveRoutePressed(route.id, root);
|
||||
});
|
||||
|
||||
input.addEventListener("input", e =>
|
||||
this.onRouteReferenceChange(e.target.value, route.id, input)
|
||||
);
|
||||
matchTypeMenulist.addEventListener("command", e =>
|
||||
this.onRouteMatchTypeChange(e.target.value, route.id, input)
|
||||
);
|
||||
openInMenulist.addEventListener("command", e =>
|
||||
this.onRouteOpenInChange(e.target.value, route.id)
|
||||
);
|
||||
|
||||
this.updateShowNoRouteText();
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the text for when no routes are
|
||||
* created should be displayed
|
||||
*/
|
||||
updateShowNoRouteText() {
|
||||
const container = this.doc.getElementById("sr-content");
|
||||
const noRoutesText = this.doc.getElementById("sr-empty-content");
|
||||
|
||||
// One because of the element itself
|
||||
noRoutesText.style.display =
|
||||
container.children.length == 1 ? "flex" : "none";
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the reference text changes
|
||||
*
|
||||
* @param {string} value - The new value
|
||||
* @param {string} routeId - The ID of the affected route
|
||||
* @param {Element} input - The input element
|
||||
*/
|
||||
onRouteReferenceChange(value, routeId, input) {
|
||||
const route = gZenSpaceRoutingManager.getRoute(routeId);
|
||||
route.reference = value;
|
||||
|
||||
this.updateInputPlaceholder(route.matchType, input);
|
||||
|
||||
// Don't update the route if the regex is invalid
|
||||
if (route.matchType == "regex") {
|
||||
if (!this.onCheckRegexValid(input)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gZenSpaceRoutingManager.updateRoute(route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the open in attribute changes
|
||||
*
|
||||
* @param {string} value - The new value
|
||||
* @param {string} routeId - The ID of the affected route
|
||||
*/
|
||||
onRouteOpenInChange(value, routeId) {
|
||||
const route = gZenSpaceRoutingManager.getRoute(routeId);
|
||||
route.openIn = value;
|
||||
gZenSpaceRoutingManager.updateRoute(route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the route match type changes
|
||||
*
|
||||
* @param {string} value - The new value
|
||||
* @param {string} routeId - The ID of the affected route
|
||||
* @param {Element} input - The text input
|
||||
*/
|
||||
onRouteMatchTypeChange(value, routeId, input) {
|
||||
const route = gZenSpaceRoutingManager.getRoute(routeId);
|
||||
route.matchType = value;
|
||||
|
||||
this.updateInputPlaceholder(route.matchType, input);
|
||||
|
||||
// Don't update the route if the regex is invalid
|
||||
if (route.matchType == "regex") {
|
||||
if (!this.onCheckRegexValid(input)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gZenSpaceRoutingManager.updateRoute(route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the input placeholder based on the
|
||||
* current route match type
|
||||
*
|
||||
* @param {string} matchType - The match type (e.g. "contains", "equal-to", "regex")
|
||||
* @param {Element} input - The input element
|
||||
*/
|
||||
updateInputPlaceholder(matchType, input) {
|
||||
switch (matchType) {
|
||||
case "regex":
|
||||
input.placeholder = "zen-browser\\.app";
|
||||
break;
|
||||
default:
|
||||
input.placeholder = "zen-browser.app";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will validate and return the validity of the
|
||||
* regex. Applies a tint to the input if an error occurs.
|
||||
*
|
||||
* @param {Element} input - The input element for the regex
|
||||
* @returns {bool} True if regex is valid
|
||||
*/
|
||||
onCheckRegexValid(input) {
|
||||
const reference = input.value;
|
||||
|
||||
// Ignore empty
|
||||
if (reference.trim() == "") {
|
||||
input.classList.remove("invalid");
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
new RegExp(reference);
|
||||
} catch (e) {
|
||||
input.classList.add("invalid");
|
||||
return false;
|
||||
}
|
||||
input.classList.remove("invalid");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the default external route changes
|
||||
*
|
||||
* @param {string} value - The new value
|
||||
*/
|
||||
onRouteDefaultExternalChange(value) {
|
||||
gZenSpaceRoutingManager.setDefaultExternalRoute(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the options list selects
|
||||
*
|
||||
* @param {Element} selectElement - The menulist element
|
||||
* @param {string} value - The initial value
|
||||
*/
|
||||
async createOpenInList(selectElement, value) {
|
||||
const popupElement =
|
||||
selectElement.querySelector("menupopup") || selectElement;
|
||||
popupElement.replaceChildren(); // Clear existing
|
||||
|
||||
const [openInSpace, mostRecentSpace] = await this.doc.l10n.formatMessages([
|
||||
"zen-space-routing-open-in-space",
|
||||
"zen-space-routing-most-recent-space",
|
||||
]);
|
||||
|
||||
const sectionHeader = this.doc.createXULElement("menuitem");
|
||||
sectionHeader.setAttribute("label", openInSpace.value);
|
||||
sectionHeader.setAttribute("disabled", "true");
|
||||
sectionHeader.classList.add("menu-section-header");
|
||||
popupElement.appendChild(sectionHeader);
|
||||
|
||||
let availOptions = [];
|
||||
|
||||
let createXulItem = (text, id, iconPath = null) => {
|
||||
if (text === "sep") {
|
||||
popupElement.appendChild(this.doc.createXULElement("menuseparator"));
|
||||
return;
|
||||
}
|
||||
|
||||
availOptions.push(id || text);
|
||||
const menuItem = this.doc.createXULElement("menuitem");
|
||||
menuItem.setAttribute("label", text);
|
||||
menuItem.setAttribute("value", id || text);
|
||||
|
||||
if (iconPath) {
|
||||
if (iconPath.startsWith("chrome://")) {
|
||||
menuItem.setAttribute("class", "menuitem-iconic");
|
||||
menuItem.setAttribute("image", iconPath);
|
||||
} else {
|
||||
menuItem.setAttribute("label", `${iconPath} ${text}`);
|
||||
}
|
||||
}
|
||||
|
||||
popupElement.appendChild(menuItem);
|
||||
};
|
||||
|
||||
const workspaces = this.openerWindow.gZenWorkspaces.getWorkspaces();
|
||||
|
||||
createXulItem(mostRecentSpace.value, "most-recent-space");
|
||||
createXulItem("sep");
|
||||
|
||||
workspaces.forEach(workspace => {
|
||||
createXulItem(workspace.name, workspace.uuid, workspace.icon);
|
||||
});
|
||||
|
||||
// Check if the workspace still exists, if not use default
|
||||
if (availOptions.includes(value)) {
|
||||
selectElement.value = value;
|
||||
} else {
|
||||
selectElement.value = "most-recent-space";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninitializes the boost editor by cleaning up event listeners and observers.
|
||||
*/
|
||||
uninit() {
|
||||
nsZenSpaceRoutingDialog.OBSERVERS.forEach(observe => {
|
||||
Services.obs.removeObserver(this, observe);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Kills all other Space Routing dialog instances
|
||||
*/
|
||||
killOtherShareInstances() {
|
||||
Services.obs.notifyObservers(null, "zen-space-routing-kill");
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer callback that handles notifications from the observer service.
|
||||
* Closes the control window when a 'zen-space-routing-kill' notification is received.
|
||||
*
|
||||
* @param {object} subject - The subject of the notification.
|
||||
* @param {string} topic - The topic of the notification.
|
||||
*/
|
||||
observe(subject, topic) {
|
||||
switch (topic) {
|
||||
case "zen-space-routing-kill":
|
||||
this.editorWindow.close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when the user presses the close button
|
||||
*/
|
||||
onClosePressed() {
|
||||
this.editorWindow.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the window close event
|
||||
*/
|
||||
handleClose() {
|
||||
gZenSpaceRoutingManager.saveRoutes();
|
||||
}
|
||||
}
|
||||
452
src/zen/space-routing/ZenSpaceRoutingManager.sys.mjs
Normal file
452
src/zen/space-routing/ZenSpaceRoutingManager.sys.mjs
Normal file
@@ -0,0 +1,452 @@
|
||||
/* 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 { JSONFile } from "resource://gre/modules/JSONFile.sys.mjs";
|
||||
|
||||
class nsZenSpaceRoutingManager {
|
||||
#file = null;
|
||||
#saveFilename = "zen-space-routing.jsonlz4";
|
||||
|
||||
static SKIP_TYPE = {
|
||||
NONE: "none",
|
||||
SKIPPED_TAB: "skipped_tab",
|
||||
RESTORED_TAB: "restored_tab",
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.#readFromDisk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that will be executed from tabbrowser.js
|
||||
* This method can be used to stop the tab from being created.
|
||||
*
|
||||
* @param {string} uriString - The URI as a string
|
||||
* @param {object} options - The tab creation options
|
||||
* @param {Window} win - The window which the tab will be added to
|
||||
* @returns {object} Returns an object with { shouldEarlyExit, userContextId, isRouteFound, targetRoute }
|
||||
*/
|
||||
onBeforeAddTab(uriString, options, win) {
|
||||
let userContextId = null;
|
||||
let isRouteFound = false;
|
||||
let targetRoute = null;
|
||||
|
||||
if (
|
||||
this.#shouldSkipProcessing(options, win) !=
|
||||
nsZenSpaceRoutingManager.SKIP_TYPE.NONE
|
||||
) {
|
||||
return {
|
||||
shouldEarlyExit: false,
|
||||
userContextId,
|
||||
isRouteFound,
|
||||
targetRoute,
|
||||
};
|
||||
}
|
||||
|
||||
targetRoute = this.routeUri(uriString, options);
|
||||
switch (targetRoute) {
|
||||
case "most-recent-space":
|
||||
break;
|
||||
default: {
|
||||
const targetWorkspace =
|
||||
win?.gZenWorkspaces?.getWorkspaceFromId(targetRoute);
|
||||
|
||||
if (targetWorkspace) {
|
||||
userContextId = targetWorkspace.containerTabId;
|
||||
isRouteFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { shouldEarlyExit: false, userContextId, isRouteFound, targetRoute };
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that will be executed from tabbrowser.js
|
||||
*
|
||||
* @param {string} uriString - The URI as a string
|
||||
* @param {Element} newTab - The tab element
|
||||
* @param {object} options - The tab creation options
|
||||
* @param {Window} win - The window which the tab was added to
|
||||
* @param {object} [beforeResult] - The result returned by onBeforeAddTab for
|
||||
* this tab. When present its precomputed targetRoute is reused instead of
|
||||
* running routeUri() a second time.
|
||||
*/
|
||||
onAfterAddTab(uriString, newTab, options, win, beforeResult) {
|
||||
const targetRoute = beforeResult?.targetRoute;
|
||||
if (!targetRoute) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#routeToWorkspace(targetRoute, newTab, win);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether an in-place top-level navigation should be pulled out of
|
||||
* the current tab and re-opened in a new tab, so that addTab()'s routing can
|
||||
* move it into the space its rule points at.
|
||||
*
|
||||
* Only navigations whose rule targets a *different* space than the one the
|
||||
* navigating tab already lives in are redirected. Staying put when the tab is
|
||||
* already in the destination space keeps normal browsing in place and also
|
||||
* prevents the freshly routed tab from being redirected again (infinite loop).
|
||||
*
|
||||
* @param {string} uriString - The destination URI
|
||||
* @param {string|null} currentWorkspaceId - The zen-workspace-id of the navigating tab
|
||||
* @param {Window} win - The owning browser window
|
||||
* @returns {boolean} True when the navigation should open in a new routed tab
|
||||
*/
|
||||
shouldRedirectNavigation(uriString, currentWorkspaceId, win) {
|
||||
if (!win?.gZenWorkspaces?.workspaceEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetRoute = this.routeUri(uriString, { fromExternal: false });
|
||||
|
||||
// No specific destination, or the tab is already where the rule points.
|
||||
if (
|
||||
targetRoute === "most-recent-space" ||
|
||||
targetRoute === currentWorkspaceId
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only redirect when the destination space actually exists.
|
||||
return !!win.gZenWorkspaces.getWorkspaceFromId(targetRoute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the tab should be processed or not
|
||||
*
|
||||
* @param {object} options - The tab creation options
|
||||
* @param {Window} win - The owning window
|
||||
* @returns {SKIP_TYPE} The type of skip or null if not skipped
|
||||
*/
|
||||
#shouldSkipProcessing(options, win) {
|
||||
if (options.skipRoute || options.pinned || options.tabGroup) {
|
||||
return nsZenSpaceRoutingManager.SKIP_TYPE.SKIPPED_TAB;
|
||||
}
|
||||
|
||||
// addTab() is being called when the session restores.
|
||||
// To avoid automatically routing these tabs,
|
||||
// a check if the restore is already complete is needed
|
||||
if (!win.gZenStartup.isReady) {
|
||||
return nsZenSpaceRoutingManager.SKIP_TYPE.RESTORED_TAB;
|
||||
}
|
||||
|
||||
return nsZenSpaceRoutingManager.SKIP_TYPE.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will route the given tab to a space if a rule applies
|
||||
*
|
||||
* @param {string} targetRoute - The precomputed route for the tab
|
||||
* @param {Element} newTab - The tab element
|
||||
* @param {Window} win - The window which the tab was added to
|
||||
* @private
|
||||
*/
|
||||
async #routeToWorkspace(targetRoute, newTab, win) {
|
||||
try {
|
||||
if (!newTab || !newTab.parentNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (targetRoute) {
|
||||
case "most-recent-space":
|
||||
break;
|
||||
|
||||
default: {
|
||||
const workspaces = win?.gZenWorkspaces;
|
||||
const targetWorkspace = workspaces?.getWorkspaceFromId?.(targetRoute);
|
||||
|
||||
if (targetWorkspace) {
|
||||
workspaces.moveTabToWorkspace(newTab, targetWorkspace.uuid);
|
||||
const mostRecentWindow =
|
||||
Services.wm.getMostRecentWindow("navigator:browser");
|
||||
const isOriginatingWindow = win === mostRecentWindow;
|
||||
if (isOriginatingWindow) {
|
||||
win.gZenWorkspaces.lastSelectedWorkspaceTabs[
|
||||
targetWorkspace.uuid
|
||||
] = newTab;
|
||||
await win.gZenWorkspaces.changeWorkspace(targetWorkspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("[ZenSpaceRouting]: Error moving tab to workspace:", err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will give the id of the workspace this uri will
|
||||
* route to, or "most-recent-space"
|
||||
*
|
||||
* @param {string} uriString - The uri which will be routed
|
||||
* @param {object} options - The tab creation options
|
||||
* @returns {string} Route instructions
|
||||
*/
|
||||
routeUri(uriString, options) {
|
||||
const isExternal = options.fromExternal;
|
||||
|
||||
// Go over all routes and return the open type for the first match
|
||||
const allRoutes = this.getAllRoutes();
|
||||
for (const route of allRoutes) {
|
||||
if (this.isRouteMatching(uriString, route)) {
|
||||
return route.openIn;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing matches and it's an external link,
|
||||
// use the default external route
|
||||
if (isExternal) {
|
||||
return this.getDefaultExternalRoute();
|
||||
}
|
||||
|
||||
// If nothing matches, open in most recent space
|
||||
return "most-recent-space";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given rule matches a uriString
|
||||
*
|
||||
* @param {string} uriString - The uri
|
||||
* @param {object} route - The route
|
||||
* @returns {boolean} True if the rule matches
|
||||
*/
|
||||
isRouteMatching(uriString, route) {
|
||||
if (typeof uriString !== "string" || typeof route?.reference !== "string") {
|
||||
return false;
|
||||
}
|
||||
|
||||
let reference = route.reference.toLowerCase();
|
||||
if (reference.trim() == "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uri = uriString.toLowerCase();
|
||||
switch (route.matchType) {
|
||||
case "contains":
|
||||
if (uri.includes(reference)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "equal-to":
|
||||
if (this.#normalizeURL(uri) == this.#normalizeURL(reference)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case "regex": {
|
||||
let unmodifiedReference = route.reference;
|
||||
try {
|
||||
// Use unmodified parameters for the regex test
|
||||
const regex = new RegExp(unmodifiedReference);
|
||||
if (regex.test(uriString)) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
"[ZenSpaceRouting] Failed to resolve regular expression:",
|
||||
unmodifiedReference,
|
||||
e
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will remove any protocol sequences to normalize the url
|
||||
*
|
||||
* @param {string} uriString - The url
|
||||
* @returns {string} The normalized url
|
||||
*/
|
||||
#normalizeURL(uriString) {
|
||||
if (!uriString) {
|
||||
return "";
|
||||
}
|
||||
let clean = uriString.trim();
|
||||
|
||||
// Remove protocol sequences with regex
|
||||
clean = clean.replace(/^https?:\/\//i, "");
|
||||
clean = clean.replace(/^www\./i, "");
|
||||
|
||||
// If there is a trailing slash, remove
|
||||
if (clean.endsWith("/")) {
|
||||
clean = clean.slice(0, -1);
|
||||
}
|
||||
|
||||
return clean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Space Routing editor in a new popup window.
|
||||
*
|
||||
* @param {Window} parentWindow - The parent browser window
|
||||
* @returns {Window|null} The instanced editor window
|
||||
*/
|
||||
async openSpaceRoutingDialog(parentWindow) {
|
||||
await parentWindow.gDialogBox.open(
|
||||
"chrome://browser/content/zen-components/windows/zen-space-routing.xhtml",
|
||||
{
|
||||
features: "resizable=no",
|
||||
sizeTo: "available",
|
||||
allowDuplicateDialogs: false,
|
||||
parentWindow,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {object} Returns a new empty Space Routing route
|
||||
*/
|
||||
getEmptyRoute() {
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
reference: "",
|
||||
openIn: "most-recent-space",
|
||||
matchType: "contains",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Array<object>} A copy of the routes list
|
||||
*/
|
||||
getAllRoutes() {
|
||||
if (!this.#file?.data?.routes) {
|
||||
return [];
|
||||
}
|
||||
return structuredClone(this.#file.data.routes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific route
|
||||
*
|
||||
* @param {string} id - The ID of the given route
|
||||
* @returns {object|null} The route, or null if no route has the given id
|
||||
*/
|
||||
getRoute(id) {
|
||||
const idx = this.#file.data.routes.findIndex(r => r.id === id);
|
||||
if (idx === -1) {
|
||||
return null;
|
||||
}
|
||||
return structuredClone(this.#file.data.routes[idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will update an existing route
|
||||
*
|
||||
* @param {object} route - The updated route
|
||||
*/
|
||||
updateRoute(route) {
|
||||
const idx = this.#file.data.routes.findIndex(r => r.id === route.id);
|
||||
if (idx === -1) {
|
||||
return;
|
||||
}
|
||||
this.#file.data.routes[idx] = structuredClone(route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new route and returns it
|
||||
*
|
||||
* @returns {object} Returns the empty route
|
||||
*/
|
||||
createNewRoute() {
|
||||
const newRoute = this.getEmptyRoute();
|
||||
this.#file.data.routes.push(newRoute);
|
||||
|
||||
return structuredClone(newRoute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an existing route with the given id
|
||||
*
|
||||
* @param {string} id - The given id
|
||||
*/
|
||||
removeRoute(id) {
|
||||
const objWithIdIndex = this.#file.data.routes.findIndex(r => r.id === id);
|
||||
if (objWithIdIndex === -1) {
|
||||
return;
|
||||
}
|
||||
this.#file.data.routes.splice(objWithIdIndex, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} Returns the default route type for external links
|
||||
*/
|
||||
getDefaultExternalRoute() {
|
||||
return this.#file?.data?.defaultRouteExternal ?? "most-recent-space";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} routeType - Sets the default route type for external links
|
||||
*/
|
||||
setDefaultExternalRoute(routeType) {
|
||||
this.#file.data.defaultRouteExternal = routeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves all routes. The list of
|
||||
* routes is stripped of empty routes
|
||||
* before being saved
|
||||
*/
|
||||
saveRoutes() {
|
||||
this.#file.data.routes = this.#file.data.routes.filter(
|
||||
route => route.reference.trim() !== ""
|
||||
);
|
||||
this.#writeToDisk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the Space Routing data back onto the disk.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
#writeToDisk() {
|
||||
this.#file.saveSoon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads Space Routing data from disk and decompresses it.
|
||||
*
|
||||
* @returns {Promise<Map>} A promise that resolves to an array of Space Routing rules.
|
||||
* @private
|
||||
*/
|
||||
async #readFromDisk() {
|
||||
this.#file = new JSONFile({
|
||||
path: this.#storePath,
|
||||
compression: "lz4",
|
||||
|
||||
dataPostProcessor(data) {
|
||||
if (!data || typeof data !== "object") {
|
||||
data = {};
|
||||
}
|
||||
if (!Array.isArray(data.routes)) {
|
||||
data.routes = [];
|
||||
}
|
||||
if (typeof data.defaultRouteExternal !== "string") {
|
||||
data.defaultRouteExternal = "most-recent-space";
|
||||
}
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
await this.#file.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file path where Space Routing data is stored in the user's profile directory.
|
||||
*
|
||||
* @returns {string} The full path to the Space Routing storage file.
|
||||
* @private
|
||||
*/
|
||||
get #storePath() {
|
||||
const profilePath = PathUtils.profileDir;
|
||||
return PathUtils.join(profilePath, this.#saveFilename);
|
||||
}
|
||||
}
|
||||
|
||||
export const gZenSpaceRoutingManager = new nsZenSpaceRoutingManager();
|
||||
9
src/zen/space-routing/jar.inc.mn
Normal file
9
src/zen/space-routing/jar.inc.mn
Normal file
@@ -0,0 +1,9 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Styles
|
||||
content/browser/zen-styles/zen-space-routing.css (../../zen/space-routing/zen-space-routing.css)
|
||||
|
||||
# Windows
|
||||
* content/browser/zen-components/windows/zen-space-routing.xhtml (../../zen/space-routing/zen-space-routing.inc.xhtml)
|
||||
8
src/zen/space-routing/moz.build
Normal file
8
src/zen/space-routing/moz.build
Normal file
@@ -0,0 +1,8 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES.zen.spacerouting += [
|
||||
"ZenSpaceRoutingDialog.mjs",
|
||||
"ZenSpaceRoutingManager.sys.mjs",
|
||||
]
|
||||
288
src/zen/space-routing/zen-space-routing.css
Normal file
288
src/zen/space-routing/zen-space-routing.css
Normal file
@@ -0,0 +1,288 @@
|
||||
/* 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/. */
|
||||
|
||||
@namespace html "http://www.w3.org/1999/xhtml";
|
||||
@namespace xul "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
:root {
|
||||
--background-color-canvas: light-dark(white, #212223) !important;
|
||||
|
||||
--select-background-color: light-dark(#eceef0, #3e3f43);
|
||||
--input-background-color: light-dark(#f1f2f4, #2c2d31);
|
||||
--hr-color: light-dark(#cdced4, #313235);
|
||||
|
||||
--sr-width: 510px;
|
||||
--sr-height: 500px;
|
||||
|
||||
--content-padding: 26px;
|
||||
--content-padding-vertical: 16px;
|
||||
|
||||
--text-color: light-dark(#4c4c4c, #dbdcdf);
|
||||
--text-color-secondary: light-dark(#5c5e65, #8b8e98);
|
||||
--text-color-error: light-dark(#9d2222, #d03535);
|
||||
|
||||
--rules-gap: 14px;
|
||||
|
||||
--sr-border-radius: 12px;
|
||||
}
|
||||
|
||||
window {
|
||||
height: var(--sr-height);
|
||||
max-height: var(--sr-height);
|
||||
min-height: var(--sr-height);
|
||||
|
||||
width: var(--sr-width);
|
||||
max-width: var(--sr-width);
|
||||
min-width: var(--sr-width);
|
||||
}
|
||||
|
||||
#sr-container {
|
||||
height: var(--sr-height);
|
||||
width: var(--sr-width);
|
||||
|
||||
border-radius: var(--sr-border-radius);
|
||||
overflow: hidden;
|
||||
font-family: system-ui !important;
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#sr-empty-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
gap: 24px;
|
||||
|
||||
position: absolute;
|
||||
left: 84px;
|
||||
right: 84px;
|
||||
|
||||
bottom: 100px;
|
||||
top: 100px;
|
||||
justify-content: center;
|
||||
|
||||
& image {
|
||||
aspect-ratio: 1;
|
||||
height: 75px;
|
||||
|
||||
min-height: 0;
|
||||
max-height: none;
|
||||
max-width: none;
|
||||
min-width: 0;
|
||||
|
||||
color: var(--text-color-secondary);
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.65;
|
||||
}
|
||||
|
||||
& p {
|
||||
font-size: small;
|
||||
opacity: 0.8;
|
||||
color: var(--text-color);
|
||||
}
|
||||
}
|
||||
|
||||
#sr-new-route {
|
||||
padding: 4px 6px !important;
|
||||
}
|
||||
|
||||
html|hr {
|
||||
border-color: var(--hr-color) !important;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-left: 22px;
|
||||
margin-right: 22px;
|
||||
border-width: 0.5px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: medium;
|
||||
color: var(--text-color);
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: small;
|
||||
color: var(--text-color-secondary);
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.select {
|
||||
width: 150px;
|
||||
min-height: unset;
|
||||
height: 26px;
|
||||
padding: 4px;
|
||||
background-color: var(--select-background-color) !important;
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
|
||||
&.match-type-select {
|
||||
width: 100px;
|
||||
}
|
||||
&.open-in-select {
|
||||
width: 165px;
|
||||
}
|
||||
}
|
||||
|
||||
menulist[image]::part(icon) {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
min-width: 16px;
|
||||
min-height: 16px;
|
||||
-moz-context-properties: fill, stroke;
|
||||
fill: currentColor;
|
||||
margin-inline-end: 0;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
.sr-rule-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sr-rule-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
margin: 0 24px;
|
||||
|
||||
& p {
|
||||
color: var(--text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.sr-rule-bottom {
|
||||
margin-left: 87px;
|
||||
}
|
||||
|
||||
.input {
|
||||
background-color: var(--input-background-color);
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
color: var(--text-color-error) !important;
|
||||
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: wavy;
|
||||
text-decoration-thickness: 1px;
|
||||
text-decoration-color: var(--text-color-error);
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: var(--select-background-color) !important;
|
||||
min-height: unset !important;
|
||||
|
||||
padding: 2px !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
margin: 0;
|
||||
|
||||
& hbox {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sr-remove,
|
||||
.close-icon {
|
||||
& hbox {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
opacity: 0.5;
|
||||
appearance: none !important;
|
||||
border: none !important;
|
||||
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
padding: 3px;
|
||||
|
||||
min-width: 0 !important;
|
||||
color: var(--text-color-secondary);
|
||||
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
|
||||
&:not(:hover) {
|
||||
background: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
#sr-header {
|
||||
width: 100%;
|
||||
padding: var(--content-padding) 20px;
|
||||
align-items: center;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sr-left {
|
||||
margin-left: auto;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
& button {
|
||||
color: var(--text-color);
|
||||
opacity: 1;
|
||||
|
||||
&:hover .sr-remove {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#sr-footer {
|
||||
width: 100%;
|
||||
padding: var(--content-padding);
|
||||
align-items: center;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#sr-content {
|
||||
width: 100%;
|
||||
overflow: scroll;
|
||||
padding: 20px var(--content-padding);
|
||||
flex-grow: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--rules-gap);
|
||||
}
|
||||
|
||||
.sr-label-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
color: var(--text-color-secondary);
|
||||
}
|
||||
|
||||
.sr-label {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sr-url-icon,
|
||||
.sr-open-in-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.65;
|
||||
}
|
||||
96
src/zen/space-routing/zen-space-routing.inc.xhtml
Normal file
96
src/zen/space-routing/zen-space-routing.inc.xhtml
Normal file
@@ -0,0 +1,96 @@
|
||||
#filter substitution
|
||||
<?xml version="1.0"?>
|
||||
|
||||
# -*- Mode: HTML -*-
|
||||
#
|
||||
# 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/.
|
||||
|
||||
<!DOCTYPE window>
|
||||
|
||||
<window
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
windowtype="Zen:SpaceRouting"
|
||||
customtitlebar="true"
|
||||
id="zenSpaceRoutingDialog"
|
||||
dialogroot="true"
|
||||
>
|
||||
<linkset>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://browser/content/zen-styles/zen-space-routing.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://global/skin/global.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://browser/content/zen-styles/zen-theme.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
href="chrome://browser/skin/zen-icons/icons.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<html:link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="chrome://browser/content/zen-styles/zen-popup.css"
|
||||
/>
|
||||
<html:link rel="localization" href="browser/zen-space-routing.ftl" />
|
||||
</linkset>
|
||||
|
||||
<vbox id="sr-container">
|
||||
<hbox id="sr-header">
|
||||
<h3 data-l10n-id="zen-space-routing-dialog-title"></h3>
|
||||
<html:div class="sr-left">
|
||||
<button
|
||||
id="sr-new-route"
|
||||
data-l10n-id="zen-space-routing-new-route"
|
||||
></button>
|
||||
<button
|
||||
class="close-icon"
|
||||
data-l10n-id="zen-space-routing-close-button"
|
||||
id="sr-close"
|
||||
></button>
|
||||
</html:div>
|
||||
</hbox>
|
||||
<html:hr />
|
||||
<vbox id="sr-content">
|
||||
<vbox id="sr-empty-content">
|
||||
<image class="sr-airplane"></image>
|
||||
<p data-l10n-id="zen-space-routing-rulepanel-placeholder"></p>
|
||||
</vbox>
|
||||
# All rules will be injected here later
|
||||
</vbox>
|
||||
<html:hr />
|
||||
<hbox id="sr-footer">
|
||||
<h4 data-l10n-id="zen-space-routing-external-default"></h4>
|
||||
<html:div class="sr-left">
|
||||
<menulist class="select" id="sr-default-external-open-in">
|
||||
<menupopup id="sr-default-external-open-in-popup">
|
||||
# Select open in types will be injected here
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</html:div>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<script>
|
||||
const { nsZenSpaceRoutingDialog } = ChromeUtils.importESModule(
|
||||
"resource:///modules/zen/spacerouting/ZenSpaceRoutingDialog.mjs",
|
||||
);
|
||||
const args = window.arguments?.[0] || {};
|
||||
window.spaceroutingDialog = new nsZenSpaceRoutingDialog(
|
||||
document,
|
||||
window,
|
||||
args.parentWindow,
|
||||
);
|
||||
</script>
|
||||
</window>
|
||||
@@ -177,6 +177,7 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
|
||||
|
||||
handleDarkModeChange() {
|
||||
this.updateCurrentWorkspace();
|
||||
Services.obs.notifyObservers(null, "zen-theme-change");
|
||||
}
|
||||
|
||||
get isDarkMode() {
|
||||
@@ -1494,12 +1495,9 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
|
||||
return color;
|
||||
}
|
||||
|
||||
getToolbarColor(isDarkMode = false, accentColor = null) {
|
||||
getToolbarColor(isDarkMode = false) {
|
||||
const opacity = 0.8;
|
||||
let baseColor = isDarkMode ? [255, 255, 255, opacity] : [0, 0, 0, opacity]; // Default toolbar
|
||||
if (accentColor) {
|
||||
return this.blendColors(baseColor.slice(0, 3), accentColor, 75).concat(1);
|
||||
}
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
@@ -1765,7 +1763,7 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
|
||||
docElement.style.setProperty("--zen-primary-color", primaryColor);
|
||||
|
||||
// Set `--toolbox-textcolor` to have a contrast with the primary color
|
||||
let textColor = this.getToolbarColor(isDarkMode, dominantColor);
|
||||
let textColor = this.getToolbarColor(isDarkMode);
|
||||
docElement.style.setProperty(
|
||||
"--toolbox-textcolor",
|
||||
`rgba(${textColor[0]}, ${textColor[1]}, ${textColor[2]}, ${textColor[3]})`
|
||||
@@ -2011,7 +2009,7 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
|
||||
grain: theme.texture ?? 0,
|
||||
isDarkMode,
|
||||
isExplicitMode,
|
||||
toolbarColor: this.getToolbarColor(isDarkMode, dominantColor),
|
||||
toolbarColor: this.getToolbarColor(isDarkMode),
|
||||
primaryColor: this.getAccentColorForUI(dominantColor, isDarkMode),
|
||||
};
|
||||
this.currentOpacity = previousOpacity;
|
||||
|
||||
@@ -15,12 +15,12 @@ class nsZenWorkspaceIcons extends MozXULElement {
|
||||
|
||||
this.initDragAndDrop();
|
||||
this.addEventListener("mouseover", e => {
|
||||
if (this.isReorderMode) {
|
||||
if (e.shiftKey || this.isReorderMode) {
|
||||
return;
|
||||
}
|
||||
const target = e.target.closest("toolbarbutton[zen-workspace-id]");
|
||||
if (target) {
|
||||
this.scrollLeft = target.offsetLeft - 10;
|
||||
target.scrollIntoView({ behavior: "smooth", inline: "nearest" });
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -178,7 +178,7 @@ class nsZenWorkspaceIcons extends MozXULElement {
|
||||
return;
|
||||
}
|
||||
buttons[selected].setAttribute("active", true);
|
||||
this.scrollLeft = buttons[selected].offsetLeft - 10;
|
||||
buttons[selected].scrollIntoView({ behavior: "smooth", inline: "nearest" });
|
||||
this.setAttribute("selected", selected);
|
||||
}
|
||||
|
||||
|
||||
@@ -861,6 +861,7 @@ class nsZenWorkspaces {
|
||||
"Selecting empty tab because startup page didnt select a valid tab"
|
||||
);
|
||||
this.selectEmptyTab();
|
||||
initialTabWasEmpty = true;
|
||||
}
|
||||
this.log("Removing empty tab added by startup page");
|
||||
this._removedByStartupPage = true;
|
||||
@@ -954,7 +955,7 @@ class nsZenWorkspaces {
|
||||
}
|
||||
gZenEmojiPicker.open(anchor, {
|
||||
closeOnSelect: false,
|
||||
allowNone: hasNoIcon,
|
||||
allowNone: !hasNoIcon,
|
||||
onSelect: async icon => {
|
||||
const workspace = this.getWorkspaceFromId(workspaceId);
|
||||
if (!workspace) {
|
||||
@@ -1009,6 +1010,14 @@ class nsZenWorkspaces {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Closing a glance tab tears down the overlay and restores selection
|
||||
// to its parent tab. Don't run the last-tab handling here:
|
||||
// in a pinned-only window the glance child is the only unpinned tab,
|
||||
// so this would switch to an empty tab and clobber the restore-to-parent.
|
||||
if (tab.hasAttribute("glance-id")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let workspaceID = tab.getAttribute("zen-workspace-id");
|
||||
if (!workspaceID) {
|
||||
return null;
|
||||
@@ -1497,7 +1506,6 @@ class nsZenWorkspaces {
|
||||
continue;
|
||||
}
|
||||
|
||||
tab.owner = null;
|
||||
if (container) {
|
||||
if (tab.group?.hasAttribute("split-view-group")) {
|
||||
gBrowser.zenHandleTabMove(tab.group, () => {
|
||||
@@ -2281,6 +2289,27 @@ class nsZenWorkspaces {
|
||||
);
|
||||
}
|
||||
|
||||
onBeforeTabSelect(aTab) {
|
||||
if (this.#inChangingWorkspace) {
|
||||
// Just in case, Let's not do these checks while we are
|
||||
// in the middle of changing workspace,
|
||||
return false;
|
||||
}
|
||||
const tabSpace = aTab?.getAttribute("zen-workspace-id");
|
||||
if (
|
||||
tabSpace &&
|
||||
tabSpace !== this.activeWorkspace &&
|
||||
!aTab.hasAttribute("zen-empty-tab") &&
|
||||
!aTab.hasAttribute("zen-essential")
|
||||
) {
|
||||
this.lastSelectedWorkspaceTabs[tabSpace] =
|
||||
gZenGlanceManager.getTabOrGlanceParent(aTab);
|
||||
this.changeWorkspaceWithID(tabSpace);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_shouldShowTab(tab, workspaceUuid, containerId, workspaces) {
|
||||
const isEssential = tab.getAttribute("zen-essential") === "true";
|
||||
const tabWorkspaceId = tab.getAttribute("zen-workspace-id");
|
||||
@@ -2978,11 +3007,19 @@ class nsZenWorkspaces {
|
||||
|
||||
// Tab browser utilities
|
||||
|
||||
getContextIdIfNeeded(userContextId, fromExternal) {
|
||||
getContextIdIfNeeded(userContextId, fromExternal, triggeringPrincipal) {
|
||||
if (!this.workspaceEnabled) {
|
||||
return [userContextId, false, undefined];
|
||||
}
|
||||
|
||||
if (
|
||||
triggeringPrincipal &&
|
||||
triggeringPrincipal.isAddonOrExpandedAddonPrincipal &&
|
||||
typeof userContextId === "undefined"
|
||||
) {
|
||||
return [userContextId, false, undefined];
|
||||
}
|
||||
|
||||
if (
|
||||
this.shouldForceContainerTabsToWorkspace &&
|
||||
typeof userContextId !== "undefined" &&
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
border-radius: var(--button-border-radius) !important;
|
||||
background: transparent;
|
||||
appearance: unset !important;
|
||||
height: fit-content;
|
||||
@@ -41,6 +40,7 @@
|
||||
fill-opacity: 0.6;
|
||||
-moz-context-properties: fill-opacity, fill;
|
||||
fill: currentColor;
|
||||
scroll-margin: 0 20px;
|
||||
|
||||
& .zen-workspace-icon {
|
||||
pointer-events: none;
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
&[icons-overflow] {
|
||||
gap: 0 !important;
|
||||
justify-content: center;
|
||||
justify-content: safe center;
|
||||
|
||||
& toolbarbutton {
|
||||
margin: 0;
|
||||
@@ -321,8 +321,11 @@ zen-workspace {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
color: var(--toolbox-textcolor);
|
||||
will-change: transform;
|
||||
color: color-mix(in srgb, var(--toolbox-textcolor) 95%, var(--zen-primary-color));
|
||||
|
||||
--tab-selected-bgcolor: color-mix(in srgb, light-dark(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.18)) 95%, var(--zen-primary-color)) !important;
|
||||
--tab-selected-shadow: 0 0.8px 1.5px 0px light-dark(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.05)) !important;
|
||||
--tab-selected-textcolor: color-mix(in srgb, var(--toolbox-textcolor) 95%, var(--zen-primary-color)) !important;
|
||||
|
||||
@media not (prefers-reduced-motion: reduce) {
|
||||
transition: padding-top 0.1s;
|
||||
|
||||
@@ -1226,7 +1226,10 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
const currentTab = gZenGlanceManager.getTabOrGlanceParent(
|
||||
window.gBrowser.selectedTab
|
||||
);
|
||||
const newTab = this.openAndSwitchToTab(url, { inBackground: false });
|
||||
const newTab = this.openAndSwitchToTab(url, {
|
||||
skipRoute: true,
|
||||
inBackground: false,
|
||||
});
|
||||
this.splitTabs([currentTab, newTab], undefined, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -303,8 +303,6 @@
|
||||
border-bottom: 0 solid transparent !important;
|
||||
|
||||
--tab-block-margin: 2px;
|
||||
--tab-selected-bgcolor: light-dark(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.18));
|
||||
--tab-selected-shadow: 0 0.8px 1.5px 0px light-dark(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.05)) !important;
|
||||
grid-gap: 0 !important;
|
||||
|
||||
&[overflow]::after,
|
||||
@@ -1131,7 +1129,6 @@
|
||||
transition:
|
||||
max-height 0.3s ease-out,
|
||||
grid-template-columns 0.3s ease-out;
|
||||
will-change: transform;
|
||||
opacity: 1;
|
||||
--min-essentials-width-wrap: calc(var(--tab-min-height) + 4px);
|
||||
grid-template-columns: repeat(auto-fit, minmax(max(23.7%, var(--min-essentials-width-wrap)), 1fr));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user