Compare commits

...
Sign in to create a new pull request.

23 commits

Author SHA1 Message Date
Kendall Werts
ec2cabe613 working on the never-ask test 2020-02-26 10:56:41 -06:00
Kendall Werts
088b12fadd never-ask test progress 2020-02-25 15:25:20 -06:00
Kendall Werts
9002e3b3a2 All tests work except the confirm page test 2020-02-25 14:34:33 -06:00
Kendall Werts
4920f478fb updates to make tests work 2020-02-25 11:20:25 -06:00
Kendall Werts
a66cdbf0bd working on mocha tests 2020-02-24 16:14:17 -06:00
Kendall Werts
88062b32b4 linting issues 2020-02-21 11:34:14 -06:00
Kendall Werts
bd40dfbcfb keyboard shortcuts 2020-02-21 11:07:22 -06:00
Kendall Werts
313fe8892c Now can reopen in default container. Added an 'OK' button to new container panel. Fixed some css 2020-02-21 11:07:22 -06:00
Kendall Werts
393d6228e0 css linting 2020-02-21 11:07:22 -06:00
Kendall Werts
951b048153 pulled out the picker panels 2020-02-21 11:07:22 -06:00
Kendall Werts
7117166566 some edits to panels 2020-02-21 11:07:22 -06:00
Kendall Werts
0371b26fb9 fixed info panel 2020-02-21 11:07:22 -06:00
Kendall Werts
28caada86d working on info panel 2020-02-21 11:07:22 -06:00
Kendall Werts
afa3abe967 updated browserAction icons to match default themes 2020-02-21 11:07:22 -06:00
Kendall Werts
bdf5b2673d added info icon as ling to options page 2020-02-21 11:07:22 -06:00
Kendall Werts
d1dd1748b3 updates to all panels 2020-02-21 11:07:22 -06:00
Kendall Werts
8e44652242 container info panel complete 2020-02-21 11:07:22 -06:00
Kendall Werts
eafbef960c fixed picker panel 2020-02-21 11:07:22 -06:00
Kendall Werts
cc793b9025 ReOpenIn Picker Panel functional 2020-02-21 11:07:22 -06:00
Kendall Werts
00f1be774c Page action assigns site to a container and simultaneously reopens site in container. 2020-02-21 11:07:22 -06:00
Kendall Werts
dd6f084ad1 testing keyboard shortcuts 2020-02-21 11:07:22 -06:00
Kendall Werts
f600c24879 Added Facebook Container Fence icon. Fixes #1425 2020-02-21 11:07:22 -06:00
Kendall Werts
055f47102f Implemented UI/UX for container list Panel (first panel). 2020-02-21 11:07:22 -06:00
35 changed files with 1568 additions and 612 deletions

View file

@ -46,7 +46,7 @@ module.exports = {
"error", "error",
{ {
"escape": { "escape": {
"taggedTemplates": ["escaped"] "taggedTemplates": ["escaped", "Utils.escaped"]
} }
} }
], ],

View file

@ -10,6 +10,11 @@
"rules": { "rules": {
"declaration-block-no-duplicate-properties": true, "declaration-block-no-duplicate-properties": true,
"order/declaration-block-properties-alphabetical-order": true, "order/declaration-block-properties-alphabetical-order": true,
"property-no-unknown": [
true, {
ignoreProperties:
["inset-block-end", "inset-block-start"]
}],
"property-blacklist": [ "property-blacklist": [
"/(min[-]|max[-])height/", "/(min[-]|max[-])height/",
"/width/", "/width/",

View file

@ -2,7 +2,7 @@
"name": "testpilot-containers", "name": "testpilot-containers",
"title": "Multi-Account 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.", "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": "6.2.1", "version": "6.2.2",
"author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston",
"bugs": { "bugs": {
"url": "https://github.com/mozilla/multi-account-containers/issues" "url": "https://github.com/mozilla/multi-account-containers/issues"

View file

@ -91,7 +91,7 @@ table {
} }
.scrollable { .scrollable {
border-block-start: 1px solid #f1f1f1; flex: 1;
inline-size: 100%; inline-size: 100%;
max-block-size: 400px; max-block-size: 400px;
overflow: auto; overflow: auto;
@ -107,6 +107,7 @@ table {
/* Effect borrowed from tabs in Firefox, ensure that the element flexes to the full width */ /* Effect borrowed from tabs in Firefox, ensure that the element flexes to the full width */
.truncate-text { .truncate-text {
inline-size: 100%;
mask-image: linear-gradient(to left, transparent, black 1em); mask-image: linear-gradient(to left, transparent, black 1em);
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
@ -206,6 +207,10 @@ table {
--identity-icon: url("/img/usercontext.svg#chill"); --identity-icon: url("/img/usercontext.svg#chill");
} }
[data-identity-icon="fence"] {
--identity-icon: url("/img/usercontext.svg#fence");
}
#current-tab [data-identity-icon="default-tab"] { #current-tab [data-identity-icon="default-tab"] {
background: center center no-repeat url("/img/blank-tab.svg"); background: center center no-repeat url("/img/blank-tab.svg");
fill: currentColor; fill: currentColor;
@ -269,6 +274,7 @@ table {
.panel-content { .panel-content {
flex: 1; flex: 1;
padding-block-start: 16px;
} }
/* Column panels for edit screens */ /* Column panels for edit screens */
@ -439,6 +445,7 @@ manage things like container crud */
block-size: 48px; block-size: 48px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
padding-block-start: 16px;
} }
.panel-header .usercontext-icon { .panel-header .usercontext-icon {
@ -488,24 +495,6 @@ manage things like container crud */
margin-inline-start: var(--inline-item-space-size); margin-inline-start: var(--inline-item-space-size);
} }
#container-panel #sort-containers-link {
align-items: center;
block-size: var(--block-url-label-size);
border: 1px solid #d8d8d8;
border-radius: var(--small-radius);
color: var(--title-text-color);
display: flex;
font-size: var(--small-text-size);
inline-size: var(--inline-button-size);
justify-content: center;
text-decoration: none;
}
#container-panel #sort-containers-link:hover,
#container-panel #sort-containers-link:focus {
background: #f2f2f2;
}
span ~ .panel-header-text { span ~ .panel-header-text {
padding-block-end: 0; padding-block-end: 0;
padding-block-start: 0; padding-block-start: 0;
@ -644,12 +633,20 @@ span ~ .panel-header-text {
background-image: var(--identity-icon); background-image: var(--identity-icon);
background-position: center center; background-position: center center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 20px 20px; background-size: 16px 16px;
block-size: 100%; block-size: 100%;
fill: var(--identity-icon-color); fill: var(--identity-icon-color);
filter: url('/img/filters.svg#fill'); filter: url('/img/filters.svg#fill');
} }
.mac-icon {
background-image: url('/img/multiaccountcontainer-16.svg');
background-position: center center;
background-repeat: no-repeat;
background-size: 16px 16px;
block-size: 100%;
}
.container-panel-row:hover .clickable .usercontext-icon, .container-panel-row:hover .clickable .usercontext-icon,
.container-panel-row:focus .clickable .usercontext-icon, .container-panel-row:focus .clickable .usercontext-icon,
.container-panel-row .clickable:focus .usercontext-icon { .container-panel-row .clickable:focus .usercontext-icon {
@ -758,17 +755,6 @@ span ~ .panel-header-text {
margin-inline-end: 0; margin-inline-end: 0;
} }
.container-info-list {
display: flex;
flex-direction: column;
margin-block-start: 4px;
padding-block-start: 4px;
}
.container-info-list tbody {
display: contents;
}
.clickable { .clickable {
cursor: pointer; cursor: pointer;
} }
@ -826,10 +812,6 @@ span ~ .panel-header-text {
overflow: hidden; /* Bugfix: issue 948 */ overflow: hidden; /* Bugfix: issue 948 */
} }
#edit-sites-assigned {
flex: 1000; /* Bugfix: issue 948 */
}
#edit-sites-assigned h3 { #edit-sites-assigned h3 {
font-size: 14px; font-size: 14px;
font-weight: normal; font-weight: normal;
@ -849,21 +831,13 @@ span ~ .panel-header-text {
margin-inline-end: 10px; margin-inline-end: 10px;
} }
.assigned-sites-list > div > .delete-assignment {
display: none;
}
.assigned-sites-list > div:hover > .delete-assignment {
display: block;
}
.assigned-sites-list > div > .hostname { .assigned-sites-list > div > .hostname {
flex: 1; flex: 1;
} }
.radio-choice > .radio-container { .radio-choice > .radio-container {
align-items: center; align-items: center;
block-size: 29px; block-size: 25px;
display: flex; display: flex;
flex: 0 0 calc(100% / var(--icon-fit)); flex: 0 0 calc(100% / var(--icon-fit));
} }
@ -923,7 +897,7 @@ span ~ .panel-header-text {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
inline-size: 100%; inline-size: 80%;
margin-block-end: 10px; margin-block-end: 10px;
margin-inline-end: 0; margin-inline-end: 0;
margin-inline-start: 0; margin-inline-start: 0;
@ -948,10 +922,17 @@ span ~ .panel-header-text {
padding-inline-start: 5px; padding-inline-start: 5px;
} }
.edit-container-panel legend { .edit-container-panel legend,
.options-header {
flex: 1 0; flex: 1 0;
font-size: 14px !important; font-size: 14px !important;
padding-block-end: 6px; margin-block-end: 4px;
margin-block-start: -6px;
}
.options-header {
margin-block-end: 8px;
margin-block-start: 6px;
} }
/* Achievement panel elements */ /* Achievement panel elements */
@ -1003,3 +984,275 @@ span ~ .panel-header-text {
.amo-rate-cta { .amo-rate-cta {
background: #0f1126; background: #0f1126;
} }
body {
color: #000;
font-family: 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 13px;
inline-size: 320px;
letter-spacing: -0.1px;
}
h3.title {
block-size: 40px;
color: #000;
font-size: 13px;
font-weight: bold;
inline-size: 100%;
letter-spacing: -0.1px;
line-height: 40px;
text-align: center;
}
.menu {
border-style: none;
inline-size: 100%;
}
.menu-item {
cursor: pointer;
height: 24px;
inline-size: 100%;
line-height: 24px;
}
.disabled-menu-item {
color: grey;
cursor: default;
font-style: italic;
}
.hover-highlight:hover {
background: #1296f8;
color: #fff;
}
.menu-text {
line-height: 24px;
}
.menu-icon {
display: block;
float: left;
height: 16px;
inline-size: 16px;
margin-block-end: 4px;
margin-block-start: 4px;
margin-inline-end: 8px;
margin-inline-start: 16px;
text-align: center;
}
.menu-right-float {
display: inline-block;
float: right;
height: 24px;
inline-size: 60px;
text-align: right;
}
.container-count {
opacity: 0.6;
padding-block-end: 0;
padding-block-start: 0;
padding-inline-end: 6px;
padding-inline-start: 0;
text-align: right;
}
.menu-arrow {
display: inline-block;
float: right;
height: 24px;
inline-size: 18px;
padding-block-end: 6px;
padding-block-start: 6px;
padding-inline-end: 12px;
padding-inline-start: 0;
text-align: center;
}
.menu-arrow img {
height: 12px;
inline-size: 12px;
padding-block-end: 2px;
padding-block-start: 2px;
padding-inline-end: 2px;
padding-inline-start: 2px;
}
hr {
border: 0;
border-block-start: 1px solid #e3e3e3;
display: block;
margin-block-end: 0;
margin-block-start: 6px;
margin-inline-end: 0;
margin-inline-start: 0;
padding-block-end: 6px;
padding-block-start: 0;
padding-inline-end: 0;
padding-inline-start: 0;
}
.sub-header {
color: #737373;
height: 24px;
line-height: 24px;
padding-block-end: 0;
padding-block-start: 0;
padding-inline-end: 16px;
padding-inline-start: 16px;
}
.edit-form {
color: #737373;
flex: 1;
padding-block-end: 0;
padding-block-start: 0;
padding-inline-end: 16px;
padding-inline-start: 16px;
}
.identities-list {
margin-block-end: 41px;
margin-block-start: 0;
margin-inline-end: 0;
margin-inline-start: 0;
}
.bottom-btn {
background-color: #e3e3e3;
border: solid 1px #d9d9d9;
cursor: pointer;
height: 41px;
inline-size: 100%;
inset-block-end: 0;
line-height: 41px;
padding-block-end: 0;
padding-block-start: 0;
padding-inline-end: 16px;
padding-inline-start: 16px;
position: fixed;
}
.delete-container {
background-color: #fff;
border-block-start: solid 1px #e3e3e3;
cursor: default;
display: flex;
height: 65px;
inline-size: 100%;
justify-content: space-between;
padding-block-end: 27px;
padding-block-start: 9px;
padding-inline-end: 18px;
padding-inline-start: 17px;
}
.delete-btn {
background-color: rgba(12, 12, 13, 0.1);
border: 0;
border-radius: 2px;
cursor: pointer;
height: 30px;
inline-size: 100%;
line-height: 30px;
text-align: center;
}
.btn-return.arrow-left {
background-color: rgba(255, 255, 255, 1);
background-image: url("/img/arrow-icon-left.svg");
border: 0;
cursor: pointer;
height: 1.2rem;
inline-size: 1.2rem;
inset-block-start: 15px;
left: 15px;
position: absolute;
}
input {
border: solid 1px #bebebe;
border-radius: 2px;
}
.form-header {
height: 23px;
line-height: 23px;
padding-block-end: 0;
padding-block-start: 0;
padding-inline-end: 0;
padding-inline-start: 0;
}
#edit-container-panel-name-input {
height: 29px;
}
.container-options {
height: 23px;
}
#site-isolation {
inset-block-end: auto;
position: fixed;
}
.options-label {
cursor: pointer;
padding-inline-start: 25px;
}
#manage-assigned-sites-list {
color: #5a9de6;
}
#info-icon {
border: solid 1px #000;
border-radius: 7px;
color: #000;
cursor: pointer;
font-size: 10px;
font-weight: bold;
height: 14px;
inline-size: 14px;
inset-block-start: 13px;
position: absolute;
right: 13px;
text-align: center;
text-decoration: none;
}
.delete-warning {
padding-block-end: 8px;
padding-block-start: 8px;
padding-inline-end: 0;
padding-inline-start: 0;
}
.trash-button {
display: inline-block;
float: right;
height: 16px;
inline-size: 16px;
margin-block-end: 4px;
margin-block-start: 4px;
margin-inline-end: 10px;
margin-inline-start: 0;
text-align: center;
}
tr > td > .trash-button {
display: none;
}
tr:hover > td > .trash-button {
display: block;
}
.new-container-icon {
font-size: 24px;
margin-block-start: -2px;
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="context-fill" d="M6.414 8l4.293-4.293a1 1 0 0 0-1.414-1.414l-5 5a1 1 0 0 0 0 1.414l5 5a1 1 0 0 0 1.414-1.414z"></path></svg>

After

Width:  |  Height:  |  Size: 220 B

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="5px" height="8px" viewBox="0 0 5 8" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 53.2 (72643) - https://sketchapp.com -->
<title>Arrow</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M5.00090934,9.5006316 C4.79840046,9.50099392 4.61567086,9.37916873 4.53812503,9.19209489 C4.4605792,9.00502105 4.5035325,8.78964579 4.64690934,8.6466316 L7.29490934,6.0006316 L4.64690934,3.3546316 C4.45140054,3.1591228 4.45140054,2.8421404 4.64690934,2.6466316 C4.84241814,2.4511228 5.15940054,2.4511228 5.35490934,2.6466316 L8.35490934,5.6466316 C8.44895104,5.74043586 8.50180313,5.86780434 8.50180313,6.0006316 C8.50180313,6.13345886 8.44895104,6.26082734 8.35490934,6.3546316 L5.35490934,9.3546316 C5.26095861,9.44834555 5.13360821,9.5008686 5.00090934,9.5006316 Z" id="path-1"></path>
</defs>
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.6">
<g id="Icons-/-12-/-Arrowhead-Right-12---Thin" transform="translate(-4.000000, -2.000000)">
<rect id="bouding-box" x="0" y="0" width="12" height="12"></rect>
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Shape" fill-rule="nonzero"></g>
<g id="Color-/-Photon-/-Primary---Grey-90-80%" mask="url(#mask-2)" fill="#0C0C0D" fill-opacity="0.8" fill-rule="evenodd">
<rect id="Rectangle" x="0" y="0" width="12" height="12"></rect>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 7 7">
<polygon fill="#4c4c4c" points="5.8,0 3.5,2.4 1.2,0 0,1.2 2.4,3.5 0.1,5.8 1.2,7 3.5,4.7 5.8,7 7,5.8 4.7,3.5 7,1.2"/> <polygon fill="#FFFFFF" points="5.8,0 3.5,2.4 1.2,0 0,1.2 2.4,3.5 0.1,5.8 1.2,7 3.5,4.7 5.8,7 7,5.8 4.7,3.5 7,1.2"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 183 B

View file

@ -3,7 +3,7 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 12 12" style="enable-background:new 0 0 12 12;" xml:space="preserve"> viewBox="0 0 12 12" style="enable-background:new 0 0 12 12;" xml:space="preserve">
<style type="text/css"> <style type="text/css">
.st0{fill:#858585;} .st0{fill:#FFFFFF;}
</style> </style>
<path class="st0" d="M4.6,0.3h2.7c0.1,0,0.2,0.1,0.2,0.2v1H4.4v-1C4.4,0.4,4.5,0.3,4.6,0.3z M1.7,1.5h8.6c0.1,0,0.2,0.1,0.2,0.2 <path class="st0" d="M4.6,0.3h2.7c0.1,0,0.2,0.1,0.2,0.2v1H4.4v-1C4.4,0.4,4.5,0.3,4.6,0.3z M1.7,1.5h8.6c0.1,0,0.2,0.1,0.2,0.2
l0.2,1.4H1.3l0.2-1.4C1.5,1.6,1.6,1.5,1.7,1.5z M6,11.7H3.2L2.1,3.9H6h3.9l-1.1,7.8H6L6,11.7z"/> l0.2,1.4H1.3l0.2-1.4C1.5,1.6,1.6,1.5,1.7,1.5z M6,11.7H3.2L2.1,3.9H6h3.9l-1.1,7.8H6L6,11.7z"/>

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 626 B

View file

@ -0,0 +1,7 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg data-name="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M15.85 12.15l-3-3a0.49 0.49 0 0 0-0.7 0.7L14.29 12H9.5a0.5 0.5 0 0 0 0 1h4.79l-2.14 2.15a0.48 0.48 0 0 0 0 0.7 0.48 0.48 0 0 0 0.7 0l3-3a0.36 0.36 0 0 0 0.11-0.16 0.5 0.5 0 0 0 0-0.38 0.36 0.36 0 0 0-0.11-0.16z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M13 1H3a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h4a1 1 0 0 0 0-2H3a1 1 0 0 1-1-1V6h12v2a1 1 0 0 0 2 0V4a3 3 0 0 0-3-3zM2 5V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1z"/>
</svg>

After

Width:  |  Height:  |  Size: 796 B

View file

@ -0,0 +1,7 @@
<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: 590 B

View file

@ -0,0 +1,7 @@
<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"/>
<rect x="9" y="9" width="6" height="6" rx="1"/>
</svg>

After

Width:  |  Height:  |  Size: 586 B

View file

@ -0,0 +1,7 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg data-name="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M14.92 1.62a1 1 0 0 0-0.54-0.54A1 1 0 0 0 14 1H9a1 1 0 0 0 0 2h2.59l-3.3 3.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0L13 4.41V7a1 1 0 0 0 2 0V2a1 1 0 0 0-0.08-0.38z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 10a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h1a1 1 0 0 0 0-2H4a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3v-1a1 1 0 0 0-1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 747 B

View file

@ -0,0 +1,7 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg data-name="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M14 10a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h1a1 1 0 0 0 0-2H4a3 3 0 0 0-3 3v8a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3v-1a1 1 0 0 0-1-1z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M12.91 4.5l1.8-1.79a1 1 0 1 0-1.42-1.42l-1.79 1.8-1.79-1.8a1 1 0 0 0-1.42 1.42l1.8 1.79-1.8 1.79a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l1.79-1.8 1.79 1.8a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42z"/>
</svg>

After

Width:  |  Height:  |  Size: 772 B

View 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="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M12 7l-4 4a4 4 0 0 0 4-4z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M15.66 7.71a7.78 7.78 0 0 0-1.55-2.82L12.7 6.3a5.9 5.9 0 0 1 1 1.7A6 6 0 0 1 8 12a7.28 7.28 0 0 1-.93-.07l-1.64 1.64A7.92 7.92 0 0 0 8 14a8 8 0 0 0 7.66-5.71 1 1 0 0 0 0-.58zM14.71 1.29a1 1 0 0 0-1.42 0l-1.63 1.64A7.8 7.8 0 0 0 8 2a8 8 0 0 0-7.66 5.71 1 1 0 0 0 0 .58 7.8 7.8 0 0 0 2.34 3.62l-1.39 1.38a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l12-12a1 1 0 0 0 0-1.42zM8.5 5a1.43 1.43 0 0 1 .82.26L7.26 7.32A1.43 1.43 0 0 1 7 6.5 1.5 1.5 0 0 1 8.5 5zM2.35 8a6 6 0 0 1 2.11-2.82A3.91 3.91 0 0 0 5 9.61l-.9.9A5.91 5.91 0 0 1 2.35 8z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M12 7l-4 4a4 4 0 0 0 4-4z"/>
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M16 7.7a8.06 8.06 0 0 0-1.72-2.94l-1.45 1.41A5.91 5.91 0 0 1 13.94 8 6.33 6.33 0 0 1 8 12a7.28 7.28 0 0 1-.93-.07l-1.66 1.66A8.56 8.56 0 0 0 8 14a8.34 8.34 0 0 0 8-5.7 1.22 1.22 0 0 0 0-.6zM14.71 1.29a1 1 0 0 0-1.42 0L11.7 2.88A8.43 8.43 0 0 0 8 2a8.34 8.34 0 0 0-8 5.7 1.22 1.22 0 0 0 0 .6A7.87 7.87 0 0 0 2.58 12l-1.29 1.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l12-12a1 1 0 0 0 0-1.42zM8.5 5a1.43 1.43 0 0 1 .82.26L7.26 7.32A1.43 1.43 0 0 1 7 6.5 1.5 1.5 0 0 1 8.5 5zM2.06 8a6 6 0 0 1 2.49-3A4 4 0 0 0 4 7a4 4 0 0 0 1 2.61l-1 1A5.94 5.94 0 0 1 2.06 8z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

6
src/img/refresh-16.svg Normal file
View file

@ -0,0 +1,6 @@
<!-- 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="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M15 1a1 1 0 0 0-1 1v2.42A7 7 0 1 0 13 13a1 1 0 0 0-1.41-1.41 5 5 0 1 1 1-5.54H10a1 1 0 0 0 0 2h5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 495 B

6
src/img/sort-16_1.svg Normal file
View file

@ -0,0 +1,6 @@
<!-- 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="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M14.71 4.29l-3-3a1 1 0 0 0-1.42 1.42L11.59 4H4a1 1 0 0 0 0 2h7.59l-1.3 1.29a1 1 0 0 0 0 1.42 1 1 0 0 0 1.42 0l3-3a1 1 0 0 0 0-1.42zM12 10H4.41l1.3-1.29a1 1 0 1 0-1.42-1.42l-3 3a1 1 0 0 0 0 1.42l3 3a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42L4.41 12H12a1 1 0 0 0 0-2z"/>
</svg>

After

Width:  |  Height:  |  Size: 625 B

6
src/img/tab-new-16.svg Normal file
View file

@ -0,0 +1,6 @@
<!-- 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="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="context-fill" fill-opacity="context-fill-opacity" d="M11 11V9a1 1 0 0 1 1-1h1a1 1 0 0 1 1 1V5a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v6H1a1 1 0 0 0 0 2h7v-1a1 1 0 0 1 1-1zm4.5 1H13V9.5a0.5 0.5 0 0 0-1 0V12H9.5a0.5 0.5 0 0 0 0 1H12v2.5a0.5 0.5 0 0 0 1 0V13h2.5a0.5 0.5 0 0 0 0-1z"/>
</svg>

After

Width:  |  Height:  |  Size: 583 B

View file

@ -13,6 +13,7 @@
display: none; display: none;
} }
</style> </style>
<path id="fence" d="M28 4l-2 2v4h-4V6l-2-2-2 2v4h-4V6l-2-2-2 2v4H6V6L4 4 2 6v22h4v-4h4v4h4v-4h4v4h4v-4h4v4h4V6l-2-2zM6 22V12h4v10H6zm8 0V12h4v10h-4zm8 0V12h4v10h-4z"/>
<path id="dollar" d="M16.2,0c-8.9,0-16,7.3-16,16c0,8.9,7.1,16,15.8,16s15.8-7.1,15.8-16C32,7.3,24.9,0,16.2,0z M17.1,25.1v1.6 <path id="dollar" d="M16.2,0c-8.9,0-16,7.3-16,16c0,8.9,7.1,16,15.8,16s15.8-7.1,15.8-16C32,7.3,24.9,0,16.2,0z M17.1,25.1v1.6
c0,0.4-0.4,0.5-0.7,0.5c-0.4,0-0.7-0.2-0.7-0.5v-1.6c-3.2-0.2-5-1.8-5.5-4.3c0-0.2,0-0.2,0-0.4c0-0.5,0.4-0.9,0.9-0.9 c0,0.4-0.4,0.5-0.7,0.5c-0.4,0-0.7-0.2-0.7-0.5v-1.6c-3.2-0.2-5-1.8-5.5-4.3c0-0.2,0-0.2,0-0.4c0-0.5,0.4-0.9,0.9-0.9
c0.2,0,0.2,0,0.4,0c0.5,0,0.9,0.2,1.1,0.7c0.4,1.8,1.2,2.7,3.4,2.8v-6.8c-3.6-0.4-5.3-1.8-5.3-4.6c0-3,2.5-4.6,5.2-4.8V5.7 c0.2,0,0.2,0,0.4,0c0.5,0,0.9,0.2,1.1,0.7c0.4,1.8,1.2,2.7,3.4,2.8v-6.8c-3.6-0.4-5.3-1.8-5.3-4.6c0-3,2.5-4.6,5.2-4.8V5.7
@ -69,4 +70,12 @@
s1.6,0.5,1.8,1.4v0.2c0,0.2,0,0.2,0,0.4c0,2,0.7,3.7,2.1,5c1.4,1.4,3,2.1,5,2.1l0,0c2,0,3.6-0.7,5-2.1c1.4-1.2,2.1-3.2,2.1-5V9.2 s1.6,0.5,1.8,1.4v0.2c0,0.2,0,0.2,0,0.4c0,2,0.7,3.7,2.1,5c1.4,1.4,3,2.1,5,2.1l0,0c2,0,3.6-0.7,5-2.1c1.4-1.2,2.1-3.2,2.1-5V9.2
C32,5.2,28.8,2,24.7,2"/> C32,5.2,28.8,2,24.7,2"/>
<circle id="circle" r="16" cx="16" cy="16" fill-rule="evenodd"/> <circle id="circle" r="16" cx="16" cy="16" fill-rule="evenodd"/>
<path id="bullhorn" d="M1.5 5A.5.5 0 0 0 1 5.5v5a.5.5 0 0 0 1 0v-5A.5.5 0 0 0 1.5 5zM14.6 2.2A1 1 0 0 0 13.71 2l-10 3A1 1 0 0 0 3 6v4a1 1 0 0 0 .71 1L5 11.35a.4.4 0 0 0 0 .15v1a2.5 2.5 0 0 0 5 .33L13.71 14A1 1 0 0 0 14 14a1 1 0 0 0 .6-.2A1 1 0 0 0 15 13V3a1 1 0 0 0-.4-.8zM7.5 14A1.5 1.5 0 0 1 6 12.5v-.86l3 .9A1.51 1.51 0 0 1 7.5 14zm5.5-2.34l-8-2.4V6.74l8-2.4z"/>
<path id="folder" d="M13 4H8.41L7 2.59A2 2 0 0 0 5.59 2H3a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z"/>
<path id="hat" d="M15 10a1 1 0 0 0-1 1 1 1 0 0 1-1 1V6a4 4 0 0 0-4-4H7a4 4 0 0 0-4 4v6a1 1 0 0 1-1-1 1 1 0 0 0-2 0 3 3 0 0 0 3 3h10a3 3 0 0 0 3-3 1 1 0 0 0-1-1zM7 4h2a2 2 0 0 1 2 2v3H5V6a2 2 0 0 1 2-2z"/>
<path id="wallet" d="M14 2H2C1 2 0.06 3 0 4.86v6.34A1.94 1.94 0 0 0 1.22 13l7 2.86A2 2 0 0 0 9 16a2 2 0 0 0 1.14-0.35A1.9 1.9 0 0 0 11 14.07V7.8A1.94 1.94 0 0 0 9.78 6L4.85 4h8.65a0.5 0.5 0 0 1 0 1H9.92l0.24 0.1a2.93 2.93 0 0 1 1.2 0.9h2.14A0.5 0.5 0 0 1 14 6.5v3a0.51 0.51 0 0 1-0.5 0.5H12v2h2a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2zm-6 8.5a0.5 0.5 0 0 1 1 0v1a0.5 0.5 0 0 1-1 0z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -8,6 +8,7 @@ module.exports = {
"backgroundLogic": true, "backgroundLogic": true,
"identityState": true, "identityState": true,
"messageHandler": true, "messageHandler": true,
"sync": true "sync": true,
"Utils": true
} }
}; };

View file

@ -1,3 +1,4 @@
const NUMBER_OF_KEYBOARD_SHORTCUTS = 2;
const DEFAULT_TAB = "about:newtab"; const DEFAULT_TAB = "about:newtab";
const backgroundLogic = { const backgroundLogic = {
NEW_TAB_PAGES: new Set([ NEW_TAB_PAGES: new Set([
@ -7,6 +8,17 @@ const backgroundLogic = {
"about:blank" "about:blank"
]), ]),
unhideQueue: [], unhideQueue: [],
init() {
browser.commands.onCommand.addListener(function (command) {
for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) {
const key = "open_container_" + i;
const cookieStoreId = identityState.keyboardShortcut[key];
if (command === key) {
browser.tabs.create({cookieStoreId});
}
}
});
},
async getExtensionInfo() { async getExtensionInfo() {
const manifestPath = browser.extension.getURL("manifest.json"); const manifestPath = browser.extension.getURL("manifest.json");
@ -329,6 +341,10 @@ const backgroundLogic = {
}, },
cookieStoreId(userContextId) { cookieStoreId(userContextId) {
if(userContextId === 0) return "firefox-default";
return `firefox-container-${userContextId}`; return `firefox-container-${userContextId}`;
} }
}; };
backgroundLogic.init();

View file

@ -1,4 +1,7 @@
const NUM_OF_KEYBOARD_SHORTCUTS = 2;
window.identityState = { window.identityState = {
keyboardShortcut: {},
storageArea: { storageArea: {
area: browser.storage.local, area: browser.storage.local,
@ -42,6 +45,19 @@ window.identityState = {
return this.area.remove([storeKey]); return this.area.remove([storeKey]);
}, },
async setKeyboardShortcut(shortcutId, cookieStoreId) {
identityState.keyboardShortcut[shortcutId] = cookieStoreId;
return this.area.set({[shortcutId]: cookieStoreId});
},
async loadKeyboardShortcuts () {
for (let i=0; i < NUM_OF_KEYBOARD_SHORTCUTS; i++) {
const key = "open_container_" + i;
const storageObject = await this.area.get(key);
identityState.keyboardShortcut[key] = storageObject[key];
}
},
/* /*
* Looks for abandoned identity keys in local storage, and makes sure all * Looks for abandoned identity keys in local storage, and makes sure all
* identities registered in the browser are also in local storage. (this * identities registered in the browser are also in local storage. (this
@ -72,7 +88,8 @@ window.identityState = {
} }
} }
} }
} },
}, },
_createTabObject(tab) { _createTabObject(tab) {
@ -153,8 +170,14 @@ window.identityState = {
macAddonUUID: uuidv4() macAddonUUID: uuidv4()
}; };
}, },
init() {
this.storageArea.loadKeyboardShortcuts();
}
}; };
identityState.init();
function uuidv4() { function uuidv4() {
// https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript // https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>

View file

@ -10,6 +10,13 @@ const messageHandler = {
let response; let response;
switch (m.method) { switch (m.method) {
case "getShortcuts":
console.log("getShortcuts", identityState.keyboardShortcut);
response = identityState.keyboardShortcut;
break;
case "setShortcut":
identityState.storageArea.setKeyboardShortcut(m.shortcut, m.cookieStoreId);
break;
case "resetSync": case "resetSync":
response = sync.resetSync(); response = sync.resetSync();
break; break;
@ -73,7 +80,18 @@ const messageHandler = {
case "exemptContainerAssignment": case "exemptContainerAssignment":
response = assignManager._exemptTab(m); response = assignManager._exemptTab(m);
break; break;
case "reloadInContainer":
response = assignManager.reloadPageInContainer(
m.url,
m.currentUserContextId,
m.newUserContextId,
m.tabIndex,
m.active,
true
);
break;
} }
console.log(m.method, "response", response);
return response; return response;
}); });

View file

@ -1,3 +1,5 @@
const NUMBER_OF_KEYBOARD_SHORTCUTS = 2;
async function requestPermissions() { async function requestPermissions() {
const checkbox = document.querySelector("#bookmarksPermissions"); const checkbox = document.querySelector("#bookmarksPermissions");
if (checkbox.checked) { if (checkbox.checked) {
@ -22,7 +24,7 @@ async function enableDisableSync() {
browser.runtime.sendMessage({ method: "resetSync" }); browser.runtime.sendMessage({ method: "resetSync" });
} }
async function restoreOptions() { async function setupOptions() {
const hasPermission = await browser.permissions.contains({permissions: ["bookmarks"]}); const hasPermission = await browser.permissions.contains({permissions: ["bookmarks"]});
const { syncEnabled } = await browser.storage.local.get("syncEnabled"); const { syncEnabled } = await browser.storage.local.get("syncEnabled");
if (hasPermission) { if (hasPermission) {
@ -33,9 +35,50 @@ async function restoreOptions() {
} else { } else {
document.querySelector("#syncCheck").checked = false; document.querySelector("#syncCheck").checked = false;
} }
setupContainerShortcutSelects();
} }
async function setupContainerShortcutSelects () {
const keyboardShortcut = await browser.runtime.sendMessage({method: "getShortcuts"});
// console.log(keyboardShortcut);
const identities = await browser.contextualIdentities.query({});
const fragment = document.createDocumentFragment();
const noneOption = document.createElement("option");
noneOption.value = "none";
noneOption.textContent = "None";
fragment.append(noneOption);
document.addEventListener("DOMContentLoaded", restoreOptions); for (const identity of identities) {
const option = document.createElement("option");
option.value = identity.cookieStoreId;
option.id = identity.cookieStoreId;
option.textContent = identity.name;
fragment.append(option);
}
for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) {
const shortcutKey = "open_container_"+i;
const shortcutSelect = document.getElementById(shortcutKey);
shortcutSelect.appendChild(fragment.cloneNode(true));
if (keyboardShortcut && keyboardShortcut[shortcutKey]) {
shortcutSelect.getElementById(keyboardShortcut[shortcutKey]).selected = true;
}
}
}
function storeShortcutChoice (event) {
browser.runtime.sendMessage({
method: "setShortcut",
shortcut: event.target.id,
cookieStoreId: event.target.value
});
}
document.addEventListener("DOMContentLoaded", setupOptions);
document.querySelector("#bookmarksPermissions").addEventListener( "change", requestPermissions); document.querySelector("#bookmarksPermissions").addEventListener( "change", requestPermissions);
document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync); document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync);
for (let i=0; i < NUMBER_OF_KEYBOARD_SHORTCUTS; i++) {
document.querySelector("#open_container_"+i)
.addEventListener("change", storeShortcutChoice);
}

36
src/js/pageAction.js Normal file
View file

@ -0,0 +1,36 @@
async function init() {
const fragment = document.createDocumentFragment();
const identities = await browser.contextualIdentities.query({});
identities.forEach(identity => {
const tr = document.createElement("tr");
tr.classList.add("menu-item", "hover-highlight");
const td = document.createElement("td");
td.innerHTML = Utils.escaped`
<div class="menu-icon">
<div class="usercontext-icon"
data-identity-icon="${identity.icon}"
data-identity-color="${identity.color}">
</div>
</div>
<span class="menu-text">${identity.name}</span>`;
fragment.appendChild(tr);
tr.appendChild(td);
Utils.addEnterHandler(tr, async () => {
Utils.alwaysOpenInContainer(identity);
window.close();
});
});
const list = document.querySelector("#picker-identities-list");
list.innerHTML = "";
list.appendChild(fragment);
}
init();

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
const DEFAULT_FAVICON = "/img/blank-favicon.svg"; const DEFAULT_FAVICON = "/img/blank-favicon.svg";
// TODO use export here instead of globals // TODO use export here instead of globals
window.Utils = { const Utils = {
createFavIconElement(url) { createFavIconElement(url) {
const imageElement = document.createElement("img"); const imageElement = document.createElement("img");
imageElement.classList.add("icon", "offpage"); imageElement.classList.add("icon", "offpage", "menu-icon");
imageElement.src = url; imageElement.src = url;
const loadListener = (e) => { const loadListener = (e) => {
e.target.classList.remove("offpage"); e.target.classList.remove("offpage");
@ -18,6 +18,110 @@ window.Utils = {
imageElement.addEventListener("error", errorListener); imageElement.addEventListener("error", errorListener);
imageElement.addEventListener("load", loadListener); imageElement.addEventListener("load", loadListener);
return imageElement; return imageElement;
},
/**
* Escapes any occurances of &, ", <, > or / with XML entities.
*
* @param {string} str
* The string to escape.
* @return {string} The escaped string.
*/
escapeXML(str) {
const replacements = { "&": "&amp;", "\"": "&quot;", "'": "&apos;", "<": "&lt;", ">": "&gt;", "/": "&#x2F;" };
return String(str).replace(/[&"'<>/]/g, m => replacements[m]);
},
/**
* A tagged template function which escapes any XML metacharacters in
* interpolated values.
*
* @param {Array<string>} strings
* An array of literal strings extracted from the templates.
* @param {Array} values
* An array of interpolated values extracted from the template.
* @returns {string}
* The result of the escaped values interpolated with the literal
* strings.
*/
escaped(strings, ...values) {
const result = [];
for (const [i, string] of strings.entries()) {
result.push(string);
if (i < values.length)
result.push(this.escapeXML(values[i]));
}
return result.join("");
},
async currentTab() {
const activeTabs = await browser.tabs.query({ active: true, windowId: browser.windows.WINDOW_ID_CURRENT });
if (activeTabs.length > 0) {
return activeTabs[0];
}
return false;
},
addEnterHandler(element, handler) {
element.addEventListener("click", (e) => {
handler(e);
});
element.addEventListener("keydown", (e) => {
if (e.keyCode === 13) {
e.preventDefault();
handler(e);
}
});
},
userContextId(cookieStoreId = "") {
const userContextId = cookieStoreId.replace("firefox-container-", "");
return (userContextId !== cookieStoreId) ? Number(userContextId) : false;
},
setOrRemoveAssignment(tabId, url, userContextId, value) {
return browser.runtime.sendMessage({
method: "setOrRemoveAssignment",
tabId,
url,
userContextId,
value
});
},
reloadInContainer(url, currentUserContextId, newUserContextId, tabIndex, active) {
return browser.runtime.sendMessage({
method: "reloadInContainer",
url,
currentUserContextId,
newUserContextId,
tabIndex,
active
});
},
async alwaysOpenInContainer(identity) {
const currentTab = await this.currentTab();
const assignedUserContextId = this.userContextId(identity.cookieStoreId);
Utils.setOrRemoveAssignment(
currentTab.id,
currentTab.url,
assignedUserContextId,
false
);
if (currentTab.cookieStoreId !== identity.cookieStoreId) {
Utils.reloadInContainer(
currentTab.url,
false,
assignedUserContextId,
currentTab.index + 1,
currentTab.active
);
}
} }
}; };
window.Utils = Utils;

View file

@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Firefox Multi-Account Containers", "name": "Firefox Multi-Account Containers",
"version": "6.2.1", "version": "6.2.2",
"incognito": "not_allowed", "incognito": "not_allowed",
"description": "Multi-Account 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.", "description": "Multi-Account 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.",
"icons": { "icons": {
@ -39,21 +39,41 @@
"mac": "MacCtrl+Period" "mac": "MacCtrl+Period"
}, },
"description": "Open containers panel" "description": "Open containers panel"
},
"open_container_0": {
"suggested_key": {
"default": "Ctrl+Shift+0"
},
"description": "Container Shortcut 0"
},
"open_container_1": {
"suggested_key": {
"default": "Ctrl+Shift+1"
},
"description": "Container Shortcut 1"
} }
}, },
"browser_action": { "browser_action": {
"browser_style": true, "browser_style": true,
"default_icon": "img/container-site.svg", "default_icon": "img/multiaccountcontainer-16.svg",
"default_title": "Multi-Account Containers", "default_title": "Multi-Account Containers",
"default_popup": "popup.html", "default_popup": "popup.html",
"theme_icons": [ "theme_icons": [
{ {
"light": "img/container-site-light.svg", "light": "img/multiaccountcontainer-16-dark.svg",
"dark": "img/container-site.svg", "dark": "img/multiaccountcontainer-16.svg",
"size": 32 "size": 32
} }
] ]
}, },
"page_action": {
"browser_style": true,
"default_icon": "img/multiaccountcontainer-16.svg",
"default_title": "Always open this in a Container",
"default_popup": "pageActionPopup.html",
"pinned": false,
"show_matches": ["*://*/*"]
},
"background": { "background": {
"page": "js/background/index.html" "page": "js/background/index.html"
}, },

View file

@ -17,6 +17,18 @@
Enable Sync Enable Sync
</label> </label>
<p>This setting allows you to sync your containers and site assignments across devices.</p> <p>This setting allows you to sync your containers and site assignments across devices.</p>
<p><label>
Container to open with Keyboard Shortcut 0
<select id="open_container_0">
<!-- <option value="none">None</option> -->
</select>
</label></p>
<p><label>
Container to open with Keyboard Shortcut 1
<select id="open_container_1">
<!-- <option value="none">None</option> -->
</select>
</label></p>
</form> </form>
<script src="js/options.js"></script> <script src="js/options.js"></script>
</body> </body>

34
src/pageActionPopup.html Normal file
View file

@ -0,0 +1,34 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Multi-Account Containers</title>
<link rel="stylesheet" type="text/css" href="css/popup.css">
</head>
<body>
<div class="page-action-container-picker" id="container-picker-panel">
<h3 class="title">
Always Open this Site in...
</h3>
<hr>
<div class="scrollable identities-list">
<table class="menu" id="picker-identities-list">
<tr class="menu-item hover-highlight">
<td>
<div class="menu-icon">
<div class="usercontext-icon"
data-identity-icon="pet"
data-identity-color="blue">
</div>
</div>
<span class="menu-text">Default</span>
</td>
</tr>
</table>
</div>
</div>
<script src="js/utils.js"></script>
<script src="js/pageAction.js"></script>
</body>
</html>

View file

@ -115,117 +115,227 @@
<a href="#" id="achievement-done-button" class="onboarding-button">Done</a> <a href="#" id="achievement-done-button" class="onboarding-button">Done</a>
</div> </div>
<div class="panel container-panel hide" id="container-panel"> <div class="panel menu-panel container-panel hide" id="container-panel">
<div id="current-tab"> <h3 class="title">
<h3>Current Tab</h3> Multi-Account Containers
<div id="current-page"></div> </h3>
<label for="container-page-assigned"> <a href="#" id="info-icon" tabindex="10">i</a>
<input type="checkbox" id="container-page-assigned" /> <hr>
<span class="truncate-text"> <table class="menu">
Always open in <tr class="menu-item hover-highlight" id="open-new-tab-in" tabindex="0">
<span id="current-container"></span> <td>
<img class="menu-icon" alt="Open in New Tab" src="/img/tab-new-16.svg" />
<span class="menu-text">Open New Tab in...</span>
<span class="menu-arrow">
<img alt="Container Info" src="/img/arrow-icon-right.svg" />
</span> </span>
</label> </td>
</tr>
<tr class="menu-item hover-highlight" id="reopen-site-in" tabindex="0">
<td>
<img class="menu-icon" alt="Open in New Tab" src="/img/refresh-16.svg" />
<span class="menu-text">Reopen This Site in...</span>
<span class="menu-arrow">
<img alt="Container Info" src="/img/arrow-icon-right.svg" />
</span>
</td>
</tr>
</table>
<hr>
<table class="menu">
<tr class="menu-item hover-highlight" id="sort-containers-link" tabindex="0">
<td>
<img class="menu-icon" alt="Open in New Tab" src="/img/sort-16_1.svg" />
<span class="menu-text">Sort Tabs by Container</span>
<span class="menu-arrow">
</span>
</td>
</tr>
<tr class="menu-item hover-highlight" id="always-open-in" tabindex="0">
<td>
<img class="menu-icon" alt="Open in New Tab" src="/img/open-in-new-16.svg" />
<span class="menu-text">Always Open This Site in...</span>
<span class="menu-arrow">
<img alt="Container Info" src="/img/arrow-icon-right.svg" />
</span>
</td>
</tr>
</table>
<hr>
<div class="sub-header">
Containers
</div> </div>
<div class="container-panel-controls"> <div class="scrollable identities-list">
<a href="#" class="action-link" id="sort-containers-link" title="Sort tabs into container order">Sort Tabs</a> <table class="menu" id="identities-list">
<tr class="menu-item hover-highlight">
<td>
<div class="menu-icon">
<div class="usercontext-icon"
data-identity-icon="pet"
data-identity-color="blue">
</div> </div>
<div class="scrollable panel-content" tabindex="-1"> </div>
<table class="identities-list"> <span class="menu-text">Default</span>
<tbody></tbody> <span class="menu-right-float">
<span class="container-count">22</span>
<span class="menu-arrow">
<img alt="Container Info" src="/img/arrow-icon-right.svg" />
</span>
</span>
</td>
</tr>
</table> </table>
</div> </div>
<div class="panel-footer edit-identities"> <div class="bottom-btn" id="manage-containers-link" tabindex="0">
<div class="edit-containers-text panel-footer-secondary"> Manage Containers
<a href="#" tabindex="0" id="edit-containers-link">Edit Containers</a>
</div>
<a href="#" tabindex="0" class="add-container-link pop-button" id="container-add-link" title="Create new container">
<img class="pop-button-image-small icon" alt="Create new container icon" src="/img/container-add.svg" />
</a>
</div> </div>
</div> </div>
<div class="hide panel container-info-panel" id="container-info-panel" tabindex="-1"> <div class="hide panel menu-panel container-info-panel" id="container-info-panel" tabindex="-1">
<div class="columns"> <h3 class="title" id="container-info-title">
<div class="panel-back-arrow" id="close-container-info-panel"> Personal
<img alt="Panel Back Arrow" src="/img/container-arrow.svg" class="back-arrow-img" /> </h3>
<button class="btn-return arrow-left" id="close-container-info-panel" tabindex="0"></button>
<hr>
<table class="menu">
<tr class="menu-item hover-highlight" id="hideorshow-container" tabindex="0">
<td>
<img id="container-info-hideorshow-icon" class="menu-icon" alt="Hide This Container" src="img/password-hide.svg" />
<span id="container-info-hideorshow-label" class="menu-text">Hide This Container</span>
<span class="menu-arrow">
</span>
</td>
</tr>
<tr class="menu-item hover-highlight" id="move-to-new-window" tabindex="0">
<td>
<img class="menu-icon" alt="Move Tabs to a New Window" src="/img/movetowindow-16.svg" />
<span class="menu-text">Move Tabs to a New Window</span>
<span class="menu-arrow">
</span>
</td>
</tr>
<tr class="menu-item hover-highlight hover-highlight" id="always-open" tabindex="0">
<td>
<img class="menu-icon" alt="Always Open Site in Container" src="/img/open-in-new-16.svg" />
<span class="menu-text" id="always-open-in-info-panel">Always Open Site in Container</span>
<span class="menu-arrow">
</span>
</td>
</tr>
</table>
<hr>
<div class="sub-header">
Open Tabs
</div> </div>
<div class="column-panel-content">
<div class="panel-header container-info-panel-header">
<span class="usercontext-icon" id="container-info-icon"></span>
<h3 id="container-info-name" class="panel-header-text container-name truncate-text"></h3>
</div>
<div class="select-row clickable container-info-panel-hide container-info-has-tabs" id="container-info-hideorshow">
<img id="container-info-hideorshow-icon" alt="Hide Container icon" src="/img/container-hide.svg" class="icon container-info-panel-hideorshow-icon"/>
<span id="container-info-hideorshow-label">Hide this container</span>
</div>
<div class="select-row clickable container-info-panel-movetabs container-info-has-tabs" id="container-info-movetabs">Move tabs to a new window</div>
<div class="scrollable"> <div class="scrollable">
<table id="container-info-table" class="container-info-list"> <table class="menu" id="container-info-table">
<tr class="menu-item hover-highlight" tabindex="0">
<td>
<div class="favicon"><img class="menu-icon" src="https://www.mozilla.org/favicon.ico" /></div>
<span class="menu-text truncate-text">www.mozillllllllllllllllllllllllllllllllllllla.org</span>
<img class="trash-button" src="/img/container-close-tab.svg" />
</td>
</tr>
</table>
</div>
<div class="bottom-btn" id="manage-container-link">
Manage This Container
</div>
</div>
<div class="panel menu-panel container-picker-panel hide" id="container-picker-panel">
<h3 class="title" id="picker-title">
Multi-Account Containers
</h3>
<button class="btn-return arrow-left" id="close-container-picker-panel" tabindex="0"></button>
<hr>
<div id="new-container-div"></div>
<div class="scrollable identities-list">
<table class="menu" id="picker-identities-list">
<tr class="menu-item hover-highlight">
<td>
<div class="menu-icon">
<div class="usercontext-icon"
data-identity-icon="pet"
data-identity-color="blue">
</div>
</div>
<span class="menu-text">Default</span>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
</div>
</div>
<div class="panel menu-panel edit-container-panel hide" id="edit-container-panel">
<div class="panel edit-containers-panel hide" id="edit-containers-panel"> <h3 class="title" id="container-edit-title">
<div class="panel-header"> Default
<h3 class="panel-header-text">Edit Containers</h3> </h3>
</div> <button class="btn-return arrow-left" id="close-container-edit-panel"></button>
<div class="scrollable panel-content"> <hr>
<table class="unstriped"> <div class="scrollable edit-form">
<tbody id="edit-identities-list"></tbody>
</table>
</div>
<div class="panel-footer edit-containers-panel-footer">
<a href="#" id="exit-edit-mode-link" class="exit-edit-mode-link edit-containers-exit-text">
<img src="/img/container-arrow.svg"/>Exit Edit Mode</a>
</div>
</div>
<div class="panel edit-container-panel hide" id="edit-container-panel">
<div class="columns">
<div class="panel-back-arrow" id="edit-container-panel-back-arrow">
<img alt="Panel Back Arrow" src="/img/container-arrow.svg" class="back-arrow-img" />
</div>
<div class="column-panel-content">
<form id="edit-container-panel-form"> <form id="edit-container-panel-form">
<input type="hidden" name="container-id" id="edit-container-panel-usercontext-input" /> <input type="hidden" name="container-id" id="edit-container-panel-usercontext-input" />
<fieldset> <fieldset>
<legend>Name</legend> <legend class="form-header">Name</legend>
<input type="text" name="container-name" id="edit-container-panel-name-input" maxlength="25"/> <input type="text" name="container-name" id="edit-container-panel-name-input" maxlength="25"/>
</fieldset> </fieldset>
<fieldset id="edit-container-panel-choose-color" class="radio-choice"> <fieldset id="edit-container-panel-choose-color" class="radio-choice">
<legend>Choose a color</legend> <legend class="form-header">Color</legend>
</fieldset> </fieldset>
<fieldset id="edit-container-panel-choose-icon" class="radio-choice"> <fieldset id="edit-container-panel-choose-icon" class="radio-choice">
<legend>Choose an icon</legend> <legend class="form-header">Icon</legend>
</fieldset> </fieldset>
</form> </form>
<div id="edit-sites-assigned" class="scrollable" hidden> <div class="options-header">Options</div>
<h3>Sites assigned to this container</h3> <div class="container-options">
<div class="assigned-sites-list"> <input type="checkbox" id="site-isolation" name="site-isolation">
<label for="site-isolation" class="options-label">Limit to Designated Sites</label>
</div> </div>
<div class="container-options options-label" id="manage-assigned-sites-list">Manage Site List...
</div>
</div>
<div class="delete-container">
<button class="delete-btn" id="delete-container-button">Delete This Container</button>
</div> </div>
<div class="panel-footer"> <div class="panel-footer">
<a href="#" class="button secondary expanded footer-button cancel-button" id="edit-container-cancel-link">Cancel</a> <a href="#" class="button expanded secondary footer-button cancel-button" id="create-container-cancel-link">Cancel</a>
<a class="button primary expanded footer-button" id="edit-container-ok-link">OK</a> <a href="#" class="button expanded primary footer-button" id="create-container-ok-link">OK</a>
</div> </div>
</div> </div>
<div class="panel menu-panel edit-container-assignments hide" id="edit-container-assignments">
<h3 class="title" id="edit-assignments-title">
Default
</h3>
<button class="btn-return arrow-left" id="close-container-assignment-panel"></button>
<hr>
<div class="scrollable edit-sites-assigned">
<div class="sub-header">Sites assigned to this container</div>
<table class="menu scrollable" id="edit-sites-assigned">
<tr class="menu-item hover-highlight" tabindex="0">
<td>
<div class="favicon"><img class="menu-icon" src="https://www.mozilla.org/favicon.ico" /></div>
<span class="menu-text truncate-text">www.mozillllllllllllllllllllllllllllla.org</span>
<img class="trash-button" src="/img/container-delete.svg" />
</td>
</tr>
</table>
</div> </div>
</div> </div>
<div class="hide panel delete-container-panel" id="delete-container-panel"> <div class="hide panel delete-container-panel" id="delete-container-panel">
<div class="panel-header"> <h3 class="title" id="container-delete-title">
<span class="usercontext-icon" id="delete-container-icon"></span> Default
<h3 id="delete-container-name" class="panel-header-text container-name"></h3> </h3>
</div> <button class="btn-return arrow-left" id="close-container-delete-panel"></button>
<hr>
<div class="panel-content delete-container-confirm"> <div class="panel-content delete-container-confirm">
<h4 class="delete-container-confirm-title">Remove This Container</h4> <h4 class="delete-container-confirm-title">Remove This Container</h4>
<p><span id="delete-container-tab-warning"></span> Are you sure you want to remove this Container?</p> <p class="delete-warning" id="delete-container-tab-warning"></p>
<p class="delete-warning">Are you sure you want to remove this Container?</p>
</div> </div>
<div class="panel-footer"> <div class="panel-footer">
<a href="#" class="button expanded secondary footer-button cancel-button" id="delete-container-cancel-link">Cancel</a> <a href="#" class="button expanded secondary footer-button cancel-button" id="delete-container-cancel-link">Cancel</a>

View file

@ -70,6 +70,17 @@ const buildPopupDom = popup => {
}); });
}; };
const buildConfirmPage = async (url) => {
console.log(url)
const webExtension = await webExtensionsJSDOM
.fromFile(path.join(__dirname, "../src/confirm-page.html"), {
apiFake: true,
jsdom: {url}
});
return webExtension;
};
const initializeWithTab = async (details = { const initializeWithTab = async (details = {
cookieStoreId: "firefox-default" cookieStoreId: "firefox-default"
}) => { }) => {
@ -108,4 +119,5 @@ module.exports = {
sinon, sinon,
expect, expect,
nextTick, nextTick,
buildConfirmPage
}; };

View file

@ -1,11 +1,12 @@
const {initializeWithTab} = require("../common"); const {initializeWithTab} = require("../common");
const {buildConfirmPage} = require("../common");
describe("Assignment Feature", function () { describe("Assignment Reopen Feature", function () {
const url = "http://example.com"; const url = "http://example.com";
beforeEach(async function () { beforeEach(async function () {
this.webExt = await initializeWithTab({ this.webExt = await initializeWithTab({
cookieStoreId: "firefox-container-1", cookieStoreId: "firefox-default",
url url
}); });
}); });
@ -17,12 +18,45 @@ describe("Assignment Feature", function () {
describe("click the 'Always open in' checkbox in the popup", function () { describe("click the 'Always open in' checkbox in the popup", function () {
beforeEach(async function () { beforeEach(async function () {
// popup click to set assignment for activeTab.url // popup click to set assignment for activeTab.url
await this.webExt.popup.helper.clickElementById("container-page-assigned"); await this.webExt.popup.helper.clickElementById("always-open-in");
await this.webExt.popup.helper.clickElementByQuerySelectorAll("#picker-identities-list > .menu-item");
});
it("should open the page in the assigned container", async function () {
// should have created a new tab with the confirm page
this.webExt.background.browser.tabs.create.should.have.been.calledWithMatch({
active: true,
cookieStoreId: "firefox-container-4",
index: 1,
openerTabId: null,
url: "http://example.com"
});
});
});
});
describe("Assignment Comfirm Page Feature", function () {
const url = "http://example.com";
beforeEach(async function () {
this.webExt = await initializeWithTab({
cookieStoreId: "firefox-container-4",
url
});
});
afterEach(function () {
this.webExt.destroy();
}); });
describe("open new Tab with the assigned URL in the default container", function () { describe("open new Tab with the assigned URL in the default container", function () {
let newTab; let newTab;
beforeEach(async function () { beforeEach(async function () {
await this.webExt.popup.helper.clickElementById("always-open-in");
await this.webExt.popup.helper.clickElementByQuerySelectorAll("#picker-identities-list > .menu-item");
// new Tab opening activeTab.url in default container // new Tab opening activeTab.url in default container
newTab = await this.webExt.background.browser.tabs._create({ newTab = await this.webExt.background.browser.tabs._create({
cookieStoreId: "firefox-default", cookieStoreId: "firefox-default",
@ -50,26 +84,42 @@ describe("Assignment Feature", function () {
it("should remove the new Tab that got opened in the default container", function () { it("should remove the new Tab that got opened in the default container", function () {
this.webExt.background.browser.tabs.remove.should.have.been.calledWith(newTab.id); this.webExt.background.browser.tabs.remove.should.have.been.calledWith(newTab.id);
}); });
describe("Set assignment to 'never ask' ", function () {
beforeEach(async function () {
// click confirm page to always open in container
const confirmPage = await buildConfirmPage("moz-extension://fake/confirm-page.html?" +
`url=${encodeURIComponent(url)}` +
`&cookieStoreId=${this.webExt.tab.cookieStoreId}`);
confirmPage.browser.runtime.sendMessage.callsFake((...args) => {
this.webExt.browser.runtime.onMessage.addListener.yield(...args);
});
await confirmPage.document.getElementById("never-ask").click();
await confirmPage.document.getElementById("confirm").click();
}); });
describe("click the 'Always open in' checkbox in the popup again", function () { describe("open new Tab with url set to 'never ask' ", function () {
beforeEach(async function () { beforeEach(async function () {
// popup click to remove assignment for activeTab.url // new Tab trying to open url in default container
await this.webExt.popup.helper.clickElementById("container-page-assigned");
});
describe("open new Tab with the no longer assigned URL in the default container", function () {
beforeEach(async function () {
// new Tab opening activeTab.url in default container
await this.webExt.background.browser.tabs._create({ await this.webExt.background.browser.tabs._create({
cookieStoreId: "firefox-default", cookieStoreId: "firefox-default",
url url
}); });
const tabs = await this.webExt.background.browser.tabs.query({});
console.log("tabs", tabs);
}); });
it("should not open the confirm page", async function () { it("should not open the confirm page", async function () {
// should not have created a new tab // should have created a new tab with the assigned url
this.webExt.background.browser.tabs.create.should.not.have.been.called; this.webExt.background.browser.tabs.create.should.have.been.calledWithMatch({
url,
cookieStoreId: "firefox-container-4",
openerTabId: null,
index: 3,
active: true
});
}); });
}); });
}); });

View file

@ -11,8 +11,9 @@ describe("Containers Management", function () {
describe("creating a new container", function () { describe("creating a new container", function () {
beforeEach(async function () { beforeEach(async function () {
await this.webExt.popup.helper.clickElementById("container-add-link"); await this.webExt.popup.helper.clickElementById("manage-containers-link");
await this.webExt.popup.helper.clickElementById("edit-container-ok-link"); await this.webExt.popup.helper.clickElementById("new-container");
await this.webExt.popup.helper.clickElementById("create-container-ok-link");
}); });
it("should create it in the browser as well", function () { it("should create it in the browser as well", function () {
@ -21,8 +22,9 @@ describe("Containers Management", function () {
describe("removing it afterwards", function () { describe("removing it afterwards", function () {
beforeEach(async function () { beforeEach(async function () {
await this.webExt.popup.helper.clickElementById("edit-containers-link"); await this.webExt.popup.helper.clickElementById("manage-containers-link");
await this.webExt.popup.helper.clickElementByQuerySelectorAll(".delete-container-icon", "last"); await this.webExt.popup.helper.clickElementByQuerySelectorAll("#picker-identities-list > .menu-item", "last");
await this.webExt.popup.helper.clickElementById("delete-container-button");
await this.webExt.popup.helper.clickElementById("delete-container-ok-link"); await this.webExt.popup.helper.clickElementById("delete-container-ok-link");
}); });

View file

@ -5,11 +5,12 @@ describe("External Webextensions", function () {
beforeEach(async function () { beforeEach(async function () {
this.webExt = await initializeWithTab({ this.webExt = await initializeWithTab({
cookieStoreId: "firefox-container-1", cookieStoreId: "firefox-container-4",
url url
}); });
await this.webExt.popup.helper.clickElementById("container-page-assigned"); await this.webExt.popup.helper.clickElementById("always-open-in");
await this.webExt.popup.helper.clickElementByQuerySelectorAll("#picker-identities-list > .menu-item", "last");
}); });
afterEach(function () { afterEach(function () {
@ -32,7 +33,7 @@ describe("External Webextensions", function () {
const [promise] = this.webExt.background.browser.runtime.onMessageExternal.addListener.yield(message, sender); const [promise] = this.webExt.background.browser.runtime.onMessageExternal.addListener.yield(message, sender);
const answer = await promise; const answer = await promise;
expect(answer.userContextId === "1").to.be.true; expect(answer.userContextId === "4").to.be.true;
expect(answer.neverAsk === false).to.be.true; expect(answer.neverAsk === false).to.be.true;
expect( expect(
Object.prototype.hasOwnProperty.call( Object.prototype.hasOwnProperty.call(

View file

@ -4,11 +4,12 @@ describe("#940", function () {
describe("when other onBeforeRequestHandlers are faster and redirect with the same requestId", function () { describe("when other onBeforeRequestHandlers are faster and redirect with the same requestId", function () {
it("should not open two confirm pages", async function () { it("should not open two confirm pages", async function () {
const webExtension = await initializeWithTab({ const webExtension = await initializeWithTab({
cookieStoreId: "firefox-container-1", cookieStoreId: "firefox-container-4",
url: "http://example.com" url: "http://example.com"
}); });
await webExtension.popup.helper.clickElementById("container-page-assigned"); await webExtension.popup.helper.clickElementById("always-open-in");
await webExtension.popup.helper.clickElementByQuerySelectorAll("#picker-identities-list > .menu-item");
const responses = {}; const responses = {};
await webExtension.background.browser.tabs._create({ await webExtension.background.browser.tabs._create({
@ -36,10 +37,12 @@ describe("#940", function () {
beforeEach(async function () { beforeEach(async function () {
this.webExt = await initializeWithTab({ this.webExt = await initializeWithTab({
cookieStoreId: "firefox-container-1", cookieStoreId: "firefox-container-4",
url: "https://www.youtube.com" url: "https://www.youtube.com"
}); });
await this.webExt.popup.helper.clickElementById("container-page-assigned");
await this.webExt.popup.helper.clickElementById("always-open-in");
await this.webExt.popup.helper.clickElementByQuerySelectorAll("#picker-identities-list > .menu-item");
global.clock = sinon.useFakeTimers(); global.clock = sinon.useFakeTimers();
this.redirectedRequest = async (options = {}) => { this.redirectedRequest = async (options = {}) => {