cherry picked

This commit is contained in:
Kendall Werts 2020-02-14 00:08:37 -06:00
parent 44206f3400
commit 2ae3a4d9bf
9 changed files with 304 additions and 173 deletions

View file

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

View file

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

View file

@ -474,6 +474,7 @@ window.assignManager = {
},
async _setOrRemoveAssignment(tabId, pageUrl, userContextId, remove) {
console.log(userContextId)
let actionName;
// https://github.com/mozilla/testpilot-containers/issues/626

View file

@ -73,6 +73,16 @@ const messageHandler = {
case "exemptContainerAssignment":
response = assignManager._exemptTab(m);
break;
case "reloadInContainer":
response = assignManager.reloadPageInContainer(
m.url,
m.currentUserContextId,
m.newUserContextId,
m.tabIndex,
m.active,
true
);
break;
}
return response;
});

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

@ -0,0 +1,51 @@
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");
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 () => {
const currentTab = await Utils.currentTab();
const assignedUserContextId = Utils.userContextId(identity.cookieStoreId);
Utils.setOrRemoveAssignment(
currentTab.id,
currentTab.url,
assignedUserContextId,
false
);
console.log(currentTab);
Utils.reloadInContainer(
currentTab.url,
false,
assignedUserContextId,
currentTab.index + 1,
currentTab.active
);
window.close();
});
});
const list = document.querySelector("#picker-identities-list");
list.innerHTML = "";
list.appendChild(fragment);
}
init();

View file

@ -26,41 +26,6 @@ const P_CONTAINER_EDIT = "containerEdit";
const P_CONTAINER_DELETE = "containerDelete";
const P_CONTAINERS_ACHIEVEMENT = "containersAchievement";
/**
* Escapes any occurances of &, ", <, > or / with XML entities.
*
* @param {string} str
* The string to escape.
* @return {string} The escaped string.
*/
function 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.
*/
function escaped(strings, ...values) {
const result = [];
for (const [i, string] of strings.entries()) {
result.push(string);
if (i < values.length)
result.push(escapeXML(values[i]));
}
return result.join("");
}
async function getExtensionInfo() {
const manifestPath = browser.extension.getURL("manifest.json");
@ -197,31 +162,6 @@ const Logic = {
}
},
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;
},
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;
},
async numTabs() {
const activeTabs = await browser.tabs.query({ windowId: browser.windows.WINDOW_ID_CURRENT });
return activeTabs.length;
@ -333,7 +273,7 @@ const Logic = {
currentUserContextId() {
const identity = Logic.currentIdentity();
return Logic.userContextId(identity.cookieStoreId);
return Utils.userContextId(identity.cookieStoreId);
},
currentCookieStoreId() {
@ -369,16 +309,6 @@ const Logic = {
});
},
setOrRemoveAssignment(tabId, url, userContextId, value) {
return browser.runtime.sendMessage({
method: "setOrRemoveAssignment",
tabId,
url,
userContextId,
value
});
},
generateIdentityName() {
const defaultName = "Container #";
const ids = [];
@ -418,7 +348,7 @@ Logic.registerPanel(P_ONBOARDING_1, {
initialize() {
// Let's move to the next panel.
[...document.querySelectorAll(".onboarding-start-button")].forEach(startElement => {
Logic.addEnterHandler(startElement, async () => {
Utils.addEnterHandler(startElement, async () => {
await Logic.setOnboardingStage(1);
Logic.showPanel(P_ONBOARDING_2);
});
@ -442,7 +372,7 @@ Logic.registerPanel(P_ONBOARDING_2, {
initialize() {
// Let's move to the containers list panel.
[...document.querySelectorAll(".onboarding-next-button")].forEach(nextElement => {
Logic.addEnterHandler(nextElement, async () => {
Utils.addEnterHandler(nextElement, async () => {
await Logic.setOnboardingStage(2);
Logic.showPanel(P_ONBOARDING_3);
});
@ -466,7 +396,7 @@ Logic.registerPanel(P_ONBOARDING_3, {
initialize() {
// Let's move to the containers list panel.
[...document.querySelectorAll(".onboarding-almost-done-button")].forEach(almostElement => {
Logic.addEnterHandler(almostElement, async () => {
Utils.addEnterHandler(almostElement, async () => {
await Logic.setOnboardingStage(3);
Logic.showPanel(P_ONBOARDING_4);
});
@ -488,7 +418,7 @@ Logic.registerPanel(P_ONBOARDING_4, {
// This method is called when the object is registered.
initialize() {
// Let's move to the containers list panel.
Logic.addEnterHandler(document.querySelector("#onboarding-done-button"), async () => {
Utils.addEnterHandler(document.querySelector("#onboarding-done-button"), async () => {
await Logic.setOnboardingStage(4);
Logic.showPanel(P_ONBOARDING_5);
});
@ -509,7 +439,7 @@ Logic.registerPanel(P_ONBOARDING_5, {
// This method is called when the object is registered.
initialize() {
// Let's move to the containers list panel.
Logic.addEnterHandler(document.querySelector("#onboarding-longpress-button"), async () => {
Utils.addEnterHandler(document.querySelector("#onboarding-longpress-button"), async () => {
await Logic.setOnboardingStage(5);
Logic.showPanel(P_ONBOARDING_6);
});
@ -530,7 +460,7 @@ Logic.registerPanel(P_ONBOARDING_6, {
// This method is called when the object is registered.
initialize() {
// Let's move to the containers list panel.
Logic.addEnterHandler(document.querySelector("#start-sync-button"), async () => {
Utils.addEnterHandler(document.querySelector("#start-sync-button"), async () => {
await Logic.setOnboardingStage(6);
await browser.storage.local.set({syncEnabled: true});
await browser.runtime.sendMessage({
@ -538,7 +468,7 @@ Logic.registerPanel(P_ONBOARDING_6, {
});
Logic.showPanel(P_ONBOARDING_7);
});
Logic.addEnterHandler(document.querySelector("#no-sync"), async () => {
Utils.addEnterHandler(document.querySelector("#no-sync"), async () => {
await Logic.setOnboardingStage(7);
await browser.storage.local.set({syncEnabled: false});
await browser.runtime.sendMessage({
@ -563,14 +493,14 @@ Logic.registerPanel(P_ONBOARDING_7, {
// This method is called when the object is registered.
initialize() {
// Let's move to the containers list panel.
Logic.addEnterHandler(document.querySelector("#sign-in"), async () => {
Utils.addEnterHandler(document.querySelector("#sign-in"), async () => {
browser.tabs.create({
url: "https://accounts.firefox.com/?service=sync&action=email&context=fx_desktop_v3&entrypoint=multi-account-containers&utm_source=addon&utm_medium=panel&utm_campaign=container-sync",
});
await Logic.setOnboardingStage(7);
Logic.showPanel(P_CONTAINERS_LIST);
});
Logic.addEnterHandler(document.querySelector("#no-sign-in"), async () => {
Utils.addEnterHandler(document.querySelector("#no-sign-in"), async () => {
await Logic.setOnboardingStage(7);
Logic.showPanel(P_CONTAINERS_LIST);
});
@ -589,17 +519,21 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
// This method is called when the object is registered.
async initialize() {
Logic.addEnterHandler(document.querySelector("#container-add-link"), () => {
Logic.showPanel(P_CONTAINER_EDIT, { name: Logic.generateIdentityName() });
});
Logic.addEnterHandler(document.querySelector("#edit-containers-link"), (e) => {
Utils.addEnterHandler(document.querySelector("#manage-containers-link"), (e) => {
if (!e.target.classList.contains("disable-edit-containers")) {
Logic.showPanel(P_CONTAINERS_EDIT);
}
});
Logic.addEnterHandler(document.querySelector("#sort-containers-link"), async () => {
Utils.addEnterHandler(document.querySelector("#open-new-tab-in"), () => {
Logic.showPanel(P_CONTAINER_PICKER, null, OPEN_NEW_CONTAINER_PICKER);
});
Utils.addEnterHandler(document.querySelector("#reopen-site-in"), () => {
Logic.showPanel(P_CONTAINER_PICKER, null, REOPEN_IN_CONTAINER);
});
Utils.addEnterHandler(document.querySelector("#always-open-in"), () => {
Logic.showPanel(P_CONTAINER_PICKER, null, ALWAYS_OPEN_IN_PICKER);
});
Utils.addEnterHandler(document.querySelector("#sort-containers-link"), async () => {
try {
await browser.runtime.sendMessage({
method: "sortTabs"
@ -737,18 +671,12 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
Logic.identities().forEach(identity => {
const hasTabs = (identity.hasHiddenTabs || identity.hasOpenTabs);
const tr = document.createElement("tr");
const context = document.createElement("td");
const manage = document.createElement("td");
tr.classList.add("menu-item");
const td = document.createElement("td");
const openTabs = identity.numberOfOpenTabs || "" ;
tr.classList.add("container-panel-row");
context.classList.add("userContext-wrapper", "open-newtab", "clickable", "firstTabindex");
manage.classList.add("show-tabs", "pop-button");
manage.setAttribute("title", `View ${identity.name} container`);
context.setAttribute("tabindex", "0");
context.setAttribute("title", `Create ${identity.name} tab`);
context.innerHTML = escaped`
<div class="userContext-icon-wrapper open-newtab">
td.innerHTML = Utils.escaped`
<div class="menu-icon">
<div class="usercontext-icon"
data-identity-icon="${identity.icon}"
data-identity-color="${identity.color}">
@ -762,25 +690,8 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
tr.appendChild(context);
if (hasTabs) {
tr.appendChild(manage);
}
Logic.addEnterHandler(tr, async (e) => {
if (e.target.matches(".open-newtab")
|| e.target.parentNode.matches(".open-newtab")
|| e.type === "keydown") {
try {
browser.tabs.create({
cookieStoreId: identity.cookieStoreId
});
window.close();
} catch (e) {
window.close();
}
} else if (hasTabs) {
Utils.addEnterHandler(tr, () => {
Logic.showPanel(P_CONTAINER_INFO, identity);
}
});
});
@ -827,12 +738,12 @@ Logic.registerPanel(P_CONTAINER_INFO, {
const closeContEl = document.querySelector("#close-container-info-panel");
closeContEl.setAttribute("tabindex", "0");
closeContEl.classList.add("firstTabindex");
Logic.addEnterHandler(closeContEl, () => {
Utils.addEnterHandler(closeContEl, () => {
Logic.showPreviousPanel();
});
const hideContEl = document.querySelector("#container-info-hideorshow");
hideContEl.setAttribute("tabindex", "0");
Logic.addEnterHandler(hideContEl, async () => {
Utils.addEnterHandler(hideContEl, async () => {
const identity = Logic.currentIdentity();
try {
browser.runtime.sendMessage({
@ -865,7 +776,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
Logic._disableMoveTabs("Cannot move a tab from a single-tab window.");
return;
}
Logic.addEnterHandler(moveTabsEl, async () => {
Utils.addEnterHandler(moveTabsEl, async () => {
await browser.runtime.sendMessage({
method: "moveTabsToWindow",
windowId: browser.windows.WINDOW_ID_CURRENT,
@ -919,7 +830,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
const tr = document.createElement("tr");
fragment.appendChild(tr);
tr.classList.add("container-info-tab-row");
tr.innerHTML = escaped`
tr.innerHTML = Utils.escaped`
<td></td>
<td class="container-info-tab-title truncate-text" title="${tab.url}" ><div class="container-tab-title">${tab.title}</div></td>`;
tr.querySelector("td").appendChild(Utils.createFavIconElement(tab.favIconUrl));
@ -946,14 +857,14 @@ Logic.registerPanel(P_CONTAINER_INFO, {
tr.addEventListener("mouseout", tabTitleHoverEvent);
tr.classList.add("clickable");
Logic.addEnterHandler(tr, async () => {
Utils.addEnterHandler(tr, async () => {
await browser.tabs.update(tab.id, { active: true });
window.close();
});
const closeTab = document.getElementById(tab.id);
if (closeTab) {
Logic.addEnterHandler(closeTab, async (e) => {
Utils.addEnterHandler(closeTab, async (e) => {
await browser.tabs.remove(Number(e.target.id));
window.close();
});
@ -971,50 +882,81 @@ Logic.registerPanel(P_CONTAINERS_EDIT, {
// This method is called when the object is registered.
initialize() {
Logic.addEnterHandler(document.querySelector("#exit-edit-mode-link"), () => {
Logic.showPanel(P_CONTAINERS_LIST);
});
// Utils.addEnterHandler(document.querySelector("#exit-edit-mode-link"), () => {
// Logic.showPanel(P_CONTAINERS_LIST);
// });
},
// This method is called when the panel is shown.
prepare() {
const fragment = document.createDocumentFragment();
let pickedFunction;
switch (Logic.pickerType) {
case OPEN_NEW_CONTAINER_PICKER:
pickedFunction = function (identity) {
try {
browser.tabs.create({
cookieStoreId: identity.cookieStoreId
});
window.close();
} catch (e) {
window.close();
}
};
break;
case MANAGE_CONTAINERS_PICKER:
pickedFunction = function (identity) {
Logic.showPanel(P_CONTAINER_EDIT, identity);
};
break;
case REOPEN_IN_CONTAINER:
pickedFunction = function (identity) {
try {
browser.tabs.create({
cookieStoreId: identity.cookieStoreId
});
window.close();
} catch (e) {
window.close();
}
};
break;
case ALWAYS_OPEN_IN_PICKER:
default:
pickedFunction = async function (identity) {
const userContextId = Utils.userContextId(identity.cookieStoreId);
const currentTab = await Utils.currentTab();
Utils.setOrRemoveAssignment(
currentTab.id,
currentTab.url,
userContextId,
false
);
window.close();
};
break;
}
Logic.identities().forEach(identity => {
const tr = document.createElement("tr");
fragment.appendChild(tr);
tr.classList.add("container-panel-row");
tr.innerHTML = escaped`
<td class="userContext-wrapper">
<div class="userContext-icon-wrapper">
tr.classList.add("menu-item");
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>
<div class="container-name truncate-text"></div>
</td>
<td class="edit-container pop-button edit-container-icon">
<img
src="/img/container-edit.svg"
class="pop-button-image" />
</td>
<td class="remove-container pop-button delete-container-icon">
<img
class="pop-button-image"
src="/img/container-delete.svg"
/>
</td>`;
tr.querySelector(".container-name").textContent = identity.name;
tr.querySelector(".edit-container").setAttribute("title", `Edit ${identity.name} container`);
tr.querySelector(".remove-container").setAttribute("title", `Remove ${identity.name} container`);
<span class="menu-text">${identity.name}</span>`;
fragment.appendChild(tr);
Logic.addEnterHandler(tr, e => {
if (e.target.matches(".edit-container-icon") || e.target.parentNode.matches(".edit-container-icon")) {
Logic.showPanel(P_CONTAINER_EDIT, identity);
} else if (e.target.matches(".delete-container-icon") || e.target.parentNode.matches(".delete-container-icon")) {
Logic.showPanel(P_CONTAINER_DELETE, identity);
}
tr.appendChild(td);
Utils.addEnterHandler(tr, () => {
pickedFunction(identity);
});
});
@ -1037,7 +979,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
initialize() {
this.initializeRadioButtons();
Logic.addEnterHandler(document.querySelector("#edit-container-panel-back-arrow"), () => {
Utils.addEnterHandler(document.querySelector("#edit-container-panel-back-arrow"), () => {
const formValues = new FormData(this._editForm);
if (formValues.get("container-id") !== NEW_CONTAINER_ID) {
this._submitForm();
@ -1046,13 +988,13 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
}
});
Logic.addEnterHandler(document.querySelector("#edit-container-cancel-link"), () => {
Utils.addEnterHandler(document.querySelector("#edit-container-cancel-link"), () => {
Logic.showPreviousPanel();
});
this._editForm = document.getElementById("edit-container-panel-form");
const editLink = document.querySelector("#edit-container-ok-link");
Logic.addEnterHandler(editLink, () => {
Utils.addEnterHandler(editLink, () => {
this._submitForm();
});
editLink.addEventListener("submit", () => {
@ -1104,7 +1046,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
/* As we don't have the full or correct path the best we can assume is the path is HTTPS and then replace with a broken icon later if it doesn't load.
This is pending a better solution for favicons from web extensions */
const assumedUrl = `https://${site.hostname}/favicon.ico`;
trElement.innerHTML = escaped`
trElement.innerHTML = Utils.escaped`
<div class="favicon"></div>
<div title="${site.hostname}" class="truncate-text hostname">
${site.hostname}
@ -1116,12 +1058,12 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
trElement.getElementsByClassName("favicon")[0].appendChild(Utils.createFavIconElement(assumedUrl));
const deleteButton = trElement.querySelector(".delete-assignment");
const that = this;
Logic.addEnterHandler(deleteButton, async () => {
Utils.addEnterHandler(deleteButton, async () => {
const userContextId = Logic.currentUserContextId();
// Lets show the message to the current tab
// TODO remove then when firefox supports arrow fn async
const currentTab = await Logic.currentTab();
Logic.setOrRemoveAssignment(currentTab.id, assumedUrl, userContextId, true);
const currentTab = await Utils.currentTab();
Utils.setOrRemoveAssignment(currentTab.id, assumedUrl, userContextId, true);
delete assignments[siteKey];
that.showAssignedContainers(assignments);
});
@ -1133,7 +1075,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
initializeRadioButtons() {
const colorRadioTemplate = (containerColor) => {
return escaped`<input type="radio" value="${containerColor}" name="container-color" id="edit-container-panel-choose-color-${containerColor}" />
return Utils.escaped`<input type="radio" value="${containerColor}" name="container-color" id="edit-container-panel-choose-color-${containerColor}" />
<label for="edit-container-panel-choose-color-${containerColor}" class="usercontext-icon choose-color-icon" data-identity-icon="circle" data-identity-color="${containerColor}">`;
};
const colors = ["blue", "turquoise", "green", "yellow", "orange", "red", "pink", "purple"];
@ -1147,7 +1089,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
});
const iconRadioTemplate = (containerIcon) => {
return escaped`<input type="radio" value="${containerIcon}" name="container-icon" id="edit-container-panel-choose-icon-${containerIcon}" />
return Utils.escaped`<input type="radio" value="${containerIcon}" name="container-icon" id="edit-container-panel-choose-icon-${containerIcon}" />
<label for="edit-container-panel-choose-icon-${containerIcon}" class="usercontext-icon choose-color-icon" data-identity-color="grey" data-identity-icon="${containerIcon}">`;
};
const icons = ["fingerprint", "briefcase", "dollar", "cart", "vacation", "gift", "food", "fruit", "pet", "tree", "chill", "circle"];
@ -1197,18 +1139,18 @@ Logic.registerPanel(P_CONTAINER_DELETE, {
// This method is called when the object is registered.
initialize() {
Logic.addEnterHandler(document.querySelector("#delete-container-cancel-link"), () => {
Utils.addEnterHandler(document.querySelector("#delete-container-cancel-link"), () => {
Logic.showPreviousPanel();
});
Logic.addEnterHandler(document.querySelector("#delete-container-ok-link"), async () => {
Utils.addEnterHandler(document.querySelector("#delete-container-ok-link"), async () => {
/* This promise wont resolve if the last tab was removed from the window.
as the message async callback stops listening, this isn't an issue for us however it might be in future
if you want to do anything post delete do it in the background script.
Browser console currently warns about not listening also.
*/
try {
await Logic.removeIdentity(Logic.userContextId(Logic.currentIdentity().cookieStoreId));
await Logic.removeIdentity(Utils.userContextId(Logic.currentIdentity().cookieStoreId));
await Logic.refreshIdentities();
Logic.showPreviousPanel();
} catch (e) {
@ -1249,7 +1191,7 @@ Logic.registerPanel(P_CONTAINERS_ACHIEVEMENT, {
// This method is called when the object is registered.
initialize() {
// Set done and move to the containers list panel.
Logic.addEnterHandler(document.querySelector("#achievement-done-button"), async () => {
Utils.addEnterHandler(document.querySelector("#achievement-done-button"), async () => {
await Logic.setAchievementDone("manyContainersOpened");
Logic.showPanel(P_CONTAINERS_LIST);
});

View file

@ -1,7 +1,7 @@
const DEFAULT_FAVICON = "/img/blank-favicon.svg";
// TODO use export here instead of globals
window.Utils = {
const Utils = {
createFavIconElement(url) {
const imageElement = document.createElement("img");
@ -18,6 +18,90 @@ window.Utils = {
imageElement.addEventListener("error", errorListener);
imageElement.addEventListener("load", loadListener);
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
});
}
};
window.Utils = Utils;

View file

@ -66,6 +66,14 @@
}
]
},
"page_action": {
"browser_style": true,
"default_icon": "img/container-site.svg",
"default_title": "Always open this in a Container",
"default_popup": "pageActionPopup.html",
"pinned": false,
"show_matches": ["*://*/*"]
},
"background": {
"page": "js/background/index.html"
},

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">
Reopen and Always Open this Site in...
</h3>
<hr>
<div class="scrollable identities-list">
<table class="menu" id="picker-identities-list">
<tr class="menu-item">
<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>