Merge pull request #576 from jonathanKingston/shield-study
Shield study work
This commit is contained in:
commit
fc789a49ac
11 changed files with 460 additions and 131 deletions
|
@ -9,6 +9,7 @@ module.exports = {
|
||||||
"webextensions": true
|
"webextensions": true
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
|
"Utils": true,
|
||||||
"CustomizableUI": true,
|
"CustomizableUI": true,
|
||||||
"CustomizableWidgets": true,
|
"CustomizableWidgets": true,
|
||||||
"SessionStore": true,
|
"SessionStore": true,
|
||||||
|
|
|
@ -56,19 +56,25 @@ const assignManager = {
|
||||||
return this.area.remove([siteStoreKey]);
|
return this.area.remove([siteStoreKey]);
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteContainer(userContextId) {
|
async deleteContainer(userContextId) {
|
||||||
const removeKeys = [];
|
const sitesByContainer = await this.getByContainer(userContextId);
|
||||||
this.area.get().then((siteConfigs) => {
|
this.area.remove(Object.keys(sitesByContainer));
|
||||||
Object.keys(siteConfigs).forEach((key) => {
|
},
|
||||||
// For some reason this is stored as string... lets check them both as that
|
|
||||||
if (String(siteConfigs[key].userContextId) === String(userContextId)) {
|
async getByContainer(userContextId) {
|
||||||
removeKeys.push(key);
|
const sites = {};
|
||||||
}
|
const siteConfigs = await this.area.get();
|
||||||
});
|
Object.keys(siteConfigs).forEach((key) => {
|
||||||
this.area.remove(removeKeys);
|
// For some reason this is stored as string... lets check them both as that
|
||||||
}).catch((e) => {
|
if (String(siteConfigs[key].userContextId) === String(userContextId)) {
|
||||||
throw e;
|
const site = siteConfigs[key];
|
||||||
|
// In hindsight we should have stored this
|
||||||
|
// TODO file a follow up to clean the storage onLoad
|
||||||
|
site.hostname = key.replace(/^siteContainerMap@@_/, "");
|
||||||
|
sites[key] = site;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
return sites;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -104,6 +110,7 @@ const assignManager = {
|
||||||
if (options.frameId !== 0 || options.tabId === -1) {
|
if (options.frameId !== 0 || options.tabId === -1) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
this.removeContextMenu();
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
browser.tabs.get(options.tabId),
|
browser.tabs.get(options.tabId),
|
||||||
this.storageArea.get(options.url)
|
this.storageArea.get(options.url)
|
||||||
|
@ -151,15 +158,11 @@ const assignManager = {
|
||||||
// let actionName;
|
// let actionName;
|
||||||
let remove;
|
let remove;
|
||||||
if (info.menuItemId === this.MENU_ASSIGN_ID) {
|
if (info.menuItemId === this.MENU_ASSIGN_ID) {
|
||||||
//actionName = "added";
|
|
||||||
// storageAction = this._setAssignment(info.pageUrl, userContextId, setOrRemove);
|
|
||||||
remove = false;
|
remove = false;
|
||||||
} else {
|
} else {
|
||||||
// actionName = "removed";
|
|
||||||
//storageAction = this.storageArea.remove(info.pageUrl);
|
|
||||||
remove = true;
|
remove = true;
|
||||||
}
|
}
|
||||||
await this._setOrRemoveAssignment(info.pageUrl, userContextId, remove);
|
await this._setOrRemoveAssignment(tab.id, info.pageUrl, userContextId, remove);
|
||||||
this.calculateContextMenu(tab);
|
this.calculateContextMenu(tab);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -192,7 +195,7 @@ const assignManager = {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
async _setOrRemoveAssignment(pageUrl, userContextId, remove) {
|
async _setOrRemoveAssignment(tabId, pageUrl, userContextId, remove) {
|
||||||
let actionName;
|
let actionName;
|
||||||
if (!remove) {
|
if (!remove) {
|
||||||
await this.storageArea.set(pageUrl, {
|
await this.storageArea.set(pageUrl, {
|
||||||
|
@ -205,11 +208,8 @@ const assignManager = {
|
||||||
await this.storageArea.remove(pageUrl);
|
await this.storageArea.remove(pageUrl);
|
||||||
actionName = "removed";
|
actionName = "removed";
|
||||||
}
|
}
|
||||||
browser.notifications.create({
|
browser.tabs.sendMessage(tabId, {
|
||||||
type: "basic",
|
text: `Successfully ${actionName} site to always open in this container`
|
||||||
title: "Containers",
|
|
||||||
message: `Successfully ${actionName} site to always open in this container`,
|
|
||||||
iconUrl: browser.extension.getURL("/img/onboarding-1.png")
|
|
||||||
});
|
});
|
||||||
backgroundLogic.sendTelemetryPayload({
|
backgroundLogic.sendTelemetryPayload({
|
||||||
event: `${actionName}-container-assignment`,
|
event: `${actionName}-container-assignment`,
|
||||||
|
@ -227,7 +227,11 @@ const assignManager = {
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
async calculateContextMenu(tab) {
|
_getByContainer(userContextId) {
|
||||||
|
return this.storageArea.getByContainer(userContextId);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeContextMenu() {
|
||||||
// There is a focus issue in this menu where if you change window with a context menu click
|
// There is a focus issue in this menu where if you change window with a context menu click
|
||||||
// you get the wrong menu display because of async
|
// you get the wrong menu display because of async
|
||||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1215376#c16
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1215376#c16
|
||||||
|
@ -235,6 +239,10 @@ const assignManager = {
|
||||||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1352102
|
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1352102
|
||||||
browser.contextMenus.remove(this.MENU_ASSIGN_ID);
|
browser.contextMenus.remove(this.MENU_ASSIGN_ID);
|
||||||
browser.contextMenus.remove(this.MENU_REMOVE_ID);
|
browser.contextMenus.remove(this.MENU_REMOVE_ID);
|
||||||
|
},
|
||||||
|
|
||||||
|
async calculateContextMenu(tab) {
|
||||||
|
this.removeContextMenu();
|
||||||
const siteSettings = await this._getAssignment(tab);
|
const siteSettings = await this._getAssignment(tab);
|
||||||
// ✓ This is to mitigate https://bugzilla.mozilla.org/show_bug.cgi?id=1351418
|
// ✓ This is to mitigate https://bugzilla.mozilla.org/show_bug.cgi?id=1351418
|
||||||
let prefix = " "; // Alignment of non breaking space, unknown why this requires so many spaces to align with the tick
|
let prefix = " "; // Alignment of non breaking space, unknown why this requires so many spaces to align with the tick
|
||||||
|
@ -429,10 +437,13 @@ const messageHandler = {
|
||||||
return assignManager._getAssignment(tab);
|
return assignManager._getAssignment(tab);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case "getAssignmentObjectByContainer":
|
||||||
|
response = assignManager._getByContainer(m.message.userContextId);
|
||||||
|
break;
|
||||||
case "setOrRemoveAssignment":
|
case "setOrRemoveAssignment":
|
||||||
response = browser.tabs.get(m.tabId).then((tab) => {
|
response = browser.tabs.get(m.tabId).then((tab) => {
|
||||||
const userContextId = assignManager.getUserContextIdFromCookieStore(tab);
|
const userContextId = assignManager.getUserContextIdFromCookieStore(tab);
|
||||||
return assignManager._setOrRemoveAssignment(tab.url, userContextId, m.value);
|
return assignManager._setOrRemoveAssignment(tab.id, tab.url, userContextId, m.value);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "exemptContainerAssignment":
|
case "exemptContainerAssignment":
|
||||||
|
@ -474,6 +485,7 @@ const messageHandler = {
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.tabs.onActivated.addListener((info) => {
|
browser.tabs.onActivated.addListener((info) => {
|
||||||
|
assignManager.removeContextMenu();
|
||||||
browser.tabs.get(info.tabId).then((tab) => {
|
browser.tabs.get(info.tabId).then((tab) => {
|
||||||
tabPageCounter.initTabCounter(tab);
|
tabPageCounter.initTabCounter(tab);
|
||||||
assignManager.calculateContextMenu(tab);
|
assignManager.calculateContextMenu(tab);
|
||||||
|
@ -483,6 +495,7 @@ const messageHandler = {
|
||||||
});
|
});
|
||||||
|
|
||||||
browser.windows.onFocusChanged.addListener((windowId) => {
|
browser.windows.onFocusChanged.addListener((windowId) => {
|
||||||
|
assignManager.removeContextMenu();
|
||||||
browser.tabs.query({active: true, windowId}).then((tabs) => {
|
browser.tabs.query({active: true, windowId}).then((tabs) => {
|
||||||
if (tabs && tabs[0]) {
|
if (tabs && tabs[0]) {
|
||||||
tabPageCounter.initTabCounter(tabs[0]);
|
tabPageCounter.initTabCounter(tabs[0]);
|
||||||
|
@ -511,6 +524,7 @@ const messageHandler = {
|
||||||
if (details.frameId !== 0 || details.tabId === -1) {
|
if (details.frameId !== 0 || details.tabId === -1) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
assignManager.removeContextMenu();
|
||||||
|
|
||||||
browser.tabs.get(details.tabId).then((tab) => {
|
browser.tabs.get(details.tabId).then((tab) => {
|
||||||
tabPageCounter.incrementTabCount(tab);
|
tabPageCounter.incrementTabCount(tab);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script src="js/utils.js"></script>
|
||||||
<script src="js/confirm-page.js"></script>
|
<script src="js/confirm-page.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
22
webextension/css/content.css
Normal file
22
webextension/css/content.css
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
.container-notification {
|
||||||
|
background: #33f70c;
|
||||||
|
color: #003f07;
|
||||||
|
display: block;
|
||||||
|
inline-size: 100vw;
|
||||||
|
offset-block-start: 0;
|
||||||
|
offset-inline-start: 0;
|
||||||
|
padding-block-end: 8px;
|
||||||
|
padding-block-start: 8px;
|
||||||
|
padding-inline-end: 8px;
|
||||||
|
padding-inline-start: 8px;
|
||||||
|
position: fixed;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
transition: transform 0.3s cubic-bezier(0.07, 0.95, 0, 1) 0.3s;
|
||||||
|
z-index: 999999999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-notification img {
|
||||||
|
block-size: 16px;
|
||||||
|
inline-size: 16px;
|
||||||
|
margin-inline-end: 3px;
|
||||||
|
}
|
|
@ -1,16 +1,55 @@
|
||||||
/* General Rules and Resets */
|
/* General Rules and Resets */
|
||||||
body {
|
* {
|
||||||
inline-size: 300px;
|
font-size: inherit;
|
||||||
max-inline-size: 300px;
|
margin-block-end: 0;
|
||||||
|
margin-block-start: 0;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
padding-block-end: 0;
|
||||||
|
padding-block-start: 0;
|
||||||
|
padding-inline-end: 0;
|
||||||
|
padding-inline-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Roboto, Noto, "San Francisco", Ubuntu, "Segoe UI", "Fira Sans", message-box, Arial, sans-serif;
|
||||||
|
inline-size: 300px;
|
||||||
|
max-inline-size: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--font-size-heading: 16px;
|
|
||||||
--primary-action-color: #248aeb;
|
--primary-action-color: #248aeb;
|
||||||
|
--title-text-color: #000;
|
||||||
|
--text-normal-color: #4a4a4a;
|
||||||
|
--text-heading-color: #000;
|
||||||
|
|
||||||
|
/* calculated from 12px */
|
||||||
|
--font-size-heading: 1.33rem; /* 16px */
|
||||||
|
--block-line-space-size: 0.5rem; /* 6px */
|
||||||
|
--inline-item-space-size: 0.5rem; /* 6px */
|
||||||
|
--block-line-separation-size: 0.33rem; /* 10px */
|
||||||
|
--inline-icon-space-size: 0.833rem; /* 10px */
|
||||||
|
|
||||||
|
/* Use for url and icon size */
|
||||||
|
--block-url-label-size: 2rem; /* 24px */
|
||||||
|
--inline-start-size: 1.66rem; /* 20px */
|
||||||
|
--inline-button-size: 5.833rem; /* 70px */
|
||||||
|
--icon-size: 1.166rem; /* 14px */
|
||||||
|
|
||||||
|
--small-text-size: 0.833rem; /* 10px */
|
||||||
|
--small-radius: 3px;
|
||||||
|
--icon-button-size: calc(calc(var(--block-line-separation-size) * 2) + 1.66rem); /* 20px */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-resolution: 1dppx) {
|
||||||
|
html {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
|
@ -19,6 +58,13 @@ html {
|
||||||
box-sizing: inherit;
|
box-sizing: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-block-end: 0;
|
||||||
|
margin-block-start: 0;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
border: 0;
|
border: 0;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
|
@ -35,6 +81,7 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
.scrollable {
|
.scrollable {
|
||||||
|
border-block-start: 1px solid #f1f1f1;
|
||||||
inline-size: 100%;
|
inline-size: 100%;
|
||||||
max-block-size: 400px;
|
max-block-size: 400px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -146,6 +193,10 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buttons */
|
/* Buttons */
|
||||||
|
.button {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
.button.primary {
|
.button.primary {
|
||||||
background-color: #0996f8;
|
background-color: #0996f8;
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -216,7 +267,7 @@ table {
|
||||||
.column-panel-content .button,
|
.column-panel-content .button,
|
||||||
.panel-footer .button {
|
.panel-footer .button {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
block-size: 54px;
|
block-size: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -265,7 +316,7 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
.onboarding p {
|
.onboarding p {
|
||||||
color: #4a4a4a;
|
color: var(--text-normal-color);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-block-end: 16px;
|
margin-block-end: 16px;
|
||||||
max-inline-size: 84%;
|
max-inline-size: 84%;
|
||||||
|
@ -294,9 +345,10 @@ table {
|
||||||
manage things like container crud */
|
manage things like container crud */
|
||||||
.pop-button {
|
.pop-button {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
block-size: 48px;
|
block-size: var(--icon-button-size);
|
||||||
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 48px;
|
flex: 0 0 var(--icon-button-size);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +373,10 @@ manage things like container crud */
|
||||||
.pop-button-image {
|
.pop-button-image {
|
||||||
block-size: 20px;
|
block-size: 20px;
|
||||||
flex: 0 0 20px;
|
flex: 0 0 20px;
|
||||||
|
margin-block-end: auto;
|
||||||
|
margin-block-start: auto;
|
||||||
|
margin-inline-end: auto;
|
||||||
|
margin-inline-start: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pop-button-image-small {
|
.pop-button-image-small {
|
||||||
|
@ -332,18 +388,21 @@ manage things like container crud */
|
||||||
.panel-header {
|
.panel-header {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
block-size: 48px;
|
block-size: 48px;
|
||||||
border-block-end: 1px solid #ebebeb;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-header .usercontext-icon {
|
||||||
|
inline-size: var(--icon-button-size);
|
||||||
|
}
|
||||||
|
|
||||||
.column-panel-content .panel-header {
|
.column-panel-content .panel-header {
|
||||||
flex: 0 0 48px;
|
flex: 0 0 48px;
|
||||||
inline-size: 100%;
|
inline-size: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-header-text {
|
.panel-header-text {
|
||||||
color: #4a4a4a;
|
color: var(--text-normal-color);
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: var(--font-size-heading);
|
font-size: var(--font-size-heading);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
@ -371,8 +430,31 @@ manage things like container crud */
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container-panel-controls {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-block-end: var(--block-line-space-size);
|
||||||
|
margin-block-start: var(--block-line-space-size);
|
||||||
|
margin-inline-end: var(--inline-item-space-size);
|
||||||
|
margin-inline-start: var(--inline-item-space-size);
|
||||||
|
}
|
||||||
|
|
||||||
#container-panel #sort-containers-link {
|
#container-panel #sort-containers-link {
|
||||||
margin-inline-end: 16px;
|
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 {
|
||||||
|
@ -383,41 +465,75 @@ span ~ .panel-header-text {
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-tab {
|
#current-tab {
|
||||||
|
align-items: center;
|
||||||
|
color: var(--text-normal-color);
|
||||||
|
display: grid;
|
||||||
|
font-size: var(--small-text-size);
|
||||||
|
grid-column-gap: var(--inline-item-space-size);
|
||||||
|
grid-row-gap: var(--block-line-space-size);
|
||||||
|
grid-template-columns: var(--icon-size) var(--icon-size) 1fr;
|
||||||
|
margin-block-end: var(--block-line-space-size);
|
||||||
|
margin-block-start: var(--block-line-separation-size);
|
||||||
|
margin-inline-end: var(--inline-start-size);
|
||||||
|
margin-inline-start: var(--inline-start-size);
|
||||||
max-inline-size: 100%;
|
max-inline-size: 100%;
|
||||||
min-block-size: 91px;
|
}
|
||||||
padding-block-end: 13px;
|
|
||||||
padding-block-start: 13px;
|
#current-tab img {
|
||||||
padding-inline-end: 16px;
|
max-block-size: var(--icon-size);
|
||||||
padding-inline-start: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-tab > h3 {
|
#current-tab > h3 {
|
||||||
color: #4a4a4a;
|
color: var(--text-heading-color);
|
||||||
font-size: var(--font-size-heading);
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin-block-end: 3px;
|
grid-column: span 3;
|
||||||
|
margin-block-end: 0;
|
||||||
margin-block-start: 0;
|
margin-block-start: 0;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
margin-inline-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-page > img {
|
#current-page {
|
||||||
block-size: 16px;
|
display: contents;
|
||||||
inline-size: 16px;
|
}
|
||||||
|
|
||||||
|
#current-tab .page-title {
|
||||||
|
font-size: var(--font-size-heading);
|
||||||
|
grid-column: 2 / 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-tab > label {
|
#current-tab > label {
|
||||||
align-items: center;
|
display: contents;
|
||||||
display: flex;
|
font-size: var(--small-text-size);
|
||||||
margin-inline-start: 17px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-tab > label > input {
|
#current-tab > label > input {
|
||||||
display: inline;
|
-moz-appearance: none;
|
||||||
|
block-size: var(--icon-size);
|
||||||
|
border: 1px solid #d8d8d8;
|
||||||
|
border-radius: var(--small-radius);
|
||||||
|
display: block;
|
||||||
|
grid-column-start: 2;
|
||||||
|
inline-size: var(--icon-size);
|
||||||
|
margin-block-end: 0;
|
||||||
|
margin-block-start: 0;
|
||||||
|
margin-inline-end: 0;
|
||||||
|
margin-inline-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#current-tab > label > input[disabled] {
|
||||||
|
background-color: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#current-tab > label > input:checked {
|
||||||
|
background-image: url("chrome://global/skin/in-content/check.svg#check-native");
|
||||||
|
background-position: -1px -1px;
|
||||||
|
background-size: var(--icon-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-container {
|
#current-container {
|
||||||
|
color: var(--identity-tab-color);
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-transform: lowercase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-tab > label > .usercontext-icon {
|
#current-tab > label > .usercontext-icon {
|
||||||
|
@ -434,7 +550,6 @@ span ~ .panel-header-text {
|
||||||
.container-panel-row {
|
.container-panel-row {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #fefefe !important;
|
background-color: #fefefe !important;
|
||||||
block-size: 48px;
|
|
||||||
border-block-end: 1px solid #f1f1f1;
|
border-block-end: 1px solid #f1f1f1;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -465,8 +580,9 @@ span ~ .panel-header-text {
|
||||||
}
|
}
|
||||||
|
|
||||||
.userContext-icon-wrapper {
|
.userContext-icon-wrapper {
|
||||||
block-size: 48px;
|
block-size: var(--icon-button-size);
|
||||||
flex: 0 0 48px;
|
flex: 0 0 var(--icon-button-size);
|
||||||
|
margin-inline-start: var(--inline-icon-space-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .userContext-icon is used natively, Bug 1333811 was raised to fix */
|
/* .userContext-icon is used natively, Bug 1333811 was raised to fix */
|
||||||
|
@ -475,24 +591,28 @@ span ~ .panel-header-text {
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 20px 20px;
|
background-size: 20px 20px;
|
||||||
block-size: 48px;
|
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');
|
||||||
flex: 0 0 48px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.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 {
|
||||||
background-image: url('/img/container-newtab.svg');
|
background-image: url('/img/container-newtab.svg');
|
||||||
fill: 'gray';
|
fill: #979797;
|
||||||
filter: url('/img/filters.svg#fill');
|
filter: url('/img/filters.svg#fill');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container-panel-row .clickable:hover .usercontext-icon,
|
||||||
|
.container-panel-row .clickable:focus .usercontext-icon {
|
||||||
|
fill: #0094fb;
|
||||||
|
}
|
||||||
|
|
||||||
/* Panel Footer */
|
/* Panel Footer */
|
||||||
.panel-footer {
|
.panel-footer {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: #efefef;
|
background: #efefef;
|
||||||
block-size: 54px;
|
block-size: var(--icon-button-size);
|
||||||
border-block-end: 1px solid #d8d8d8;
|
border-block-end: 1px solid #d8d8d8;
|
||||||
color: #000;
|
color: #000;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -501,14 +621,9 @@ span ~ .panel-header-text {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-footer .pop-button {
|
|
||||||
block-size: 54px;
|
|
||||||
flex: 0 0 54px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-containers-text {
|
.edit-containers-text {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
block-size: 54px;
|
block-size: 100%;
|
||||||
border-inline-end: solid 1px #d8d8d8;
|
border-inline-end: solid 1px #d8d8d8;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -517,7 +632,7 @@ span ~ .panel-header-text {
|
||||||
|
|
||||||
.edit-containers-text a {
|
.edit-containers-text a {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
block-size: 54px;
|
block-size: 100%;
|
||||||
color: #0a0a0a;
|
color: #0a0a0a;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -525,8 +640,8 @@ span ~ .panel-header-text {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Container info list */
|
/* Container info list */
|
||||||
#container-info-name {
|
.container-info-tab-title {
|
||||||
margin-inline-end: 0.5rem;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#container-info-hideorshow {
|
#container-info-hideorshow {
|
||||||
|
@ -574,13 +689,16 @@ span ~ .panel-header-text {
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-info-list {
|
.container-info-list {
|
||||||
border-block-start: 1px solid #ebebeb;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-block-start: 4px;
|
margin-block-start: 4px;
|
||||||
padding-block-start: 4px;
|
padding-block-start: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container-info-list tbody {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
.clickable {
|
.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -631,6 +749,32 @@ span ~ .panel-header-text {
|
||||||
padding-inline-start: 16px;
|
padding-inline-start: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#edit-sites-assigned {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-sites-assigned h3 {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
padding-block-end: 5px;
|
||||||
|
padding-inline-end: 16px;
|
||||||
|
padding-inline-start: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-sites-assigned table td {
|
||||||
|
display: flex;
|
||||||
|
padding-inline-end: 16px;
|
||||||
|
padding-inline-start: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-sites-assigned .delete-assignment {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-sites-assigned tr:hover > td > .delete-assignment {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.column-panel-content form span {
|
.column-panel-content form span {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
block-size: 44px;
|
block-size: 44px;
|
||||||
|
@ -679,6 +823,10 @@ span ~ .panel-header-text {
|
||||||
padding-inline-start: 0;
|
padding-inline-start: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-container-panel fieldset:last-of-type {
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.edit-container-panel input[type="text"] {
|
.edit-container-panel input[type="text"] {
|
||||||
block-size: 36px;
|
block-size: 36px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
|
|
@ -5,7 +5,7 @@ async function load() {
|
||||||
const currentCookieStoreId = searchParams.get("currentCookieStoreId");
|
const currentCookieStoreId = searchParams.get("currentCookieStoreId");
|
||||||
const redirectUrlElement = document.getElementById("redirect-url");
|
const redirectUrlElement = document.getElementById("redirect-url");
|
||||||
redirectUrlElement.textContent = redirectUrl;
|
redirectUrlElement.textContent = redirectUrl;
|
||||||
createFavicon(redirectUrl, redirectUrlElement);
|
appendFavicon(redirectUrl, redirectUrlElement);
|
||||||
|
|
||||||
const container = await browser.contextualIdentities.get(cookieStoreId);
|
const container = await browser.contextualIdentities.get(cookieStoreId);
|
||||||
[...document.querySelectorAll(".container-name")].forEach((containerNameElement) => {
|
[...document.querySelectorAll(".container-name")].forEach((containerNameElement) => {
|
||||||
|
@ -32,12 +32,11 @@ async function load() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createFavicon(pageUrl, redirectUrlElement) {
|
function appendFavicon(pageUrl, redirectUrlElement) {
|
||||||
const origin = new URL(pageUrl).origin;
|
const origin = new URL(pageUrl).origin;
|
||||||
const imageElement = document.createElement("img");
|
const favIconElement = Utils.createFavIconElement(`${origin}/favicon.ico`);
|
||||||
imageElement.src = `${origin}/favicon.ico`;
|
|
||||||
|
|
||||||
redirectUrlElement.prepend(imageElement);
|
redirectUrlElement.prepend(favIconElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmSubmit(redirectUrl, cookieStoreId) {
|
function confirmSubmit(redirectUrl, cookieStoreId) {
|
||||||
|
|
53
webextension/js/content-script.js
Normal file
53
webextension/js/content-script.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
async function delayAnimation(delay = 350) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, delay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doAnimation(element, property, value) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const handler = () => {
|
||||||
|
resolve();
|
||||||
|
element.removeEventListener("transitionend", handler);
|
||||||
|
};
|
||||||
|
element.addEventListener("transitionend", handler);
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
element.style[property] = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
async function awaitEvent(eventName) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const handler = () => {
|
||||||
|
resolve();
|
||||||
|
divElement.removeEventListener(eventName, handler);
|
||||||
|
};
|
||||||
|
divElement.addEventListener(eventName, handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
async function addMessage(message) {
|
||||||
|
const divElement = document.createElement("div");
|
||||||
|
divElement.classList.add("container-notification");
|
||||||
|
// For the eager eyed, this is an experiment. It is however likely that a website will know it is "contained" anyway
|
||||||
|
divElement.innerText = message.text;
|
||||||
|
|
||||||
|
const imageElement = document.createElement("img");
|
||||||
|
imageElement.src = browser.extension.getURL("/img/container-site-d-24.png");
|
||||||
|
divElement.prepend(imageElement);
|
||||||
|
|
||||||
|
document.body.appendChild(divElement);
|
||||||
|
|
||||||
|
await delayAnimation(100);
|
||||||
|
await doAnimation(divElement, "transform", "translateY(0)");
|
||||||
|
await delayAnimation(2000);
|
||||||
|
await doAnimation(divElement, "transform", "translateY(-100%)");
|
||||||
|
|
||||||
|
divElement.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener((message) => {
|
||||||
|
addMessage(message);
|
||||||
|
});
|
|
@ -18,7 +18,6 @@ const P_CONTAINERS_EDIT = "containersEdit";
|
||||||
const P_CONTAINER_INFO = "containerInfo";
|
const P_CONTAINER_INFO = "containerInfo";
|
||||||
const P_CONTAINER_EDIT = "containerEdit";
|
const P_CONTAINER_EDIT = "containerEdit";
|
||||||
const P_CONTAINER_DELETE = "containerDelete";
|
const P_CONTAINER_DELETE = "containerDelete";
|
||||||
const DEFAULT_FAVICON = "moz-icon://goat?size=16";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Escapes any occurances of &, ", <, > or / with XML entities.
|
* Escapes any occurances of &, ", <, > or / with XML entities.
|
||||||
|
@ -119,7 +118,9 @@ const Logic = {
|
||||||
},
|
},
|
||||||
|
|
||||||
addEnterHandler(element, handler) {
|
addEnterHandler(element, handler) {
|
||||||
element.addEventListener("click", handler);
|
element.addEventListener("click", (e) => {
|
||||||
|
handler(e);
|
||||||
|
});
|
||||||
element.addEventListener("keydown", (e) => {
|
element.addEventListener("keydown", (e) => {
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
handler(e);
|
handler(e);
|
||||||
|
@ -208,6 +209,11 @@ const Logic = {
|
||||||
return this._currentIdentity;
|
return this._currentIdentity;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
currentUserContextId() {
|
||||||
|
const identity = Logic.currentIdentity();
|
||||||
|
return Logic.userContextId(identity.cookieStoreId);
|
||||||
|
},
|
||||||
|
|
||||||
sendTelemetryPayload(message = {}) {
|
sendTelemetryPayload(message = {}) {
|
||||||
if (!message.event) {
|
if (!message.event) {
|
||||||
throw new Error("Missing event name for telemetry");
|
throw new Error("Missing event name for telemetry");
|
||||||
|
@ -234,10 +240,19 @@ const Logic = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
setOrRemoveAssignment(tab, value) {
|
getAssignmentObjectByContainer(userContextId) {
|
||||||
|
return browser.runtime.sendMessage({
|
||||||
|
method: "getAssignmentObjectByContainer",
|
||||||
|
message: {userContextId}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setOrRemoveAssignment(tabId, url, userContextId, value) {
|
||||||
return browser.runtime.sendMessage({
|
return browser.runtime.sendMessage({
|
||||||
method: "setOrRemoveAssignment",
|
method: "setOrRemoveAssignment",
|
||||||
tabId: tab.id,
|
tabId,
|
||||||
|
url,
|
||||||
|
userContextId,
|
||||||
value
|
value
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -437,7 +452,8 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
const currentTabElement = document.getElementById("current-tab");
|
const currentTabElement = document.getElementById("current-tab");
|
||||||
const assignmentCheckboxElement = document.getElementById("container-page-assigned");
|
const assignmentCheckboxElement = document.getElementById("container-page-assigned");
|
||||||
assignmentCheckboxElement.addEventListener("change", () => {
|
assignmentCheckboxElement.addEventListener("change", () => {
|
||||||
Logic.setOrRemoveAssignment(currentTab, !assignmentCheckboxElement.checked);
|
const userContextId = Logic.userContextId(currentTab.cookieStoreId);
|
||||||
|
Logic.setOrRemoveAssignment(currentTab.id, currentTab.url, userContextId, !assignmentCheckboxElement.checked);
|
||||||
});
|
});
|
||||||
currentTabElement.hidden = !currentTab;
|
currentTabElement.hidden = !currentTab;
|
||||||
this.setupAssignmentCheckbox(false);
|
this.setupAssignmentCheckbox(false);
|
||||||
|
@ -446,29 +462,14 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
const siteSettings = await Logic.getAssignment(currentTab);
|
const siteSettings = await Logic.getAssignment(currentTab);
|
||||||
this.setupAssignmentCheckbox(siteSettings);
|
this.setupAssignmentCheckbox(siteSettings);
|
||||||
const currentPage = document.getElementById("current-page");
|
const currentPage = document.getElementById("current-page");
|
||||||
const favIconUrl = currentTab.favIconUrl || "";
|
currentPage.innerHTML = escaped`<span class="page-title truncate-text">${currentTab.title}</span>`;
|
||||||
currentPage.innerHTML = escaped`
|
const favIconElement = Utils.createFavIconElement(currentTab.favIconUrl || "");
|
||||||
<img class="offpage" src="${favIconUrl}" /> ${currentTab.title}
|
currentPage.prepend(favIconElement);
|
||||||
`;
|
|
||||||
|
|
||||||
const imageElement = currentPage.querySelector("img");
|
|
||||||
const loadListener = (e) => {
|
|
||||||
e.target.classList.remove("offpage");
|
|
||||||
e.target.removeEventListener("load", loadListener);
|
|
||||||
e.target.removeEventListener("error", errorListener);
|
|
||||||
};
|
|
||||||
const errorListener = (e) => {
|
|
||||||
e.target.src = DEFAULT_FAVICON;
|
|
||||||
};
|
|
||||||
imageElement.addEventListener("error", errorListener);
|
|
||||||
imageElement.addEventListener("load", loadListener);
|
|
||||||
|
|
||||||
const currentContainer = document.getElementById("current-container");
|
const currentContainer = document.getElementById("current-container");
|
||||||
currentContainer.innerText = identity.name;
|
currentContainer.innerText = identity.name;
|
||||||
|
|
||||||
const currentContainerIcon = document.getElementById("current-container-icon");
|
currentContainer.setAttribute("data-identity-color", identity.color);
|
||||||
currentContainerIcon.setAttribute("data-identity-icon", identity.icon);
|
|
||||||
currentContainerIcon.setAttribute("data-identity-color", identity.color);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -530,15 +531,21 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const list = document.querySelector(".identities-list");
|
const list = document.querySelector(".identities-list tbody");
|
||||||
|
|
||||||
list.innerHTML = "";
|
list.innerHTML = "";
|
||||||
list.appendChild(fragment);
|
list.appendChild(fragment);
|
||||||
/* Not sure why extensions require a focus for the doorhanger,
|
/* Not sure why extensions require a focus for the doorhanger,
|
||||||
however it allows us to have a tabindex before the first selected item
|
however it allows us to have a tabindex before the first selected item
|
||||||
*/
|
*/
|
||||||
document.addEventListener("focus", () => {
|
const focusHandler = () => {
|
||||||
list.querySelector("tr").focus();
|
list.querySelector("tr").focus();
|
||||||
|
document.removeEventListener("focus", focusHandler);
|
||||||
|
};
|
||||||
|
document.addEventListener("focus", focusHandler);
|
||||||
|
/* If the user mousedown's first then remove the focus handler */
|
||||||
|
document.addEventListener("mousedown", () => {
|
||||||
|
document.removeEventListener("focus", focusHandler);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -561,7 +568,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
const identity = Logic.currentIdentity();
|
const identity = Logic.currentIdentity();
|
||||||
browser.runtime.sendMessage({
|
browser.runtime.sendMessage({
|
||||||
method: identity.hasHiddenTabs ? "showTabs" : "hideTabs",
|
method: identity.hasHiddenTabs ? "showTabs" : "hideTabs",
|
||||||
userContextId: Logic.userContextId(identity.cookieStoreId)
|
userContextId: Logic.currentUserContextId()
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
window.close();
|
window.close();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
@ -633,7 +640,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
// Let's retrieve the list of tabs.
|
// Let's retrieve the list of tabs.
|
||||||
return browser.runtime.sendMessage({
|
return browser.runtime.sendMessage({
|
||||||
method: "getTabs",
|
method: "getTabs",
|
||||||
userContextId: Logic.userContextId(identity.cookieStoreId),
|
userContextId: Logic.currentUserContextId(),
|
||||||
}).then(this.buildInfoTable);
|
}).then(this.buildInfoTable);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -645,8 +652,9 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
fragment.appendChild(tr);
|
fragment.appendChild(tr);
|
||||||
tr.classList.add("container-info-tab-row");
|
tr.classList.add("container-info-tab-row");
|
||||||
tr.innerHTML = escaped`
|
tr.innerHTML = escaped`
|
||||||
<td><img class="icon" src="${tab.favicon}" /></td>
|
<td></td>
|
||||||
<td class="container-info-tab-title truncate-text">${tab.title}</td>`;
|
<td class="container-info-tab-title truncate-text">${tab.title}</td>`;
|
||||||
|
tr.querySelector("td").appendChild(Utils.createFavIconElement(tab.favicon));
|
||||||
|
|
||||||
// On click, we activate this tab. But only if this tab is active.
|
// On click, we activate this tab. But only if this tab is active.
|
||||||
if (tab.active) {
|
if (tab.active) {
|
||||||
|
@ -743,27 +751,19 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
this.initializeRadioButtons();
|
this.initializeRadioButtons();
|
||||||
|
|
||||||
Logic.addEnterHandler(document.querySelector("#edit-container-panel-back-arrow"), () => {
|
Logic.addEnterHandler(document.querySelector("#edit-container-panel-back-arrow"), () => {
|
||||||
Logic.showPreviousPanel();
|
this._submitForm();
|
||||||
});
|
});
|
||||||
|
|
||||||
Logic.addEnterHandler(document.querySelector("#edit-container-cancel-link"), () => {
|
|
||||||
Logic.showPreviousPanel();
|
|
||||||
});
|
|
||||||
|
|
||||||
this._editForm = document.getElementById("edit-container-panel-form");
|
this._editForm = document.getElementById("edit-container-panel-form");
|
||||||
const editLink = document.querySelector("#edit-container-ok-link");
|
|
||||||
Logic.addEnterHandler(editLink, this._submitForm.bind(this));
|
|
||||||
editLink.addEventListener("submit", this._submitForm.bind(this));
|
|
||||||
this._editForm.addEventListener("submit", this._submitForm.bind(this));
|
this._editForm.addEventListener("submit", this._submitForm.bind(this));
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_submitForm() {
|
_submitForm() {
|
||||||
const identity = Logic.currentIdentity();
|
|
||||||
const formValues = new FormData(this._editForm);
|
const formValues = new FormData(this._editForm);
|
||||||
return browser.runtime.sendMessage({
|
return browser.runtime.sendMessage({
|
||||||
method: "createOrUpdateContainer",
|
method: "createOrUpdateContainer",
|
||||||
message: {
|
message: {
|
||||||
userContextId: Logic.userContextId(identity.cookieStoreId) || false,
|
userContextId: Logic.currentUserContextId() || false,
|
||||||
params: {
|
params: {
|
||||||
name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(),
|
name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(),
|
||||||
icon: formValues.get("container-icon") || DEFAULT_ICON,
|
icon: formValues.get("container-icon") || DEFAULT_ICON,
|
||||||
|
@ -779,6 +779,50 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showAssignedContainers(assignments) {
|
||||||
|
const assignmentPanel = document.getElementById("edit-sites-assigned");
|
||||||
|
const assignmentKeys = Object.keys(assignments);
|
||||||
|
assignmentPanel.hidden = !(assignmentKeys.length > 0);
|
||||||
|
if (assignments) {
|
||||||
|
const tableElement = assignmentPanel.querySelector("table > tbody");
|
||||||
|
/* Remove previous assignment list,
|
||||||
|
after removing one we rerender the list */
|
||||||
|
while (tableElement.firstChild) {
|
||||||
|
tableElement.firstChild.remove();
|
||||||
|
}
|
||||||
|
assignmentKeys.forEach((siteKey) => {
|
||||||
|
const site = assignments[siteKey];
|
||||||
|
const trElement = document.createElement("tr");
|
||||||
|
/* 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}`;
|
||||||
|
trElement.innerHTML = escaped`
|
||||||
|
<td><img class="icon" src="${assumedUrl}/favicon.ico"></td>
|
||||||
|
<td title="${site.hostname}" class="truncate-text">${site.hostname}
|
||||||
|
<img
|
||||||
|
class="pop-button-image delete-assignment"
|
||||||
|
src="/img/container-delete.svg"
|
||||||
|
/>
|
||||||
|
</td>`;
|
||||||
|
const deleteButton = trElement.querySelector(".delete-assignment");
|
||||||
|
Logic.addEnterHandler(deleteButton, () => {
|
||||||
|
const userContextId = Logic.currentUserContextId();
|
||||||
|
// Lets show the message to the current tab
|
||||||
|
// TODO remove then when firefox supports arrow fn async
|
||||||
|
Logic.currentTab().then((currentTab) => {
|
||||||
|
Logic.setOrRemoveAssignment(currentTab.id, assumedUrl, userContextId, true);
|
||||||
|
delete assignments[siteKey];
|
||||||
|
this.showAssignedContainers(assignments);
|
||||||
|
}).catch((e) => {
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
trElement.classList.add("container-info-tab-row", "clickable");
|
||||||
|
tableElement.appendChild(trElement);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
initializeRadioButtons() {
|
initializeRadioButtons() {
|
||||||
const colorRadioTemplate = (containerColor) => {
|
const colorRadioTemplate = (containerColor) => {
|
||||||
return escaped`<input type="radio" value="${containerColor}" name="container-color" id="edit-container-panel-choose-color-${containerColor}" />
|
return escaped`<input type="radio" value="${containerColor}" name="container-color" id="edit-container-panel-choose-color-${containerColor}" />
|
||||||
|
@ -808,8 +852,13 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
},
|
},
|
||||||
|
|
||||||
// This method is called when the panel is shown.
|
// This method is called when the panel is shown.
|
||||||
prepare() {
|
async prepare() {
|
||||||
const identity = Logic.currentIdentity();
|
const identity = Logic.currentIdentity();
|
||||||
|
|
||||||
|
const userContextId = Logic.currentUserContextId();
|
||||||
|
const assignments = await Logic.getAssignmentObjectByContainer(userContextId);
|
||||||
|
this.showAssignedContainers(assignments);
|
||||||
|
|
||||||
document.querySelector("#edit-container-panel-name-input").value = identity.name || "";
|
document.querySelector("#edit-container-panel-name-input").value = identity.name || "";
|
||||||
[...document.querySelectorAll("[name='container-color']")].forEach(colorInput => {
|
[...document.querySelectorAll("[name='container-color']")].forEach(colorInput => {
|
||||||
colorInput.checked = colorInput.value === identity.color;
|
colorInput.checked = colorInput.value === identity.color;
|
||||||
|
|
23
webextension/js/utils.js
Normal file
23
webextension/js/utils.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
const DEFAULT_FAVICON = "moz-icon://goat?size=16";
|
||||||
|
|
||||||
|
// TODO use export here instead of globals
|
||||||
|
window.Utils = {
|
||||||
|
|
||||||
|
createFavIconElement(url) {
|
||||||
|
const imageElement = document.createElement("img");
|
||||||
|
imageElement.classList.add("icon", "offpage");
|
||||||
|
imageElement.src = url;
|
||||||
|
const loadListener = (e) => {
|
||||||
|
e.target.classList.remove("offpage");
|
||||||
|
e.target.removeEventListener("load", loadListener);
|
||||||
|
e.target.removeEventListener("error", errorListener);
|
||||||
|
};
|
||||||
|
const errorListener = (e) => {
|
||||||
|
e.target.src = DEFAULT_FAVICON;
|
||||||
|
};
|
||||||
|
imageElement.addEventListener("error", errorListener);
|
||||||
|
imageElement.addEventListener("load", loadListener);
|
||||||
|
return imageElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -26,7 +26,6 @@
|
||||||
"contextualIdentities",
|
"contextualIdentities",
|
||||||
"history",
|
"history",
|
||||||
"idle",
|
"idle",
|
||||||
"notifications",
|
|
||||||
"storage",
|
"storage",
|
||||||
"tabs",
|
"tabs",
|
||||||
"webRequestBlocking",
|
"webRequestBlocking",
|
||||||
|
@ -36,7 +35,7 @@
|
||||||
"commands": {
|
"commands": {
|
||||||
"_execute_browser_action": {
|
"_execute_browser_action": {
|
||||||
"suggested_key": {
|
"suggested_key": {
|
||||||
"default": "Ctrl+Y"
|
"default": "Ctrl+Period"
|
||||||
},
|
},
|
||||||
"description": "Open containers panel"
|
"description": "Open containers panel"
|
||||||
}
|
}
|
||||||
|
@ -54,5 +53,17 @@
|
||||||
|
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": ["background.js"]
|
"scripts": ["background.js"]
|
||||||
}
|
},
|
||||||
|
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"matches": ["<all_urls>"],
|
||||||
|
"js": ["js/content-script.js"],
|
||||||
|
"css": ["css/content.css"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
"web_accessible_resources": [
|
||||||
|
"/img/container-site-d-24.png"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||||
<title>Containers browserAction Popup</title>
|
<title>Containers browserAction Popup</title>
|
||||||
<link rel="stylesheet" href="/css/popup.css">
|
<link rel="stylesheet" href="/css/popup.css">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
@ -40,21 +41,21 @@
|
||||||
<div class="panel container-panel hide" id="container-panel">
|
<div class="panel container-panel hide" id="container-panel">
|
||||||
<div id="current-tab">
|
<div id="current-tab">
|
||||||
<h3>Current Tab</h3>
|
<h3>Current Tab</h3>
|
||||||
<div id="current-page" class="truncate-text"></div>
|
<div id="current-page"></div>
|
||||||
<label for="container-page-assigned">
|
<label for="container-page-assigned">
|
||||||
<input type="checkbox" id="container-page-assigned" />
|
<input type="checkbox" id="container-page-assigned" />
|
||||||
Always open in
|
<span class="truncate-text">
|
||||||
<div id="current-container-icon" class="usercontext-icon"></div>
|
Always open in
|
||||||
<span id="current-container" class="truncate-text"></span>
|
<span id="current-container"></span>
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-header">
|
<div class="container-panel-controls">
|
||||||
<h3 class="panel-header-text">Containers</h3>
|
|
||||||
<a href="#" class="action-link" id="sort-containers-link">Sort Tabs</a>
|
<a href="#" class="action-link" id="sort-containers-link">Sort Tabs</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="scrollable panel-content" tabindex="-1">
|
<div class="scrollable panel-content" tabindex="-1">
|
||||||
<table>
|
<table class="identities-list">
|
||||||
<tbody class="identities-list"></tbody>
|
<tbody></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer edit-identities">
|
<div class="panel-footer edit-identities">
|
||||||
|
@ -125,9 +126,16 @@
|
||||||
<legend>Choose an icon</legend>
|
<legend>Choose an icon</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
<div class="panel-footer">
|
<div id="edit-sites-assigned" class="scrollable" hidden>
|
||||||
<a href="#" class="button secondary expanded footer-button cancel-button" id="edit-container-cancel-link">Cancel</a>
|
<table id="container-assignement-table" class="container-info-list">
|
||||||
<a class="button primary expanded footer-button" id="edit-container-ok-link">OK</a>
|
<thead>
|
||||||
|
<th colspan="3">
|
||||||
|
<h3>Sites assigned to this container</h3>
|
||||||
|
</th>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -148,7 +156,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="js/utils.js"></script>
|
||||||
<script src="js/popup.js"></script>
|
<script src="js/popup.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Reference in a new issue