Merge pull request #280 from mozilla/master
Merge 1.0 into production branch to publish signed .xpi
This commit is contained in:
commit
55dea83cfd
8 changed files with 144 additions and 36 deletions
|
@ -105,16 +105,23 @@ value, or chrome url path as an alternate selector mitiages this bug.*/
|
|||
#userContext-indicator {
|
||||
height: 16px;
|
||||
list-style-image: none !important;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#userContext-label {
|
||||
margin-inline-end: 5px;
|
||||
color: var(--identity-tab-color) !important;
|
||||
margin-inline-end: 5px;
|
||||
max-inline-size: 75px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#userContext-icons {
|
||||
-moz-box-align: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
max-inline-size: 120px;
|
||||
}
|
||||
|
||||
.userContext-icon,
|
||||
|
|
|
@ -169,6 +169,15 @@ of a `testpilottest` telemetry ping for each scenario.
|
|||
}
|
||||
```
|
||||
|
||||
* When a user encounters the disabled "move" feature because of incompatible add-ons
|
||||
|
||||
```js
|
||||
{
|
||||
"uuid": <uuid>,
|
||||
"event": "incompatible-addons-detected"
|
||||
}
|
||||
```
|
||||
|
||||
### A Redshift schema for the payload:
|
||||
|
||||
```lua
|
||||
|
|
104
index.js
104
index.js
|
@ -8,6 +8,12 @@ const DEFAULT_TAB = "about:newtab";
|
|||
const SHOW_MENU_TIMEOUT = 100;
|
||||
const HIDE_MENU_TIMEOUT = 300;
|
||||
|
||||
const INCOMPATIBLE_ADDON_IDS = [
|
||||
"pulse@mozilla.com",
|
||||
"snoozetabs@mozilla.com",
|
||||
"jid1-NeEaf3sAHdKHPA@jetpack" // PageShot
|
||||
];
|
||||
|
||||
const IDENTITY_COLORS = [
|
||||
{ name: "blue", color: "#00a7e0" },
|
||||
{ name: "turquoise", color: "#01bdad" },
|
||||
|
@ -40,6 +46,7 @@ const PREFS = [
|
|||
[ "privacy.usercontext.about_newtab_segregation.enabled", true ],
|
||||
];
|
||||
|
||||
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
|
||||
const { attachTo, detachFrom } = require("sdk/content/mod");
|
||||
const { Cu } = require("chrome");
|
||||
const { ContextualIdentityService } = require("resource://gre/modules/ContextualIdentityService.jsm");
|
||||
|
@ -105,6 +112,7 @@ const ContextualIdentityProxy = {
|
|||
const ContainerService = {
|
||||
_identitiesState: {},
|
||||
_windowMap: new Map(),
|
||||
_containerWasEnabled: false,
|
||||
|
||||
init(installation) {
|
||||
// If we are just been installed, we must store some information for the
|
||||
|
@ -139,8 +147,23 @@ const ContainerService = {
|
|||
identity.color);
|
||||
}
|
||||
}
|
||||
|
||||
// Let's create the default containers in case there are none.
|
||||
if (prefService.get("privacy.userContext.enabled") !== true &&
|
||||
ss.storage.savedConfiguration.preInstalledIdentities.length === 0) {
|
||||
// Note: we have to create them in this way because there is no way to
|
||||
// reuse the same ID and the localized strings.
|
||||
ContextualIdentityService.create("Personal", "fingerprint", "blue");
|
||||
ContextualIdentityService.create("Work", "briefcase", "orange");
|
||||
ContextualIdentityService.create("Finance", "dollar", "green");
|
||||
ContextualIdentityService.create("Shopping", "cart", "pink");
|
||||
}
|
||||
}
|
||||
|
||||
// Let's see if containers were enabled before this addon.
|
||||
this._containerWasEnabled =
|
||||
ss.storage.savedConfiguration.prefs["privacy.userContext.enabled"];
|
||||
|
||||
// Enabling preferences
|
||||
|
||||
PREFS.forEach((pref) => {
|
||||
|
@ -170,7 +193,8 @@ const ContainerService = {
|
|||
"removeIdentity",
|
||||
"updateIdentity",
|
||||
"getPreference",
|
||||
"sendTelemetryPayload"
|
||||
"sendTelemetryPayload",
|
||||
"checkIncompatibleAddons"
|
||||
];
|
||||
|
||||
// Map of identities.
|
||||
|
@ -477,6 +501,21 @@ const ContainerService = {
|
|||
this._sendEvent(payload);
|
||||
},
|
||||
|
||||
checkIncompatibleAddons() {
|
||||
return new Promise(resolve => {
|
||||
AddonManager.getAddonsByIDs(INCOMPATIBLE_ADDON_IDS, (addons) => {
|
||||
addons = addons.filter((a) => a && a.isActive);
|
||||
const incompatibleAddons = addons.length !== 0;
|
||||
if (incompatibleAddons) {
|
||||
this.sendTelemetryPayload({
|
||||
"event": "incompatible-addons-detected"
|
||||
});
|
||||
}
|
||||
resolve(incompatibleAddons);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Tabs management
|
||||
|
||||
hideTabs(args) {
|
||||
|
@ -673,6 +712,11 @@ const ContainerService = {
|
|||
return;
|
||||
}
|
||||
|
||||
this._remapTabsIfMissing(args.userContextId);
|
||||
if (!this._isKnownContainer(args.userContextId)) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
this.sendTelemetryPayload({
|
||||
"event": "move-tabs-to-window",
|
||||
"userContextId": args.userContextId,
|
||||
|
@ -686,7 +730,8 @@ const ContainerService = {
|
|||
});
|
||||
|
||||
// Nothing to do
|
||||
if (list.length === 0) {
|
||||
if (list.length === 0 &&
|
||||
this._identitiesState[args.userContextId].hiddenTabs.length === 0) {
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
@ -702,6 +747,13 @@ const ContainerService = {
|
|||
newBrowserWindow.gBrowser.adoptTab(viewFor(tab), pos++, false);
|
||||
}
|
||||
|
||||
// Let's show the hidden tabs.
|
||||
for (let object of this._identitiesState[args.userContextId].hiddenTabs) { // eslint-disable-line prefer-const
|
||||
newBrowserWindow.gBrowser.addTab(object.url || DEFAULT_TAB, { userContextId: args.userContextId });
|
||||
}
|
||||
|
||||
this._identitiesState[args.userContextId].hiddenTabs = [];
|
||||
|
||||
// Let's close all the normal tab in the new window. In theory it
|
||||
// should be only the first tab, but maybe there are addons doing
|
||||
// crazy stuff.
|
||||
|
@ -964,16 +1016,16 @@ const ContainerService = {
|
|||
|
||||
for (let window of windows.browserWindows) { // eslint-disable-line prefer-const
|
||||
// Let's close all the container tabs.
|
||||
// Note 1: we don't care if containers are supported but the current FF
|
||||
// version.
|
||||
// Note 2: We cannot use _closeTabs() because at this point tab.window is
|
||||
// null.
|
||||
for (let tab of window.tabs) { // eslint-disable-line prefer-const
|
||||
if (this._getUserContextIdFromTab(tab)) {
|
||||
tab.close();
|
||||
try {
|
||||
SessionStore.forgetClosedTab(viewFor(window), 0);
|
||||
} catch(e) {} // eslint-disable-line no-empty
|
||||
// Note: We cannot use _closeTabs() because at this point tab.window is
|
||||
// null.
|
||||
if (!this._containerWasEnabled) {
|
||||
for (let tab of window.tabs) { // eslint-disable-line prefer-const
|
||||
if (this._getUserContextIdFromTab(tab)) {
|
||||
tab.close();
|
||||
try {
|
||||
SessionStore.forgetClosedTab(viewFor(window), 0);
|
||||
} catch(e) {} // eslint-disable-line no-empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1101,14 +1153,16 @@ ContainerWindow.prototype = {
|
|||
},
|
||||
|
||||
_configurePlusButtonMenuElement(buttonElement) {
|
||||
// Let's remove the tooltip because it can go over our panel.
|
||||
this._tooltipCache.set(buttonElement, buttonElement.getAttribute("tooltip"));
|
||||
buttonElement.setAttribute("tooltip", "");
|
||||
this._disableElement(buttonElement);
|
||||
if (buttonElement) {
|
||||
// Let's remove the tooltip because it can go over our panel.
|
||||
this._tooltipCache.set(buttonElement, buttonElement.getAttribute("tooltip"));
|
||||
buttonElement.setAttribute("tooltip", "");
|
||||
this._disableElement(buttonElement);
|
||||
|
||||
buttonElement.addEventListener("mouseover", this);
|
||||
buttonElement.addEventListener("click", this);
|
||||
buttonElement.addEventListener("mouseout", this);
|
||||
buttonElement.addEventListener("mouseover", this);
|
||||
buttonElement.addEventListener("click", this);
|
||||
buttonElement.addEventListener("mouseout", this);
|
||||
}
|
||||
},
|
||||
|
||||
_configurePlusButtonMenu() {
|
||||
|
@ -1318,12 +1372,14 @@ ContainerWindow.prototype = {
|
|||
},
|
||||
|
||||
_shutDownPlusButtonMenuElement(buttonElement) {
|
||||
this._shutdownElement(buttonElement);
|
||||
buttonElement.setAttribute("tooltip", this._tooltipCache.get(buttonElement));
|
||||
if (buttonElement) {
|
||||
this._shutdownElement(buttonElement);
|
||||
buttonElement.setAttribute("tooltip", this._tooltipCache.get(buttonElement));
|
||||
|
||||
buttonElement.removeEventListener("mouseover", this);
|
||||
buttonElement.removeEventListener("click", this);
|
||||
buttonElement.removeEventListener("mouseout", this);
|
||||
buttonElement.removeEventListener("mouseover", this);
|
||||
buttonElement.removeEventListener("click", this);
|
||||
buttonElement.removeEventListener("mouseout", this);
|
||||
}
|
||||
},
|
||||
|
||||
_shutdownPlusButtonMenu() {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "testpilot-containers",
|
||||
"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.",
|
||||
"version": "0.9.4",
|
||||
"version": "1.0.0",
|
||||
"author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston",
|
||||
"bugs": {
|
||||
"url": "https://github.com/mozilla/testpilot-containers/issues"
|
||||
|
|
|
@ -416,11 +416,24 @@ span ~ .panel-header-text {
|
|||
}
|
||||
|
||||
/* Container info list */
|
||||
#container-info-name {
|
||||
margin-inline-end: 0.5rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#container-info-hideorshow {
|
||||
margin-block-start: 4px;
|
||||
}
|
||||
|
||||
.container-info-tab-row:not(.clickable) {
|
||||
#container-info-movetabs-incompat {
|
||||
font-size: 10px;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.container-info-tab-row:not(.clickable),
|
||||
.select-row:not(.clickable) {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
|
|
|
@ -302,13 +302,36 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
|||
});
|
||||
});
|
||||
|
||||
document.querySelector("#container-info-movetabs").addEventListener("click", () => {
|
||||
return browser.runtime.sendMessage({
|
||||
method: "moveTabsToWindow",
|
||||
userContextId: Logic.currentIdentity().userContextId,
|
||||
}).then(() => {
|
||||
window.close();
|
||||
});
|
||||
// Check if the user has incompatible add-ons installed
|
||||
browser.runtime.sendMessage({
|
||||
method: "checkIncompatibleAddons"
|
||||
}).then(incompatible => {
|
||||
const moveTabsEl = document.querySelector("#container-info-movetabs");
|
||||
if (incompatible) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
const incompatEl = document.createElement("div");
|
||||
|
||||
moveTabsEl.classList.remove("clickable");
|
||||
moveTabsEl.setAttribute("title", "Moving container tabs is incompatible with Pulse, PageShot, and SnoozeTabs.");
|
||||
|
||||
fragment.appendChild(incompatEl);
|
||||
incompatEl.setAttribute("id", "container-info-movetabs-incompat");
|
||||
incompatEl.innerText = "Incompatible with other Experiments.";
|
||||
incompatEl.classList.add("container-info-tab-row");
|
||||
|
||||
moveTabsEl.parentNode.insertBefore(fragment, moveTabsEl.nextSibling);
|
||||
} else {
|
||||
moveTabsEl.addEventListener("click", () => {
|
||||
return browser.runtime.sendMessage({
|
||||
method: "moveTabsToWindow",
|
||||
userContextId: Logic.currentIdentity().userContextId,
|
||||
}).then(() => {
|
||||
window.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
throw new Error("Could not check for incompatible add-ons.");
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Containers Experiment",
|
||||
"version": "0.9.4",
|
||||
"version": "1.0.0",
|
||||
|
||||
"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": {
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
<form id="edit-container-panel-form">
|
||||
<fieldset>
|
||||
<legend>Name</legend>
|
||||
<input type="text" name="container-name" id="edit-container-panel-name-input"/>
|
||||
<input type="text" name="container-name" id="edit-container-panel-name-input" maxlength="25"/>
|
||||
</fieldset>
|
||||
<fieldset id="edit-container-panel-choose-color">
|
||||
<legend>Choose a color</legend>
|
||||
|
|
Loading…
Add table
Reference in a new issue