Compare commits
1 commit
main
...
versionBum
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e7356bdf18 |
|
@ -1,6 +1,6 @@
|
|||
module.exports = {
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2021
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
|
@ -19,7 +19,6 @@ module.exports = {
|
|||
"OS": true,
|
||||
"ADDON_UNINSTALL": true,
|
||||
"ADDON_DISABLE": true,
|
||||
"CONTAINER_ORDER_STORAGE_KEY": true,
|
||||
"proxifiedContainers": true,
|
||||
"MozillaVPN": true,
|
||||
"MozillaVPN_Background": true
|
||||
|
|
27
.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
Feel free to ignore this Issue template if you just want to ask or suggest something. If you experience an Issue then please provide all asked information.
|
||||
|
||||
Also please make sure that:
|
||||
- "Firefox will: Never remember history" in the Firefox Preferences/Options under "Privacy & Security > History" is NOT selected
|
||||
- You are NOT using Firefox in a Private Window
|
||||
- You can see a grayed out but ticked Checkbox with the description "Enable Container Tabs" in the Firefox Preferences/Options under "Tabs"
|
||||
-->
|
||||
- Multi-Account Containers Version:
|
||||
- Operating System + Version:
|
||||
- Firefox Version:
|
||||
- Other installed Add-ons + Version + Enabled/Disabled-Status:
|
||||
<!-- To be able to copy & paste the full list of your Add-ons navigate to "about:support" and scroll down to "Extensions" -->
|
||||
|
||||
|
||||
### Actual behavior
|
||||
|
||||
|
||||
### Expected behavior
|
||||
|
||||
|
||||
### Steps to reproduce
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
### Notes
|
53
.github/ISSUE_TEMPLATE/bug.yml
vendored
|
@ -1,53 +0,0 @@
|
|||
name: Bug Report
|
||||
description: Report a problem in Multi-Account Containers
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: before-bug-report
|
||||
attributes:
|
||||
label: Before submitting a bug report
|
||||
options:
|
||||
- label: "I updated to the latest version of Multi-Account Container and tested if I can reproduce the issue"
|
||||
required: true
|
||||
- label: "I searched for existing reports to see if it hasn't already been reported"
|
||||
required: true
|
||||
- type: textarea
|
||||
id: step_to_reproduce
|
||||
attributes:
|
||||
label: "Step to reproduce"
|
||||
description: "Provide a list of steps you did to trigger this bug"
|
||||
placeholder: |
|
||||
1. I opened ...
|
||||
2. I clicked on ...
|
||||
3. ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual_behavior
|
||||
attributes:
|
||||
label: "Actual behavior"
|
||||
description: "Provide a description of what is currently happening"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected_behavior
|
||||
attributes:
|
||||
label: "Expected behavior"
|
||||
description: "Provide a description of what should happen"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional_informations
|
||||
attributes:
|
||||
label: "Additional informations"
|
||||
description: "Provide any other information revelant to this issue"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: about_support
|
||||
attributes:
|
||||
label: "Provide a copy of Troubleshooting Information page (optional)"
|
||||
description: "To get a copy of the Troubleshooting Information page, type *about:support* in the address bar and click on the *Copy text to clipboard* button."
|
||||
render: "plain text"
|
||||
validations:
|
||||
required: false
|
17
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,17 +0,0 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: "Explore our help articles"
|
||||
url: "https://support.mozilla.org/kb/containers"
|
||||
about: "Dig into the knowledge base, tips and tricks, troubleshooting, and so much more."
|
||||
- name: "Ask a support question"
|
||||
url: "https://support.mozilla.org/questions/new/desktop/form"
|
||||
about: "Get support from our contributors or staff members."
|
||||
- name: "Submit new ideas"
|
||||
url: "https://connect.mozilla.org/t5/discussions/how-to-submit-a-great-idea-in-five-easy-steps/td-p/24"
|
||||
about: "Have an idea for a new product feature? Share it with our community and staff members!"
|
||||
- name: "Discussions"
|
||||
url: "https://connect.mozilla.org/t5/discussions/bd-p/discussions"
|
||||
about: "Give feedback and participate in meaningful conversations with the community and Mozilla employees"
|
||||
- name: "Discover more awesome tools"
|
||||
url: "https://www.mozilla.org/firefox/products/"
|
||||
about: "Learn more about other products from Mozilla"
|
24
.github/pull_request_template.md
vendored
|
@ -1,24 +0,0 @@
|
|||
**Before submitting your pull request**
|
||||
|
||||
- [ ] I agree to license my code under the [MPL 2.0 license](https://www.mozilla.org/en-US/MPL/2.0/).
|
||||
- [ ] I rebased my work on top of the main branch.
|
||||
- [ ] I ran `npm test` and all tests passed.
|
||||
- [ ] I added test coverages if relevant.
|
||||
|
||||
# Description
|
||||
|
||||
*Please include a summary of the changes including relevant motivation and context.*
|
||||
|
||||
## Type of change
|
||||
|
||||
*Select all that apply.*
|
||||
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Major change (fix or feature that would cause existing functionality to work differently than in the current version)
|
||||
|
||||
Tag issues related to this pull request:
|
||||
|
||||
*
|
||||
*
|
||||
*
|
6
.github/workflows/builds.yaml
vendored
|
@ -14,11 +14,11 @@ on:
|
|||
jobs:
|
||||
builds:
|
||||
name: Builds
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Create the package
|
||||
shell: bash
|
||||
|
@ -26,7 +26,7 @@ jobs:
|
|||
./bin/build-addon.sh nightly.xpi
|
||||
|
||||
- name: Uploading
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: ${{matrix.config.name}} Build
|
||||
path: src/web-ext-artifacts
|
||||
|
|
28
.github/workflows/test.yaml
vendored
|
@ -1,28 +0,0 @@
|
|||
name: Test
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- production
|
||||
pull_request:
|
||||
branches:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --legacy-peer-deps
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test
|
2
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
.DS_Store
|
||||
package-lock.json
|
||||
node_modules
|
||||
README.html
|
||||
*.xpi
|
||||
|
@ -8,7 +9,6 @@ README.html
|
|||
addon.env
|
||||
|
||||
src/web-ext-artifacts/*
|
||||
web-ext-artifacts
|
||||
|
||||
# JetBrains IDE files
|
||||
.idea
|
||||
|
|
10
.travis.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "lts/*"
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
- "ircs://irc.mozilla.org:6697/#testpilot-containers-bots"
|
||||
|
||||
install:
|
||||
- npm install --legacy-peer-deps
|
|
@ -1,54 +1,35 @@
|
|||
# Contributing
|
||||
|
||||
## Requirements
|
||||
Everyone is welcome to contribute to containers. Reach out to team members if you have questions:
|
||||
|
||||
* Firefox 91.1.0+
|
||||
* Git 2.13+
|
||||
* Node 7+
|
||||
- Matrix chat: [#containers:mozilla.org](https://matrix.to/#/#containers:mozilla.org)
|
||||
- Email: containers@mozilla.com
|
||||
|
||||
## Getting Started
|
||||
## Filing bugs
|
||||
|
||||
1. Follow the instructions on [How to fork a repository][fork]
|
||||
2. Fetch the locales:
|
||||
If you find a bug with containers, please file a issue.
|
||||
|
||||
```
|
||||
cd multi-account-containers
|
||||
git submodule update --init
|
||||
```
|
||||
3. Install the project dependencies
|
||||
```
|
||||
npm install --legacy-peer-deps
|
||||
```
|
||||
4. Run `npm run dev`.
|
||||
Check first if the bug might already exist: https://github.com/mozilla/multi-account-containers/issues
|
||||
|
||||
## Translations
|
||||
[Open an issue](https://github.com/mozilla/multi-account-containers/issues/new)
|
||||
|
||||
The translations are located in `src/_locales`. This directory is a git
|
||||
repository like any other. Before editing files in this folder, you need to:
|
||||
1. Visit about:support
|
||||
2. Click "Copy raw data to clipboard" and paste into the bug. Alternatively copy the following sections into the issue:
|
||||
- Application Basics
|
||||
- Nightly Features (if you are in nightly)
|
||||
- Extensions
|
||||
- Experimental Features
|
||||
3. Include clear steps to reproduce the issue you have experienced.
|
||||
4. Include screenshots if possible.
|
||||
|
||||
1. `cd src/_locales/`
|
||||
2. `git checkout -b message-updates-yyyymmdd`
|
||||
3. `git push -u origin message-updates-yyyymmdd`
|
||||
## Sending Pull Requests
|
||||
|
||||
You can then [open a pull request][pr] on [the l10n repository][l10n].
|
||||
Patches should be submitted as pull requests. When submitting patches as PRs:
|
||||
|
||||
## Tips for contributing
|
||||
- You agree to license your code under the project's open source license (MPL 2.0).
|
||||
- Base your branch off the current master (see below for an example workflow).
|
||||
- Add both your code and new tests if relevant.
|
||||
- Run npm test to make sure all tests still pass.
|
||||
- Please do not include merge commits in pull requests; include only commits with the new relevant code.
|
||||
|
||||
1. Choose [an issue][issues] that you would like to work on.
|
||||
2. Fork the repository and follow the instructions for setting it up locally.
|
||||
3. Run the add-on locally and try reproducing the issue.
|
||||
4. Debug add-ons by clicking the “Settings” icon in about:addons, and then clicking “Debug Add-ons”
|
||||
5. Click “Inspect” on the MAC add-on to open developer tools for the popup extension (see [this documentation][extension-doc] for more information)
|
||||
6. Once you have a fix ready, commit your changes with the following commit message template: “Fix #<insert issue id #>: <short description>”
|
||||
7. Push your changes and open a pull request for review.
|
||||
|
||||
If you run into an issue, you can always ask the other community members in the [discussions board][discussions].
|
||||
|
||||
<!-- Please keep the list in alphabetical order -->
|
||||
[discussions]: https://github.com/mozilla/multi-account-containers/discussions
|
||||
[extension-doc]: https://extensionworkshop.com/documentation/develop/debugging/
|
||||
[fork]: https://docs.github.com/en/get-started/quickstart/fork-a-repo
|
||||
[issues]: https://github.com/mozilla/multi-account-containers/issues
|
||||
[l10n]: https://github.com/mozilla-l10n/multi-account-containers-l10n/
|
||||
[pr]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests
|
||||
[web-ext]: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext
|
||||
See the main [README](./README.md) for information on prerequisites, installing, running and testing.
|
||||
|
|
120
README.md
|
@ -1,33 +1,109 @@
|
|||
# Multi-Account Containers
|
||||
|
||||
[](https://github.com/mozilla/multi-account-containers/actions/workflows/test.yaml)
|
||||
The Firefox Multi-Account Containers extension lets you carve out a separate box for each of your online lives – no more opening a different browser just to check your work email! [Learn More Here](https://blog.mozilla.org/firefox/introducing-firefox-multi-account-containers/)
|
||||
|
||||
The Firefox Multi-Account Containers extension lets you carve out a separate box for each of your online lives – no more opening a different browser just to check your work email!
|
||||
[Available on addons.mozilla.org](https://addons.mozilla.org/firefox/addon/multi-account-containers/)
|
||||
|
||||
Learn more about Multi-Account Containers in
|
||||
[our end-user documentation][enduser].
|
||||
For more info, see:
|
||||
|
||||
## Contributing
|
||||
* [Test Pilot Product Hypothesis Document](https://docs.google.com/document/d/1WQdHTVXROk7dYkSFluc6_hS44tqZjIrG9I-uPyzevE8/edit#)
|
||||
* [Shield Product Hypothesis Document](https://docs.google.com/document/d/1vMD-fH_5hGDDqNvpRZk12_RhCN2WAe4_yaBamaNdtik/edit#)
|
||||
|
||||
Everyone is welcome to contribute to Multi-Account Containers. To learn how
|
||||
to contribute a patch to Multi-Account Container, please
|
||||
[read our contributing guide][contributing].
|
||||
|
||||
You can also chat with us on [our Matrix room][matrix] or ask in [our discussions board][discussions].
|
||||
## Requirements
|
||||
|
||||
This repository is governed by Mozilla's code of conduct and etiquette
|
||||
guidelines. For more details, [please read the Mozilla Community Participation Guidelines][cpg].
|
||||
* node 7+ (for jpm)
|
||||
* Firefox 91.1.0+
|
||||
|
||||
### License
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
## Development
|
||||
|
||||
<!-- Please keep the list in alphabetical order -->
|
||||
[contributing]: CONTRIBUTING.md
|
||||
[cpg]: https://www.mozilla.org/about/governance/policies/participation/
|
||||
[enduser]: https://support.mozilla.org/en-US/kb/containers
|
||||
[forum]: https://discourse.mozilla.org/c/containers/223
|
||||
[discussions]: https://github.com/mozilla/multi-account-containers/discussions
|
||||
[matrix]: https://matrix.to/#/#containers:mozilla.org
|
||||
### Running Locally
|
||||
|
||||
#### Via WebExtensions API (web-ext)
|
||||
|
||||
1. Fetch the locales updating the git-submodules: `git submodule init && git submodule update --remote --depth 1 src/_locales`
|
||||
2. Install the [web-ext](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext) tool.
|
||||
3. Run `web-ext run -s src/`. This launches Firefox and installs the extension automatically.
|
||||
|
||||
This tool provides some additional development features, such as [automatic reloading](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext#Automatic_extension_reloading).
|
||||
|
||||
#### Via about:debugging in Firefox
|
||||
|
||||
1. Fetch the locales updating the git-submodules: `git submodule init && git submodule update --remote --depth 1 src/_locales`
|
||||
2. Open the `about:debugging` page in Firefox.
|
||||
3. Click on `This Firefox`.
|
||||
4. Click on [Load Temporary Add-on](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox).
|
||||
5. Select `src/manifest.json`.
|
||||
|
||||
Here is a [video](https://www.youtube.com/watch?v=cer9EUKegG4) that demonstrates how to do this.
|
||||
|
||||
### Testing
|
||||
|
||||
* Install dependencies:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
* Run all tests:
|
||||
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
* Only run the linter:
|
||||
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
There is a timeout test that sometimes fails on certain machines, so make sure to run the tests on your clone before you make any changes to see if you have this problem.
|
||||
|
||||
#### Add/update messages for translation
|
||||
|
||||
The `src/_locales` directory is a git repository like any other, so to make changes to the messages:
|
||||
|
||||
1. Make whatever changes you need in `src/_locales/en` as you work.
|
||||
|
||||
2. `cd src/_locales/en`
|
||||
|
||||
3. `git branch message-updates-yyyymmdd`
|
||||
|
||||
4. `git push -u origin message-updates-yyyymmdd`
|
||||
|
||||
You can then open a pull request from the `message-updates-yyyymmdd` branch to
|
||||
|
||||
[the l10n repo](https://github.com/mozilla-l10n/multi-account-containers-l10n/) `main` branch.
|
||||
|
||||
### Distributing
|
||||
#### Make the new version
|
||||
|
||||
1. Bump the version number in `package.json` and `manifest.json`
|
||||
2. Commit the version number bump
|
||||
3. Create a git tag for the version: `git tag <version>`
|
||||
4. Push the tag up to GitHub: `git push --tags`
|
||||
|
||||
#### Publish to AMO
|
||||
|
||||
1. `./bin/build-addon.sh`
|
||||
2. [Upload the `.zip` to AMO](https://addons.mozilla.org/developers/addon/multi-account-containers/versions/submit/)
|
||||
|
||||
#### Publish to GitHub
|
||||
|
||||
Finally, we also publish the release to GitHub for those followers.
|
||||
|
||||
1. Download the signed `.xpi` from [the addon versions page](https://addons.mozilla.org/developers/addon/multi-account-containers/versions)
|
||||
2. [Make the new release on
|
||||
GitHub](https://github.com/mozilla/multi-account-containers/releases/new)
|
||||
* Use the version number for "Tag version" and "Release title"
|
||||
* Release notes: copy the output of `git log --no-merges --pretty=format:"%h %s" <previous-version>..<new-version>`
|
||||
* Attach binaries: select the signed `.xpi` file
|
||||
|
||||
### Links
|
||||
|
||||
Facebook & Twitter icons CC-Attrib https://fairheadcreative.com.
|
||||
|
||||
- [License](./LICENSE.txt)
|
||||
- [Contributing](./CONTRIBUTING.md)
|
||||
- [Code Of Conduct](./CODE_OF_CONDUCT.md)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -32,4 +32,4 @@ rm -rf $TMPDIR/src/_locales/.github || die
|
|||
print G "done."
|
||||
|
||||
print Y "Running the test..."
|
||||
npx addons-linter $TMPDIR/src || die
|
||||
$(npm bin)/addons-linter $TMPDIR/src || die
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -23,4 +23,4 @@ if [[ $# -gt 0 ]]; then
|
|||
EXTRA_PARAMS="--filename $1"
|
||||
fi
|
||||
|
||||
npx web-ext build --overwrite-dest $EXTRA_PARAMS || die
|
||||
$(npm bin)/web-ext build --overwrite-dest $EXTRA_PARAMS || die
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
|
31
docs/acceptance.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Acceptance Criteria
|
||||
|
||||
## User Experience
|
||||
- [ ] It should place a containers button on the user’s browser toolbar
|
||||
- [ ] It should include all containers management UI inside a door hanger from this toolbar button
|
||||
- [ ] It should provide a set of default container choices for users to pick from (work, home, travel etc.)
|
||||
- [ ] Each container type should have a color, icon and name
|
||||
- [ ] It should allow users to create new containers
|
||||
- [ ] It should allow users to delete containers
|
||||
- [ ] It should allow users to open container tabs
|
||||
- [ ] each container tab should be clearly demarcated by color/icon etc.
|
||||
- [ ] It should provide a control to show/hide all open tabs of one container type
|
||||
- [ ] It should provide a control to sort tabs by container type
|
||||
- [ ] It should provide a control to allow users to open containers in new tab or new window by default
|
||||
|
||||
## User Experience Non-Requirements (out of scope)
|
||||
- [ ] It should not show any UI in browser settings
|
||||
- [ ] It should not effect the awesome bar
|
||||
- [ ] It should not effect the Firefox Library
|
||||
- [ ] It should not make any changes to sync functionality
|
||||
|
||||
## Measurements
|
||||
- [ ] It should measure container tab creations per session
|
||||
- [ ] It should measure the type of container tab created
|
||||
- [ ] It should measure container tab creations
|
||||
- [ ] It should measure new container creations
|
||||
- [ ] It should measure container deletes
|
||||
- [ ] It should measure container sorts
|
||||
- [ ] It should measure container hides
|
||||
- [ ] It should report URIs accessed across multiple containers
|
||||
- [ ] It should measure the % of tab-based vs windows-based containers
|
BIN
docs/kpi-1.png
Normal file
After Width: | Height: | Size: 95 KiB |
|
@ -1,31 +0,0 @@
|
|||
# Release a new version
|
||||
|
||||
## Make the new version
|
||||
|
||||
1. Bump the version number in `package.json` and `manifest.json`
|
||||
2. Commit the version number bump
|
||||
3. Create a git tag for the version: `git tag <version>`
|
||||
4. Push the tag up to GitHub: `git push --tags`
|
||||
|
||||
## Publish to AMO
|
||||
|
||||
1. Run `./bin/build-addon.sh`
|
||||
2. [Upload the zip file to AMO][amo-upload]
|
||||
|
||||
## Publish to GitHub
|
||||
|
||||
Finally, we also publish the release to GitHub.
|
||||
|
||||
1. Download the signed `.xpi` from [the addon versions page][addon-page]
|
||||
2. [Create a new release on GitHub][gh-release]
|
||||
* For *Tag version* and *Release title*, use the version number
|
||||
* For *Release notes*, copy the output of:
|
||||
```
|
||||
git log --no-merges \
|
||||
--pretty=format:"%h %s" <previous-version>..<new-version>
|
||||
```
|
||||
* For the *Attach binaries*, select the signed `.xpi` file
|
||||
|
||||
[addon-page]: https://addons.mozilla.org/developers/addon/multi-account-containers/versions
|
||||
[amo-upload]: https://addons.mozilla.org/developers/addon/multi-account-containers/versions/submit/
|
||||
[gh-release]: https://github.com/mozilla/multi-account-containers/releases/new
|
25098
package-lock.json
generated
13
package.json
|
@ -2,14 +2,14 @@
|
|||
"name": "testpilot-containers",
|
||||
"title": "Multi-Account Containers",
|
||||
"description": "Containers helps you keep all the parts of your online life contained in different tabs. Custom labels and color-coded tabs help keep different activities — like online shopping, travel planning, or checking work email — separate.",
|
||||
"version": "8.3.0",
|
||||
"version": "8.0.7",
|
||||
"author": "Andrea Marchesini, Luke Crouch, Lesley Norton, Kendall Werts, Maxx Crawford, Jonathan Kingston",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mozilla/multi-account-containers/issues"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"addons-linter": "^5.28.0",
|
||||
"addons-linter": "^3.23.0",
|
||||
"ajv": "^6.6.3",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
|
@ -17,7 +17,7 @@
|
|||
"eslint-plugin-promise": "^5.2.0",
|
||||
"htmllint-cli": "0.0.7",
|
||||
"json": ">=10.0.0",
|
||||
"mocha": "^10.1.0",
|
||||
"mocha": "^6.2.2",
|
||||
"npm-run-all": "^4.0.0",
|
||||
"nyc": "^15.0.0",
|
||||
"sinon": "^7.5.0",
|
||||
|
@ -25,7 +25,7 @@
|
|||
"stylelint": "^13.5.0",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"stylelint-order": "^4.0.0",
|
||||
"web-ext": "^7.5.0",
|
||||
"web-ext": "^5.4.1",
|
||||
"webextensions-jsdom": "^1.2.1"
|
||||
},
|
||||
"homepage": "https://github.com/mozilla/multi-account-containers#readme",
|
||||
|
@ -36,16 +36,13 @@
|
|||
"url": "git+https://github.com/mozilla/multi-account-containers.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "web-ext build -s src/",
|
||||
"dev": "npm run remove-locales-github && web-ext run -s src/",
|
||||
"webext": "web-ext run -s src/",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"lint:addon": "./bin/addons-linter.sh",
|
||||
"lint:css": "stylelint src/css/*.css",
|
||||
"lint:html": "htmllint *.html",
|
||||
"lint:js": "eslint .",
|
||||
"package": "rm -rf src/web-ext-artifacts && npm run build && mv src/web-ext-artifacts/firefox_multi-account_containers-*.zip addon.xpi",
|
||||
"restore-locales-github": "cd src/_locales && git restore .github/",
|
||||
"remove-locales-github": "rm -rf src/_locales/.github",
|
||||
"test": "npm run lint && npm run coverage",
|
||||
"test:once": "mocha test/**/*.test.js",
|
||||
"test:watch": "npm run test:once -- --watch",
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit bdaa01291b7367a5e815470fd263ea36c862fe32
|
||||
Subproject commit f3da295d004b7d6314c5baa321d9a5418ec937d9
|
|
@ -3,7 +3,6 @@
|
|||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title data-i18n-message-id="confirmNavigationTitle"></title>
|
||||
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="chrome://browser/skin/aboutNetError.css" type="text/css" media="all" />
|
||||
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="chrome://global/skin/aboutNetError.css" type="text/css" media="all" />
|
||||
<script type="text/javascript" src="./js/i18n.js"></script>
|
||||
<link rel="stylesheet" href="/css/confirm-page.css" />
|
||||
</head>
|
||||
|
@ -24,21 +23,8 @@
|
|||
</label>
|
||||
<br />
|
||||
<div class="button-container">
|
||||
<button id="deny"
|
||||
class="button"
|
||||
data-message-id="openInContainer"
|
||||
data-message-arg="current-container-name">
|
||||
</button>
|
||||
<button id="deny-no-container"
|
||||
class="button"
|
||||
data-message-id="openInNoContainer">
|
||||
</button>
|
||||
<button id="confirm"
|
||||
class="button primary"
|
||||
autofocus
|
||||
data-message-id="openInContainer"
|
||||
data-message-arg="container-name">
|
||||
</button>
|
||||
<button id="deny" class="button" data-message-id="openInContainer" data-message-arg="current-container-name"></button>
|
||||
<button id="confirm" class="button primary" autofocus data-message-id="openInContainer" data-message-arg="container-name"></button>
|
||||
</div>
|
||||
</form>
|
||||
</main>
|
||||
|
|
1072
src/css/popup.css
BIN
src/img/container-site-d-24.png
Normal file
After Width: | Height: | Size: 342 B |
BIN
src/img/container-site-d-48.png
Normal file
After Width: | Height: | Size: 578 B |
BIN
src/img/container-site-d-96.png
Normal file
After Width: | Height: | Size: 1 KiB |
9
src/img/multiaccountcontainer-16-dark.svg
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --><svg data-name="Flat (For Export)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<style>rect,path {fill: rgba(249, 249, 250, 0.8);}</style>
|
||||
<rect x="1" y="1" width="6" height="6" rx="1"/>
|
||||
<path d="M14.75 3H13V1.25A0.25 0.25 0 0 0 12.75 1h-1.5A0.25 0.25 0 0 0 11 1.25V3H9.25A0.25 0.25 0 0 0 9 3.25v1.5A0.25 0.25 0 0 0 9.25 5H11v1.75A0.25 0.25 0 0 0 11.25 7h1.5A0.25 0.25 0 0 0 13 6.75V5h1.75A0.25 0.25 0 0 0 15 4.75v-1.5A0.25 0.25 0 0 0 14.75 3z" fill-rule="evenodd"/>
|
||||
<rect x="1" y="9" width="6" height="6" rx="1"/>
|
||||
<rect x="9" y="9" width="6" height="6" rx="1"/>
|
||||
</svg>
|
After Width: | Height: | Size: 801 B |
|
@ -1,11 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<style>
|
||||
:root { color-scheme: light dark; }
|
||||
rect, path { fill: rgb(24, 25, 26); }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
rect, path { fill: rgba(249, 249, 250, 0.8); }
|
||||
}
|
||||
</style>
|
||||
<svg data-name="Flat (For Export)" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<style>rect,path {fill: rgba(24, 25, 26, 01);}</style>
|
||||
<rect x="1" y="1" width="6" height="6" rx="1"/>
|
||||
<path d="M14.75 3H13V1.25A0.25 0.25 0 0 0 12.75 1h-1.5A0.25 0.25 0 0 0 11 1.25V3H9.25A0.25 0.25 0 0 0 9 3.25v1.5A0.25 0.25 0 0 0 9.25 5H11v1.75A0.25 0.25 0 0 0 11.25 7h1.5A0.25 0.25 0 0 0 13 6.75V5h1.75A0.25 0.25 0 0 0 15 4.75v-1.5A0.25 0.25 0 0 0 14.75 3z" fill-rule="evenodd"/>
|
||||
<rect x="1" y="9" width="6" height="6" rx="1"/>
|
||||
|
|
Before Width: | Height: | Size: 727 B After Width: | Height: | Size: 586 B |
|
@ -4,7 +4,6 @@
|
|||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32" style="enable-background:new 0 0 32 32;">
|
||||
<style>
|
||||
:root { color-scheme: light dark; }
|
||||
path, circle, g {
|
||||
fill: menutext;
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
@ -61,9 +61,8 @@ window.assignManager = {
|
|||
this.area.get([siteStoreKey]).then((storageResponse) => {
|
||||
if (storageResponse && siteStoreKey in storageResponse) {
|
||||
resolve(storageResponse[siteStoreKey]);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
resolve(null);
|
||||
}).catch((e) => {
|
||||
reject(e);
|
||||
});
|
||||
|
@ -103,7 +102,6 @@ window.assignManager = {
|
|||
async deleteContainer(userContextId) {
|
||||
const sitesByContainer = await this.getAssignedSites(userContextId);
|
||||
this.area.remove(Object.keys(sitesByContainer));
|
||||
identityState.storageArea.remove(backgroundLogic.cookieStoreId(userContextId));
|
||||
},
|
||||
|
||||
async getAssignedSites(userContextId = null) {
|
||||
|
@ -166,17 +164,11 @@ window.assignManager = {
|
|||
_neverAsk(m) {
|
||||
const pageUrl = m.pageUrl;
|
||||
if (m.neverAsk === true) {
|
||||
if (m.defaultContainer === true) {
|
||||
this.storageArea.remove(pageUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have existing data and for some reason it hasn't been
|
||||
// deleted etc lets update it
|
||||
this.storageArea.get(pageUrl).then((siteSettings) => {
|
||||
if (siteSettings) {
|
||||
siteSettings.neverAsk = true;
|
||||
siteSettings.userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(m.cookieStoreId);
|
||||
this.storageArea.set(pageUrl, siteSettings);
|
||||
}
|
||||
}).catch((e) => {
|
||||
|
@ -205,17 +197,12 @@ window.assignManager = {
|
|||
return {};
|
||||
}
|
||||
|
||||
// proxyDNS only works for SOCKS proxies
|
||||
if (["socks", "socks4"].includes(result.proxy.type)) {
|
||||
result.proxy.proxyDNS = true;
|
||||
}
|
||||
|
||||
if (!result.proxy.mozProxyEnabled) {
|
||||
return result.proxy;
|
||||
return { ...result.proxy, proxyDNS: true };
|
||||
}
|
||||
|
||||
// Let's add the isolation key.
|
||||
return [{ ...result.proxy, connectionIsolationKey: "" + MozillaVPN_Background.isolationKey }];
|
||||
return [{ ...result.proxy, connectionIsolationKey: "" + MozillaVPN_Background.isolationKey, proxyDNS: true }];
|
||||
},
|
||||
|
||||
// Before a request is handled by the browser we decide if we should
|
||||
|
@ -326,8 +313,7 @@ window.assignManager = {
|
|||
options.url,
|
||||
tab.index + 1,
|
||||
tab.active,
|
||||
openTabId,
|
||||
tab.groupId
|
||||
openTabId
|
||||
);
|
||||
} else {
|
||||
this.reloadPageInContainer(
|
||||
|
@ -337,8 +323,7 @@ window.assignManager = {
|
|||
tab.index + 1,
|
||||
tab.active,
|
||||
siteSettings.neverAsk,
|
||||
openTabId,
|
||||
tab.groupId
|
||||
openTabId
|
||||
);
|
||||
}
|
||||
this.calculateContextMenu(tab);
|
||||
|
@ -483,7 +468,9 @@ window.assignManager = {
|
|||
},
|
||||
|
||||
contextualIdentityRemoved(changeInfo) {
|
||||
this.removeMenuItem(changeInfo.contextualIdentity.cookieStoreId);
|
||||
browser.contextMenus.remove(
|
||||
changeInfo.contextualIdentity.cookieStoreId
|
||||
);
|
||||
},
|
||||
|
||||
async _onClickedHandler(info, tab) {
|
||||
|
@ -578,16 +565,6 @@ window.assignManager = {
|
|||
return true;
|
||||
},
|
||||
|
||||
async _resetCookiesForSite(hostname, cookieStoreId) {
|
||||
const hostNameTruncated = hostname.replace(/^www\./, ""); // Remove "www." from the hostname
|
||||
await browser.browsingData.removeCookies({
|
||||
cookieStoreId: cookieStoreId,
|
||||
hostnames: [hostNameTruncated] // This does not remove cookies from associated domains. To remove all cookies, we have a container storage removal option.
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
async _setOrRemoveAssignment(tabId, pageUrl, userContextId, remove) {
|
||||
let actionName;
|
||||
// https://github.com/mozilla/testpilot-containers/issues/626
|
||||
|
@ -639,7 +616,7 @@ window.assignManager = {
|
|||
},
|
||||
|
||||
async _maybeRemoveSiteIsolation(userContextId) {
|
||||
const assignments = await this.storageArea.getAssignedSites(userContextId);
|
||||
const assignments = await this.storageArea.getByContainer(userContextId);
|
||||
const hasAssignments = assignments && Object.keys(assignments).length > 0;
|
||||
if (hasAssignments) {
|
||||
return;
|
||||
|
@ -670,11 +647,11 @@ window.assignManager = {
|
|||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1215376#c16
|
||||
// We also can't change for always private mode
|
||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1352102
|
||||
this.removeMenuItem(this.MENU_ASSIGN_ID);
|
||||
this.removeMenuItem(this.MENU_REMOVE_ID);
|
||||
this.removeMenuItem(this.MENU_SEPARATOR_ID);
|
||||
this.removeMenuItem(this.MENU_HIDE_ID);
|
||||
this.removeMenuItem(this.MENU_MOVE_ID);
|
||||
browser.contextMenus.remove(this.MENU_ASSIGN_ID);
|
||||
browser.contextMenus.remove(this.MENU_REMOVE_ID);
|
||||
browser.contextMenus.remove(this.MENU_SEPARATOR_ID);
|
||||
browser.contextMenus.remove(this.MENU_HIDE_ID);
|
||||
browser.contextMenus.remove(this.MENU_MOVE_ID);
|
||||
},
|
||||
|
||||
async calculateContextMenu(tab) {
|
||||
|
@ -695,7 +672,7 @@ window.assignManager = {
|
|||
}
|
||||
browser.contextMenus.create({
|
||||
id: menuId,
|
||||
title: browser.i18n.getMessage("alwaysOpenSiteInContainer"),
|
||||
title: "Always Open in This Container",
|
||||
checked,
|
||||
type: "checkbox",
|
||||
contexts: ["all"],
|
||||
|
@ -709,13 +686,13 @@ window.assignManager = {
|
|||
|
||||
browser.contextMenus.create({
|
||||
id: this.MENU_HIDE_ID,
|
||||
title: browser.i18n.getMessage("hideThisContainer"),
|
||||
title: "Hide This Container",
|
||||
contexts: ["all"],
|
||||
});
|
||||
|
||||
browser.contextMenus.create({
|
||||
id: this.MENU_MOVE_ID,
|
||||
title: browser.i18n.getMessage("moveTabsToANewWindow"),
|
||||
title: "Move Tabs to a New Window",
|
||||
contexts: ["all"],
|
||||
});
|
||||
},
|
||||
|
@ -727,15 +704,7 @@ window.assignManager = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {number} index
|
||||
* @param {boolean} active
|
||||
* @param {number} [openerTabId]
|
||||
* @param {number} [groupId]
|
||||
* @returns {void}
|
||||
*/
|
||||
reloadPageInDefaultContainer(url, index, active, openerTabId, groupId) {
|
||||
reloadPageInDefaultContainer(url, index, active, openerTabId) {
|
||||
// To create a new tab in the default container, it is easiest just to omit the
|
||||
// cookieStoreId entirely.
|
||||
//
|
||||
|
@ -754,58 +723,16 @@ window.assignManager = {
|
|||
// does not automatically return to the original opener tab. To get this desired behaviour,
|
||||
// we MUST specify the openerTabId when creating the new tab.
|
||||
const cookieStoreId = "firefox-default";
|
||||
this.createTabWrapper(url, cookieStoreId, index, active, openerTabId, groupId);
|
||||
browser.tabs.create({url, cookieStoreId, index, active, openerTabId});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Wraps around `browser.tabs.create` and `browser.tabs.group` to create a
|
||||
* tab and ensure that it ends up in the requested tab group, if applicable.
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {string} cookieStoreId
|
||||
* @param {number} index
|
||||
* @param {boolean} active
|
||||
* @param {number} openerTabId
|
||||
* @param {number} [groupId] Tab group ID
|
||||
* @returns {Promise<Tab>}
|
||||
*/
|
||||
async createTabWrapper(url, cookieStoreId, index, active, openerTabId, groupId) {
|
||||
const newTab = await browser.tabs.create({
|
||||
url,
|
||||
cookieStoreId,
|
||||
index,
|
||||
active,
|
||||
openerTabId,
|
||||
});
|
||||
|
||||
if (groupId >= 0) {
|
||||
// If the original tab was in a tab group, make sure that the reopened tab
|
||||
// stays in the same tab group.
|
||||
await browser.tabs.group({ groupId, tabIds: newTab.id });
|
||||
}
|
||||
|
||||
return newTab;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {string} currentUserContextId
|
||||
* @param {string} userContextId
|
||||
* @param {number} index
|
||||
* @param {boolean} active
|
||||
* @param {boolean} [neverAsk=false]
|
||||
* @param {number} [openerTabId=null]
|
||||
* @param {number} [groupId]
|
||||
* @returns {Promise<Tab>}
|
||||
*/
|
||||
reloadPageInContainer(url, currentUserContextId, userContextId, index, active, neverAsk = false, openerTabId = null, groupId = undefined) {
|
||||
reloadPageInContainer(url, currentUserContextId, userContextId, index, active, neverAsk = false, openerTabId = null) {
|
||||
const cookieStoreId = backgroundLogic.cookieStoreId(userContextId);
|
||||
const loadPage = browser.runtime.getURL("confirm-page.html");
|
||||
// False represents assignment is not permitted
|
||||
// If the user has explicitly checked "Never Ask Again" on the warning page we will send them straight there
|
||||
if (neverAsk) {
|
||||
return this.createTabWrapper(url, cookieStoreId, index, active, openerTabId, groupId);
|
||||
return browser.tabs.create({url, cookieStoreId, index, active, openerTabId});
|
||||
} else {
|
||||
let confirmUrl = `${loadPage}?url=${this.encodeURLProperty(url)}&cookieStoreId=${cookieStoreId}`;
|
||||
let currentCookieStoreId;
|
||||
|
@ -813,14 +740,13 @@ window.assignManager = {
|
|||
currentCookieStoreId = backgroundLogic.cookieStoreId(currentUserContextId);
|
||||
confirmUrl += `¤tCookieStoreId=${currentCookieStoreId}`;
|
||||
}
|
||||
return this.createTabWrapper(
|
||||
confirmUrl,
|
||||
currentCookieStoreId,
|
||||
index,
|
||||
active,
|
||||
return browser.tabs.create({
|
||||
url: confirmUrl,
|
||||
cookieStoreId: currentCookieStoreId,
|
||||
openerTabId,
|
||||
groupId
|
||||
).then(() => {
|
||||
index,
|
||||
active
|
||||
}).then(() => {
|
||||
// We don't want to sync this URL ever nor clutter the users history
|
||||
browser.history.deleteUrl({url: confirmUrl});
|
||||
}).catch((e) => {
|
||||
|
@ -832,7 +758,7 @@ window.assignManager = {
|
|||
async initBookmarksMenu() {
|
||||
browser.contextMenus.create({
|
||||
id: this.OPEN_IN_CONTAINER,
|
||||
title: browser.i18n.getMessage("openBookmarkInContainerTab"),
|
||||
title: "Open Bookmark in Container Tab",
|
||||
contexts: ["bookmark"],
|
||||
});
|
||||
|
||||
|
@ -848,19 +774,12 @@ window.assignManager = {
|
|||
},
|
||||
|
||||
async removeBookmarksMenu() {
|
||||
this.removeMenuItem(this.OPEN_IN_CONTAINER);
|
||||
browser.contextMenus.remove(this.OPEN_IN_CONTAINER);
|
||||
const identities = await browser.contextualIdentities.query({});
|
||||
for (const identity of identities) {
|
||||
this.removeMenuItem(identity.cookieStoreId);
|
||||
browser.contextMenus.remove(identity.cookieStoreId);
|
||||
}
|
||||
},
|
||||
|
||||
removeMenuItem(menuItemId) {
|
||||
// Callers do not check whether the menu exists before attempting to remove
|
||||
// it. contextMenus.remove rejects when the menu does not exist, so we need
|
||||
// to catch and swallow the error to avoid logspam.
|
||||
browser.contextMenus.remove(menuItemId).catch(() => {});
|
||||
}
|
||||
};
|
||||
|
||||
assignManager.init();
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
/* 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/. */
|
||||
|
||||
const DEFAULT_TAB = "about:newtab";
|
||||
|
||||
const backgroundLogic = {
|
||||
NEW_TAB_PAGES: new Set([
|
||||
"about:startpage",
|
||||
|
@ -14,13 +9,7 @@ const backgroundLogic = {
|
|||
NUMBER_OF_KEYBOARD_SHORTCUTS: 10,
|
||||
unhideQueue: [],
|
||||
init() {
|
||||
|
||||
browser.commands.onCommand.addListener(function (command) {
|
||||
if (command === "sort_tabs") {
|
||||
backgroundLogic.sortTabs();
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i=0; i < backgroundLogic.NUMBER_OF_KEYBOARD_SHORTCUTS; i++) {
|
||||
const key = "open_container_" + i;
|
||||
const cookieStoreId = identityState.keyboardShortcut[key];
|
||||
|
@ -33,49 +22,6 @@ const backgroundLogic = {
|
|||
|
||||
browser.permissions.onAdded.addListener(permissions => this.resetPermissions(permissions));
|
||||
browser.permissions.onRemoved.addListener(permissions => this.resetPermissions(permissions));
|
||||
|
||||
// Update Translation in Manifest
|
||||
browser.runtime.onInstalled.addListener((details) => {
|
||||
this.updateTranslationInManifest();
|
||||
this._undoDefault820SortTabsKeyboardShortcut(details);
|
||||
});
|
||||
browser.runtime.onStartup.addListener(this.updateTranslationInManifest);
|
||||
},
|
||||
|
||||
/**
|
||||
* One-time migration after updating from v8.2.0:
|
||||
* Unset the default keyboard shortcut (Ctrl+Comma) for the `sort_tabs`
|
||||
* command if it was set in v8.2.0 of this addon. If the user remapped
|
||||
* a different shortcut manually, retain their shortcut. Users who used
|
||||
* the default keyboard shortcut will need to manually set a shortcut.
|
||||
* See https://support.mozilla.org/en-US/kb/manage-extension-shortcuts-firefox
|
||||
*
|
||||
* @param {{reason: runtime.OnInstalledReason, previousVersion?: string}} details
|
||||
*/
|
||||
async _undoDefault820SortTabsKeyboardShortcut(details) {
|
||||
if (details.reason === "update" && details.previousVersion === "8.2.0") {
|
||||
const commands = await browser.commands.getAll();
|
||||
const sortTabsCommand = commands.find(command => command.name === "sort_tabs");
|
||||
if (sortTabsCommand) {
|
||||
const previouslySuggestedKeys = [
|
||||
"Ctrl+Comma", // "default"
|
||||
"MacCtrl+Comma", // "mac"
|
||||
];
|
||||
if (previouslySuggestedKeys.includes(sortTabsCommand.shortcut)) {
|
||||
browser.commands.reset("sort_tabs");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateTranslationInManifest() {
|
||||
for (let index = 0; index < 10; index++) {
|
||||
const ajustedIndex = index + 1; // We want to start from 1 instead of 0 in the UI.
|
||||
browser.commands.update({
|
||||
name: `open_container_${index}`,
|
||||
description: browser.i18n.getMessage("containerShortcut", `${ajustedIndex}`)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
resetPermissions(permissions) {
|
||||
|
@ -104,19 +50,6 @@ const backgroundLogic = {
|
|||
return extensionInfo;
|
||||
},
|
||||
|
||||
// Remove container data (cookies, localStorage and cache)
|
||||
async deleteContainerDataOnly(userContextId) {
|
||||
await browser.browsingData.removeCookies({
|
||||
cookieStoreId: this.cookieStoreId(userContextId)
|
||||
});
|
||||
|
||||
await browser.browsingData.removeLocalStorage({
|
||||
cookieStoreId: this.cookieStoreId(userContextId)
|
||||
});
|
||||
|
||||
return {done: true, userContextId};
|
||||
},
|
||||
|
||||
getUserContextIdFromCookieStoreId(cookieStoreId) {
|
||||
if (!cookieStoreId) {
|
||||
return false;
|
||||
|
@ -185,8 +118,7 @@ const backgroundLogic = {
|
|||
// We can't open these we just have to throw them away
|
||||
if (protocol === "about:"
|
||||
|| protocol === "chrome:"
|
||||
|| protocol === "moz-extension:"
|
||||
|| protocol === "file:") {
|
||||
|| protocol === "moz-extension:") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -372,13 +304,7 @@ const backgroundLogic = {
|
|||
let pos = 0;
|
||||
|
||||
// Let's collect UCIs/tabs for this window.
|
||||
/** @type {Map<string, {order: string, tabs: Tab[]}>} */
|
||||
const map = new Map;
|
||||
|
||||
const lastTab = tabs.at(-1);
|
||||
/** @type {boolean} */
|
||||
let lastTabIsInTabGroup = !!lastTab && lastTab.groupId >= 0;
|
||||
|
||||
for (const tab of tabs) {
|
||||
if (pinnedTabs && !tab.pinned) {
|
||||
// We don't have, or we already handled all the pinned tabs.
|
||||
|
@ -391,51 +317,26 @@ const backgroundLogic = {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (tab.groupId >= 0) {
|
||||
// Skip over tabs in tab groups until it's possible to handle them better.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!map.has(tab.cookieStoreId)) {
|
||||
const userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId);
|
||||
map.set(tab.cookieStoreId, { order: userContextId, tabs: [] });
|
||||
if (!map.has(userContextId)) {
|
||||
map.set(userContextId, []);
|
||||
}
|
||||
map.get(tab.cookieStoreId).tabs.push(tab);
|
||||
}
|
||||
|
||||
const containerOrderStorage = await browser.storage.local.get([CONTAINER_ORDER_STORAGE_KEY]);
|
||||
const containerOrder =
|
||||
containerOrderStorage && containerOrderStorage[CONTAINER_ORDER_STORAGE_KEY];
|
||||
|
||||
if (containerOrder) {
|
||||
map.forEach((obj, key) => {
|
||||
obj.order = (key in containerOrder) ? containerOrder[key] : -1;
|
||||
});
|
||||
map.get(userContextId).push(tab);
|
||||
}
|
||||
|
||||
// Let's sort the map.
|
||||
const sortMap = new Map([...map.entries()].sort((a, b) => a[1].order > b[1].order));
|
||||
const sortMap = new Map([...map.entries()].sort((a, b) => a[0] > b[0]));
|
||||
|
||||
// Let's move tabs.
|
||||
for (const { tabs } of sortMap.values()) {
|
||||
sortMap.forEach(tabs => {
|
||||
for (const tab of tabs) {
|
||||
++pos;
|
||||
browser.tabs.move(tab.id, {
|
||||
windowId: windowObj.id,
|
||||
index: pinnedTabs ? pos : -1
|
||||
index: pos
|
||||
});
|
||||
// Pinned tabs are never grouped and always inserted in the front.
|
||||
if (!pinnedTabs && lastTabIsInTabGroup && browser.tabs.ungroup) {
|
||||
// If the last item in the tab strip is a grouped tab, moving a tab
|
||||
// to its position will also add it to the tab group. Since this code
|
||||
// is only sorting ungrouped tabs, this forcibly ungroups the first
|
||||
// tab to be moved. All subsequent iterations will only be moving
|
||||
// ungrouped tabs to the position of other ungrouped tabs.
|
||||
lastTabIsInTabGroup = false;
|
||||
browser.tabs.ungroup(tab.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
async hideTabs(options) {
|
||||
|
|
|
@ -23,9 +23,6 @@ const messageHandler = {
|
|||
case "deleteContainer":
|
||||
response = backgroundLogic.deleteContainer(m.message.userContextId);
|
||||
break;
|
||||
case "deleteContainerDataOnly":
|
||||
response = backgroundLogic.deleteContainerDataOnly(m.message.userContextId);
|
||||
break;
|
||||
case "createOrUpdateContainer":
|
||||
response = backgroundLogic.createOrUpdateContainer(m.message);
|
||||
break;
|
||||
|
@ -48,9 +45,6 @@ const messageHandler = {
|
|||
// m.url is the assignment to be removed/added
|
||||
response = assignManager._setOrRemoveAssignment(m.tabId, m.url, m.userContextId, m.value);
|
||||
break;
|
||||
case "resetCookiesForSite":
|
||||
response = assignManager._resetCookiesForSite(m.pageUrl, m.cookieStoreId);
|
||||
break;
|
||||
case "sortTabs":
|
||||
backgroundLogic.sortTabs();
|
||||
break;
|
||||
|
@ -91,9 +85,7 @@ const messageHandler = {
|
|||
m.newUserContextId,
|
||||
m.tabIndex,
|
||||
m.active,
|
||||
true,
|
||||
null,
|
||||
m.groupId
|
||||
true
|
||||
);
|
||||
break;
|
||||
case "assignAndReloadInContainer":
|
||||
|
@ -103,9 +95,7 @@ const messageHandler = {
|
|||
m.newUserContextId,
|
||||
m.tabIndex,
|
||||
m.active,
|
||||
true,
|
||||
null,
|
||||
m.groupId
|
||||
true
|
||||
);
|
||||
// m.tabId is used for where to place the in content message
|
||||
// m.url is the assignment to be removed/added
|
||||
|
@ -230,9 +220,7 @@ const messageHandler = {
|
|||
// if it's a container tab wait for it to complete and
|
||||
// unhide other tabs from this container
|
||||
if (tab.cookieStoreId.startsWith("firefox-container")) {
|
||||
browser.tabs.onUpdated.addListener(this.tabUpdateHandler, {
|
||||
properties: ["status"]
|
||||
});
|
||||
browser.tabs.onUpdated.addListener(this.tabUpdateHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,21 +7,14 @@ async function load() {
|
|||
redirectUrlElement.textContent = redirectUrl;
|
||||
appendFavicon(redirectUrl, redirectUrlElement);
|
||||
|
||||
// Option for staying on the previous container
|
||||
document.getElementById("deny").addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
denySubmit(redirectUrl, currentCookieStoreId);
|
||||
});
|
||||
|
||||
// Option for going to the default container (no container)
|
||||
document.getElementById("deny-no-container").addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
denySubmit(redirectUrl, currentCookieStoreId);
|
||||
denySubmit(redirectUrl);
|
||||
});
|
||||
|
||||
const container = await browser.contextualIdentities.get(cookieStoreId);
|
||||
const currentContainer = currentCookieStoreId ? await browser.contextualIdentities.get(currentCookieStoreId) : null;
|
||||
const currentContainerName = currentContainer ? setDenyButton(currentContainer.name) : setDenyButton("");
|
||||
const currentContainerName = currentContainer ? currentContainer.name : "";
|
||||
|
||||
document.querySelectorAll("[data-message-id]").forEach(el => {
|
||||
const elementData = el.dataset;
|
||||
|
@ -29,25 +22,12 @@ async function load() {
|
|||
el.textContent = browser.i18n.getMessage(elementData.messageId, containerName);
|
||||
});
|
||||
|
||||
// Option for going to newly selected container
|
||||
document.getElementById("confirm").addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
confirmSubmit(redirectUrl, cookieStoreId);
|
||||
});
|
||||
}
|
||||
|
||||
function setDenyButton(currentContainerName) {
|
||||
const buttonDeny = document.getElementById("deny");
|
||||
const buttonDenyNoContainer = document.getElementById("deny-no-container");
|
||||
|
||||
if (currentContainerName) {
|
||||
buttonDenyNoContainer.style.display = "none";
|
||||
return currentContainerName;
|
||||
}
|
||||
buttonDeny.style.display = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
function appendFavicon(pageUrl, redirectUrlElement) {
|
||||
const origin = new URL(pageUrl).origin;
|
||||
const favIconElement = Utils.createFavIconElement(`${origin}/favicon.ico`);
|
||||
|
@ -62,42 +42,24 @@ function confirmSubmit(redirectUrl, cookieStoreId) {
|
|||
browser.runtime.sendMessage({
|
||||
method: "neverAsk",
|
||||
neverAsk: true,
|
||||
cookieStoreId: cookieStoreId,
|
||||
pageUrl: redirectUrl
|
||||
});
|
||||
}
|
||||
openInContainer(redirectUrl, cookieStoreId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Tab>}
|
||||
*/
|
||||
async function getCurrentTab() {
|
||||
const tabs = await browser.tabs.query({
|
||||
function getCurrentTab() {
|
||||
return browser.tabs.query({
|
||||
active: true,
|
||||
windowId: browser.windows.WINDOW_ID_CURRENT
|
||||
});
|
||||
return tabs[0];
|
||||
}
|
||||
|
||||
async function denySubmit(redirectUrl, currentCookieStoreId) {
|
||||
async function denySubmit(redirectUrl) {
|
||||
const tab = await getCurrentTab();
|
||||
const currentContainer = currentCookieStoreId ? await browser.contextualIdentities.get(currentCookieStoreId) : null;
|
||||
const neverAsk = document.getElementById("never-ask").checked;
|
||||
|
||||
if (neverAsk) {
|
||||
await browser.runtime.sendMessage({
|
||||
method: "neverAsk",
|
||||
neverAsk: true,
|
||||
cookieStoreId: currentCookieStoreId,
|
||||
pageUrl: redirectUrl,
|
||||
defaultContainer: !currentContainer
|
||||
});
|
||||
}
|
||||
|
||||
await browser.runtime.sendMessage({
|
||||
method: "exemptContainerAssignment",
|
||||
tabId: tab.id,
|
||||
tabId: tab[0].id,
|
||||
pageUrl: redirectUrl
|
||||
});
|
||||
document.location.replace(redirectUrl);
|
||||
|
@ -107,15 +69,12 @@ load();
|
|||
|
||||
async function openInContainer(redirectUrl, cookieStoreId) {
|
||||
const tab = await getCurrentTab();
|
||||
const reopenedTab = await browser.tabs.create({
|
||||
index: tab.index + 1,
|
||||
await browser.tabs.create({
|
||||
index: tab[0].index + 1,
|
||||
cookieStoreId,
|
||||
url: redirectUrl
|
||||
});
|
||||
if (tab.groupId >= 0) {
|
||||
// If the original tab was in a tab group, make sure that the reopened tab
|
||||
// stays in the same tab group.
|
||||
await browser.tabs.group({ groupId: tab.groupId, tabIds: reopenedTab.id });
|
||||
if (tab.length > 0) {
|
||||
browser.tabs.remove(tab[0].id);
|
||||
}
|
||||
await browser.tabs.remove(tab.id);
|
||||
}
|
||||
|
|
|
@ -24,12 +24,11 @@ async function addMessage(message) {
|
|||
divElement.innerText = message.text;
|
||||
|
||||
const imageElement = document.createElement("img");
|
||||
const imagePath = browser.runtime.getURL("/img/multiaccountcontainer-16.svg");
|
||||
const imagePath = browser.runtime.getURL("/img/container-site-d-24.png");
|
||||
const response = await fetch(imagePath);
|
||||
const blob = await response.blob();
|
||||
const objectUrl = URL.createObjectURL(blob);
|
||||
imageElement.src = objectUrl;
|
||||
imageElement.width = imageElement.height = 24;
|
||||
divElement.prepend(imageElement);
|
||||
|
||||
document.body.appendChild(divElement);
|
||||
|
|
|
@ -34,8 +34,11 @@ const MozillaVPN = {
|
|||
}
|
||||
if (!mozillaVpnConnected && proxy.mozProxyEnabled) {
|
||||
flag.classList.add("proxy-unavailable");
|
||||
const tooltip = el.querySelector(".tooltip.proxy-unavailable");
|
||||
if (tooltip) {
|
||||
tooltip.textContent = tooltipProxyWarning;
|
||||
}
|
||||
const menuItemName = el.querySelector(".menu-item-name");
|
||||
menuItemName.setAttribute("title", tooltipProxyWarning);
|
||||
if (menuItemName) {
|
||||
el.querySelector(".menu-item-name").dataset.mozProxyWarning = "proxy-unavailable";
|
||||
}
|
||||
|
@ -65,11 +68,14 @@ const MozillaVPN = {
|
|||
const mozillaVpnConnected = await browser.runtime.sendMessage({ method: "MozillaVPN_getConnectionStatus" });
|
||||
const connectionStatusStringId = mozillaVpnConnected ? "moz-vpn-connected" : "moz-vpn-disconnected";
|
||||
const connectionStatusLocalizedString = browser.i18n.getMessage(connectionStatusStringId);
|
||||
const connectionStatusTooltip = document.querySelector(".vpn-status-container-list");
|
||||
connectionStatusTooltip.setAttribute("title", connectionStatusLocalizedString);
|
||||
|
||||
statusIconEls.forEach(el => {
|
||||
el.style.backgroundImage = mozillaVpnConnected ? connectedIndicatorSrc : disconnectedIndicatorSrc;
|
||||
if (el.querySelector(".tooltip")) {
|
||||
el.querySelector(".tooltip").textContent = connectionStatusLocalizedString;
|
||||
} else {
|
||||
el.textContent = connectionStatusLocalizedString;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -53,20 +53,11 @@ async function enableDisableReplaceTab() {
|
|||
await browser.storage.local.set({replaceTabEnabled: !!checkbox.checked});
|
||||
}
|
||||
|
||||
async function changeTheme(event) {
|
||||
const theme = event.currentTarget;
|
||||
await browser.storage.local.set({currentTheme: theme.value});
|
||||
await browser.storage.local.set({currentThemeId: theme.selectedIndex});
|
||||
}
|
||||
|
||||
async function setupOptions() {
|
||||
const { syncEnabled } = await browser.storage.local.get("syncEnabled");
|
||||
const { replaceTabEnabled } = await browser.storage.local.get("replaceTabEnabled");
|
||||
const { currentThemeId } = await browser.storage.local.get("currentThemeId");
|
||||
|
||||
document.querySelector("#syncCheck").checked = !!syncEnabled;
|
||||
document.querySelector("#replaceTabCheck").checked = !!replaceTabEnabled;
|
||||
document.querySelector("#changeTheme").selectedIndex = currentThemeId;
|
||||
setupContainerShortcutSelects();
|
||||
}
|
||||
|
||||
|
@ -123,8 +114,6 @@ browser.permissions.onRemoved.addListener(resetPermissionsUi);
|
|||
document.addEventListener("DOMContentLoaded", setupOptions);
|
||||
document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync);
|
||||
document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab);
|
||||
document.querySelector("#changeTheme").addEventListener( "change", changeTheme);
|
||||
|
||||
maybeShowPermissionsWarningIcon();
|
||||
for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) {
|
||||
document.querySelector("#open_container_"+i)
|
||||
|
|
|
@ -32,9 +32,6 @@ async function init() {
|
|||
list.appendChild(fragment);
|
||||
|
||||
MozillaVPN.handleContainerList(identities);
|
||||
|
||||
// Set the theme
|
||||
Utils.applyTheme();
|
||||
}
|
||||
|
||||
init();
|
||||
|
|
190
src/js/popup.js
|
@ -10,6 +10,7 @@ const DEFAULT_ICON = "circle";
|
|||
const NEW_CONTAINER_ID = "new";
|
||||
|
||||
const ONBOARDING_STORAGE_KEY = "onboarding-stage";
|
||||
const CONTAINER_ORDER_STORAGE_KEY = "container-order";
|
||||
const CONTAINER_DRAG_DATA_TYPE = "firefox-container";
|
||||
|
||||
// List of panels
|
||||
|
@ -32,7 +33,6 @@ const P_CONTAINER_EDIT = "containerEdit";
|
|||
const P_CONTAINER_DELETE = "containerDelete";
|
||||
const P_CONTAINERS_ACHIEVEMENT = "containersAchievement";
|
||||
const P_CONTAINER_ASSIGNMENTS = "containerAssignments";
|
||||
const P_CLEAR_CONTAINER_STORAGE = "clearContainerStorage";
|
||||
|
||||
const P_MOZILLA_VPN_SERVER_LIST = "moz-vpn-server-list";
|
||||
const P_ADVANCED_PROXY_SETTINGS = "advanced-proxy-settings-panel";
|
||||
|
@ -66,9 +66,6 @@ const Logic = {
|
|||
method: "MozillaVPN_attemptPort"
|
||||
}),
|
||||
|
||||
// Set the theme
|
||||
Utils.applyTheme();
|
||||
|
||||
// Remove browserAction "upgraded" badge when opening panel
|
||||
this.clearBrowserActionBadge();
|
||||
|
||||
|
@ -123,19 +120,6 @@ const Logic = {
|
|||
|
||||
},
|
||||
|
||||
notify(i18nOpts) {
|
||||
const notificationCards = document.querySelectorAll(".popup-notification-card");
|
||||
const text = browser.i18n.getMessage(i18nOpts.messageId, i18nOpts.placeholders);
|
||||
notificationCards.forEach(notificationCard => {
|
||||
notificationCard.textContent = text;
|
||||
notificationCard.classList.add("is-shown");
|
||||
|
||||
setTimeout(() => {
|
||||
notificationCard.classList.remove("is-shown");
|
||||
}, 2000);
|
||||
});
|
||||
},
|
||||
|
||||
async showAchievementOrContainersListPanel() {
|
||||
// Do we need to show an achievement panel?
|
||||
let showAchievements = false;
|
||||
|
@ -225,11 +209,6 @@ const Logic = {
|
|||
async saveContainerOrder(rows) {
|
||||
const containerOrder = {};
|
||||
rows.forEach((node, index) => {
|
||||
if (typeof browser.contextualIdentities.move === "function") {
|
||||
browser.contextualIdentities.move(
|
||||
node.dataset.containerId, index);
|
||||
}
|
||||
|
||||
return containerOrder[node.dataset.containerId] = index;
|
||||
});
|
||||
await browser.storage.local.set({
|
||||
|
@ -415,11 +394,7 @@ const Logic = {
|
|||
},
|
||||
|
||||
shortcutListener(e){
|
||||
function openTopContainers() {
|
||||
const identities = Logic.identities();
|
||||
const key = e.code.substring(5);
|
||||
const identity = e.code === "Digit0" ? identities[9] : identities[key - 1];
|
||||
|
||||
function openNewContainerTab(identity) {
|
||||
try {
|
||||
browser.tabs.create({
|
||||
cookieStoreId: identity.cookieStoreId
|
||||
|
@ -429,34 +404,12 @@ const Logic = {
|
|||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
// We monitor if the search input is focused so we can disable opening
|
||||
// containers by typing a digit between 0-9 while the popup is open.
|
||||
const searchInput = document.getElementById("search-terms");
|
||||
let isSearchInputFocused = false;
|
||||
|
||||
if (document.activeElement === searchInput) {
|
||||
isSearchInputFocused = true;
|
||||
}
|
||||
|
||||
if (Logic._currentPanel === "containersList" && !isSearchInputFocused) {
|
||||
switch(e.code) {
|
||||
case "Digit0":
|
||||
case "Digit1":
|
||||
case "Digit2":
|
||||
case "Digit3":
|
||||
case "Digit4":
|
||||
case "Digit5":
|
||||
case "Digit6":
|
||||
case "Digit7":
|
||||
case "Digit8":
|
||||
case "Digit9":
|
||||
openTopContainers();
|
||||
break;
|
||||
case "Slash":
|
||||
document.getElementById("search-terms").focus();
|
||||
e.preventDefault();
|
||||
break;
|
||||
const identities = Logic.identities();
|
||||
if ((e.keyCode >= 49 && e.keyCode <= 57) &&
|
||||
Logic._currentPanel === "containersList") {
|
||||
const identity = identities[e.keyCode - 49];
|
||||
if (identity) {
|
||||
openNewContainerTab(identity);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -509,23 +462,6 @@ const Logic = {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
filterContainerList() {
|
||||
const pattern = /^\s+|\s+$/g;
|
||||
const list = Array.from(document.querySelectorAll("#identities-list tr"));
|
||||
const search = document.querySelector("#search-terms").value.replace(pattern, "").toLowerCase();
|
||||
|
||||
for (const i in list) {
|
||||
const text = list[i].querySelector("td div span");
|
||||
|
||||
if (text.innerText.replace(pattern, "").toLowerCase().includes(search) ||
|
||||
!search) {
|
||||
list[i].style.display = "block";
|
||||
} else {
|
||||
list[i].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -685,7 +621,7 @@ Logic.registerPanel(P_ONBOARDING_7, {
|
|||
// Let's move to the containers list panel.
|
||||
Utils.addEnterHandler(document.querySelector("#sign-in"), async () => {
|
||||
browser.tabs.create({
|
||||
url: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=multi-account-containers&utm_source=addon&utm_medium=panel&utm_campaign=container-sync&brand=mozilla",
|
||||
url: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=multi-account-containers&utm_source=addon&utm_medium=panel&utm_campaign=container-sync",
|
||||
});
|
||||
await Logic.setOnboardingStage(7);
|
||||
Logic.showPanel(P_ONBOARDING_8);
|
||||
|
@ -767,6 +703,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
|||
}
|
||||
});
|
||||
|
||||
const mozillaVpnToutName = "moz-tout-main-panel";
|
||||
const mozillaVpnPermissionsWarningDotName = "moz-permissions-warning-dot";
|
||||
|
||||
let { mozillaVpnHiddenToutsList } = await browser.storage.local.get("mozillaVpnHiddenToutsList");
|
||||
|
@ -775,6 +712,31 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
|||
mozillaVpnHiddenToutsList = [];
|
||||
}
|
||||
|
||||
// Decide whether to show Mozilla VPN tout
|
||||
const mozVpnTout = document.getElementById("moz-vpn-tout");
|
||||
const mozillaVpnInstalled = await browser.runtime.sendMessage({ method: "MozillaVPN_getInstallationStatus" });
|
||||
const mozillaVpnToutShouldBeHidden = mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnToutName);
|
||||
if (mozillaVpnInstalled || mozillaVpnToutShouldBeHidden) {
|
||||
mozVpnTout.remove();
|
||||
}
|
||||
|
||||
// Add handlers if tout is visible
|
||||
const mozVpnDismissTout = document.querySelector(".dismiss-moz-vpn-tout");
|
||||
if (mozVpnDismissTout) {
|
||||
Utils.addEnterHandler((mozVpnDismissTout), async() => {
|
||||
mozVpnTout.remove();
|
||||
mozillaVpnHiddenToutsList.push({
|
||||
name: mozillaVpnToutName
|
||||
});
|
||||
await browser.storage.local.set({ mozillaVpnHiddenToutsList });
|
||||
});
|
||||
|
||||
Utils.addEnterHandler(document.querySelector("#moz-vpn-learn-more"), () => {
|
||||
MozillaVPN.handleMozillaCtaClick("mac-main-panel-btn");
|
||||
window.close();
|
||||
});
|
||||
}
|
||||
|
||||
// Badge Options icon if both nativeMessaging and/or proxy permissions are disabled
|
||||
const bothMozillaVpnPermissionsEnabled = await MozillaVPN.bothPermissionsEnabled();
|
||||
const warningDotShouldBeHidden = mozillaVpnHiddenToutsList.find(tout => tout.name === mozillaVpnPermissionsWarningDotName);
|
||||
|
@ -824,6 +786,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
|||
</div>
|
||||
</div>
|
||||
<span class="menu-text">${identity.name}</span>
|
||||
<span class="tooltip proxy-unavailable"></span>
|
||||
</div>
|
||||
<span class="menu-right-float">
|
||||
<img alt="" class="always-open-in-flag flag-img" src="/img/flags/.png"/>
|
||||
|
@ -882,7 +845,6 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
|||
|
||||
document.addEventListener("keydown", Logic.keyboardNavListener);
|
||||
document.addEventListener("keydown", Logic.shortcutListener);
|
||||
document.addEventListener("input", Logic.filterContainerList);
|
||||
|
||||
MozillaVPN.handleContainerList(identities);
|
||||
|
||||
|
@ -959,7 +921,6 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
|||
Utils.alwaysOpenInContainer(identity);
|
||||
window.close();
|
||||
});
|
||||
|
||||
// Show or not the has-tabs section.
|
||||
for (let trHasTabs of document.getElementsByClassName("container-info-has-tabs")) { // eslint-disable-line prefer-const
|
||||
trHasTabs.style.display = !identity.hasHiddenTabs && !identity.hasOpenTabs ? "none" : "";
|
||||
|
@ -983,13 +944,6 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
|||
Utils.addEnterHandler(manageContainer, async () => {
|
||||
Logic.showPanel(P_CONTAINER_EDIT, identity);
|
||||
});
|
||||
const clearContainerStorageButton = document.getElementById("clear-container-storage-info");
|
||||
Utils.addEnterHandler(clearContainerStorageButton, async () => {
|
||||
const granted = await browser.permissions.request({ permissions: ["browsingData"] });
|
||||
if (granted) {
|
||||
Logic.showPanel(P_CLEAR_CONTAINER_STORAGE, identity);
|
||||
}
|
||||
});
|
||||
return this.buildOpenTabTable(tabs);
|
||||
},
|
||||
|
||||
|
@ -1280,8 +1234,7 @@ Logic.registerPanel(REOPEN_IN_CONTAINER_PICKER, {
|
|||
false,
|
||||
newUserContextId,
|
||||
currentTab.index + 1,
|
||||
currentTab.active,
|
||||
currentTab.groupId
|
||||
currentTab.active
|
||||
);
|
||||
window.close();
|
||||
};
|
||||
|
@ -1291,7 +1244,6 @@ Logic.registerPanel(REOPEN_IN_CONTAINER_PICKER, {
|
|||
if (currentTab.cookieStoreId !== "firefox-default") {
|
||||
const tr = document.createElement("tr");
|
||||
tr.classList.add("menu-item", "hover-highlight", "keyboard-nav");
|
||||
tr.setAttribute("tabindex", "0");
|
||||
const td = document.createElement("td");
|
||||
|
||||
td.innerHTML = Utils.escaped`
|
||||
|
@ -1311,8 +1263,7 @@ Logic.registerPanel(REOPEN_IN_CONTAINER_PICKER, {
|
|||
false,
|
||||
0,
|
||||
currentTab.index + 1,
|
||||
currentTab.active,
|
||||
currentTab.groupId
|
||||
currentTab.active
|
||||
);
|
||||
window.close();
|
||||
});
|
||||
|
@ -1453,14 +1404,11 @@ Logic.registerPanel(P_CONTAINER_ASSIGNMENTS, {
|
|||
/* As we don't have the full or correct path the best we can assume is the path is HTTPS and then replace with a broken icon later if it doesn't load.
|
||||
This is pending a better solution for favicons from web extensions */
|
||||
const assumedUrl = `https://${site.hostname}/favicon.ico`;
|
||||
const resetSiteCookiesInfo = browser.i18n.getMessage("clearSiteCookiesTooltipInfo");
|
||||
const deleteSiteInfo = browser.i18n.getMessage("deleteSiteTooltipInfo");
|
||||
trElement.innerHTML = Utils.escaped`
|
||||
<td>
|
||||
<div class="favicon"></div>
|
||||
<span title="${site.hostname}" class="menu-text truncate-text">${site.hostname}</span>
|
||||
<img title="${resetSiteCookiesInfo}" class="reset-button reset-assignment" src="/img/refresh-16.svg" />
|
||||
<img title="${deleteSiteInfo}" class="trash-button delete-assignment" src="/img/container-delete.svg" />
|
||||
<span title="${site.hostname}" class="menu-text">${site.hostname}</span>
|
||||
<img class="trash-button delete-assignment" src="/img/container-delete.svg" />
|
||||
</td>`;
|
||||
trElement.getElementsByClassName("favicon")[0].appendChild(Utils.createFavIconElement(assumedUrl));
|
||||
const deleteButton = trElement.querySelector(".trash-button");
|
||||
|
@ -1472,20 +1420,6 @@ Logic.registerPanel(P_CONTAINER_ASSIGNMENTS, {
|
|||
delete assignments[siteKey];
|
||||
this.showAssignedContainers(assignments);
|
||||
});
|
||||
const resetButton = trElement.querySelector(".reset-button");
|
||||
Utils.addEnterHandler(resetButton, async () => {
|
||||
const cookieStoreId = Logic.currentCookieStoreId();
|
||||
const granted = await browser.permissions.request({ permissions: ["browsingData"] });
|
||||
if (!granted) {
|
||||
return;
|
||||
}
|
||||
const result = await Utils.resetCookiesForSite(site.hostname, cookieStoreId);
|
||||
if (result === true) {
|
||||
Logic.notify({messageId: "cookiesClearedSuccess", placeholders: [site.hostname]});
|
||||
} else {
|
||||
Logic.notify({messageId: "cookiesCouldNotBeCleared", placeholders: [site.hostname]});
|
||||
}
|
||||
});
|
||||
trElement.classList.add("menu-item", "hover-highlight", "keyboard-nav");
|
||||
tableElement.appendChild(trElement);
|
||||
});
|
||||
|
@ -1613,7 +1547,6 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
|||
this.updateProxyDependentUi(proxy);
|
||||
} else {
|
||||
this.switch.checked = false;
|
||||
this.updateProxyDependentUi({});
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
@ -1744,6 +1677,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
|||
this.currentCityName.textContent = proxyInfo.cityName;
|
||||
this.countryCode = proxyInfo.countryCode;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
expandUi() {
|
||||
|
@ -1958,7 +1892,6 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
|||
if (proxyPermissionEnabled) {
|
||||
const proxyData = await proxifiedContainers.retrieve(identity.cookieStoreId);
|
||||
if (proxyData && proxyData.proxy.mozProxyEnabled && !mozillaVpnConnected) {
|
||||
mozillaVpnUi.updateProxyDependentUi({});
|
||||
return;
|
||||
}
|
||||
const proxy = proxyData ? proxyData.proxy : {};
|
||||
|
@ -2261,47 +2194,6 @@ Logic.registerPanel(P_MOZILLA_VPN_SERVER_LIST, {
|
|||
}
|
||||
});
|
||||
|
||||
// P_CLEAR_CONTAINER_STORAGE: Page for confirming container storage removal.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Logic.registerPanel(P_CLEAR_CONTAINER_STORAGE, {
|
||||
panelSelector: "#clear-container-storage-panel",
|
||||
|
||||
// This method is called when the object is registered.
|
||||
initialize() {
|
||||
|
||||
Utils.addEnterHandler(document.querySelector("#clear-container-storage-cancel-link"), () => {
|
||||
const identity = Logic.currentIdentity();
|
||||
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
|
||||
});
|
||||
Utils.addEnterHandler(document.querySelector("#close-clear-container-storage-panel"), () => {
|
||||
const identity = Logic.currentIdentity();
|
||||
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
|
||||
});
|
||||
Utils.addEnterHandler(document.querySelector("#clear-container-storage-ok-link"), async () => {
|
||||
const identity = Logic.currentIdentity();
|
||||
const userContextId = Utils.userContextId(identity.cookieStoreId);
|
||||
const result = await browser.runtime.sendMessage({
|
||||
method: "deleteContainerDataOnly",
|
||||
message: { userContextId }
|
||||
});
|
||||
if (result.done === true) {
|
||||
Logic.notify({messageId: "storageWasClearedConfirmation", placeholders: [identity.name]});
|
||||
}
|
||||
Logic.showPanel(P_CONTAINER_INFO, identity, false, false);
|
||||
});
|
||||
},
|
||||
|
||||
// This method is called when the panel is shown.
|
||||
prepare() {
|
||||
const identity = Logic.currentIdentity();
|
||||
|
||||
// Populating the panel: name, icon, and warning message
|
||||
document.getElementById("container-clear-storage-title").textContent = identity.name;
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
});
|
||||
|
||||
// P_CONTAINER_DELETE: Delete a container.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ proxifiedContainers = {
|
|||
|
||||
// Parses a proxy description string of the format type://host[:port] or type://username:password@host[:port] (port is optional)
|
||||
parseProxy(proxy_str, mozillaVpnData = null) {
|
||||
const proxyRegexp = /(?<type>(https?)|(socks4?)):\/\/(\b(?<username>[\w-]+):(?<password>[\w-]+)@)?(?<host>((?:\d{1,3}\.){3}\d{1,3}\b)|(\b([\w.-]+)+))(:(?<port>\d+))?/;
|
||||
const proxyRegexp = /(?<type>(https?)|(socks4?)):\/\/(\b(?<username>\w+):(?<password>\w+)@)?(?<host>((?:\d{1,3}\.){3}\d{1,3}\b)|(\b([\w.-]+)+))(:(?<port>\d+))?/;
|
||||
const matches = proxyRegexp.exec(proxy_str);
|
||||
if (!matches) {
|
||||
return false;
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
const DEFAULT_FAVICON = "/img/blank-favicon.svg";
|
||||
|
||||
// eslint-disable-next-line
|
||||
const CONTAINER_ORDER_STORAGE_KEY = "container-order";
|
||||
|
||||
// TODO use export here instead of globals
|
||||
const Utils = {
|
||||
|
||||
|
@ -94,9 +91,6 @@ const Utils = {
|
|||
return result.join("");
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Promise<Tab|false>}
|
||||
*/
|
||||
async currentTab() {
|
||||
const activeTabs = await browser.tabs.query({ active: true, windowId: browser.windows.WINDOW_ID_CURRENT });
|
||||
if (activeTabs.length > 0) {
|
||||
|
@ -141,32 +135,14 @@ const Utils = {
|
|||
});
|
||||
},
|
||||
|
||||
resetCookiesForSite(pageUrl, cookieStoreId) {
|
||||
return browser.runtime.sendMessage({
|
||||
method: "resetCookiesForSite",
|
||||
pageUrl,
|
||||
cookieStoreId,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @param {string} currentUserContextId
|
||||
* @param {string} newUserContextId
|
||||
* @param {number} tabIndex
|
||||
* @param {boolean} active
|
||||
* @param {number} [groupId]
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
async reloadInContainer(url, currentUserContextId, newUserContextId, tabIndex, active, groupId = undefined) {
|
||||
async reloadInContainer(url, currentUserContextId, newUserContextId, tabIndex, active) {
|
||||
return await browser.runtime.sendMessage({
|
||||
method: "reloadInContainer",
|
||||
url,
|
||||
currentUserContextId,
|
||||
newUserContextId,
|
||||
tabIndex,
|
||||
active,
|
||||
groupId
|
||||
active
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -180,8 +156,7 @@ const Utils = {
|
|||
currentUserContextId: false,
|
||||
newUserContextId: assignedUserContextId,
|
||||
tabIndex: currentTab.index +1,
|
||||
active: currentTab.active,
|
||||
groupId: currentTab.groupId
|
||||
active:currentTab.active
|
||||
});
|
||||
}
|
||||
await Utils.setOrRemoveAssignment(
|
||||
|
@ -191,26 +166,6 @@ const Utils = {
|
|||
false
|
||||
);
|
||||
},
|
||||
/* Theme helper
|
||||
*
|
||||
* First, we look if there's a theme already set in the local storage. If
|
||||
* there isn't one, we set the theme based on `prefers-color-scheme`.
|
||||
* */
|
||||
getTheme(currentTheme, window) {
|
||||
if (typeof currentTheme !== "undefined" && currentTheme !== "auto") {
|
||||
return currentTheme;
|
||||
}
|
||||
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||
return "dark";
|
||||
}
|
||||
return "light";
|
||||
},
|
||||
async applyTheme() {
|
||||
const { currentTheme } = await browser.storage.local.get("currentTheme");
|
||||
const popup = document.getElementsByTagName("html")[0];
|
||||
const theme = Utils.getTheme(currentTheme, window);
|
||||
popup.setAttribute("data-theme", theme);
|
||||
}
|
||||
};
|
||||
|
||||
window.Utils = Utils;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Firefox Multi-Account Containers",
|
||||
"version": "8.3.0",
|
||||
"version": "8.0.7",
|
||||
"incognito": "not_allowed",
|
||||
"description": "__MSG_extensionDescription__",
|
||||
"icons": {
|
||||
"48": "img/multiaccountcontainer-16.svg",
|
||||
"96": "img/multiaccountcontainer-16.svg"
|
||||
"48": "img/container-site-d-48.png",
|
||||
"96": "img/container-site-d-96.png"
|
||||
},
|
||||
"homepage_url": "https://github.com/mozilla/multi-account-containers#readme",
|
||||
"permissions": [
|
||||
|
@ -26,7 +26,6 @@
|
|||
],
|
||||
"optional_permissions": [
|
||||
"bookmarks",
|
||||
"browsingData",
|
||||
"nativeMessaging",
|
||||
"proxy"
|
||||
],
|
||||
|
@ -42,81 +41,77 @@
|
|||
"default": "Ctrl+Period",
|
||||
"mac": "MacCtrl+Period"
|
||||
},
|
||||
"description": "__MSG_openContainerPanel__"
|
||||
},
|
||||
"sort_tabs": {
|
||||
"description": "__MSG_sortTabsByContainer__"
|
||||
"description": "Open containers panel"
|
||||
},
|
||||
"open_container_0": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+1"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 1"
|
||||
},
|
||||
"open_container_1": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+2"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 2"
|
||||
},
|
||||
"open_container_2": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+3"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 3"
|
||||
},
|
||||
"open_container_3": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+4"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 4"
|
||||
},
|
||||
"open_container_4": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+5"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 5"
|
||||
},
|
||||
"open_container_5": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+6"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 6"
|
||||
},
|
||||
"open_container_6": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+7"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 7"
|
||||
},
|
||||
"open_container_7": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+8"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 8"
|
||||
},
|
||||
"open_container_8": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+9"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 9"
|
||||
},
|
||||
"open_container_9": {
|
||||
"suggested_key": {
|
||||
"default": "Ctrl+Shift+0"
|
||||
},
|
||||
"description": "__MSG_containerShortcut__"
|
||||
"description": "Container Shortcut 10"
|
||||
}
|
||||
},
|
||||
"browser_action": {
|
||||
"browser_style": true,
|
||||
"default_icon": "img/multiaccountcontainer-16.svg",
|
||||
"default_title": "Firefox Multi-Account Containers",
|
||||
"default_title": "Multi-Account Containers",
|
||||
"default_popup": "popup.html",
|
||||
"default_area": "navbar",
|
||||
"theme_icons": [
|
||||
{
|
||||
"light": "img/multiaccountcontainer-16.svg",
|
||||
"light": "img/multiaccountcontainer-16-dark.svg",
|
||||
"dark": "img/multiaccountcontainer-16.svg",
|
||||
"size": 32
|
||||
}
|
||||
|
@ -125,7 +120,7 @@
|
|||
"page_action": {
|
||||
"browser_style": true,
|
||||
"default_icon": "img/container-openin-16.svg",
|
||||
"default_title": "__MSG_alwaysOpenSiteInContainer__",
|
||||
"default_title": "Always open this in a Container",
|
||||
"default_popup": "pageActionPopup.html",
|
||||
"pinned": false,
|
||||
"show_matches": ["*://*/*"]
|
||||
|
@ -149,7 +144,7 @@
|
|||
],
|
||||
"default_locale": "en",
|
||||
"web_accessible_resources": [
|
||||
"/img/multiaccountcontainer-16.svg"
|
||||
"/img/container-site-d-24.png"
|
||||
],
|
||||
"options_ui": {
|
||||
"page": "options.html",
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3 data-i18n-message-id="sync"></h3>
|
||||
<h3 data-i18n-message-id="firefoxAccountsSync"></h3>
|
||||
<div class="settings-group">
|
||||
<label>
|
||||
<input type="checkbox" id="syncCheck">
|
||||
|
@ -59,24 +59,6 @@
|
|||
<p><em data-i18n-message-id="replaceTabDescription"></em></p>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
TODO
|
||||
- Add data-i18n
|
||||
-->
|
||||
<h3 data-i18n-message-id="theme"></h3>
|
||||
|
||||
<p><label class="keyboard-shortcut">
|
||||
<span data-i18n-message-id="chooseTheme"></span>
|
||||
<select id="changeTheme" name="changeTheme">
|
||||
<option value="auto" selected data-i18n-message-id="themeAuto">
|
||||
</option>
|
||||
<option value="light" data-i18n-message-id="themeLight">
|
||||
</option>
|
||||
<option value="dark" data-i18n-message-id="themeDark">
|
||||
</option>
|
||||
</select>
|
||||
</label></p>
|
||||
|
||||
<h3 data-i18n-message-id="keyboardShortCuts"></h3>
|
||||
<p><em data-i18n-message-id="editWhichContainer"></em></p>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Firefox Multi-Account Containers</title>
|
||||
<title>Multi-Account Containers</title>
|
||||
<script type="text/javascript" src="./js/i18n.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="css/popup.css">
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<html data-theme="auto">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<title>Firefox Multi-Account Containers</title>
|
||||
<title>Multi-Account Containers</title>
|
||||
<script type="text/javascript" src="./js/i18n.js"></script>
|
||||
<link rel="stylesheet" href="./css/popup.css">
|
||||
</head>
|
||||
|
@ -44,7 +44,7 @@
|
|||
<div class="panel onboarding onboarding-panel-6 hide" id="onboarding-panel-6">
|
||||
<img class="onboarding-img" alt="" src="/img/Sync.svg" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-6-header"></h3>
|
||||
<p data-i18n-message-id="onboarding-6-description-2"></p>
|
||||
<p data-i18n-message-id="onboarding-6-description"></p>
|
||||
<div class="half-button-wrapper">
|
||||
<a href="#" id="no-sync" class="half-onboarding-button grey-button keyboard-nav" tabindex="0" data-i18n-message-id="notNow"></a>
|
||||
<a href="#" id="start-sync-button" class="half-onboarding-button keyboard-nav" tabindex="0" data-i18n-message-id="startSyncing"></a>
|
||||
|
@ -53,8 +53,8 @@
|
|||
|
||||
<div class="panel onboarding onboarding-panel-7 hide" id="onboarding-panel-7">
|
||||
<img class="onboarding-img" alt="" src="/img/Account.svg" />
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-7-header-2"></h3>
|
||||
<p data-i18n-message-id="onboarding-7-description-2"></p>
|
||||
<h3 class="onboarding-title" data-i18n-message-id="onboarding-7-header"></h3>
|
||||
<p data-i18n-message-id="onboarding-7-description"></p>
|
||||
<div class="half-button-wrapper">
|
||||
<a href="#" id="no-sign-in" class="half-onboarding-button grey-button keyboard-nav" tabindex="0" data-i18n-message-id="notNow"></a>
|
||||
<a href="#" id="sign-in" class="half-onboarding-button keyboard-nav" tabindex="0" data-i18n-message-id="signIn"></a>
|
||||
|
@ -107,8 +107,7 @@
|
|||
</div>
|
||||
|
||||
<div class="panel menu-panel container-panel hide" id="container-panel">
|
||||
<span class="popup-notification-card"></span>
|
||||
<h3 class="title">Firefox Multi-Account Containers</h3>
|
||||
<h3 class="title">Multi-Account Containers</h3>
|
||||
<a href="#" class="info-icon" id="info-icon" tabindex="10">
|
||||
<img data-i18n-attribute-message-id="info" data-i18n-attribute="alt" alt="" src="/img/info.svg" / >
|
||||
</a>
|
||||
|
@ -155,22 +154,11 @@
|
|||
<div class="sub-header" data-i18n-message-id="containers"></div>
|
||||
<h4 class="moz-vpn-logotype vpn-status-container-list display-none">Mozilla VPN
|
||||
<span class="moz-vpn-connection-status-indicator container-list-status-icon">
|
||||
<span class="tooltip"></span>
|
||||
</span>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="scrollable identities-list">
|
||||
<div class="searchbar">
|
||||
<label for="search-terms"
|
||||
class="hide-label"
|
||||
data-i18n-message-id="filterInputLabel">
|
||||
</label>
|
||||
<input type="text"
|
||||
id="search-terms"
|
||||
name="search-terms"
|
||||
placeholder="Search container name"
|
||||
data-i18n-attribute="placeholder"
|
||||
data-i18n-attribute-message-id="filterInputPlaceholder">
|
||||
</div>
|
||||
<table class="menu" id="identities-list">
|
||||
<tr class="menu-item hover-highlight">
|
||||
<td>
|
||||
|
@ -192,14 +180,24 @@
|
|||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="moz-vpn-tout" class="moz-vpn-content expanded">
|
||||
<div class="flx-row button-wrapper">
|
||||
<h4 class="moz-vpn-logo">Mozilla VPN</h4>
|
||||
<button class="controller dismiss-moz-vpn-tout" tab-index="0"></button>
|
||||
</div>
|
||||
<div class="collapsible-content flx-col controller-collapsible-content">
|
||||
<div class="flx-row flx-space-between">
|
||||
<span class="moz-vpn-subtitle" data-i18n-message-id="integrateContainers"></span>
|
||||
</div>
|
||||
<button id="moz-vpn-learn-more" class="moz-vpn-cta primary-cta" data-i18n-message-id="getMozillaVpn"></button>
|
||||
</div>
|
||||
</div>
|
||||
<v-padding-hack-footer></v-padding-hack-footer> <!--prevents last container from getting covered up by the 'manage containers button' when list is long-->
|
||||
<div class="bottom-btn keyboard-nav controller" id="manage-containers-link" tabindex="0" data-i18n-message-id="manageContainers"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hide panel menu-panel container-info-panel" id="container-info-panel" tabindex="-1">
|
||||
<span class="popup-notification-card"></span>
|
||||
<h3 class="title" id="container-info-title" data-i18n-attribute-message-id="personal"></h3>
|
||||
<button class="btn-return arrow-left controller keyboard-nav-back" id="close-container-info-panel" tabindex="0"></button>
|
||||
<hr>
|
||||
|
@ -236,14 +234,6 @@
|
|||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="menu-item hover-highlight keyboard-nav" id="clear-container-storage" tabindex="0">
|
||||
<td>
|
||||
<img class="menu-icon clear-storage-icon" alt="" src="img/container-delete.svg" />
|
||||
<span class="menu-text" id="clear-container-storage-info" data-i18n-message-id="clearContainerStorage"></span>
|
||||
<span class="menu-arrow">
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<div class="sub-header-wrapper">
|
||||
|
@ -261,14 +251,13 @@
|
|||
</table>
|
||||
</div>
|
||||
<v-padding-hack-footer></v-padding-hack-footer>
|
||||
<div class="bottom-btn keyboard-nav hover-highlight controller" id="manage-container-link" tabindex="0" data-i18n-message-id="manageThisContainer"></div>
|
||||
<div class="bottom-btn keyboard-nav hover-highlight" id="manage-container-link" tabindex="0" data-i18n-message-id="manageThisContainer"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="panel menu-panel container-picker-panel hide" id="container-picker-panel">
|
||||
<span class="popup-notification-card"></span>
|
||||
<h3 class="title" id="picker-title">
|
||||
Firefox Multi-Account Containers
|
||||
Multi-Account Containers
|
||||
</h3>
|
||||
<button class="btn-return arrow-left controller keyboard-nav-back" id="close-container-picker-panel" tabindex="0"></button>
|
||||
<hr>
|
||||
|
@ -291,7 +280,6 @@
|
|||
</div>
|
||||
|
||||
<div class="panel menu-panel edit-container-panel hide" id="edit-container-panel">
|
||||
<span class="popup-notification-card"></span>
|
||||
<h3 class="title" id="container-edit-title" data-i18n-message-id="default"></h3>
|
||||
<button class="btn-return arrow-left controller" id="close-container-edit-panel"></button>
|
||||
<hr>
|
||||
|
@ -311,7 +299,7 @@
|
|||
<legend class="form-header" data-i18n-message-id="icon"></legend>
|
||||
</fieldset>
|
||||
<fieldset class="proxies"> <!---- PROXIES -->
|
||||
<input type="text" class="proxies" name="container-proxy" id="edit-container-panel-proxy" placeholder="type://host:port" hidden/>
|
||||
<input type="text" class="proxies" name="container-proxy" id="edit-container-panel-proxy" maxlength="50" placeholder="type://host:port" hidden/>
|
||||
<input type="text" class="proxies" name="moz-proxy-enabled" id="moz-proxy-enabled" maxlength="5" hidden/>
|
||||
<input type="text" class="proxies" name="country-code" id="country-code-input" maxlength="5" hidden/>
|
||||
<input type="text" class="proxies" name="city-name" id="city-name-input" maxlength="5" hidden/>
|
||||
|
@ -354,11 +342,10 @@
|
|||
</button>
|
||||
</div>
|
||||
</moz-vpn-container-ui>
|
||||
<button id="advanced-proxy-settings-btn" class="proxy-section advanced-proxy-settings-btn">
|
||||
<button id="advanced-proxy-settings-btn" class="proxy-section advanced-proxy-settings-btn controller">
|
||||
<span class="advanced-proxy-settings-btn-label" data-i18n-message-id="advancedProxySettings"></span>
|
||||
<span id="advanced-proxy-address"></span>
|
||||
</button>
|
||||
<hr>
|
||||
<button class="delete-container delete-btn alert-text" id="delete-container-button" data-i18n-message-id="deleteThisContainer"></button>
|
||||
|
||||
<!-- TODO get UX / CONTENT on how to message about unavailable proxies -->
|
||||
|
@ -382,7 +369,6 @@
|
|||
</div>
|
||||
|
||||
<div class="panel menu-panel edit-container-assignments hide" id="edit-container-assignments">
|
||||
<span class="popup-notification-card"></span>
|
||||
<h3 class="title" id="edit-assignments-title" data-i18n-message-id="default"></h3>
|
||||
<button class="btn-return arrow-left controller" id="close-container-assignment-panel"></button>
|
||||
<hr>
|
||||
|
@ -412,23 +398,7 @@
|
|||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="#" class="button expanded secondary footer-button cancel-button" data-i18n-message-id="cancel" id="delete-container-cancel-link"></a>
|
||||
<a href="#" class="button expanded confirmation-destructive-ok-btn footer-button alert-text" data-i18n-message-id="ok" id="delete-container-ok-link"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hide panel clear-container-storage-panel" id="clear-container-storage-panel">
|
||||
<h3 class="title" id="container-clear-storage-title" data-i18n-message-id="default">
|
||||
</h3>
|
||||
|
||||
<button class="btn-return arrow-left controller" id="close-clear-container-storage-panel"></button>
|
||||
<hr>
|
||||
<div class="panel-content clear-container-storage-confirm">
|
||||
<h4 class="clear-container-storage-confirm-title" data-i18n-message-id="clearContainerStoragePanelTitle"></h4>
|
||||
<p class="clear-container-storage-warning" data-i18n-message-id="clearContainerStorageConfirmation"></p>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<a href="#" class="button expanded secondary footer-button cancel-button" data-i18n-message-id="cancel" id="clear-container-storage-cancel-link"></a>
|
||||
<a href="#" class="button expanded confirmation-destructive-ok-btn footer-button alert-text" data-i18n-message-id="ok" id="clear-container-storage-ok-link"></a>
|
||||
<a href="#" class="button expanded primary footer-button" data-i18n-message-id="ok" id="delete-container-ok-link"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -470,7 +440,7 @@
|
|||
<form class="advanced-proxy-panel-content">
|
||||
<label class="advanced-proxy-input-label" for="container-proxy" data-i18n-message-id="advancedProxySettings"></label>
|
||||
<div class="advanced-proxy-input-wrapper">
|
||||
<input id="edit-advanced-proxy-input" class="proxy-host primary-input" name="container-proxy" type="text" placeholder="type://host:port" />
|
||||
<input id="edit-advanced-proxy-input" class="proxy-host primary-input" name="container-proxy" type="text" maxlength="50" placeholder="type://host:port" />
|
||||
<button id="clear-advanced-proxy-input" class="controller" data-i18n-attribute="value" data-i18n-attribute-message-id="clearproxylabel"></button>
|
||||
<span class="proxy-validity" data-i18n-message-id="invalidProxyAlert"></span>
|
||||
</div>
|
||||
|
|
|
@ -32,10 +32,6 @@ const buildDom = async ({background = {}, popup = {}}) => {
|
|||
window.crypto = {
|
||||
getRandomValues: arr => crypto.randomBytes(arr.length),
|
||||
};
|
||||
// By default, the mock contextMenus.remove() returns undefined;
|
||||
// Let it return a Promise instead, so that .then() calls chained to
|
||||
// it (in src/js/background/assignManager.js) do not fail.
|
||||
window.browser.contextMenus.remove.resolves();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
const { sinon, nextTick, buildBackgroundDom } = require("../common");
|
||||
|
||||
describe("#1140", () => {
|
||||
beforeEach(async () => {
|
||||
this.background = await buildBackgroundDom();
|
||||
});
|
||||
|
||||
describe("removing containers", () => {
|
||||
beforeEach(async () => {
|
||||
this.background.browser.contextualIdentities.onRemoved.addListener = sinon.stub();
|
||||
const [promise] = this.background.browser.runtime.onMessage.addListener.yield({
|
||||
method: "deleteContainer",
|
||||
message: {
|
||||
userContextId: "1"
|
||||
}
|
||||
});
|
||||
await promise;
|
||||
await nextTick();
|
||||
});
|
||||
|
||||
it("should remove the identitystate from storage as well", async () => {
|
||||
this.background.browser.storage.local.remove.should.have.been.calledWith([
|
||||
"identitiesState@@_firefox-container-1"
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|