Merge d636fa584a
into 1b85642677
This commit is contained in:
commit
da17eeabfd
8 changed files with 187 additions and 29 deletions
|
@ -11,10 +11,12 @@ module.exports = {
|
||||||
"globals": {
|
"globals": {
|
||||||
"CustomizableUI": true,
|
"CustomizableUI": true,
|
||||||
"CustomizableWidgets": true,
|
"CustomizableWidgets": true,
|
||||||
"SessionStore": true
|
"SessionStore": true,
|
||||||
|
"Services": true
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"promise"
|
"promise",
|
||||||
|
"unsafe-property-assignment"
|
||||||
],
|
],
|
||||||
"root": true,
|
"root": true,
|
||||||
"rules": {
|
"rules": {
|
||||||
|
@ -27,6 +29,8 @@ module.exports = {
|
||||||
"promise/no-promise-in-callback": "warn",
|
"promise/no-promise-in-callback": "warn",
|
||||||
"promise/no-return-wrap": "error",
|
"promise/no-return-wrap": "error",
|
||||||
"promise/param-names": "error",
|
"promise/param-names": "error",
|
||||||
|
"unsafe-property-assignment/no-key-assignment": ["error"],
|
||||||
|
"unsafe-property-assignment/enforce-tagged-template-protection": ["error"],
|
||||||
|
|
||||||
"eqeqeq": "error",
|
"eqeqeq": "error",
|
||||||
"indent": ["error", 2],
|
"indent": ["error", 2],
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "6.1"
|
- "6.1"
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
irc:
|
||||||
|
- "ircs://irc.mozilla.org:6697/#testpilot-containers-bots"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Containers: Test Pilot Experiment
|
# Containers: Test Pilot Experiment
|
||||||
|
|
||||||
Soon to be [](https://testpilot.firefox.com/)
|
[](https://testpilot.firefox.com/experiments/containers)
|
||||||
|
|
||||||
[Embedded Web Extension](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Embedded_WebExtensions) to experiment with [Containers](https://blog.mozilla.org/tanvi/2016/06/16/contextual-identities-on-the-web/) in [Firefox Test Pilot](https://testpilot.firefox.com/) to learn:
|
[Embedded Web Extension](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Embedded_WebExtensions) to experiment with [Containers](https://blog.mozilla.org/tanvi/2016/06/16/contextual-identities-on-the-web/) in [Firefox Test Pilot](https://testpilot.firefox.com/) to learn:
|
||||||
|
|
||||||
|
|
59
index.js
59
index.js
|
@ -30,6 +30,7 @@ const IDENTITY_ICONS = [
|
||||||
{ name: "briefcase", image: "chrome://browser/skin/usercontext/work.svg" },
|
{ name: "briefcase", image: "chrome://browser/skin/usercontext/work.svg" },
|
||||||
{ name: "dollar", image: "chrome://browser/skin/usercontext/banking.svg" },
|
{ name: "dollar", image: "chrome://browser/skin/usercontext/banking.svg" },
|
||||||
{ name: "cart", image: "chrome://browser/skin/usercontext/shopping.svg" },
|
{ name: "cart", image: "chrome://browser/skin/usercontext/shopping.svg" },
|
||||||
|
// All of these do not exist in gecko
|
||||||
{ name: "gift", image: "gift" },
|
{ name: "gift", image: "gift" },
|
||||||
{ name: "vacation", image: "vacation" },
|
{ name: "vacation", image: "vacation" },
|
||||||
{ name: "food", image: "food" },
|
{ name: "food", image: "food" },
|
||||||
|
@ -37,7 +38,7 @@ const IDENTITY_ICONS = [
|
||||||
{ name: "pet", image: "pet" },
|
{ name: "pet", image: "pet" },
|
||||||
{ name: "tree", image: "tree" },
|
{ name: "tree", image: "tree" },
|
||||||
{ name: "chill", image: "chill" },
|
{ name: "chill", image: "chill" },
|
||||||
{ name: "circle", image: "circle" }, // this doesn't exist in m-b
|
{ name: "circle", image: "circle" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const PREFS = [
|
const PREFS = [
|
||||||
|
@ -51,10 +52,12 @@ const { attachTo, detachFrom } = require("sdk/content/mod");
|
||||||
const { Cu } = require("chrome");
|
const { Cu } = require("chrome");
|
||||||
const { ContextualIdentityService } = require("resource://gre/modules/ContextualIdentityService.jsm");
|
const { ContextualIdentityService } = require("resource://gre/modules/ContextualIdentityService.jsm");
|
||||||
const { getFavicon } = require("sdk/places/favicon");
|
const { getFavicon } = require("sdk/places/favicon");
|
||||||
|
const { LightweightThemeManager } = Cu.import("resource://gre/modules/LightweightThemeManager.jsm", {});
|
||||||
const Metrics = require("./testpilot-metrics");
|
const Metrics = require("./testpilot-metrics");
|
||||||
const { modelFor } = require("sdk/model/core");
|
const { modelFor } = require("sdk/model/core");
|
||||||
const prefService = require("sdk/preferences/service");
|
const prefService = require("sdk/preferences/service");
|
||||||
const self = require("sdk/self");
|
const self = require("sdk/self");
|
||||||
|
const { Services } = require("resource://gre/modules/Services.jsm");
|
||||||
const ss = require("sdk/simple-storage");
|
const ss = require("sdk/simple-storage");
|
||||||
const { Style } = require("sdk/stylesheet/style");
|
const { Style } = require("sdk/stylesheet/style");
|
||||||
const tabs = require("sdk/tabs");
|
const tabs = require("sdk/tabs");
|
||||||
|
@ -68,6 +71,7 @@ const windowUtils = require("sdk/window/utils");
|
||||||
Cu.import("resource:///modules/CustomizableUI.jsm");
|
Cu.import("resource:///modules/CustomizableUI.jsm");
|
||||||
Cu.import("resource:///modules/CustomizableWidgets.jsm");
|
Cu.import("resource:///modules/CustomizableWidgets.jsm");
|
||||||
Cu.import("resource:///modules/sessionstore/SessionStore.jsm");
|
Cu.import("resource:///modules/sessionstore/SessionStore.jsm");
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// ContextualIdentityProxy
|
// ContextualIdentityProxy
|
||||||
|
@ -113,6 +117,7 @@ const ContainerService = {
|
||||||
_identitiesState: {},
|
_identitiesState: {},
|
||||||
_windowMap: new Map(),
|
_windowMap: new Map(),
|
||||||
_containerWasEnabled: false,
|
_containerWasEnabled: false,
|
||||||
|
_onThemeChangedCallback: null,
|
||||||
|
|
||||||
init(installation) {
|
init(installation) {
|
||||||
// If we are just been installed, we must store some information for the
|
// If we are just been installed, we must store some information for the
|
||||||
|
@ -194,6 +199,7 @@ const ContainerService = {
|
||||||
"updateIdentity",
|
"updateIdentity",
|
||||||
"getPreference",
|
"getPreference",
|
||||||
"sendTelemetryPayload",
|
"sendTelemetryPayload",
|
||||||
|
"getTheme",
|
||||||
"checkIncompatibleAddons"
|
"checkIncompatibleAddons"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -252,6 +258,8 @@ const ContainerService = {
|
||||||
sendReply(this[message.method](message));
|
sendReply(this[message.method](message));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.registerThemeConnection(api);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
throw new Error("WebExtension startup failed. Unable to continue.");
|
throw new Error("WebExtension startup failed. Unable to continue.");
|
||||||
});
|
});
|
||||||
|
@ -290,6 +298,51 @@ const ContainerService = {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// End-Of-Hack
|
// End-Of-Hack
|
||||||
|
|
||||||
|
Services.obs.addObserver(this, "lightweight-theme-changed", false);
|
||||||
|
},
|
||||||
|
|
||||||
|
registerThemeConnection(api) {
|
||||||
|
// This is only used for theme notifications
|
||||||
|
api.browser.runtime.onConnect.addListener((port) => {
|
||||||
|
this.onThemeChanged((theme, topic) => {
|
||||||
|
port.postMessage({
|
||||||
|
type: topic,
|
||||||
|
theme
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
triggerThemeChanged(theme, topic) {
|
||||||
|
if (this._onThemeChangedCallback) {
|
||||||
|
this._onThemeChangedCallback(theme, topic);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
observe(subject, topic) {
|
||||||
|
if (topic === "lightweight-theme-changed") {
|
||||||
|
this.getTheme().then((theme) => {
|
||||||
|
this.triggerThemeChanged(theme, topic);
|
||||||
|
}).catch(() => {
|
||||||
|
throw new Error("Unable to get theme");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getTheme() {
|
||||||
|
const defaultTheme = "firefox-compact-light@mozilla.org";
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
let theme = defaultTheme;
|
||||||
|
if (LightweightThemeManager.currentTheme && LightweightThemeManager.currentTheme.id) {
|
||||||
|
theme = LightweightThemeManager.currentTheme.id;
|
||||||
|
}
|
||||||
|
resolve(theme);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onThemeChanged(callback) {
|
||||||
|
this._onThemeChangedCallback = callback;
|
||||||
},
|
},
|
||||||
|
|
||||||
// utility methods
|
// utility methods
|
||||||
|
@ -1076,6 +1129,10 @@ const ContainerService = {
|
||||||
ContextualIdentityProxy.getIdentities().forEach(identity => {
|
ContextualIdentityProxy.getIdentities().forEach(identity => {
|
||||||
if (!preInstalledIdentities.includes(identity.userContextId)) {
|
if (!preInstalledIdentities.includes(identity.userContextId)) {
|
||||||
ContextualIdentityProxy.remove(identity.userContextId);
|
ContextualIdentityProxy.remove(identity.userContextId);
|
||||||
|
} else {
|
||||||
|
// Let's cleanup all the cookies for this container.
|
||||||
|
Services.obs.notifyObservers(null, "clear-origin-attributes-data",
|
||||||
|
JSON.stringify({ userContextId: identity.userContextId }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "testpilot-containers",
|
"name": "testpilot-containers",
|
||||||
"title": "Containers Experiment",
|
"title": "Containers Experiment",
|
||||||
"description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.",
|
"description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.",
|
||||||
"version": "1.0.4",
|
"version": "1.1.1",
|
||||||
"author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston",
|
"author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/mozilla/testpilot-containers/issues"
|
"url": "https://github.com/mozilla/testpilot-containers/issues"
|
||||||
|
@ -11,8 +11,9 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"addons-linter": "^0.15.14",
|
"addons-linter": "^0.15.14",
|
||||||
"deploy-txp": "^1.0.7",
|
"deploy-txp": "^1.0.7",
|
||||||
"eslint": "^3.12.2",
|
"eslint": "^3.17.1",
|
||||||
"eslint-plugin-promise": "^3.4.0",
|
"eslint-plugin-promise": "^3.4.0",
|
||||||
|
"eslint-plugin-unsafe-property-assign": "^1.0.2",
|
||||||
"htmllint-cli": "^0.0.5",
|
"htmllint-cli": "^0.0.5",
|
||||||
"jpm": "^1.2.2",
|
"jpm": "^1.2.2",
|
||||||
"npm-run-all": "^4.0.0",
|
"npm-run-all": "^4.0.0",
|
||||||
|
|
|
@ -1,3 +1,50 @@
|
||||||
|
|
||||||
|
const themeManager = {
|
||||||
|
existingTheme: null,
|
||||||
|
init() {
|
||||||
|
this.check();
|
||||||
|
|
||||||
|
const port = browser.runtime.connect();
|
||||||
|
port.onMessage.addListener(m => {
|
||||||
|
if (m.type === "lightweight-theme-changed") {
|
||||||
|
this.update(m.theme);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setPopupIcon(theme) {
|
||||||
|
let icons = {
|
||||||
|
16: "img/container-site-d-24.png",
|
||||||
|
32: "img/container-site-d-48.png"
|
||||||
|
};
|
||||||
|
if (theme === "firefox-compact-dark@mozilla.org") {
|
||||||
|
icons = {
|
||||||
|
16: "img/container-site-w-24.png",
|
||||||
|
32: "img/container-site-w-48.png"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
browser.browserAction.setIcon({
|
||||||
|
path: icons
|
||||||
|
});
|
||||||
|
},
|
||||||
|
check() {
|
||||||
|
browser.runtime.sendMessage({
|
||||||
|
method: "getTheme"
|
||||||
|
}).then((theme) => {
|
||||||
|
this.update(theme);
|
||||||
|
}).catch(() => {
|
||||||
|
throw new Error("Unable to get theme");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
update(theme) {
|
||||||
|
if (this.existingTheme !== theme) {
|
||||||
|
this.setPopupIcon(theme);
|
||||||
|
this.existingTheme = theme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
themeManager.init();
|
||||||
|
|
||||||
browser.runtime.sendMessage({
|
browser.runtime.sendMessage({
|
||||||
method: "getPreference",
|
method: "getPreference",
|
||||||
pref: "browser.privatebrowsing.autostart"
|
pref: "browser.privatebrowsing.autostart"
|
||||||
|
|
|
@ -18,6 +18,42 @@ 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";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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("");
|
||||||
|
}
|
||||||
|
|
||||||
// This object controls all the panels, identities and many other things.
|
// This object controls all the panels, identities and many other things.
|
||||||
const Logic = {
|
const Logic = {
|
||||||
_identities: [],
|
_identities: [],
|
||||||
|
@ -32,7 +68,8 @@ const Logic = {
|
||||||
|
|
||||||
// Routing to the correct panel.
|
// Routing to the correct panel.
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (localStorage.getItem("onboarded3")) {
|
// If localStorage is disabled, we don't show the onboarding.
|
||||||
|
if (!localStorage || localStorage.getItem("onboarded3")) {
|
||||||
this.showPanel(P_CONTAINERS_LIST);
|
this.showPanel(P_CONTAINERS_LIST);
|
||||||
} else if (localStorage.getItem("onboarded2")) {
|
} else if (localStorage.getItem("onboarded2")) {
|
||||||
this.showPanel(P_ONBOARDING_3);
|
this.showPanel(P_ONBOARDING_3);
|
||||||
|
@ -234,7 +271,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
tr.classList.add("container-panel-row");
|
tr.classList.add("container-panel-row");
|
||||||
context.classList.add("userContext-wrapper", "open-newtab", "clickable");
|
context.classList.add("userContext-wrapper", "open-newtab", "clickable");
|
||||||
manage.classList.add("show-tabs", "pop-button");
|
manage.classList.add("show-tabs", "pop-button");
|
||||||
context.innerHTML = `
|
context.innerHTML = escaped`
|
||||||
<div class="userContext-icon-wrapper open-newtab">
|
<div class="userContext-icon-wrapper open-newtab">
|
||||||
<div class="userContext-icon"
|
<div class="userContext-icon"
|
||||||
data-identity-icon="${identity.image}"
|
data-identity-icon="${identity.image}"
|
||||||
|
@ -377,7 +414,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
fragment.appendChild(tr);
|
fragment.appendChild(tr);
|
||||||
tr.classList.add("container-info-tab-row");
|
tr.classList.add("container-info-tab-row");
|
||||||
tr.innerHTML = `
|
tr.innerHTML = escaped`
|
||||||
<td><img class="icon" src="${tab.favicon}" /></td>
|
<td><img class="icon" src="${tab.favicon}" /></td>
|
||||||
<td class="container-info-tab-title">${tab.title}</td>`;
|
<td class="container-info-tab-title">${tab.title}</td>`;
|
||||||
|
|
||||||
|
@ -421,7 +458,7 @@ Logic.registerPanel(P_CONTAINERS_EDIT, {
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
fragment.appendChild(tr);
|
fragment.appendChild(tr);
|
||||||
tr.classList.add("container-panel-row");
|
tr.classList.add("container-panel-row");
|
||||||
tr.innerHTML = `
|
tr.innerHTML = escaped`
|
||||||
<td class="userContext-wrapper">
|
<td class="userContext-wrapper">
|
||||||
<div class="userContext-icon-wrapper">
|
<div class="userContext-icon-wrapper">
|
||||||
<div class="userContext-icon"
|
<div class="userContext-icon"
|
||||||
|
@ -481,46 +518,54 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
Logic.showPreviousPanel();
|
Logic.showPreviousPanel();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector("#edit-container-ok-link").addEventListener("click", () => {
|
this._editForm = document.getElementById("edit-container-panel-form");
|
||||||
const identity = Logic.currentIdentity();
|
const editLink = document.querySelector("#edit-container-ok-link");
|
||||||
const formValues = new FormData(document.getElementById("edit-container-panel-form"));
|
editLink.addEventListener("click", this._submitForm.bind(this));
|
||||||
browser.runtime.sendMessage({
|
editLink.addEventListener("submit", this._submitForm.bind(this));
|
||||||
method: identity.userContextId ? "updateIdentity" : "createIdentity",
|
this._editForm.addEventListener("submit", this._submitForm.bind(this));
|
||||||
userContextId: identity.userContextId || 0,
|
},
|
||||||
name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(),
|
|
||||||
icon: formValues.get("container-icon") || DEFAULT_ICON,
|
_submitForm() {
|
||||||
color: formValues.get("container-color") || DEFAULT_COLOR,
|
const identity = Logic.currentIdentity();
|
||||||
}).then(() => {
|
const formValues = new FormData(this._editForm);
|
||||||
return Logic.refreshIdentities();
|
browser.runtime.sendMessage({
|
||||||
}).then(() => {
|
method: identity.userContextId ? "updateIdentity" : "createIdentity",
|
||||||
Logic.showPreviousPanel();
|
userContextId: identity.userContextId || 0,
|
||||||
}).catch(() => {
|
name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(),
|
||||||
Logic.showPanel(P_CONTAINERS_LIST);
|
icon: formValues.get("container-icon") || DEFAULT_ICON,
|
||||||
});
|
color: formValues.get("container-color") || DEFAULT_COLOR,
|
||||||
|
}).then(() => {
|
||||||
|
return Logic.refreshIdentities();
|
||||||
|
}).then(() => {
|
||||||
|
Logic.showPreviousPanel();
|
||||||
|
}).catch(() => {
|
||||||
|
Logic.showPanel(P_CONTAINERS_LIST);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
initializeRadioButtons() {
|
initializeRadioButtons() {
|
||||||
const colorRadioTemplate = (containerColor) => {
|
const colorRadioTemplate = (containerColor) => {
|
||||||
return `<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}" />
|
||||||
<label for="edit-container-panel-choose-color-${containerColor}" class="usercontext-icon choose-color-icon" data-identity-icon="circle" data-identity-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" ];
|
const colors = ["blue", "turquoise", "green", "yellow", "orange", "red", "pink", "purple" ];
|
||||||
const colorRadioFieldset = document.getElementById("edit-container-panel-choose-color");
|
const colorRadioFieldset = document.getElementById("edit-container-panel-choose-color");
|
||||||
colors.forEach((containerColor) => {
|
colors.forEach((containerColor) => {
|
||||||
const templateInstance = document.createElement("span");
|
const templateInstance = document.createElement("span");
|
||||||
|
// eslint-disable-next-line unsafe-property-assignment/enforce-tagged-template-protection
|
||||||
templateInstance.innerHTML = colorRadioTemplate(containerColor);
|
templateInstance.innerHTML = colorRadioTemplate(containerColor);
|
||||||
colorRadioFieldset.appendChild(templateInstance);
|
colorRadioFieldset.appendChild(templateInstance);
|
||||||
});
|
});
|
||||||
|
|
||||||
const iconRadioTemplate = (containerIcon) => {
|
const iconRadioTemplate = (containerIcon) => {
|
||||||
return `<input type="radio" value="${containerIcon}" name="container-icon" id="edit-container-panel-choose-icon-${containerIcon}" />
|
return 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}">`;
|
<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"];
|
const icons = ["fingerprint", "briefcase", "dollar", "cart", "vacation", "gift", "food", "fruit", "pet", "tree", "chill", "circle"];
|
||||||
const iconRadioFieldset = document.getElementById("edit-container-panel-choose-icon");
|
const iconRadioFieldset = document.getElementById("edit-container-panel-choose-icon");
|
||||||
icons.forEach((containerIcon) => {
|
icons.forEach((containerIcon) => {
|
||||||
const templateInstance = document.createElement("span");
|
const templateInstance = document.createElement("span");
|
||||||
|
// eslint-disable-next-line unsafe-property-assignment/enforce-tagged-template-protection
|
||||||
templateInstance.innerHTML = iconRadioTemplate(containerIcon);
|
templateInstance.innerHTML = iconRadioTemplate(containerIcon);
|
||||||
iconRadioFieldset.appendChild(templateInstance);
|
iconRadioFieldset.appendChild(templateInstance);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Containers Experiment",
|
"name": "Containers Experiment",
|
||||||
"version": "1.0.4",
|
"version": "1.1.1",
|
||||||
|
|
||||||
"description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.",
|
"description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.",
|
||||||
"icons": {
|
"icons": {
|
||||||
|
|
Loading…
Add table
Reference in a new issue