mirror of
https://github.com/zen-browser/desktop.git
synced 2026-02-09 21:38:42 +00:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f9a932e77 | ||
|
|
f2603521e5 | ||
|
|
24f695c452 | ||
|
|
f5effd4dcd | ||
|
|
b5bb7d7c8b | ||
|
|
604365dd38 | ||
|
|
466d089fc0 | ||
|
|
e28a10f6a9 | ||
|
|
102be6cd90 | ||
|
|
6e1e1d061b | ||
|
|
43250d6d37 | ||
|
|
12f0c455d1 | ||
|
|
049c3c6f54 | ||
|
|
658ac94334 | ||
|
|
09a90099c7 | ||
|
|
051470f139 | ||
|
|
8f1cb88c11 | ||
|
|
3ef233a4c2 | ||
|
|
38fcd7e872 | ||
|
|
76f17c3a57 | ||
|
|
b5c2451525 | ||
|
|
ba2a854784 |
17
.github/workflows/sync-upstream.yml
vendored
17
.github/workflows/sync-upstream.yml
vendored
@@ -73,15 +73,13 @@ jobs:
|
|||||||
npm run sync
|
npm run sync
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Run formatter
|
- name: Install autopep8
|
||||||
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
|
run: sudo apt install python3-autopep8
|
||||||
run: |
|
|
||||||
sudo apt install python3-autopep8
|
|
||||||
npm run pretty
|
|
||||||
|
|
||||||
- name: Check if any files changed
|
- name: Check if any files changed
|
||||||
id: git-check
|
id: git-check
|
||||||
run: |
|
run: |
|
||||||
|
npm run pretty
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
if [ -n "$(git status --porcelain)" ]; then
|
||||||
echo "files_changed=true" >> $GITHUB_OUTPUT
|
echo "files_changed=true" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
@@ -111,6 +109,15 @@ jobs:
|
|||||||
if: steps.git-check.outputs.files_changed == 'true'
|
if: steps.git-check.outputs.files_changed == 'true'
|
||||||
run: python3 scripts/import_external_tests.py || true
|
run: python3 scripts/import_external_tests.py || true
|
||||||
|
|
||||||
|
- name: Import external patches
|
||||||
|
if: steps.git-check.outputs.files_changed == 'true'
|
||||||
|
run: python3 scripts/import_external_patches.py || true
|
||||||
|
|
||||||
|
- name: Run formatter
|
||||||
|
if: steps.check-upstream-branch.outputs.branch_exists == 'false'
|
||||||
|
run: |
|
||||||
|
npm run pretty
|
||||||
|
|
||||||
- name: Create pull request
|
- name: Create pull request
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v7
|
||||||
if: steps.git-check.outputs.files_changed == 'true'
|
if: steps.git-check.outputs.files_changed == 'true'
|
||||||
|
|||||||
@@ -37,5 +37,6 @@ src/zen/common/ZenEmojis.mjs
|
|||||||
|
|
||||||
src/zen/split-view/zen-decks.css
|
src/zen/split-view/zen-decks.css
|
||||||
src/zen/workspaces/zen-workspaces.css
|
src/zen/workspaces/zen-workspaces.css
|
||||||
|
src/zen/common/styles/zen-toolbar.css
|
||||||
|
|
||||||
*.inc
|
*.inc
|
||||||
|
|||||||
@@ -9,9 +9,6 @@ ac_add_options --with-app-basename=Zen
|
|||||||
# Localization (Must be an absolute path)
|
# Localization (Must be an absolute path)
|
||||||
ac_add_options --with-l10n-base="${topsrcdir}/browser/locales"
|
ac_add_options --with-l10n-base="${topsrcdir}/browser/locales"
|
||||||
|
|
||||||
# See https://github.com/zen-browser/desktop/issues/11917 for future plans.
|
|
||||||
# We should be removing this at some point and start supporting XDG dirs.
|
|
||||||
ac_add_options --with-user-appdir=".${binName}"
|
|
||||||
export MOZ_APP_BASENAME=Zen
|
export MOZ_APP_BASENAME=Zen
|
||||||
export MOZ_BRANDING_DIRECTORY=${brandingDir}
|
export MOZ_BRANDING_DIRECTORY=${brandingDir}
|
||||||
export MOZ_OFFICIAL_BRANDING_DIRECTORY=${brandingDir}
|
export MOZ_OFFICIAL_BRANDING_DIRECTORY=${brandingDir}
|
||||||
@@ -85,6 +82,11 @@ if test "$ZEN_RELEASE"; then
|
|||||||
export MOZ_PACKAGE_JSSHELL=1
|
export MOZ_PACKAGE_JSSHELL=1
|
||||||
|
|
||||||
ac_add_options --disable-crashreporter
|
ac_add_options --disable-crashreporter
|
||||||
|
|
||||||
|
# Experimental flag, enabled only on nightly for Firefox.
|
||||||
|
# Should bring in some nice performance improvements,
|
||||||
|
# but may cause stability issues.
|
||||||
|
ac_add_options --enable-replace-malloc
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ac_add_options --enable-unverified-updates
|
ac_add_options --enable-unverified-updates
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ zen-panel-ui-current-profile-text = current profile
|
|||||||
|
|
||||||
unified-extensions-description = Extensions are used to bring more extra functionality into { -brand-short-name }.
|
unified-extensions-description = Extensions are used to bring more extra functionality into { -brand-short-name }.
|
||||||
tab-context-zen-reset-pinned-tab =
|
tab-context-zen-reset-pinned-tab =
|
||||||
.label = Reset Pinned Tab
|
.label =
|
||||||
|
{ $isEssential ->
|
||||||
|
[true] Reset Essential Tab
|
||||||
|
*[false] Reset Pinned Tab
|
||||||
|
}
|
||||||
.accesskey = R
|
.accesskey = R
|
||||||
tab-context-zen-add-essential =
|
tab-context-zen-add-essential =
|
||||||
.label = Add to Essentials
|
.label = Add to Essentials
|
||||||
@@ -16,7 +20,11 @@ tab-context-zen-remove-essential =
|
|||||||
.label = Remove from Essentials
|
.label = Remove from Essentials
|
||||||
.accesskey = R
|
.accesskey = R
|
||||||
tab-context-zen-replace-pinned-url-with-current =
|
tab-context-zen-replace-pinned-url-with-current =
|
||||||
.label = Replace Pinned URL with Current
|
.label =
|
||||||
|
{ $isEssential ->
|
||||||
|
[true] Replace Essential URL with Current
|
||||||
|
*[false] Replace Pinned URL with Current
|
||||||
|
}
|
||||||
.accesskey = C
|
.accesskey = C
|
||||||
tab-context-zen-edit-title =
|
tab-context-zen-edit-title =
|
||||||
.label = Change Label...
|
.label = Change Label...
|
||||||
|
|||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -5610,9 +5610,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.23",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -54,3 +54,6 @@
|
|||||||
|
|
||||||
- name: zen.view.draggable-sidebar
|
- name: zen.view.draggable-sidebar
|
||||||
value: true
|
value: true
|
||||||
|
|
||||||
|
- name: zen.view.overflow-webext-toolbar
|
||||||
|
value: true
|
||||||
|
|||||||
@@ -32,6 +32,9 @@
|
|||||||
- name: zen.urlbar.show-pip-button
|
- name: zen.urlbar.show-pip-button
|
||||||
value: false
|
value: false
|
||||||
|
|
||||||
|
- name: zen.urlbar.open-on-startup
|
||||||
|
value: true
|
||||||
|
|
||||||
# Mark: Zen suggestions controls
|
# Mark: Zen suggestions controls
|
||||||
|
|
||||||
- name: zen.urlbar.suggestions.quick-actions
|
- name: zen.urlbar.suggestions.quick-actions
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import requests
|
|
||||||
|
|
||||||
BASE_URI = "https://phabricator.services.mozilla.com"
|
|
||||||
OUTPUT_DIR = os.path.join(os.getcwd(), "src", "firefox-patches")
|
|
||||||
|
|
||||||
|
|
||||||
def download_phab_patch(phab_id, output_file):
|
|
||||||
"""Download a Phabricator patch by its ID and save it to output_file."""
|
|
||||||
patch_url = f"{BASE_URI}/{phab_id}?download=true"
|
|
||||||
try:
|
|
||||||
print(f"Downloading patch from {patch_url}")
|
|
||||||
response = requests.get(patch_url)
|
|
||||||
response.raise_for_status() # Raise an error for bad responses
|
|
||||||
with open(output_file, 'wb') as f:
|
|
||||||
f.write(response.content)
|
|
||||||
print(f"Patch saved to {output_file}")
|
|
||||||
except requests.RequestException as e:
|
|
||||||
print(f"Error downloading patch: {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print("Usage: python download_phab_patch.py <PHABRICATOR_ID> [output_file]", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
phab_id = sys.argv[1]
|
|
||||||
output_file = sys.argv[2] if len(sys.argv) > 2 else f"phab_{phab_id}"
|
|
||||||
output_file = os.path.join(OUTPUT_DIR, output_file + ".patch")
|
|
||||||
|
|
||||||
download_phab_patch(phab_id, output_file)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -18,10 +18,18 @@ FILE_PREFIX = """
|
|||||||
# This file is autogenerated by scripts/import_external_tests.py
|
# This file is autogenerated by scripts/import_external_tests.py
|
||||||
# Do not edit manually.
|
# Do not edit manually.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
BROWSER_MANIFEST_LIST_PREFIX = """
|
||||||
BROWSER_CHROME_MANIFESTS += [
|
BROWSER_CHROME_MANIFESTS += [
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
XPCSHELL_MANIFESTS_LIST_PREFIX = """
|
||||||
|
XPCSHELL_TESTS_MANIFESTS += [
|
||||||
|
"""
|
||||||
|
|
||||||
FILE_SUFFIX = "]"
|
FILE_SUFFIX = "]"
|
||||||
|
VALID_MANIFEST_FILES = ["browser.toml", "xpcshell.toml"]
|
||||||
|
|
||||||
|
|
||||||
def get_tests_manifest():
|
def get_tests_manifest():
|
||||||
@@ -38,12 +46,17 @@ def validate_tests_path(path, files, ignore_list):
|
|||||||
for ignore in ignore_list:
|
for ignore in ignore_list:
|
||||||
if ignore not in files:
|
if ignore not in files:
|
||||||
die_with_error(f"Ignore file '{ignore}' not found in tests folder '{path}'")
|
die_with_error(f"Ignore file '{ignore}' not found in tests folder '{path}'")
|
||||||
if "browser.toml" not in files or "browser.js" in ignore_list:
|
if not any(manifest_file in files for manifest_file in VALID_MANIFEST_FILES):
|
||||||
die_with_error(f"'browser.toml' not found in tests folder '{path}'")
|
die_with_error(f"None of the valid manifest files {VALID_MANIFEST_FILES} found in tests folder '{path}'")
|
||||||
|
|
||||||
|
|
||||||
def disable_and_replace_manifest(manifest, output_path):
|
def disable_and_replace_manifest(manifest, output_path):
|
||||||
toml_file = os.path.join(output_path, "browser.toml")
|
toml_file = None
|
||||||
|
for manifest_file in VALID_MANIFEST_FILES:
|
||||||
|
candidate = os.path.join(output_path, manifest_file)
|
||||||
|
if os.path.exists(candidate):
|
||||||
|
toml_file = candidate
|
||||||
|
break
|
||||||
disabled_tests = manifest.get("disable", [])
|
disabled_tests = manifest.get("disable", [])
|
||||||
with open(toml_file, "r") as f:
|
with open(toml_file, "r") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
@@ -90,8 +103,17 @@ def write_moz_build_file(manifest):
|
|||||||
print(f"Writing moz.build file to '{moz_build_path}'")
|
print(f"Writing moz.build file to '{moz_build_path}'")
|
||||||
with open(moz_build_path, "w") as f:
|
with open(moz_build_path, "w") as f:
|
||||||
f.write(FILE_PREFIX)
|
f.write(FILE_PREFIX)
|
||||||
|
f.write(BROWSER_MANIFEST_LIST_PREFIX)
|
||||||
for test_suite in manifest.keys():
|
for test_suite in manifest.keys():
|
||||||
f.write(f'\t"{test_suite}/browser.toml",\n')
|
# add for browser.toml first
|
||||||
|
if not manifest[test_suite].get("xpcshell", False):
|
||||||
|
f.write(f'\t"{test_suite}/browser.toml",\n')
|
||||||
|
f.write(FILE_SUFFIX)
|
||||||
|
f.write(XPCSHELL_MANIFESTS_LIST_PREFIX)
|
||||||
|
for test_suite in manifest.keys():
|
||||||
|
# add for xpcshell.toml
|
||||||
|
if manifest[test_suite].get("xpcshell", False):
|
||||||
|
f.write(f'\t"{test_suite}/xpcshell.toml",\n')
|
||||||
f.write(FILE_SUFFIX)
|
f.write(FILE_SUFFIX)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ def main():
|
|||||||
os.chdir(engine_dir)
|
os.chdir(engine_dir)
|
||||||
|
|
||||||
def run_mach_with_paths(test_paths):
|
def run_mach_with_paths(test_paths):
|
||||||
command = ['./mach', 'mochitest'] + other_args + test_paths
|
command = ['./mach', 'test'] + other_args + test_paths
|
||||||
# Replace the current process with the mach command
|
# Replace the current process with the mach command
|
||||||
os.execvp(command[0], command)
|
os.execvp(command[0], command)
|
||||||
|
|
||||||
|
|||||||
99
scripts/update_external_patches.py
Normal file
99
scripts/update_external_patches.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
# 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 os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from json_with_comments import JSONWithCommentsDecoder
|
||||||
|
|
||||||
|
BASE_URI = "https://phabricator.services.mozilla.com"
|
||||||
|
OUTPUT_DIR = os.path.join(os.getcwd(), "src", "external-patches")
|
||||||
|
|
||||||
|
|
||||||
|
def die(message):
|
||||||
|
print(f"Error: {message}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def download_phab_patch(phab_id, output_file):
|
||||||
|
"""Download a Phabricator patch by its ID and save it to output_file."""
|
||||||
|
patch_url = f"{BASE_URI}/{phab_id}?download=true"
|
||||||
|
try:
|
||||||
|
print(f"Downloading patch from {patch_url}")
|
||||||
|
response = requests.get(patch_url)
|
||||||
|
response.raise_for_status() # Raise an error for bad responses
|
||||||
|
with open(output_file, 'wb') as f:
|
||||||
|
f.write(response.content)
|
||||||
|
print(f"Patch saved to {output_file}")
|
||||||
|
except requests.RequestException as e:
|
||||||
|
die(f"Failed to download patch {phab_id}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def download_patch_from_url(url, output_file):
|
||||||
|
"""Download a patch from a given URL and save it to output_file."""
|
||||||
|
try:
|
||||||
|
print(f"Downloading patch from {url}")
|
||||||
|
response = requests.get(url)
|
||||||
|
response.raise_for_status() # Raise an error for bad responses
|
||||||
|
with open(output_file, 'wb') as f:
|
||||||
|
f.write(response.content)
|
||||||
|
print(f"Patch saved to {output_file}")
|
||||||
|
except requests.RequestException as e:
|
||||||
|
die(f"Failed to download patch from {url}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(os.path.join(OUTPUT_DIR, "manifest.json"), 'r') as f:
|
||||||
|
manifest = json.load(f, cls=JSONWithCommentsDecoder)
|
||||||
|
|
||||||
|
expected_files = set()
|
||||||
|
for patch in manifest:
|
||||||
|
if patch.get("type") == "phabricator":
|
||||||
|
phab_id = patch.get("id")
|
||||||
|
name = patch.get("name")
|
||||||
|
if not phab_id or not name:
|
||||||
|
die(f"Patch entry missing 'id' or 'name': {patch}")
|
||||||
|
name = name.replace(" ", "_").lower()
|
||||||
|
output_file = os.path.join(OUTPUT_DIR, "firefox", f"{name}.patch")
|
||||||
|
print(f"Processing Phabricator patch: {phab_id} -> {output_file}")
|
||||||
|
download_phab_patch(phab_id, output_file)
|
||||||
|
expected_files.add(output_file)
|
||||||
|
elif patch.get("type") == "local":
|
||||||
|
print(f"Local patch: {patch.get('path')}")
|
||||||
|
expected_files.add(os.path.join(OUTPUT_DIR, patch.get("path")))
|
||||||
|
elif patch.get("type") == "patch":
|
||||||
|
url = patch.get("url")
|
||||||
|
dest = patch.get("dest")
|
||||||
|
if not url or not dest:
|
||||||
|
die(f"Patch entry missing 'url' or 'dest': {patch}")
|
||||||
|
filename = url.split("/")[-1]
|
||||||
|
output_file = os.path.join(OUTPUT_DIR, dest, filename)
|
||||||
|
download_patch_from_url(url, output_file)
|
||||||
|
replaces = patch.get("replaces", {})
|
||||||
|
for replace in replaces.keys():
|
||||||
|
value = replaces[replace]
|
||||||
|
with open(output_file, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
if replace not in content:
|
||||||
|
die(f"Replace string '{replace}' not found in {output_file}")
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
f.write(content.replace(replace, value))
|
||||||
|
expected_files.add(output_file)
|
||||||
|
else:
|
||||||
|
die(f"Unknown patch type: {patch.get('type')}")
|
||||||
|
|
||||||
|
# Check for unexpected files in the output directory
|
||||||
|
# and remove them if they are not in the expected_files set.
|
||||||
|
for root, dirs, files in os.walk(OUTPUT_DIR):
|
||||||
|
for file in files:
|
||||||
|
if file.endswith(".patch"):
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
if file_path not in expected_files:
|
||||||
|
print(f"Removing unexpected patch file: {file_path}")
|
||||||
|
os.remove(file_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
|
diff --git a/browser/base/content/navigator-toolbox.inc.xhtml b/browser/base/content/navigator-toolbox.inc.xhtml
|
||||||
index 68c24f730d56f548cf1e286198a04f8363529378..71418c93ce7216d71412f2fa67295322bb73abad 100644
|
index 68c24f730d56f548cf1e286198a04f8363529378..eb9aa5e77cf549062d8d3770f8057ceafe67c317 100644
|
||||||
--- a/browser/base/content/navigator-toolbox.inc.xhtml
|
--- a/browser/base/content/navigator-toolbox.inc.xhtml
|
||||||
+++ b/browser/base/content/navigator-toolbox.inc.xhtml
|
+++ b/browser/base/content/navigator-toolbox.inc.xhtml
|
||||||
@@ -2,7 +2,7 @@
|
@@ -2,7 +2,7 @@
|
||||||
@@ -22,16 +22,17 @@ index 68c24f730d56f548cf1e286198a04f8363529378..71418c93ce7216d71412f2fa67295322
|
|||||||
<toolbar id="TabsToolbar"
|
<toolbar id="TabsToolbar"
|
||||||
class="browser-toolbar browser-titlebar"
|
class="browser-toolbar browser-titlebar"
|
||||||
fullscreentoolbar="true"
|
fullscreentoolbar="true"
|
||||||
@@ -62,6 +61,8 @@
|
@@ -62,6 +61,9 @@
|
||||||
<html:sidebar-pins-promo id="drag-to-pin-promo-card"></html:sidebar-pins-promo>
|
<html:sidebar-pins-promo id="drag-to-pin-promo-card"></html:sidebar-pins-promo>
|
||||||
<arrowscrollbox id="pinned-tabs-container" orient="horizontal" clicktoscroll=""></arrowscrollbox>
|
<arrowscrollbox id="pinned-tabs-container" orient="horizontal" clicktoscroll=""></arrowscrollbox>
|
||||||
<splitter orient="vertical" id="vertical-pinned-tabs-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
<splitter orient="vertical" id="vertical-pinned-tabs-splitter" resizebefore="sibling" resizeafter="none" hidden="true"/>
|
||||||
|
+<html:div id="zen-overflow-extensions-list" skipintoolbarset="true"></html:div>
|
||||||
+<html:div id="zen-essentials" skipintoolbarset="true"></html:div>
|
+<html:div id="zen-essentials" skipintoolbarset="true"></html:div>
|
||||||
+<html:div id="zen-tabs-wrapper">
|
+<html:div id="zen-tabs-wrapper">
|
||||||
<hbox class="tab-drop-indicator" hidden="true"/>
|
<hbox class="tab-drop-indicator" hidden="true"/>
|
||||||
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" clicktoscroll="" scrolledtostart="" scrolledtoend="">
|
<arrowscrollbox id="tabbrowser-arrowscrollbox" orient="horizontal" flex="1" clicktoscroll="" scrolledtostart="" scrolledtoend="">
|
||||||
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="true" visuallyselected="" fadein=""/>
|
<tab is="tabbrowser-tab" class="tabbrowser-tab" selected="true" visuallyselected="" fadein=""/>
|
||||||
@@ -81,6 +82,7 @@
|
@@ -81,6 +83,7 @@
|
||||||
tooltip="dynamic-shortcut-tooltip"
|
tooltip="dynamic-shortcut-tooltip"
|
||||||
data-l10n-id="tabs-toolbar-new-tab"/>
|
data-l10n-id="tabs-toolbar-new-tab"/>
|
||||||
<html:span id="tabbrowser-tab-a11y-desc" hidden="true"/>
|
<html:span id="tabbrowser-tab-a11y-desc" hidden="true"/>
|
||||||
@@ -39,7 +40,7 @@ index 68c24f730d56f548cf1e286198a04f8363529378..71418c93ce7216d71412f2fa67295322
|
|||||||
</tabs>
|
</tabs>
|
||||||
|
|
||||||
<toolbarbutton id="new-tab-button"
|
<toolbarbutton id="new-tab-button"
|
||||||
@@ -106,9 +108,10 @@
|
@@ -106,9 +109,10 @@
|
||||||
#include private-browsing-indicator.inc.xhtml
|
#include private-browsing-indicator.inc.xhtml
|
||||||
<toolbarbutton class="content-analysis-indicator toolbarbutton-1 content-analysis-indicator-icon"/>
|
<toolbarbutton class="content-analysis-indicator toolbarbutton-1 content-analysis-indicator-icon"/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/components/customizableui/CustomizableUI.sys.mjs b/browser/components/customizableui/CustomizableUI.sys.mjs
|
diff --git a/browser/components/customizableui/CustomizableUI.sys.mjs b/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||||
index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..39e947ce083ce3b293337f5dbb40cd0b46db12e2 100644
|
index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..c50781a1e8fd1a71baf497ba64d85292fa1347f4 100644
|
||||||
--- a/browser/components/customizableui/CustomizableUI.sys.mjs
|
--- a/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||||
+++ b/browser/components/customizableui/CustomizableUI.sys.mjs
|
+++ b/browser/components/customizableui/CustomizableUI.sys.mjs
|
||||||
@@ -14,6 +14,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
@@ -14,6 +14,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||||
@@ -153,7 +153,17 @@ index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..39e947ce083ce3b293337f5dbb40cd0b
|
|||||||
/**
|
/**
|
||||||
* Add a widget to an area.
|
* Add a widget to an area.
|
||||||
* If the area to which you try to add is not known to CustomizableUI,
|
* If the area to which you try to add is not known to CustomizableUI,
|
||||||
@@ -7858,7 +7858,7 @@ class OverflowableToolbar {
|
@@ -7798,7 +7798,9 @@ class OverflowableToolbar {
|
||||||
|
);
|
||||||
|
|
||||||
|
if (webExtList && CustomizableUI.isWebExtensionWidget(child.id)) {
|
||||||
|
+ if (webExtList.id !== "zen-overflow-extensions-list") {
|
||||||
|
child.setAttribute("cui-anchorid", webExtButtonID);
|
||||||
|
+ }
|
||||||
|
webExtList.insertBefore(child, webExtList.firstElementChild);
|
||||||
|
} else {
|
||||||
|
child.setAttribute("cui-anchorid", this.#defaultListButton.id);
|
||||||
|
@@ -7858,7 +7860,7 @@ class OverflowableToolbar {
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -162,7 +172,7 @@ index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..39e947ce083ce3b293337f5dbb40cd0b
|
|||||||
if (child != aExceptChild) {
|
if (child != aExceptChild) {
|
||||||
sum += getInlineSize(child);
|
sum += getInlineSize(child);
|
||||||
}
|
}
|
||||||
@@ -7882,11 +7882,11 @@ class OverflowableToolbar {
|
@@ -7882,11 +7884,11 @@ class OverflowableToolbar {
|
||||||
parseFloat(style.paddingLeft) -
|
parseFloat(style.paddingLeft) -
|
||||||
parseFloat(style.paddingRight) -
|
parseFloat(style.paddingRight) -
|
||||||
toolbarChildrenWidth;
|
toolbarChildrenWidth;
|
||||||
@@ -176,7 +186,7 @@ index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..39e947ce083ce3b293337f5dbb40cd0b
|
|||||||
});
|
});
|
||||||
|
|
||||||
lazy.log.debug(
|
lazy.log.debug(
|
||||||
@@ -7901,7 +7901,14 @@ class OverflowableToolbar {
|
@@ -7901,7 +7903,14 @@ class OverflowableToolbar {
|
||||||
Math.max(targetWidth, targetChildrenWidth)
|
Math.max(targetWidth, targetChildrenWidth)
|
||||||
);
|
);
|
||||||
totalAvailWidth = Math.ceil(totalAvailWidth);
|
totalAvailWidth = Math.ceil(totalAvailWidth);
|
||||||
@@ -192,7 +202,7 @@ index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..39e947ce083ce3b293337f5dbb40cd0b
|
|||||||
return { isOverflowing, targetContentWidth, totalAvailWidth };
|
return { isOverflowing, targetContentWidth, totalAvailWidth };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7962,7 +7969,11 @@ class OverflowableToolbar {
|
@@ -7962,7 +7971,11 @@ class OverflowableToolbar {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +215,7 @@ index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..39e947ce083ce3b293337f5dbb40cd0b
|
|||||||
lazy.log.debug(
|
lazy.log.debug(
|
||||||
`Need ${minSize} but width is ${totalAvailWidth} so bailing`
|
`Need ${minSize} but width is ${totalAvailWidth} so bailing`
|
||||||
);
|
);
|
||||||
@@ -7995,7 +8006,7 @@ class OverflowableToolbar {
|
@@ -7995,7 +8008,7 @@ class OverflowableToolbar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!inserted) {
|
if (!inserted) {
|
||||||
@@ -214,7 +224,27 @@ index 9a98f56d83ee38e0f1aa41467b4ddf215c3d90f7..39e947ce083ce3b293337f5dbb40cd0b
|
|||||||
}
|
}
|
||||||
child.removeAttribute("cui-anchorid");
|
child.removeAttribute("cui-anchorid");
|
||||||
child.removeAttribute("overflowedItem");
|
child.removeAttribute("overflowedItem");
|
||||||
@@ -8340,7 +8351,7 @@ class OverflowableToolbar {
|
@@ -8121,6 +8134,9 @@ class OverflowableToolbar {
|
||||||
|
* if no such list exists.
|
||||||
|
*/
|
||||||
|
get #webExtList() {
|
||||||
|
+ if (this.#toolbar.getAttribute("addon-webext-overflowtarget") !== this.#webExtListRef?.id) {
|
||||||
|
+ this.#webExtListRef = null;
|
||||||
|
+ }
|
||||||
|
if (!this.#webExtListRef) {
|
||||||
|
let targetID = this.#toolbar.getAttribute("addon-webext-overflowtarget");
|
||||||
|
if (!targetID) {
|
||||||
|
@@ -8132,6 +8148,9 @@ class OverflowableToolbar {
|
||||||
|
let win = this.#toolbar.ownerGlobal;
|
||||||
|
let { panel } = win.gUnifiedExtensions;
|
||||||
|
this.#webExtListRef = panel.querySelector(`#${targetID}`);
|
||||||
|
+ if (!this.#webExtListRef) {
|
||||||
|
+ this.#webExtListRef = win.document.getElementById(targetID);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
return this.#webExtListRef;
|
||||||
|
}
|
||||||
|
@@ -8340,7 +8359,7 @@ class OverflowableToolbar {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "mousedown": {
|
case "mousedown": {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
|
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
|
||||||
index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96faedf6f0b 100644
|
index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2061ef7ac60371a563b4e4cd77ceab586f767a5e 100644
|
||||||
--- a/browser/components/sessionstore/SessionStore.sys.mjs
|
--- a/browser/components/sessionstore/SessionStore.sys.mjs
|
||||||
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
|
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
|
||||||
@@ -127,6 +127,9 @@ const TAB_EVENTS = [
|
@@ -127,6 +127,9 @@ const TAB_EVENTS = [
|
||||||
@@ -79,7 +79,15 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
!lazy.SessionStartup.willRestore()
|
!lazy.SessionStartup.willRestore()
|
||||||
) {
|
) {
|
||||||
// We want to split the window up into pinned tabs and unpinned tabs.
|
// We want to split the window up into pinned tabs and unpinned tabs.
|
||||||
@@ -2239,6 +2248,15 @@ var SessionStoreInternal = {
|
@@ -2211,6 +2220,7 @@ var SessionStoreInternal = {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newWindowState) {
|
||||||
|
+ lazy.ZenSessionStore.onRestoringClosedWindow(newWindowState);
|
||||||
|
// Ensure that the window state isn't hidden
|
||||||
|
this._restoreCount = 1;
|
||||||
|
let state = { windows: [newWindowState] };
|
||||||
|
@@ -2239,6 +2249,15 @@ var SessionStoreInternal = {
|
||||||
});
|
});
|
||||||
this._shouldRestoreLastSession = false;
|
this._shouldRestoreLastSession = false;
|
||||||
}
|
}
|
||||||
@@ -95,7 +103,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
|
|
||||||
if (this._restoreLastWindow && aWindow.toolbar.visible) {
|
if (this._restoreLastWindow && aWindow.toolbar.visible) {
|
||||||
// always reset (if not a popup window)
|
// always reset (if not a popup window)
|
||||||
@@ -2383,7 +2401,7 @@ var SessionStoreInternal = {
|
@@ -2383,7 +2402,7 @@ var SessionStoreInternal = {
|
||||||
|
|
||||||
var tabbrowser = aWindow.gBrowser;
|
var tabbrowser = aWindow.gBrowser;
|
||||||
|
|
||||||
@@ -104,7 +112,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
|
|
||||||
TAB_EVENTS.forEach(function (aEvent) {
|
TAB_EVENTS.forEach(function (aEvent) {
|
||||||
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
|
tabbrowser.tabContainer.removeEventListener(aEvent, this, true);
|
||||||
@@ -2434,7 +2452,7 @@ var SessionStoreInternal = {
|
@@ -2434,7 +2453,7 @@ var SessionStoreInternal = {
|
||||||
|
|
||||||
let isLastRegularWindow =
|
let isLastRegularWindow =
|
||||||
Object.values(this._windows).filter(
|
Object.values(this._windows).filter(
|
||||||
@@ -113,7 +121,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
).length == 1;
|
).length == 1;
|
||||||
this._log.debug(
|
this._log.debug(
|
||||||
`onClose, closing window isLastRegularWindow? ${isLastRegularWindow}`
|
`onClose, closing window isLastRegularWindow? ${isLastRegularWindow}`
|
||||||
@@ -2491,8 +2509,8 @@ var SessionStoreInternal = {
|
@@ -2491,8 +2510,8 @@ var SessionStoreInternal = {
|
||||||
// 2) Flush the window.
|
// 2) Flush the window.
|
||||||
// 3) When the flush is complete, revisit our decision to store the window
|
// 3) When the flush is complete, revisit our decision to store the window
|
||||||
// in _closedWindows, and add/remove as necessary.
|
// in _closedWindows, and add/remove as necessary.
|
||||||
@@ -124,7 +132,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
}
|
}
|
||||||
|
|
||||||
completionPromise = lazy.TabStateFlusher.flushWindow(aWindow).then(() => {
|
completionPromise = lazy.TabStateFlusher.flushWindow(aWindow).then(() => {
|
||||||
@@ -2512,8 +2530,9 @@ var SessionStoreInternal = {
|
@@ -2512,8 +2531,9 @@ var SessionStoreInternal = {
|
||||||
|
|
||||||
// Save non-private windows if they have at
|
// Save non-private windows if they have at
|
||||||
// least one saveable tab or are the last window.
|
// least one saveable tab or are the last window.
|
||||||
@@ -136,7 +144,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
|
|
||||||
if (!isLastWindow && winData.closedId > -1) {
|
if (!isLastWindow && winData.closedId > -1) {
|
||||||
this._addClosedAction(
|
this._addClosedAction(
|
||||||
@@ -2589,7 +2608,7 @@ var SessionStoreInternal = {
|
@@ -2589,7 +2609,7 @@ var SessionStoreInternal = {
|
||||||
* to call this method again asynchronously (for example, after
|
* to call this method again asynchronously (for example, after
|
||||||
* a window flush).
|
* a window flush).
|
||||||
*/
|
*/
|
||||||
@@ -145,7 +153,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
// Make sure SessionStore is still running, and make sure that we
|
// Make sure SessionStore is still running, and make sure that we
|
||||||
// haven't chosen to forget this window.
|
// haven't chosen to forget this window.
|
||||||
if (
|
if (
|
||||||
@@ -2606,6 +2625,7 @@ var SessionStoreInternal = {
|
@@ -2606,6 +2626,7 @@ var SessionStoreInternal = {
|
||||||
// _closedWindows from a previous call to this function.
|
// _closedWindows from a previous call to this function.
|
||||||
let winIndex = this._closedWindows.indexOf(winData);
|
let winIndex = this._closedWindows.indexOf(winData);
|
||||||
let alreadyStored = winIndex != -1;
|
let alreadyStored = winIndex != -1;
|
||||||
@@ -153,7 +161,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
// If sidebar command is truthy, i.e. sidebar is open, store sidebar settings
|
// If sidebar command is truthy, i.e. sidebar is open, store sidebar settings
|
||||||
let shouldStore = hasSaveableTabs || isLastWindow;
|
let shouldStore = hasSaveableTabs || isLastWindow;
|
||||||
|
|
||||||
@@ -3408,7 +3428,7 @@ var SessionStoreInternal = {
|
@@ -3408,7 +3429,7 @@ var SessionStoreInternal = {
|
||||||
if (!isPrivateWindow && tabState.isPrivate) {
|
if (!isPrivateWindow && tabState.isPrivate) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -162,7 +170,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4129,6 +4149,12 @@ var SessionStoreInternal = {
|
@@ -4129,6 +4150,12 @@ var SessionStoreInternal = {
|
||||||
Math.min(tabState.index, tabState.entries.length)
|
Math.min(tabState.index, tabState.entries.length)
|
||||||
);
|
);
|
||||||
tabState.pinned = false;
|
tabState.pinned = false;
|
||||||
@@ -175,7 +183,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
|
|
||||||
if (inBackground === false) {
|
if (inBackground === false) {
|
||||||
aWindow.gBrowser.selectedTab = newTab;
|
aWindow.gBrowser.selectedTab = newTab;
|
||||||
@@ -4565,6 +4591,8 @@ var SessionStoreInternal = {
|
@@ -4565,6 +4592,8 @@ var SessionStoreInternal = {
|
||||||
// Append the tab if we're opening into a different window,
|
// Append the tab if we're opening into a different window,
|
||||||
tabIndex: aSource == aTargetWindow ? pos : Infinity,
|
tabIndex: aSource == aTargetWindow ? pos : Infinity,
|
||||||
pinned: state.pinned,
|
pinned: state.pinned,
|
||||||
@@ -184,7 +192,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
userContextId: state.userContextId,
|
userContextId: state.userContextId,
|
||||||
skipLoad: true,
|
skipLoad: true,
|
||||||
preferredRemoteType,
|
preferredRemoteType,
|
||||||
@@ -5414,7 +5442,7 @@ var SessionStoreInternal = {
|
@@ -5414,7 +5443,7 @@ var SessionStoreInternal = {
|
||||||
|
|
||||||
for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
|
for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
|
||||||
let tab = tabbrowser.tabs[i];
|
let tab = tabbrowser.tabs[i];
|
||||||
@@ -193,7 +201,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
removableTabs.push(tab);
|
removableTabs.push(tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5525,7 +5553,7 @@ var SessionStoreInternal = {
|
@@ -5525,7 +5554,7 @@ var SessionStoreInternal = {
|
||||||
|
|
||||||
// collect the data for all windows
|
// collect the data for all windows
|
||||||
for (ix in this._windows) {
|
for (ix in this._windows) {
|
||||||
@@ -202,7 +210,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
// window data is still in _statesToRestore
|
// window data is still in _statesToRestore
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -5668,11 +5696,12 @@ var SessionStoreInternal = {
|
@@ -5668,11 +5697,12 @@ var SessionStoreInternal = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let tabbrowser = aWindow.gBrowser;
|
let tabbrowser = aWindow.gBrowser;
|
||||||
@@ -216,7 +224,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
// update the internal state data for this window
|
// update the internal state data for this window
|
||||||
for (let tab of tabs) {
|
for (let tab of tabs) {
|
||||||
if (tab == aWindow.FirefoxViewHandler.tab) {
|
if (tab == aWindow.FirefoxViewHandler.tab) {
|
||||||
@@ -5683,6 +5712,9 @@ var SessionStoreInternal = {
|
@@ -5683,6 +5713,9 @@ var SessionStoreInternal = {
|
||||||
tabsData.push(tabData);
|
tabsData.push(tabData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +234,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
// update tab group state for this window
|
// update tab group state for this window
|
||||||
winData.groups = [];
|
winData.groups = [];
|
||||||
for (let tabGroup of aWindow.gBrowser.tabGroups) {
|
for (let tabGroup of aWindow.gBrowser.tabGroups) {
|
||||||
@@ -5695,7 +5727,7 @@ var SessionStoreInternal = {
|
@@ -5695,7 +5728,7 @@ var SessionStoreInternal = {
|
||||||
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
|
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
|
||||||
// since it's only inserted into the tab strip after it's selected).
|
// since it's only inserted into the tab strip after it's selected).
|
||||||
if (aWindow.FirefoxViewHandler.tab?.selected) {
|
if (aWindow.FirefoxViewHandler.tab?.selected) {
|
||||||
@@ -235,7 +243,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
winData.title = tabbrowser.tabs[0].label;
|
winData.title = tabbrowser.tabs[0].label;
|
||||||
}
|
}
|
||||||
winData.selected = selectedIndex;
|
winData.selected = selectedIndex;
|
||||||
@@ -5810,8 +5842,8 @@ var SessionStoreInternal = {
|
@@ -5810,8 +5843,8 @@ var SessionStoreInternal = {
|
||||||
// selectTab represents.
|
// selectTab represents.
|
||||||
let selectTab = 0;
|
let selectTab = 0;
|
||||||
if (overwriteTabs) {
|
if (overwriteTabs) {
|
||||||
@@ -246,7 +254,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
selectTab = Math.min(selectTab, winData.tabs.length);
|
selectTab = Math.min(selectTab, winData.tabs.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5833,6 +5865,7 @@ var SessionStoreInternal = {
|
@@ -5833,6 +5866,7 @@ var SessionStoreInternal = {
|
||||||
if (overwriteTabs) {
|
if (overwriteTabs) {
|
||||||
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
|
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
|
||||||
if (!tabbrowser.tabs[i].selected) {
|
if (!tabbrowser.tabs[i].selected) {
|
||||||
@@ -254,7 +262,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
tabbrowser.removeTab(tabbrowser.tabs[i]);
|
tabbrowser.removeTab(tabbrowser.tabs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5866,6 +5899,12 @@ var SessionStoreInternal = {
|
@@ -5866,6 +5900,12 @@ var SessionStoreInternal = {
|
||||||
savedTabGroup => !openTabGroupIdsInWindow.has(savedTabGroup.id)
|
savedTabGroup => !openTabGroupIdsInWindow.has(savedTabGroup.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -267,7 +275,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
|
|
||||||
// Move the originally open tabs to the end.
|
// Move the originally open tabs to the end.
|
||||||
if (initialTabs) {
|
if (initialTabs) {
|
||||||
@@ -6419,6 +6458,25 @@ var SessionStoreInternal = {
|
@@ -6419,6 +6459,25 @@ var SessionStoreInternal = {
|
||||||
|
|
||||||
// Most of tabData has been restored, now continue with restoring
|
// Most of tabData has been restored, now continue with restoring
|
||||||
// attributes that may trigger external events.
|
// attributes that may trigger external events.
|
||||||
@@ -293,7 +301,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
|
|
||||||
if (tabData.pinned) {
|
if (tabData.pinned) {
|
||||||
tabbrowser.pinTab(tab);
|
tabbrowser.pinTab(tab);
|
||||||
@@ -6567,6 +6625,9 @@ var SessionStoreInternal = {
|
@@ -6567,6 +6626,9 @@ var SessionStoreInternal = {
|
||||||
aWindow.gURLBar.readOnly = false;
|
aWindow.gURLBar.readOnly = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,7 +311,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
|
|
||||||
let promiseParts = Promise.withResolvers();
|
let promiseParts = Promise.withResolvers();
|
||||||
aWindow.setTimeout(() => {
|
aWindow.setTimeout(() => {
|
||||||
@@ -7343,7 +7404,7 @@ var SessionStoreInternal = {
|
@@ -7343,7 +7405,7 @@ var SessionStoreInternal = {
|
||||||
|
|
||||||
let groupsToSave = new Map();
|
let groupsToSave = new Map();
|
||||||
for (let tIndex = 0; tIndex < window.tabs.length; ) {
|
for (let tIndex = 0; tIndex < window.tabs.length; ) {
|
||||||
@@ -312,7 +320,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..2f63071f78782dbc30bde25b3bcaa96f
|
|||||||
// Adjust window.selected
|
// Adjust window.selected
|
||||||
if (tIndex + 1 < window.selected) {
|
if (tIndex + 1 < window.selected) {
|
||||||
window.selected -= 1;
|
window.selected -= 1;
|
||||||
@@ -7358,7 +7419,7 @@ var SessionStoreInternal = {
|
@@ -7358,7 +7420,7 @@ var SessionStoreInternal = {
|
||||||
);
|
);
|
||||||
// We don't want to increment tIndex here.
|
// We don't want to increment tIndex here.
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
3
src/external-patches/librewolf/README.md
Normal file
3
src/external-patches/librewolf/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Patches imported from LibreWolf
|
||||||
|
|
||||||
|
Firefox sometimes makes changes without considering the impact on forks. This is the case of the patches that are imported from LibreWolf, which are already present in LibreWolf but not yet (or never) present in Firefox. Thanks to LibreWolf for making these patches available and for their work in maintaining them. We will keep these patches as long as they are needed, and we will remove them once they are no longer necessary (for example, when they are merged into Firefox or when the issue they solve is no longer present).
|
||||||
12
src/external-patches/librewolf/firefox-in-ua.patch
Normal file
12
src/external-patches/librewolf/firefox-in-ua.patch
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
diff --git a/toolkit/moz.configure b/toolkit/moz.configure
|
||||||
|
--- a/toolkit/moz.configure
|
||||||
|
+++ b/toolkit/moz.configure
|
||||||
|
@@ -28,7 +28,7 @@ project_flag(
|
||||||
|
|
||||||
|
project_flag(
|
||||||
|
env="MOZ_APP_UA_NAME",
|
||||||
|
- default="",
|
||||||
|
+ default="Firefox",
|
||||||
|
nargs=1,
|
||||||
|
help="Application name in the User Agent string",
|
||||||
|
)
|
||||||
24
src/external-patches/manifest.json
Normal file
24
src/external-patches/manifest.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// 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/.
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "phabricator",
|
||||||
|
"id": "D279007",
|
||||||
|
"name": "Fix MacOS Crash on Shutdown Firefox 149"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"path": "firefox/no_liquid_glass_icon.patch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patch",
|
||||||
|
"url": "https://codeberg.org/librewolf/source/raw/branch/main/patches/firefox-in-ua.patch",
|
||||||
|
"dest": "librewolf",
|
||||||
|
"replaces": {
|
||||||
|
// They don't correctly export this patch, so we need to replace
|
||||||
|
// the parameter's help description with the correct one.
|
||||||
|
"application": "Application"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build
|
|
||||||
index d2330003caf35c43d6831fb0d356ece513906f78..76c2faf822ddaf645eb03d93380c58b4e3b510c0 100644
|
|
||||||
--- a/netwerk/protocol/http/moz.build
|
|
||||||
+++ b/netwerk/protocol/http/moz.build
|
|
||||||
@@ -227,7 +227,7 @@ LOCAL_INCLUDES += [
|
|
||||||
"/netwerk/url-classifier",
|
|
||||||
]
|
|
||||||
|
|
||||||
-DEFINES["MOZ_APP_UA_NAME"] = f'"{CONFIG["MOZ_APP_UA_NAME"]}"'
|
|
||||||
+DEFINES["MOZ_APP_UA_NAME"] = f'"Firefox"'
|
|
||||||
|
|
||||||
if CONFIG["MOZ_AUTH_EXTENSION"]:
|
|
||||||
LOCAL_INCLUDES += [
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/toolkit/components/extensions/parent/ext-runtime.js b/toolkit/components/extensions/parent/ext-runtime.js
|
diff --git a/toolkit/components/extensions/parent/ext-runtime.js b/toolkit/components/extensions/parent/ext-runtime.js
|
||||||
index 0d7a3e505b6bd30548c6dda1504dd343a517b083..54400def5e02e886765fab68c3854a6b3c24ef2b 100644
|
index 0d7a3e505b6bd30548c6dda1504dd343a517b083..fb6c6b4ef3eae24995a02f708ec41afd31d812ef 100644
|
||||||
--- a/toolkit/components/extensions/parent/ext-runtime.js
|
--- a/toolkit/components/extensions/parent/ext-runtime.js
|
||||||
+++ b/toolkit/components/extensions/parent/ext-runtime.js
|
+++ b/toolkit/components/extensions/parent/ext-runtime.js
|
||||||
@@ -333,7 +333,7 @@ this.runtime = class extends ExtensionAPIPersistent {
|
@@ -333,7 +333,7 @@ this.runtime = class extends ExtensionAPIPersistent {
|
||||||
@@ -7,7 +7,7 @@ index 0d7a3e505b6bd30548c6dda1504dd343a517b083..54400def5e02e886765fab68c3854a6b
|
|||||||
getBrowserInfo: function () {
|
getBrowserInfo: function () {
|
||||||
const { name, vendor, version, appBuildID } = Services.appinfo;
|
const { name, vendor, version, appBuildID } = Services.appinfo;
|
||||||
- const info = { name, vendor, version, buildID: appBuildID };
|
- const info = { name, vendor, version, buildID: appBuildID };
|
||||||
+ const info = { name: 'firefox', vendor, version: AppConstants.ZEN_FIREFOX_VERSION, buildID: appBuildID };
|
+ const info = { name: 'Firefox', vendor, version: AppConstants.ZEN_FIREFOX_VERSION, buildID: appBuildID, zen: {version: AppConstants.MOZ_APP_VERSION_DISPLAY} };
|
||||||
return Promise.resolve(info);
|
return Promise.resolve(info);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
40
src/toolkit/xre/nsXREDirProvider-cpp.patch
Normal file
40
src/toolkit/xre/nsXREDirProvider-cpp.patch
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp
|
||||||
|
index 64456439499d449ce7f2861b1a5addbeecd61721..d0acdb3082b4805e2b8903f8044c97ddf29419bb 100644
|
||||||
|
--- a/toolkit/xre/nsXREDirProvider.cpp
|
||||||
|
+++ b/toolkit/xre/nsXREDirProvider.cpp
|
||||||
|
@@ -1317,9 +1317,11 @@ nsresult nsXREDirProvider::AppendFromAppData(nsIFile* aFile, bool aIsDotted) {
|
||||||
|
// Similar to nsXREDirProvider::AppendProfilePath.
|
||||||
|
// TODO: Bug 1990407 - Evaluate if refactoring might be required there in the
|
||||||
|
// future?
|
||||||
|
- if (gAppData->profile) {
|
||||||
|
+ // Use aIsDotted for a different purpose here, will probably break in the future
|
||||||
|
+ if (gAppData->profile && aIsDotted) {
|
||||||
|
nsAutoCString profile;
|
||||||
|
profile = gAppData->profile;
|
||||||
|
+ profile = "."_ns + nsDependentCString(gAppData->profile);
|
||||||
|
MOZ_TRY(aFile->AppendRelativeNativePath(profile));
|
||||||
|
} else {
|
||||||
|
nsAutoCString vendor;
|
||||||
|
@@ -1329,8 +1331,6 @@ nsresult nsXREDirProvider::AppendFromAppData(nsIFile* aFile, bool aIsDotted) {
|
||||||
|
ToLowerCase(vendor);
|
||||||
|
ToLowerCase(appName);
|
||||||
|
|
||||||
|
- MOZ_TRY(aFile->AppendRelativeNativePath(aIsDotted ? ("."_ns + vendor)
|
||||||
|
- : vendor));
|
||||||
|
MOZ_TRY(aFile->AppendRelativeNativePath(appName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1498,13 +1498,8 @@ nsresult nsXREDirProvider::GetLegacyOrXDGHomePath(const char* aHomeDir,
|
||||||
|
|
||||||
|
// If the build was made against a specific profile name, MOZ_APP_PROFILE=
|
||||||
|
// then make sure we respect this and dont move to XDG directory
|
||||||
|
- if (gAppData->profile) {
|
||||||
|
- MOZ_TRY(NS_NewNativeLocalFile(nsDependentCString(aHomeDir),
|
||||||
|
- getter_AddRefs(localDir)));
|
||||||
|
- } else {
|
||||||
|
MOZ_TRY(GetLegacyOrXDGConfigHome(aHomeDir, getter_AddRefs(localDir)));
|
||||||
|
MOZ_TRY(localDir->Clone(getter_AddRefs(parentDir)));
|
||||||
|
- }
|
||||||
|
|
||||||
|
MOZ_TRY(AppendFromAppData(localDir, false));
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
content/browser/zen-styles/zen-panel-ui.css (../../zen/common/styles/zen-panel-ui.css)
|
content/browser/zen-styles/zen-panel-ui.css (../../zen/common/styles/zen-panel-ui.css)
|
||||||
content/browser/zen-styles/zen-single-components.css (../../zen/common/styles/zen-single-components.css)
|
content/browser/zen-styles/zen-single-components.css (../../zen/common/styles/zen-single-components.css)
|
||||||
content/browser/zen-styles/zen-sidebar.css (../../zen/common/styles/zen-sidebar.css)
|
content/browser/zen-styles/zen-sidebar.css (../../zen/common/styles/zen-sidebar.css)
|
||||||
content/browser/zen-styles/zen-toolbar.css (../../zen/common/styles/zen-toolbar.css)
|
* content/browser/zen-styles/zen-toolbar.css (../../zen/common/styles/zen-toolbar.css)
|
||||||
content/browser/zen-styles/zen-browser-container.css (../../zen/common/styles/zen-browser-container.css)
|
content/browser/zen-styles/zen-browser-container.css (../../zen/common/styles/zen-browser-container.css)
|
||||||
content/browser/zen-styles/zen-omnibox.css (../../zen/common/styles/zen-omnibox.css)
|
content/browser/zen-styles/zen-omnibox.css (../../zen/common/styles/zen-omnibox.css)
|
||||||
content/browser/zen-styles/zen-popup.css (../../zen/common/styles/zen-popup.css)
|
content/browser/zen-styles/zen-popup.css (../../zen/common/styles/zen-popup.css)
|
||||||
|
|||||||
@@ -1055,7 +1055,7 @@ window.gZenVerticalTabsManager = {
|
|||||||
if (!this._hasSetSingleToolbar) {
|
if (!this._hasSetSingleToolbar) {
|
||||||
height = AppConstants.platform == "macosx" ? 34 : 32;
|
height = AppConstants.platform == "macosx" ? 34 : 32;
|
||||||
} else if (gURLBar.getAttribute("breakout-extend") !== "true") {
|
} else if (gURLBar.getAttribute("breakout-extend") !== "true") {
|
||||||
height = 40;
|
height = 38;
|
||||||
}
|
}
|
||||||
if (typeof height !== "undefined") {
|
if (typeof height !== "undefined") {
|
||||||
gURLBar.style.setProperty("--urlbar-height", `${height}px`);
|
gURLBar.style.setProperty("--urlbar-height", `${height}px`);
|
||||||
@@ -1275,6 +1275,15 @@ window.gZenVerticalTabsManager = {
|
|||||||
appContentNavbarContaienr.append(windowButtons);
|
appContentNavbarContaienr.append(windowButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this._hasSetSingleToolbar &&
|
||||||
|
Services.prefs.getBoolPref("zen.view.overflow-webext-toolbar", true)
|
||||||
|
) {
|
||||||
|
topButtons.setAttribute("addon-webext-overflowtarget", "zen-overflow-extensions-list");
|
||||||
|
} else {
|
||||||
|
topButtons.setAttribute("addon-webext-overflowtarget", "overflowed-extensions-list");
|
||||||
|
}
|
||||||
|
|
||||||
gZenCompactModeManager.updateCompactModeContext(isSingleToolbar);
|
gZenCompactModeManager.updateCompactModeContext(isSingleToolbar);
|
||||||
|
|
||||||
// Always move the splitter next to the sidebar
|
// Always move the splitter next to the sidebar
|
||||||
|
|||||||
@@ -132,6 +132,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#nav-bar {
|
#nav-bar {
|
||||||
|
overflow: clip;
|
||||||
border-top-color: transparent !important;
|
border-top-color: transparent !important;
|
||||||
|
|
||||||
:root[zen-single-toolbar="true"] & {
|
:root[zen-single-toolbar="true"] & {
|
||||||
|
|||||||
@@ -80,7 +80,7 @@
|
|||||||
|
|
||||||
#urlbar:not([breakout-extend="true"]) {
|
#urlbar:not([breakout-extend="true"]) {
|
||||||
&:hover .urlbar-background {
|
&:hover .urlbar-background {
|
||||||
background-color: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.2)) !important;
|
background-color: var(--zen-toolbar-element-bg-hover) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
src/zen/common/styles/zen-overflowing-addons.css
Normal file
48
src/zen/common/styles/zen-overflowing-addons.css
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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-overflow-extensions-list:not(:empty) {
|
||||||
|
--uei-icon-size: 14px;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 2px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
|
||||||
|
& .unified-extensions-item {
|
||||||
|
flex: 1;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .toolbarbutton-badge-stack {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 8px 0;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .unified-extensions-item-action-button {
|
||||||
|
background-color: var(--zen-toolbar-element-bg);
|
||||||
|
height: 30px;
|
||||||
|
margin: 0;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: var(--border-radius-medium);
|
||||||
|
overflow: clip;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--zen-toolbar-element-bg-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unified-extensions-item-contents,
|
||||||
|
.unified-extensions-item-menu-button,
|
||||||
|
unified-extensions-item-messagebar-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -177,6 +177,7 @@
|
|||||||
--toolbarbutton-border-radius: var(--tab-border-radius);
|
--toolbarbutton-border-radius: var(--tab-border-radius);
|
||||||
--toolbarbutton-inner-padding: 6px;
|
--toolbarbutton-inner-padding: 6px;
|
||||||
--toolbarbutton-outer-padding: 2px;
|
--toolbarbutton-outer-padding: 2px;
|
||||||
|
color: color-mix(in srgb, currentColor 60%, transparent);
|
||||||
|
|
||||||
transition:
|
transition:
|
||||||
background-color 0.1s,
|
background-color 0.1s,
|
||||||
@@ -191,6 +192,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#zen-sidebar-top-buttons toolbarbutton {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.zen-interactive-button {
|
.zen-interactive-button {
|
||||||
background: color-mix(in srgb, currentColor 6%, transparent) !important;
|
background: color-mix(in srgb, currentColor 6%, transparent) !important;
|
||||||
transition:
|
transition:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
:host(:is(.anonymous-content-host, notification-message)),
|
:host(:is(.anonymous-content-host, notification-message)),
|
||||||
:root {
|
:root:not([windowtype^="Browser:"]) {
|
||||||
/* Default values */
|
/* Default values */
|
||||||
--zen-border-radius: 7px;
|
--zen-border-radius: 7px;
|
||||||
--zen-primary-color: AccentColor;
|
--zen-primary-color: AccentColor;
|
||||||
@@ -141,14 +141,11 @@
|
|||||||
--zen-button-padding: 0.6rem 1.2rem;
|
--zen-button-padding: 0.6rem 1.2rem;
|
||||||
|
|
||||||
--zen-toolbar-element-bg: light-dark(
|
--zen-toolbar-element-bg: light-dark(
|
||||||
color-mix(in oklch, var(--toolbox-textcolor) 10%, transparent),
|
color-mix(in oklch, var(--toolbox-textcolor) 8%, transparent),
|
||||||
color-mix(in oklch, var(--toolbox-textcolor) 15%, transparent)
|
color-mix(in oklch, var(--toolbox-textcolor) 15%, transparent)
|
||||||
);
|
);
|
||||||
|
|
||||||
--zen-toolbar-element-bg-hover: light-dark(
|
--zen-toolbar-element-bg-hover: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.2));
|
||||||
color-mix(in srgb, var(--zen-toolbar-element-bg) 75%, transparent),
|
|
||||||
color-mix(in srgb, var(--zen-toolbar-element-bg) 60%, transparent)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Toolbar */
|
/* Toolbar */
|
||||||
--tab-selected-color-scheme: inherit !important;
|
--tab-selected-color-scheme: inherit !important;
|
||||||
@@ -222,7 +219,7 @@
|
|||||||
--input-border-color: var(--zen-input-border-color) !important;
|
--input-border-color: var(--zen-input-border-color) !important;
|
||||||
--zen-themed-toolbar-bg-transparent: light-dark(var(--zen-branding-bg), #171717);
|
--zen-themed-toolbar-bg-transparent: light-dark(var(--zen-branding-bg), #171717);
|
||||||
|
|
||||||
--zen-workspace-indicator-height: 46px;
|
--zen-workspace-indicator-height: 44px;
|
||||||
|
|
||||||
&:not([zen-sidebar-expanded='true']) {
|
&:not([zen-sidebar-expanded='true']) {
|
||||||
--zen-workspace-indicator-height: 38px;
|
--zen-workspace-indicator-height: 38px;
|
||||||
@@ -231,10 +228,7 @@
|
|||||||
--toolbar-field-color: var(--toolbox-textcolor) !important;
|
--toolbar-field-color: var(--toolbox-textcolor) !important;
|
||||||
|
|
||||||
&[zen-private-window='true'] {
|
&[zen-private-window='true'] {
|
||||||
--zen-main-browser-background: linear-gradient(130deg,
|
--zen-main-browser-background: color-mix(in srgb, rgb(11, 10, 11) 90%, var(--zen-themed-toolbar-bg-transparent));
|
||||||
color-mix(in srgb, rgb(10, 6, 11) 80%, var(--zen-themed-toolbar-bg-transparent)) 0%,
|
|
||||||
color-mix(in srgb, rgb(19, 7, 22) 80%, var(--zen-themed-toolbar-bg-transparent)) 100%
|
|
||||||
);
|
|
||||||
--zen-main-browser-background-toolbar: var(--zen-main-browser-background);
|
--zen-main-browser-background-toolbar: var(--zen-main-browser-background);
|
||||||
--zen-primary-color: light-dark(rgb(93, 42, 107), rgb(110, 48, 125)) !important;
|
--zen-primary-color: light-dark(rgb(93, 42, 107), rgb(110, 48, 125)) !important;
|
||||||
--toolbox-textcolor: color-mix(in srgb, currentColor 95%, transparent) !important;
|
--toolbox-textcolor: color-mix(in srgb, currentColor 95%, transparent) !important;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#nav-bar,
|
#nav-bar,
|
||||||
#zen-sidebar-top-buttons {
|
#zen-sidebar-top-buttons {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@@ -11,3 +12,5 @@
|
|||||||
:root[inDOMFullscreen="true"] #zen-appcontent-navbar-wrapper {
|
:root[inDOMFullscreen="true"] #zen-appcontent-navbar-wrapper {
|
||||||
visibility: collapse;
|
visibility: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%include zen-overflowing-addons.css
|
||||||
|
|||||||
@@ -121,8 +121,11 @@ export const ZenCustomizableUI = new (class {
|
|||||||
|
|
||||||
#initCreateNewButton(window) {
|
#initCreateNewButton(window) {
|
||||||
const button = window.document.getElementById("zen-create-new-button");
|
const button = window.document.getElementById("zen-create-new-button");
|
||||||
button.addEventListener("command", (event) => {
|
// If we use "mousedown" event for private windows (which open a new tab on "click"), we might end up with
|
||||||
if (window.gZenWorkspaces.privateWindowOrDisabled) {
|
// the urlbar flicking and therefore we use "command" event to avoid that.
|
||||||
|
let isPrivateMode = window.gZenWorkspaces.privateWindowOrDisabled;
|
||||||
|
button.addEventListener(isPrivateMode ? "command" : "mousedown", (event) => {
|
||||||
|
if (isPrivateMode) {
|
||||||
window.document.getElementById("cmd_newNavigatorTab").doCommand();
|
window.document.getElementById("cmd_newNavigatorTab").doCommand();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -962,7 +962,8 @@
|
|||||||
dropElement = dragData.dropElement;
|
dropElement = dragData.dropElement;
|
||||||
dropBefore = dragData.dropBefore;
|
dropBefore = dragData.dropBefore;
|
||||||
}
|
}
|
||||||
if (!dropElement) {
|
// Essentials should be properly handled by ::animateVerticalPinnedGridDragOver
|
||||||
|
if (!dropElement || dropElement.hasAttribute("zen-essential")) {
|
||||||
this.clearDragOverVisuals();
|
this.clearDragOverVisuals();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
|
|||||||
|
|
||||||
static rawIcon = new DOMParser().parseFromString(
|
static rawIcon = new DOMParser().parseFromString(
|
||||||
`
|
`
|
||||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="28" height="28" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient gradientUnits="userSpaceOnUse" x1="14" y1="5.625" x2="14" y2="22.375" id="gradient-0">
|
<linearGradient gradientUnits="userSpaceOnUse" x1="14" y1="5.625" x2="14" y2="22.375" id="gradient-0">
|
||||||
<stop offset="0" style="stop-color: rgb(255, 255, 255)"/>
|
<stop offset="0" style="stop-color: rgb(255, 255, 255)"/>
|
||||||
@@ -242,7 +242,7 @@ export class nsZenFolder extends MozTabbrowserTabGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get resetButton() {
|
get resetButton() {
|
||||||
return this.labelElement.parentElement.querySelector(".tab-reset-button");
|
return this.labelElement.parentElement?.querySelector(".tab-reset-button") ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
unloadAllTabs(event) {
|
unloadAllTabs(event) {
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ class nsZenSidebarObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set data(data) {
|
set data(data) {
|
||||||
|
if (typeof data !== "object") {
|
||||||
|
throw new Error("Sidebar data must be an object");
|
||||||
|
}
|
||||||
this.#sidebar = data;
|
this.#sidebar = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,6 +387,25 @@ export class nsZenSessionManager {
|
|||||||
return initialState;
|
return initialState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onRestoringClosedWindow(aWinData) {
|
||||||
|
// We only want to save all pinned tabs if the user preference allows it.
|
||||||
|
// See https://github.com/zen-browser/desktop/issues/12307
|
||||||
|
if (this.#shouldRestoreOnlyPinned && aWinData?.tabs?.length) {
|
||||||
|
this.log("Restoring only pinned tabs for closed window");
|
||||||
|
this.#filterUnpinnedTabs(aWinData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters out all unpinned tabs and groups from the given window data object.
|
||||||
|
*
|
||||||
|
* @param {object} aWindow - The window data object to filter.
|
||||||
|
*/
|
||||||
|
#filterUnpinnedTabs(aWindow) {
|
||||||
|
aWindow.tabs = aWindow.tabs.filter((tab) => tab.pinned);
|
||||||
|
aWindow.groups = aWindow.groups?.filter((group) => group.pinned);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a given window data object is saveable.
|
* Determines if a given window data object is saveable.
|
||||||
*
|
*
|
||||||
@@ -410,10 +432,11 @@ export class nsZenSessionManager {
|
|||||||
this.#collectWindowData(windows);
|
this.#collectWindowData(windows);
|
||||||
// This would save the data to disk asynchronously or when
|
// This would save the data to disk asynchronously or when
|
||||||
// quitting the app.
|
// quitting the app.
|
||||||
this.#file.data = this.#sidebar;
|
let sidebar = this.#sidebar;
|
||||||
|
this.#file.data = sidebar;
|
||||||
this.#file.saveSoon();
|
this.#file.saveSoon();
|
||||||
this.#debounceRegeneration();
|
this.#debounceRegeneration();
|
||||||
this.log(`Saving Zen session data with ${this.#sidebar.tabs?.length || 0} tabs`);
|
this.log(`Saving Zen session data with ${sidebar.tabs?.length || 0} tabs`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -514,6 +537,13 @@ export class nsZenSessionManager {
|
|||||||
this.#sidebar = sidebarData;
|
this.#sidebar = sidebarData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters out tabs that are not useful to restore, such as empty tabs with no group association.
|
||||||
|
* If removeUnpinnedTabs is true, it also filters out unpinned tabs.
|
||||||
|
*
|
||||||
|
* @param {Array} tabs - The array of tab data objects to filter.
|
||||||
|
* @returns {Array} The filtered array of tab data objects.
|
||||||
|
*/
|
||||||
#filterUnusedTabs(tabs) {
|
#filterUnusedTabs(tabs) {
|
||||||
return tabs.filter((tab) => {
|
return tabs.filter((tab) => {
|
||||||
// We need to ignore empty tabs with no group association
|
// We need to ignore empty tabs with no group association
|
||||||
@@ -568,7 +598,10 @@ export class nsZenSessionManager {
|
|||||||
// as they should be the same as the ones in the sidebar.
|
// as they should be the same as the ones in the sidebar.
|
||||||
if (lazy.gSyncOnlyPinnedTabs) {
|
if (lazy.gSyncOnlyPinnedTabs) {
|
||||||
let pinnedTabs = (sidebar.tabs || []).filter((tab) => tab.pinned);
|
let pinnedTabs = (sidebar.tabs || []).filter((tab) => tab.pinned);
|
||||||
let unpinedWindowTabs = (aWindowData.tabs || []).filter((tab) => !tab.pinned);
|
let unpinedWindowTabs = [];
|
||||||
|
if (!this.#shouldRestoreOnlyPinned) {
|
||||||
|
unpinedWindowTabs = (aWindowData.tabs || []).filter((tab) => !tab.pinned);
|
||||||
|
}
|
||||||
aWindowData.tabs = [...pinnedTabs, ...unpinedWindowTabs];
|
aWindowData.tabs = [...pinnedTabs, ...unpinedWindowTabs];
|
||||||
|
|
||||||
// We restore ALL the split view data in the sidebar, if the group doesn't exist in the window,
|
// We restore ALL the split view data in the sidebar, if the group doesn't exist in the window,
|
||||||
@@ -613,18 +646,19 @@ export class nsZenSessionManager {
|
|||||||
);
|
);
|
||||||
let windowToClone = windows[0] || {};
|
let windowToClone = windows[0] || {};
|
||||||
let newWindow = Cu.cloneInto(windowToClone, {});
|
let newWindow = Cu.cloneInto(windowToClone, {});
|
||||||
|
let shouldRestoreOnlyPinned = !lazy.gWindowSyncEnabled || lazy.gSyncOnlyPinnedTabs;
|
||||||
if (windows.length < 2) {
|
if (windows.length < 2) {
|
||||||
// We only want to restore the sidebar object if we found
|
// We only want to restore the sidebar object if we found
|
||||||
// only one normal window to clone from (which is the one
|
// only one normal window to clone from (which is the one
|
||||||
// we are opening).
|
// we are opening).
|
||||||
this.log("Restoring sidebar data into new window");
|
this.log("Restoring sidebar data into new window");
|
||||||
this.#restoreWindowData(newWindow);
|
this.#restoreWindowData(newWindow);
|
||||||
|
shouldRestoreOnlyPinned ||= this.#shouldRestoreOnlyPinned;
|
||||||
}
|
}
|
||||||
newWindow.tabs = this.#filterUnusedTabs(newWindow.tabs || []);
|
newWindow.tabs = this.#filterUnusedTabs(newWindow.tabs || []);
|
||||||
if (!lazy.gWindowSyncEnabled || lazy.gSyncOnlyPinnedTabs) {
|
if (shouldRestoreOnlyPinned) {
|
||||||
// Don't bring over any unpinned tabs if window sync is disabled or if syncing only pinned tabs.
|
// Don't bring over any unpinned tabs if window sync is disabled or if syncing only pinned tabs.
|
||||||
newWindow.tabs = newWindow.tabs.filter((tab) => tab.pinned);
|
this.#filterUnpinnedTabs(newWindow);
|
||||||
newWindow.groups = newWindow.groups?.filter((group) => group.pinned);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are window-specific from the previous window state that
|
// These are window-specific from the previous window state that
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ class nsZenWindowSync {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (INSTANT_EVENTS.includes(aEvent.type)) {
|
if (INSTANT_EVENTS.includes(aEvent.type)) {
|
||||||
this.#handleNextEvent(aEvent);
|
this.#handleNextEventInternal(aEvent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.#eventHandlingContext.window && this.#eventHandlingContext.window !== window) {
|
if (this.#eventHandlingContext.window && this.#eventHandlingContext.window !== window) {
|
||||||
@@ -374,30 +374,31 @@ class nsZenWindowSync {
|
|||||||
this.#syncHandlers.delete(aHandler);
|
this.#syncHandlers.delete(aHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#handleNextEventInternal(aEvent) {
|
||||||
|
const handler = `on_${aEvent.type}`;
|
||||||
|
if (typeof this[handler] !== "function") {
|
||||||
|
throw new Error(`No handler for event type: ${aEvent.type}`);
|
||||||
|
}
|
||||||
|
return this[handler](aEvent);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the next event by calling the appropriate handler method.
|
* Handles the next event by calling the appropriate handler method.
|
||||||
*
|
*
|
||||||
* @param {Event} aEvent - The event to handle.
|
* @param {Event} aEvent - The event to handle.
|
||||||
*/
|
*/
|
||||||
#handleNextEvent(aEvent) {
|
async #handleNextEvent(aEvent) {
|
||||||
const handler = `on_${aEvent.type}`;
|
|
||||||
try {
|
try {
|
||||||
if (typeof this[handler] === "function") {
|
await this.#handleNextEventInternal(aEvent);
|
||||||
let promise = this[handler](aEvent) || Promise.resolve();
|
|
||||||
promise.then(() => {
|
|
||||||
for (let syncHandler of this.#syncHandlers) {
|
|
||||||
try {
|
|
||||||
syncHandler(aEvent);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return promise;
|
|
||||||
}
|
|
||||||
throw new Error(`No handler for event type: ${aEvent.type}`);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Promise.reject(e);
|
console.error(e);
|
||||||
|
}
|
||||||
|
for (let syncHandler of this.#syncHandlers) {
|
||||||
|
try {
|
||||||
|
syncHandler(aEvent);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,39 +791,41 @@ class nsZenWindowSync {
|
|||||||
#styleSwapedBrowsers(aOurTab, aOtherTab, callback = undefined, promiseToWait = null) {
|
#styleSwapedBrowsers(aOurTab, aOtherTab, callback = undefined, promiseToWait = null) {
|
||||||
const ourBrowser = aOurTab.linkedBrowser;
|
const ourBrowser = aOurTab.linkedBrowser;
|
||||||
const otherBrowser = aOtherTab.linkedBrowser;
|
const otherBrowser = aOtherTab.linkedBrowser;
|
||||||
return new Promise((resolve) => {
|
// eslint-disable-next-line no-async-promise-executor
|
||||||
aOurTab.ownerGlobal.requestAnimationFrame(async () => {
|
return new Promise(async (resolve) => {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
const browserBlob = await aOtherTab.ownerGlobal.PageThumbs.captureToBlob(
|
const browserBlob = await aOtherTab.ownerGlobal.PageThumbs.captureToBlob(
|
||||||
aOtherTab.linkedBrowser,
|
aOtherTab.linkedBrowser,
|
||||||
{
|
{
|
||||||
fullScale: true,
|
fullScale: true,
|
||||||
fullViewport: true,
|
fullViewport: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let mySrc = await new Promise((r, re) => {
|
let mySrc = await new Promise((r, re) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsDataURL(browserBlob);
|
reader.readAsDataURL(browserBlob);
|
||||||
reader.onloadend = function () {
|
reader.onloadend = function () {
|
||||||
// result includes identifier 'data:image/png;base64,' plus the base64 data
|
// result includes identifier 'data:image/png;base64,' plus the base64 data
|
||||||
r(reader.result);
|
r(reader.result);
|
||||||
};
|
};
|
||||||
reader.onerror = function () {
|
reader.onerror = function () {
|
||||||
re(new Error("Failed to read blob as data URL"));
|
re(new Error("Failed to read blob as data URL"));
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#createPseudoImageForBrowser(otherBrowser, mySrc);
|
|
||||||
otherBrowser.setAttribute("zen-pseudo-hidden", "true");
|
|
||||||
await promiseToWait;
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
await promiseToWait;
|
||||||
|
this.#createPseudoImageForBrowser(otherBrowser, mySrc);
|
||||||
this.#maybeRemovePseudoImageForBrowser(ourBrowser);
|
this.#maybeRemovePseudoImageForBrowser(ourBrowser);
|
||||||
ourBrowser.removeAttribute("zen-pseudo-hidden");
|
ourBrowser.removeAttribute("zen-pseudo-hidden");
|
||||||
resolve();
|
otherBrowser.setAttribute("zen-pseudo-hidden", "true");
|
||||||
});
|
callback();
|
||||||
|
} else {
|
||||||
|
this.#maybeRemovePseudoImageForBrowser(ourBrowser);
|
||||||
|
ourBrowser.removeAttribute("zen-pseudo-hidden");
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,7 +927,9 @@ class nsZenWindowSync {
|
|||||||
// Ignore previous tabs that are still "active". These scenarios could happen for example,
|
// Ignore previous tabs that are still "active". These scenarios could happen for example,
|
||||||
// when selecting on a split view tab that was already active.
|
// when selecting on a split view tab that was already active.
|
||||||
if (aPreviousTab?._zenContentsVisible && !activeTabs.includes(aPreviousTab)) {
|
if (aPreviousTab?._zenContentsVisible && !activeTabs.includes(aPreviousTab)) {
|
||||||
let tabsToSwap = aPreviousTab.splitView ? aPreviousTab.group.tabs : [aPreviousTab];
|
let tabsToSwap = aPreviousTab.group?.hasAttribute("split-view-group")
|
||||||
|
? aPreviousTab.group.tabs
|
||||||
|
: [aPreviousTab];
|
||||||
for (const tab of tabsToSwap) {
|
for (const tab of tabsToSwap) {
|
||||||
const otherTabToShow = this.#getActiveTabFromOtherWindows(aWindow, tab.id, (t) =>
|
const otherTabToShow = this.#getActiveTabFromOtherWindows(aWindow, tab.id, (t) =>
|
||||||
t?.splitView ? t.group.tabs.some((st) => st.selected) : t?.selected
|
t?.splitView ? t.group.tabs.some((st) => st.selected) : t?.selected
|
||||||
|
|||||||
@@ -208,6 +208,10 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
if (typeof groupIndex === "undefined") {
|
if (typeof groupIndex === "undefined") {
|
||||||
groupIndex = this._data.findIndex((group) => group.tabs.includes(tab));
|
groupIndex = this._data.findIndex((group) => group.tabs.includes(tab));
|
||||||
}
|
}
|
||||||
|
// If groupIndex === -1, so `this._data.findIndex` couldn't find the split group
|
||||||
|
if (groupIndex < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const group = this._data[groupIndex];
|
const group = this._data[groupIndex];
|
||||||
const tabIndex = group.tabs.indexOf(tab);
|
const tabIndex = group.tabs.indexOf(tab);
|
||||||
group.tabs.splice(tabIndex, 1);
|
group.tabs.splice(tabIndex, 1);
|
||||||
@@ -259,6 +263,33 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_calculateDropSide(event, panelsRect) {
|
||||||
|
const { width, height } = panelsRect;
|
||||||
|
const { clientX, clientY } = event;
|
||||||
|
// TODO(octaviusz): Maybe we should add this as preference
|
||||||
|
// `zen.splitView.tab-drop-treshold`
|
||||||
|
const quarterWidth = width / 4;
|
||||||
|
const quarterHeight = height / 4;
|
||||||
|
|
||||||
|
const edges = [
|
||||||
|
{ side: "left", dist: clientX - panelsRect.left, threshold: quarterWidth },
|
||||||
|
{ side: "right", dist: panelsRect.right - clientX, threshold: quarterWidth },
|
||||||
|
{ side: "top", dist: clientY - panelsRect.top, threshold: quarterHeight },
|
||||||
|
{ side: "bottom", dist: panelsRect.bottom - clientY, threshold: quarterHeight },
|
||||||
|
];
|
||||||
|
|
||||||
|
let closestEdge = null;
|
||||||
|
let minDist = Infinity;
|
||||||
|
for (const edge of edges) {
|
||||||
|
if (edge.dist < edge.threshold && edge.dist < minDist) {
|
||||||
|
minDist = edge.dist;
|
||||||
|
closestEdge = edge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closestEdge ? closestEdge.side : null;
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line complexity
|
// eslint-disable-next-line complexity
|
||||||
onBrowserDragOverToSplit(event) {
|
onBrowserDragOverToSplit(event) {
|
||||||
gBrowser.tabContainer.tabDragAndDrop.clearSpaceSwitchTimer();
|
gBrowser.tabContainer.tabDragAndDrop.clearSpaceSwitchTimer();
|
||||||
@@ -303,6 +334,7 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
const panelsRect = gBrowser.tabbox.getBoundingClientRect();
|
const panelsRect = gBrowser.tabbox.getBoundingClientRect();
|
||||||
const panelsWidth = panelsRect.width;
|
const panelsWidth = panelsRect.width;
|
||||||
|
const panelsHeight = panelsRect.height;
|
||||||
if (
|
if (
|
||||||
event.clientX > panelsRect.left + panelsWidth - 10 ||
|
event.clientX > panelsRect.left + panelsWidth - 10 ||
|
||||||
event.clientX < panelsRect.left + 10 ||
|
event.clientX < panelsRect.left + 10 ||
|
||||||
@@ -311,11 +343,17 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const dropSide = this._calculateDropSide(event, panelsRect);
|
||||||
|
if (!dropSide) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// first quarter or last quarter of the screen, but not the middle
|
// first quarter or last quarter of the screen, but not the middle
|
||||||
if (
|
if (
|
||||||
!(
|
!(
|
||||||
event.clientX < panelsRect.left + panelsWidth / 4 ||
|
event.clientX < panelsRect.left + panelsWidth / 4 ||
|
||||||
event.clientX > panelsRect.left + (panelsWidth / 4) * 3
|
event.clientX > panelsRect.left + (panelsWidth / 4) * 3 ||
|
||||||
|
event.clientY < panelsRect.top + panelsHeight / 4 ||
|
||||||
|
event.clientY > panelsRect.top + (panelsHeight / 4) * 3
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -336,93 +374,113 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
this._canDrop = true;
|
this._canDrop = true;
|
||||||
// eslint-disable-next-line mozilla/valid-services
|
// eslint-disable-next-line mozilla/valid-services
|
||||||
Services.zen.playHapticFeedback();
|
Services.zen.playHapticFeedback();
|
||||||
{
|
this._draggingTab = draggedTab;
|
||||||
this._draggingTab = draggedTab;
|
gBrowser.selectedTab = oldTab;
|
||||||
gBrowser.selectedTab = oldTab;
|
this._hasAnimated = true;
|
||||||
this._hasAnimated = true;
|
this.tabBrowserPanel.setAttribute("dragging-split", "true");
|
||||||
this.tabBrowserPanel.setAttribute("dragging-split", "true");
|
this._animateDropEdge(dropSide, currentView, draggedTab, oldTab);
|
||||||
// Add a min width to all the browser elements to prevent them from resizing
|
}
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
const panelsWidth = gBrowser.tabbox.getBoundingClientRect().width;
|
_animateDropEdge(dropSide, currentView, draggedTab, oldTab) {
|
||||||
let numOfTabsToDivide = 2;
|
// Add a min width to all the browser elements to prevent them from resizing
|
||||||
if (currentView) {
|
// eslint-disable-next-line no-shadow
|
||||||
numOfTabsToDivide = currentView.tabs.length + 1;
|
const { height, width } = gBrowser.tabbox.getBoundingClientRect();
|
||||||
|
let numOfTabsToDivide = 2;
|
||||||
|
if (currentView) {
|
||||||
|
numOfTabsToDivide = currentView.tabs.length + 1;
|
||||||
|
}
|
||||||
|
const halfWidth = width / numOfTabsToDivide;
|
||||||
|
const halfHeight = height / numOfTabsToDivide;
|
||||||
|
const side = dropSide;
|
||||||
|
for (const browser of gBrowser.browsers) {
|
||||||
|
if (!browser) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
const halfWidth = panelsWidth / numOfTabsToDivide;
|
const { width: browserWidth, height: browserHeight } = browser.getBoundingClientRect();
|
||||||
let threshold =
|
// Only apply it to the left side because if we add it to the right side,
|
||||||
gNavToolbox.getBoundingClientRect().width *
|
// we wont be able to move the element to the left.
|
||||||
(gZenVerticalTabsManager._prefsRightSide ? 0 : 1);
|
// FIXME: This is a workaround, we should find a better way to do this
|
||||||
if (gZenCompactModeManager.preference) {
|
switch (side) {
|
||||||
threshold = 0;
|
case "left":
|
||||||
|
browser.style.minWidth = `${browserWidth}px`;
|
||||||
|
break;
|
||||||
|
case "top":
|
||||||
|
browser.style.minHeight = `${browserHeight}px`;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
const side = event.clientX - threshold > halfWidth ? "right" : "left";
|
}
|
||||||
for (const browser of gBrowser.browsers) {
|
this.fakeBrowser = document.createXULElement("vbox");
|
||||||
if (!browser) {
|
window.addEventListener("dragend", this.onBrowserDragEndToSplit, { once: true });
|
||||||
continue;
|
const padding = ZenThemeModifier.elementSeparation;
|
||||||
|
this.fakeBrowser.setAttribute("flex", "1");
|
||||||
|
this.fakeBrowser.id = "zen-split-view-fake-browser";
|
||||||
|
if (oldTab.splitView) {
|
||||||
|
this.fakeBrowser.setAttribute("has-split-view", "true");
|
||||||
|
}
|
||||||
|
gBrowser.tabbox.appendChild(this.fakeBrowser);
|
||||||
|
this.fakeBrowser.setAttribute("side", side);
|
||||||
|
let animateTabBox = null;
|
||||||
|
let animateFakeBrowser = null;
|
||||||
|
switch (side) {
|
||||||
|
case "left":
|
||||||
|
animateTabBox = {
|
||||||
|
padding: [0, `0 0 0 ${halfWidth}px`],
|
||||||
|
};
|
||||||
|
animateFakeBrowser = {
|
||||||
|
width: [0, `${halfWidth - padding}px`],
|
||||||
|
margin: [0, `0 0 0 ${-halfWidth}px`],
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case "right":
|
||||||
|
animateTabBox = {
|
||||||
|
padding: [0, `0 ${halfWidth}px 0 0`],
|
||||||
|
};
|
||||||
|
animateFakeBrowser = {
|
||||||
|
width: [0, `${halfWidth - padding}px`],
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "top":
|
||||||
|
animateTabBox = {
|
||||||
|
padding: [0, `${halfHeight}px 0 0 0`],
|
||||||
|
};
|
||||||
|
animateFakeBrowser = {
|
||||||
|
height: [0, `${halfHeight - padding}px`],
|
||||||
|
margin: [0, `${-halfHeight}px 0 0 0`],
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "bottom":
|
||||||
|
animateTabBox = {
|
||||||
|
padding: [0, `0 0 ${halfHeight}px 0`],
|
||||||
|
};
|
||||||
|
animateFakeBrowser = {
|
||||||
|
height: [0, `${halfHeight - padding}px`],
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._finishAllAnimatingPromise = Promise.all([
|
||||||
|
gZenUIManager.motion.animate(gBrowser.tabbox, animateTabBox, {
|
||||||
|
duration: 0.1,
|
||||||
|
easing: "ease-out",
|
||||||
|
}),
|
||||||
|
gZenUIManager.motion.animate(this.fakeBrowser, animateFakeBrowser, {
|
||||||
|
duration: 0.1,
|
||||||
|
easing: "ease-out",
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
if (this._finishAllAnimatingPromise) {
|
||||||
|
this._finishAllAnimatingPromise.then(() => {
|
||||||
|
if (draggedTab !== oldTab) {
|
||||||
|
draggedTab.linkedBrowser.docShellIsActive = false;
|
||||||
|
draggedTab.linkedBrowser
|
||||||
|
.closest(".browserSidebarContainer")
|
||||||
|
.classList.remove("deck-selected");
|
||||||
}
|
}
|
||||||
const width = browser.getBoundingClientRect().width;
|
this.fakeBrowser.addEventListener("dragleave", this.onBrowserDragEndToSplit);
|
||||||
// Only apply it to the left side because if we add it to the right side,
|
this._canDrop = true;
|
||||||
// we wont be able to move the element to the left.
|
});
|
||||||
// FIXME: This is a workaround, we should find a better way to do this
|
|
||||||
if (side === "left") {
|
|
||||||
browser.style.minWidth = `${width}px`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.fakeBrowser = document.createXULElement("vbox");
|
|
||||||
window.addEventListener("dragend", this.onBrowserDragEndToSplit, { once: true });
|
|
||||||
const padding = ZenThemeModifier.elementSeparation;
|
|
||||||
this.fakeBrowser.setAttribute("flex", "1");
|
|
||||||
this.fakeBrowser.id = "zen-split-view-fake-browser";
|
|
||||||
if (oldTab.splitView) {
|
|
||||||
this.fakeBrowser.setAttribute("has-split-view", "true");
|
|
||||||
}
|
|
||||||
gBrowser.tabbox.appendChild(this.fakeBrowser);
|
|
||||||
this.fakeBrowser.setAttribute("side", side);
|
|
||||||
this._finishAllAnimatingPromise = Promise.all([
|
|
||||||
gZenUIManager.motion.animate(
|
|
||||||
gBrowser.tabbox,
|
|
||||||
side === "left"
|
|
||||||
? {
|
|
||||||
paddingLeft: [0, `${halfWidth}px`],
|
|
||||||
paddingRight: 0,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
paddingRight: [0, `${halfWidth}px`],
|
|
||||||
paddingLeft: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 0.1,
|
|
||||||
easing: "ease-out",
|
|
||||||
}
|
|
||||||
),
|
|
||||||
gZenUIManager.motion.animate(
|
|
||||||
this.fakeBrowser,
|
|
||||||
{
|
|
||||||
width: [0, `${halfWidth - padding}px`],
|
|
||||||
...(side === "left"
|
|
||||||
? {
|
|
||||||
marginLeft: [0, `${-halfWidth}px`],
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
duration: 0.1,
|
|
||||||
easing: "ease-out",
|
|
||||||
}
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
if (this._finishAllAnimatingPromise) {
|
|
||||||
this._finishAllAnimatingPromise.then(() => {
|
|
||||||
if (draggedTab !== oldTab) {
|
|
||||||
draggedTab.linkedBrowser.docShellIsActive = false;
|
|
||||||
draggedTab.linkedBrowser
|
|
||||||
.closest(".browserSidebarContainer")
|
|
||||||
.classList.remove("deck-selected");
|
|
||||||
}
|
|
||||||
this.fakeBrowser.addEventListener("dragleave", this.onBrowserDragEndToSplit);
|
|
||||||
this._canDrop = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,12 +505,14 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const panelsWidth = panelsRect.width;
|
const panelsWidth = panelsRect.width;
|
||||||
|
const panelsHeight = panelsRect.height;
|
||||||
let numOfTabsToDivide = 2;
|
let numOfTabsToDivide = 2;
|
||||||
const currentView = this._data[this._lastOpenedTab.splitViewValue];
|
const currentView = this._data[this._lastOpenedTab.splitViewValue];
|
||||||
if (currentView) {
|
if (currentView) {
|
||||||
numOfTabsToDivide = currentView.tabs.length + 1;
|
numOfTabsToDivide = currentView.tabs.length + 1;
|
||||||
}
|
}
|
||||||
const halfWidth = panelsWidth / numOfTabsToDivide;
|
const halfWidth = panelsWidth / numOfTabsToDivide;
|
||||||
|
const halfHeight = panelsHeight / numOfTabsToDivide;
|
||||||
const padding = ZenThemeModifier.elementSeparation;
|
const padding = ZenThemeModifier.elementSeparation;
|
||||||
if (!this.fakeBrowser) {
|
if (!this.fakeBrowser) {
|
||||||
return;
|
return;
|
||||||
@@ -464,39 +524,60 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
...gBrowser.tabContainer.tabDragAndDrop.originalDragImageArgs
|
...gBrowser.tabContainer.tabDragAndDrop.originalDragImageArgs
|
||||||
);
|
);
|
||||||
this._canDrop = false;
|
this._canDrop = false;
|
||||||
Promise.all([
|
let animateTabBox = null;
|
||||||
gZenUIManager.motion.animate(
|
let animateFakeBrowser = null;
|
||||||
gBrowser.tabbox,
|
switch (side) {
|
||||||
side === "left"
|
case "left":
|
||||||
? {
|
animateTabBox = {
|
||||||
paddingLeft: [`${halfWidth}px`, 0],
|
padding: [`0 0 0 ${halfWidth}px`, 0],
|
||||||
}
|
};
|
||||||
: {
|
animateFakeBrowser = {
|
||||||
paddingRight: [`${halfWidth}px`, 0],
|
width: [`${halfWidth - padding}px`, 0],
|
||||||
},
|
margin: [`0 0 0 ${-halfWidth}px`, 0],
|
||||||
{
|
};
|
||||||
duration: 0.1,
|
break;
|
||||||
easing: "ease-out",
|
case "right":
|
||||||
}
|
animateTabBox = {
|
||||||
),
|
padding: [`0 ${halfWidth}px 0 0`, 0],
|
||||||
gZenUIManager.motion.animate(
|
};
|
||||||
this.fakeBrowser,
|
animateFakeBrowser = {
|
||||||
{
|
width: [`${halfWidth - padding}px`, 0],
|
||||||
width: [`${halfWidth - padding * 2}px`, 0],
|
};
|
||||||
...(side === "left"
|
break;
|
||||||
? {
|
case "top":
|
||||||
marginLeft: [`${-halfWidth}px`, 0],
|
animateTabBox = {
|
||||||
}
|
padding: [`${halfHeight}px 0 0 0`, 0],
|
||||||
: {}),
|
};
|
||||||
},
|
animateFakeBrowser = {
|
||||||
{
|
height: [`${halfHeight - padding}px`, 0],
|
||||||
duration: 0.1,
|
margin: [`${-halfHeight}px 0 0 0`, 0],
|
||||||
easing: "ease-out",
|
};
|
||||||
}
|
break;
|
||||||
),
|
case "bottom":
|
||||||
]).finally(() => {
|
animateTabBox = {
|
||||||
this._maybeRemoveFakeBrowser();
|
padding: [`0 0 ${halfHeight}px 0`, 0],
|
||||||
});
|
};
|
||||||
|
animateFakeBrowser = {
|
||||||
|
height: [`${halfHeight - padding}px`, 0],
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._finishAllAnimatingPromise = Promise.all([
|
||||||
|
gZenUIManager.motion.animate(gBrowser.tabbox, animateTabBox, {
|
||||||
|
duration: 0.1,
|
||||||
|
easing: "ease-out",
|
||||||
|
}),
|
||||||
|
gZenUIManager.motion.animate(this.fakeBrowser, animateFakeBrowser, {
|
||||||
|
duration: 0.1,
|
||||||
|
easing: "ease-out",
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
if (this._finishAllAnimatingPromise) {
|
||||||
|
this._finishAllAnimatingPromise.then(() => {
|
||||||
|
this._maybeRemoveFakeBrowser();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1845,12 +1926,24 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
const dropSide = this.fakeBrowser?.getAttribute("side");
|
const dropSide = this.fakeBrowser?.getAttribute("side");
|
||||||
const containerRect = this.fakeBrowser.getBoundingClientRect();
|
const containerRect = this.fakeBrowser.getBoundingClientRect();
|
||||||
const padding = ZenThemeModifier.elementSeparation;
|
const padding = ZenThemeModifier.elementSeparation;
|
||||||
const dropTarget = document.elementFromPoint(
|
let targetX = event.clientX;
|
||||||
dropSide === "left"
|
let targetY = event.clientY;
|
||||||
? containerRect.left + containerRect.width + padding + 5
|
switch (dropSide) {
|
||||||
: containerRect.left - padding - 5,
|
case "left":
|
||||||
event.clientY
|
targetX = containerRect.left + containerRect.width + padding + 5;
|
||||||
);
|
break;
|
||||||
|
case "right":
|
||||||
|
targetX = containerRect.left - padding - 5;
|
||||||
|
break;
|
||||||
|
case "top":
|
||||||
|
targetY = containerRect.top + containerRect.height + padding + 5;
|
||||||
|
break;
|
||||||
|
case "bottom":
|
||||||
|
targetY = containerRect.top - padding - 5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dropTarget = document.elementFromPoint(targetX, targetY);
|
||||||
const browser =
|
const browser =
|
||||||
dropTarget?.closest("browser") ??
|
dropTarget?.closest("browser") ??
|
||||||
dropTarget?.closest(".browserSidebarContainer")?.querySelector("browser");
|
dropTarget?.closest(".browserSidebarContainer")?.querySelector("browser");
|
||||||
@@ -1862,7 +1955,7 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
|
|
||||||
let droppedOnTab = gZenGlanceManager.getTabOrGlanceParent(gBrowser.getTabForBrowser(browser));
|
let droppedOnTab = gZenGlanceManager.getTabOrGlanceParent(gBrowser.getTabForBrowser(browser));
|
||||||
if (droppedOnTab === this._draggingTab) {
|
if (droppedOnTab === this._draggingTab) {
|
||||||
this.createEmptySplit(dropSide == "right");
|
this.createEmptySplit(dropSide);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1919,29 +2012,21 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const droppedOnSplitNode = this.getSplitNodeFromTab(droppedOnTab);
|
|
||||||
const parentNode = droppedOnSplitNode.parent;
|
|
||||||
|
|
||||||
// Then add the tab to the split view
|
// Then add the tab to the split view
|
||||||
group.tabs.push(draggedTab);
|
group.tabs.push(draggedTab);
|
||||||
|
|
||||||
// If dropping on a side, create a new split in that direction
|
// If dropping on a side, wrap entire layout in a new split at the root level
|
||||||
if (hoverSide !== "center") {
|
if (hoverSide !== "center") {
|
||||||
const splitDirection = hoverSide === "left" || hoverSide === "right" ? "row" : "column";
|
const splitDirection = hoverSide === "left" || hoverSide === "right" ? "row" : "column";
|
||||||
if (parentNode.direction !== splitDirection) {
|
const rootNode = group.layoutTree;
|
||||||
this.splitIntoNode(
|
const prepend = hoverSide === "left" || hoverSide === "top";
|
||||||
droppedOnSplitNode,
|
|
||||||
new nsSplitLeafNode(draggedTab, 50),
|
if (rootNode.direction === splitDirection) {
|
||||||
hoverSide,
|
// Root has the same direction, add as a new child of the root
|
||||||
0.5
|
this.addTabToSplit(draggedTab, rootNode, prepend);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
this.addTabToSplit(
|
// Different direction, wrap root in a new split node
|
||||||
draggedTab,
|
this.splitIntoNode(rootNode, new nsSplitLeafNode(draggedTab, 50), hoverSide, 0.5);
|
||||||
parentNode,
|
|
||||||
/* prepend = */ hoverSide === "left" || hoverSide === "top"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.addTabToSplit(draggedTab, group.layoutTree);
|
this.addTabToSplit(draggedTab, group.layoutTree);
|
||||||
@@ -1951,13 +2036,14 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create new split view with layout based on drop position
|
// Create new split view with layout based on drop position
|
||||||
let gridType = "vsep";
|
const gridType = dropSide === "top" || dropSide === "bottom" ? "hsep" : "vsep";
|
||||||
|
const topOrLeft = dropSide === "top" || dropSide === "left";
|
||||||
|
|
||||||
// Put tabs always as if it was dropped from the left
|
// Put tabs always as if it was dropped from the left
|
||||||
this.splitTabs(
|
this.splitTabs(
|
||||||
dropSide == "left" ? [draggedTab, droppedOnTab] : [droppedOnTab, draggedTab],
|
topOrLeft ? [draggedTab, droppedOnTab] : [droppedOnTab, draggedTab],
|
||||||
gridType,
|
gridType,
|
||||||
dropSide == "left" ? 0 : 1
|
topOrLeft ? 0 : 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2192,14 +2278,16 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createEmptySplit(rightSide = true) {
|
createEmptySplit(side = "right") {
|
||||||
const selectedTab = gBrowser.selectedTab;
|
const selectedTab = gBrowser.selectedTab;
|
||||||
const emptyTab = gZenWorkspaces._emptyTab;
|
const emptyTab = gZenWorkspaces._emptyTab;
|
||||||
let tabs = rightSide ? [selectedTab, emptyTab] : [emptyTab, selectedTab];
|
const gridType = side === "top" || side === "bottom" ? "hsep" : "vsep";
|
||||||
|
const topOrLeft = side === "top" || side === "left";
|
||||||
|
let tabs = topOrLeft ? [emptyTab, selectedTab] : [selectedTab, emptyTab];
|
||||||
const data = {
|
const data = {
|
||||||
tabs,
|
tabs,
|
||||||
gridType: "grid",
|
gridType,
|
||||||
layoutTree: this.calculateLayoutTree(tabs, "grid"),
|
layoutTree: this.calculateLayoutTree(tabs, gridType),
|
||||||
};
|
};
|
||||||
this.#withoutSplitViewTransition(() => {
|
this.#withoutSplitViewTransition(() => {
|
||||||
this._data.push(data);
|
this._data.push(data);
|
||||||
@@ -2234,9 +2322,9 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
|||||||
gBrowser.selectedTab = selectedTab;
|
gBrowser.selectedTab = selectedTab;
|
||||||
this.resetTabState(emptyTab, false);
|
this.resetTabState(emptyTab, false);
|
||||||
this.splitTabs(
|
this.splitTabs(
|
||||||
rightSide ? [selectedTab, newSelectedTab] : [newSelectedTab, selectedTab],
|
topOrLeft ? [newSelectedTab, selectedTab] : [selectedTab, newSelectedTab],
|
||||||
"grid",
|
gridType,
|
||||||
rightSide ? 1 : 0
|
topOrLeft ? 0 : 1
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|||||||
@@ -44,12 +44,12 @@
|
|||||||
#zen-splitview-dropzone {
|
#zen-splitview-dropzone {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
|
|
||||||
margin: var(--zen-split-column-gap) var(--zen-split-row-gap) !important;
|
margin: var(--zen-split-column-gap) var(--zen-split-row-gap);
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0;
|
||||||
margin-left: 0 !important;
|
margin-left: 0;
|
||||||
|
|
||||||
&.browserSidebarContainer:not([zen-split='true']) {
|
&.browserSidebarContainer:not([zen-split='true']) {
|
||||||
margin-top: 0 !important;
|
margin-top: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,6 +204,15 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
will-change: width, margin-left;
|
will-change: width, margin-left;
|
||||||
|
|
||||||
|
&[side='top'],
|
||||||
|
&[side='bottom'] {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&[has-split-view='true'] {
|
||||||
|
width: calc(100% - var(--zen-element-separation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&[side='right'] {
|
&[side='right'] {
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|
||||||
@@ -211,6 +220,10 @@
|
|||||||
right: var(--zen-element-separation);
|
right: var(--zen-element-separation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[side='bottom'] {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#zen-split-view-drag-image {
|
#zen-split-view-drag-image {
|
||||||
|
|||||||
@@ -531,8 +531,16 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
|
|||||||
const isVisible = contextTab.pinned && !contextTab.multiselected;
|
const isVisible = contextTab.pinned && !contextTab.multiselected;
|
||||||
const isEssential = contextTab.getAttribute("zen-essential");
|
const isEssential = contextTab.getAttribute("zen-essential");
|
||||||
const zenAddEssential = document.getElementById("context_zen-add-essential");
|
const zenAddEssential = document.getElementById("context_zen-add-essential");
|
||||||
document.getElementById("context_zen-reset-pinned-tab").hidden = !isVisible;
|
const zenResetPinnedTab = document.getElementById("context_zen-reset-pinned-tab");
|
||||||
document.getElementById("context_zen-replace-pinned-url-with-current").hidden = !isVisible;
|
const zenReplacePinnedUrl = document.getElementById(
|
||||||
|
"context_zen-replace-pinned-url-with-current"
|
||||||
|
);
|
||||||
|
[zenResetPinnedTab, zenReplacePinnedUrl].forEach((element) => {
|
||||||
|
if (element) {
|
||||||
|
element.hidden = !isVisible;
|
||||||
|
document.l10n.setArgs(element, { isEssential });
|
||||||
|
}
|
||||||
|
});
|
||||||
zenAddEssential.hidden = isEssential || !!contextTab.group;
|
zenAddEssential.hidden = isEssential || !!contextTab.group;
|
||||||
document.l10n
|
document.l10n
|
||||||
.formatValue("tab-context-zen-add-essential-badge", {
|
.formatValue("tab-context-zen-add-essential-badge", {
|
||||||
|
|||||||
@@ -209,7 +209,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root[zen-unsynced-window="true"] & {
|
:root[zen-unsynced-window="true"] & {
|
||||||
transform: translateY(-4px);
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,12 @@
|
|||||||
# This file is autogenerated by scripts/import_external_tests.py
|
# This file is autogenerated by scripts/import_external_tests.py
|
||||||
# Do not edit manually.
|
# Do not edit manually.
|
||||||
|
|
||||||
|
|
||||||
BROWSER_CHROME_MANIFESTS += [
|
BROWSER_CHROME_MANIFESTS += [
|
||||||
"safebrowsing/browser.toml",
|
"safebrowsing/browser.toml",
|
||||||
"sandbox/browser.toml",
|
"sandbox/browser.toml",
|
||||||
"shell/browser.toml",
|
"shell/browser.toml",
|
||||||
"tooltiptext/browser.toml",
|
"tooltiptext/browser.toml",
|
||||||
]
|
]
|
||||||
|
XPCSHELL_TESTS_MANIFESTS += [
|
||||||
|
]
|
||||||
@@ -682,13 +682,6 @@ async function testFileAccessWindowsOnly() {
|
|||||||
let tests = [];
|
let tests = [];
|
||||||
|
|
||||||
let extDir = GetPerUserExtensionDir();
|
let extDir = GetPerUserExtensionDir();
|
||||||
// We used to unconditionally create this directory from Firefox, but that
|
|
||||||
// was dropped in bug 2001887. The value of this directory is questionable;
|
|
||||||
// the test was added in Firefox 56 (bug 1403744) to cover legacy add-ons,
|
|
||||||
// but legacy add-on support was discontinued in Firefox 57, and we stopped
|
|
||||||
// sideloading add-ons from this directory on all builds except ESR in
|
|
||||||
// Firefox 74 (bug 1602840).
|
|
||||||
await IOUtils.makeDirectory(extDir.path);
|
|
||||||
tests.push({
|
tests.push({
|
||||||
desc: "per-user extensions dir",
|
desc: "per-user extensions dir",
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|||||||
@@ -22,13 +22,6 @@ add_setup(async function setup() {
|
|||||||
const xdgConfigHome = Services.env.get("XDG_CONFIG_HOME");
|
const xdgConfigHome = Services.env.get("XDG_CONFIG_HOME");
|
||||||
Assert.greater(xdgConfigHome.length, 1, "XDG_CONFIG_HOME is defined");
|
Assert.greater(xdgConfigHome.length, 1, "XDG_CONFIG_HOME is defined");
|
||||||
|
|
||||||
// Verify the profile directory is inside XDG_CONFIG_HOME
|
|
||||||
const profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
|
||||||
Assert.ok(
|
|
||||||
profileDir.path.startsWith(xdgConfigHome),
|
|
||||||
`Profile directory (${profileDir.path}) should be inside XDG_CONFIG_HOME (${xdgConfigHome})`
|
|
||||||
);
|
|
||||||
|
|
||||||
// If it is there, do actual testing
|
// If it is there, do actual testing
|
||||||
sanityChecks();
|
sanityChecks();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,14 +12,11 @@ support-files = [
|
|||||||
"browser_content_sandbox_utils.js",
|
"browser_content_sandbox_utils.js",
|
||||||
"browser_content_sandbox_fs_tests.js",
|
"browser_content_sandbox_fs_tests.js",
|
||||||
]
|
]
|
||||||
test-directories = [
|
# .config needs to exists for the sandbox to properly add it
|
||||||
"/tmp/.xdg_default_test",
|
test-directories = ["/tmp/.xdg_default_test", "/tmp/.xdg_default_test/.config"]
|
||||||
"/tmp/.xdg_default_test/.config/mozilla/firefox/xdg_default_profile",
|
|
||||||
]
|
|
||||||
environment = [
|
environment = [
|
||||||
"HOME=/tmp/.xdg_default_test",
|
"HOME=/tmp/.xdg_default_test",
|
||||||
]
|
]
|
||||||
profile-path = "/tmp/.xdg_default_test/.config/mozilla/firefox/xdg_default_profile"
|
|
||||||
|
|
||||||
["browser_content_sandbox_fs_xdg_default.js"]
|
["browser_content_sandbox_fs_xdg_default.js"]
|
||||||
run-if = ["os == 'linux'"]
|
run-if = ["os == 'linux'"]
|
||||||
|
|||||||
@@ -12,17 +12,12 @@ support-files = [
|
|||||||
"browser_content_sandbox_utils.js",
|
"browser_content_sandbox_utils.js",
|
||||||
"browser_content_sandbox_fs_tests.js",
|
"browser_content_sandbox_fs_tests.js",
|
||||||
]
|
]
|
||||||
test-directories = [
|
test-directories = ["/tmp/.xdg_mozLegacyHome_test/.config", "/tmp/.xdg_config_home_test"]
|
||||||
"/tmp/.xdg_mozLegacyHome_test/.config",
|
|
||||||
"/tmp/.xdg_config_home_test",
|
|
||||||
"/tmp/.xdg_mozLegacyHome_test/.mozilla/firefox/xdg_mozLegacyHome_profile",
|
|
||||||
]
|
|
||||||
environment = [
|
environment = [
|
||||||
"XDG_CONFIG_HOME=/tmp/.xdg_config_home_test",
|
"XDG_CONFIG_HOME=/tmp/.xdg_config_home_test",
|
||||||
"HOME=/tmp/.xdg_mozLegacyHome_test",
|
"HOME=/tmp/.xdg_mozLegacyHome_test",
|
||||||
"MOZ_LEGACY_HOME=1",
|
"MOZ_LEGACY_HOME=1",
|
||||||
]
|
]
|
||||||
profile-path = "/tmp/.xdg_mozLegacyHome_test/.mozilla/firefox/xdg_mozLegacyHome_profile"
|
|
||||||
|
|
||||||
["browser_content_sandbox_fs_xdg_mozLegacyHome.js"]
|
["browser_content_sandbox_fs_xdg_mozLegacyHome.js"]
|
||||||
run-if = ["os == 'linux'"]
|
run-if = ["os == 'linux'"]
|
||||||
|
|||||||
@@ -11,15 +11,11 @@ support-files = [
|
|||||||
"browser_content_sandbox_utils.js",
|
"browser_content_sandbox_utils.js",
|
||||||
"browser_content_sandbox_fs_tests.js",
|
"browser_content_sandbox_fs_tests.js",
|
||||||
]
|
]
|
||||||
test-directories = [
|
test-directories = "/tmp/.xdg_config_home_test"
|
||||||
"/tmp/.xdg_config_home_test",
|
|
||||||
"/tmp/.xdg_config_home_test/mozilla/firefox/xdg_config_home_profile",
|
|
||||||
]
|
|
||||||
environment = [
|
environment = [
|
||||||
"XDG_CONFIG_HOME=/tmp/.xdg_config_home_test",
|
"XDG_CONFIG_HOME=/tmp/.xdg_config_home_test",
|
||||||
"MOZ_LEGACY_HOME=0",
|
"MOZ_LEGACY_HOME=0",
|
||||||
]
|
]
|
||||||
profile-path = "/tmp/.xdg_config_home_test/mozilla/firefox/xdg_config_home_profile"
|
|
||||||
|
|
||||||
["browser_content_sandbox_fs_xdg_xdgConfigHome.js"]
|
["browser_content_sandbox_fs_xdg_xdgConfigHome.js"]
|
||||||
run-if = [
|
run-if = [
|
||||||
|
|||||||
@@ -57,12 +57,6 @@ window.ZenWorkspaceBookmarksStorage = {
|
|||||||
CREATE INDEX IF NOT EXISTS idx_bookmarks_workspaces_changes
|
CREATE INDEX IF NOT EXISTS idx_bookmarks_workspaces_changes
|
||||||
ON zen_bookmarks_workspaces_changes(bookmark_guid, workspace_uuid)
|
ON zen_bookmarks_workspaces_changes(bookmark_guid, workspace_uuid)
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Before, workspace_uuid was a FOREIGN KEY, not anymore, so we need to drop the constraint
|
|
||||||
// This is a no-op if the constraint doesn't exist
|
|
||||||
await db.execute(`
|
|
||||||
PRAGMA foreign_keys = OFF;
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ class nsZenWorkspaces {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async selectEmptyTab(newTabTarget = null, selectURLBar = true) {
|
async selectEmptyTab(newTabTarget = null) {
|
||||||
// Validate browser state first
|
// Validate browser state first
|
||||||
if (!this._validateBrowserState()) {
|
if (!this._validateBrowserState()) {
|
||||||
console.warn("Browser state invalid for empty tab selection");
|
console.warn("Browser state invalid for empty tab selection");
|
||||||
@@ -251,30 +251,6 @@ class nsZenWorkspaces {
|
|||||||
!this._emptyTab.ownerGlobal.closed &&
|
!this._emptyTab.ownerGlobal.closed &&
|
||||||
gZenVerticalTabsManager._canReplaceNewTab
|
gZenVerticalTabsManager._canReplaceNewTab
|
||||||
) {
|
) {
|
||||||
// Only set up URL bar selection if we're switching to a different tab
|
|
||||||
if (gBrowser.selectedTab !== this._emptyTab && selectURLBar) {
|
|
||||||
const tabSelectListener = () => {
|
|
||||||
// Remove the event listener first to prevent any chance of multiple executions
|
|
||||||
window.removeEventListener("TabSelect", tabSelectListener);
|
|
||||||
|
|
||||||
// Use requestAnimationFrame to ensure DOM is updated
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
// Then use setTimeout to ensure browser has time to process tab switch
|
|
||||||
setTimeout(() => {
|
|
||||||
if (gURLBar) {
|
|
||||||
try {
|
|
||||||
gURLBar.select();
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("Error selecting URL bar:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 50);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("TabSelect", tabSelectListener, { once: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Safely switch to the empty tab using our debounced method
|
// Safely switch to the empty tab using our debounced method
|
||||||
const success = await this._safelySelectTab(this._emptyTab);
|
const success = await this._safelySelectTab(this._emptyTab);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -1044,6 +1020,8 @@ class nsZenWorkspaces {
|
|||||||
delete this._initialTab;
|
delete this._initialTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showed &&= Services.prefs.getBoolPref("zen.urlbar.open-on-startup", true);
|
||||||
|
|
||||||
// Wait for the next event loop to ensure that the startup focus logic by
|
// Wait for the next event loop to ensure that the startup focus logic by
|
||||||
// firefox has finished doing it's thing.
|
// firefox has finished doing it's thing.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -1130,7 +1108,7 @@ class nsZenWorkspaces {
|
|||||||
return (
|
return (
|
||||||
!window.toolbar.visible ||
|
!window.toolbar.visible ||
|
||||||
Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab") ||
|
Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab") ||
|
||||||
this.privateWindowOrDisabled
|
(this.privateWindowOrDisabled && !this.isPrivateWindow)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2436,7 +2414,10 @@ class nsZenWorkspaces {
|
|||||||
if (!this.currentWindowIsSyncing) {
|
if (!this.currentWindowIsSyncing) {
|
||||||
containerTabId = parseInt(gBrowser.selectedTab.getAttribute("usercontextid")) || 0;
|
containerTabId = parseInt(gBrowser.selectedTab.getAttribute("usercontextid")) || 0;
|
||||||
let label = ContextualIdentityService.getUserContextLabel(containerTabId) || "Default";
|
let label = ContextualIdentityService.getUserContextLabel(containerTabId) || "Default";
|
||||||
name = this.isPrivateWindow ? "Private " + name : label;
|
name = this.isPrivateWindow ? "Incognito" : label;
|
||||||
|
if (this.isPrivateWindow) {
|
||||||
|
icon = gZenEmojiPicker.getSVGURL("eye.svg");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let workspace = {
|
let workspace = {
|
||||||
uuid: gZenUIManager.generateUuidv4(),
|
uuid: gZenUIManager.generateUuidv4(),
|
||||||
|
|||||||
@@ -156,7 +156,7 @@
|
|||||||
/* Mark workspaces indicator */
|
/* Mark workspaces indicator */
|
||||||
.zen-current-workspace-indicator {
|
.zen-current-workspace-indicator {
|
||||||
--indicator-gap: calc(var(--toolbarbutton-inner-padding) - 1px);
|
--indicator-gap: calc(var(--toolbarbutton-inner-padding) - 1px);
|
||||||
padding: calc(2px + var(--tab-inline-padding) + var(--zen-toolbox-padding));
|
padding: calc(3px + var(--tab-inline-padding) + var(--zen-toolbox-padding));
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
position: relative;
|
position: relative;
|
||||||
max-height: var(--zen-workspace-indicator-height);
|
max-height: var(--zen-workspace-indicator-height);
|
||||||
@@ -177,10 +177,10 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: var(--zen-toolbox-padding);
|
top: 4px;
|
||||||
left: calc(var(--zen-toolbox-padding) + 2px);
|
left: calc(var(--zen-toolbox-padding) + 2px);
|
||||||
width: calc(100% - var(--zen-toolbox-padding) * 3);
|
width: calc(100% - var(--zen-toolbox-padding) * 2.5);
|
||||||
height: calc(100% - var(--zen-toolbox-padding) * 2);
|
height: calc(100% - 8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
:root[zen-private-window] & {
|
:root[zen-private-window] & {
|
||||||
|
|||||||
Reference in New Issue
Block a user