cherry picked
This commit is contained in:
parent
44206f3400
commit
2ae3a4d9bf
9 changed files with 304 additions and 173 deletions
|
@ -46,7 +46,7 @@ module.exports = {
|
|||
"error",
|
||||
{
|
||||
"escape": {
|
||||
"taggedTemplates": ["escaped"]
|
||||
"taggedTemplates": ["escaped", "Utils.escaped"]
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -8,6 +8,7 @@ module.exports = {
|
|||
"backgroundLogic": true,
|
||||
"identityState": true,
|
||||
"messageHandler": true,
|
||||
"sync": true
|
||||
"sync": true,
|
||||
"Utils": true
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
51
src/js/pageAction.js
Normal 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();
|
282
src/js/popup.js
282
src/js/popup.js
|
@ -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 = { "&": "&", "\"": """, "'": "'", "<": "<", ">": ">", "/": "/" };
|
||||
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) {
|
||||
Logic.showPanel(P_CONTAINER_INFO, identity);
|
||||
}
|
||||
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">
|
||||
<div class="usercontext-icon"
|
||||
data-identity-icon="${identity.icon}"
|
||||
data-identity-color="${identity.color}">
|
||||
</div>
|
||||
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 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`);
|
||||
</div>
|
||||
<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);
|
||||
});
|
||||
|
|
|
@ -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 = { "&": "&", "\"": """, "'": "'", "<": "<", ">": ">", "/": "/" };
|
||||
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;
|
|
@ -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
34
src/pageActionPopup.html
Normal 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>
|
Loading…
Add table
Reference in a new issue