Merge pull request #487 from jonathanKingston/remove-sdk-further
Interim WIP patch of more removal
This commit is contained in:
commit
46b155c90f
3 changed files with 270 additions and 253 deletions
406
index.js
406
index.js
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||||
const DEFAULT_TAB = "about:newtab";
|
const DEFAULT_TAB = "about:newtab";
|
||||||
|
const LOOKUP_KEY = "$ref";
|
||||||
|
|
||||||
const SHOW_MENU_TIMEOUT = 100;
|
const SHOW_MENU_TIMEOUT = 100;
|
||||||
const HIDE_MENU_TIMEOUT = 300;
|
const HIDE_MENU_TIMEOUT = 300;
|
||||||
|
@ -73,41 +74,43 @@ 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");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// ContextualIdentityProxy
|
// ContextualIdentityProxy
|
||||||
|
|
||||||
const ContextualIdentityProxy = {
|
const ContextualIdentityProxy = {
|
||||||
getIdentities() {
|
getIdentities() {
|
||||||
|
let response;
|
||||||
if ("getPublicIdentities" in ContextualIdentityService) {
|
if ("getPublicIdentities" in ContextualIdentityService) {
|
||||||
return ContextualIdentityService.getPublicIdentities();
|
response = ContextualIdentityService.getPublicIdentities();
|
||||||
|
} else {
|
||||||
|
response = ContextualIdentityService.getIdentities();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ContextualIdentityService.getIdentities();
|
return response.map((identity) => {
|
||||||
},
|
return this._convert(identity);
|
||||||
|
});
|
||||||
getUserContextLabel(userContextId) {
|
|
||||||
return ContextualIdentityService.getUserContextLabel(userContextId);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getIdentityFromId(userContextId) {
|
getIdentityFromId(userContextId) {
|
||||||
|
let response;
|
||||||
if ("getPublicIdentityFromId" in ContextualIdentityService) {
|
if ("getPublicIdentityFromId" in ContextualIdentityService) {
|
||||||
return ContextualIdentityService.getPublicIdentityFromId(userContextId);
|
response = ContextualIdentityService.getPublicIdentityFromId(userContextId);
|
||||||
|
} else {
|
||||||
|
response = ContextualIdentityService.getIdentityFromId(userContextId);
|
||||||
}
|
}
|
||||||
|
if (response) {
|
||||||
return ContextualIdentityService.getIdentityFromId(userContextId);
|
return this._convert(response);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
},
|
},
|
||||||
|
|
||||||
create(name, icon, color) {
|
_convert(identity) {
|
||||||
return ContextualIdentityService.create(name, icon, color);
|
return {
|
||||||
|
name: ContextualIdentityService.getUserContextLabel(identity.userContextId),
|
||||||
|
icon: identity.icon,
|
||||||
|
color: identity.color,
|
||||||
|
userContextId: identity.userContextId,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
update(userContextId, name, icon, color) {
|
|
||||||
return ContextualIdentityService.update(userContextId, name, icon, color);
|
|
||||||
},
|
|
||||||
|
|
||||||
remove(userContextId) {
|
|
||||||
return ContextualIdentityService.remove(userContextId);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -119,7 +122,7 @@ const ContainerService = {
|
||||||
_containerWasEnabled: false,
|
_containerWasEnabled: false,
|
||||||
_onBackgroundConnectCallback: null,
|
_onBackgroundConnectCallback: null,
|
||||||
|
|
||||||
init(installation, reason) {
|
async init(installation, reason) {
|
||||||
// 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
|
||||||
// uninstallation. This object contains also a version number, in case we
|
// uninstallation. This object contains also a version number, in case we
|
||||||
// need to implement a migration in the future.
|
// need to implement a migration in the future.
|
||||||
|
@ -149,7 +152,7 @@ const ContainerService = {
|
||||||
// Maybe rename the Banking container.
|
// Maybe rename the Banking container.
|
||||||
const identity = ContextualIdentityProxy.getIdentityFromId(3);
|
const identity = ContextualIdentityProxy.getIdentityFromId(3);
|
||||||
if (identity && identity.l10nID === "userContextBanking.label") {
|
if (identity && identity.l10nID === "userContextBanking.label") {
|
||||||
ContextualIdentityProxy.update(identity.userContextId,
|
ContextualIdentityService.update(identity.userContextId,
|
||||||
"Finance",
|
"Finance",
|
||||||
identity.icon,
|
identity.icon,
|
||||||
identity.color);
|
identity.color);
|
||||||
|
@ -167,6 +170,18 @@ const ContainerService = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TOCHECK should this run on all code
|
||||||
|
ContextualIdentityProxy.getIdentities().forEach(identity => {
|
||||||
|
const newIcon = this._fromIconToName(identity.icon);
|
||||||
|
const newColor = this._fromColorToName(identity.color);
|
||||||
|
if (newIcon !== identity.icon || newColor !== identity.color) {
|
||||||
|
ContextualIdentityService.update(identity.userContextId,
|
||||||
|
ContextualIdentityService.getUserContextLabel(identity.userContextId),
|
||||||
|
newIcon,
|
||||||
|
newColor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Let's see if containers were enabled before this addon.
|
// Let's see if containers were enabled before this addon.
|
||||||
this._containerWasEnabled =
|
this._containerWasEnabled =
|
||||||
ss.storage.savedConfiguration.prefs["privacy.userContext.enabled"];
|
ss.storage.savedConfiguration.prefs["privacy.userContext.enabled"];
|
||||||
|
@ -192,9 +207,8 @@ const ContainerService = {
|
||||||
"sortTabs",
|
"sortTabs",
|
||||||
"getTabs",
|
"getTabs",
|
||||||
"showTab",
|
"showTab",
|
||||||
"openTab",
|
|
||||||
"moveTabsToWindow",
|
"moveTabsToWindow",
|
||||||
"queryIdentities",
|
"queryIdentitiesState",
|
||||||
"getIdentity",
|
"getIdentity",
|
||||||
"getPreference",
|
"getPreference",
|
||||||
"sendTelemetryPayload",
|
"sendTelemetryPayload",
|
||||||
|
@ -253,7 +267,8 @@ const ContainerService = {
|
||||||
|
|
||||||
// WebExtension startup
|
// WebExtension startup
|
||||||
|
|
||||||
webExtension.startup().then(api => {
|
try {
|
||||||
|
const api = await webExtension.startup();
|
||||||
api.browser.runtime.onMessage.addListener((message, sender, sendReply) => {
|
api.browser.runtime.onMessage.addListener((message, sender, sendReply) => {
|
||||||
if ("method" in message && methods.indexOf(message.method) !== -1) {
|
if ("method" in message && methods.indexOf(message.method) !== -1) {
|
||||||
sendReply(this[message.method](message));
|
sendReply(this[message.method](message));
|
||||||
|
@ -261,9 +276,9 @@ const ContainerService = {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.registerBackgroundConnection(api);
|
this.registerBackgroundConnection(api);
|
||||||
}).catch(() => {
|
} catch (e) {
|
||||||
throw new Error("WebExtension startup failed. Unable to continue.");
|
throw new Error("WebExtension startup failed. Unable to continue.");
|
||||||
});
|
}
|
||||||
|
|
||||||
this._sendEvent = new Metrics({
|
this._sendEvent = new Metrics({
|
||||||
type: "sdk",
|
type: "sdk",
|
||||||
|
@ -308,7 +323,7 @@ const ContainerService = {
|
||||||
},
|
},
|
||||||
|
|
||||||
registerBackgroundConnection(api) {
|
registerBackgroundConnection(api) {
|
||||||
// This is only used for theme notifications
|
// This is only used for theme notifications and new tab
|
||||||
api.browser.runtime.onConnect.addListener((port) => {
|
api.browser.runtime.onConnect.addListener((port) => {
|
||||||
this._onBackgroundConnectCallback = (message, topic) => {
|
this._onBackgroundConnectCallback = (message, topic) => {
|
||||||
port.postMessage({
|
port.postMessage({
|
||||||
|
@ -325,13 +340,14 @@ const ContainerService = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
observe(subject, topic) {
|
async observe(subject, topic) {
|
||||||
if (topic === "lightweight-theme-changed") {
|
if (topic === "lightweight-theme-changed") {
|
||||||
this.getTheme().then((theme) => {
|
try {
|
||||||
|
const theme = await this.getTheme();
|
||||||
this.triggerBackgroundCallback(theme, topic);
|
this.triggerBackgroundCallback(theme, topic);
|
||||||
}).catch(() => {
|
} catch (e) {
|
||||||
throw new Error("Unable to get theme");
|
throw new Error("Unable to get theme");
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -396,18 +412,6 @@ const ContainerService = {
|
||||||
return containersCounts;
|
return containersCounts;
|
||||||
},
|
},
|
||||||
|
|
||||||
_convert(identity) {
|
|
||||||
// Let's convert the known colors to their color names.
|
|
||||||
return {
|
|
||||||
name: ContextualIdentityProxy.getUserContextLabel(identity.userContextId),
|
|
||||||
image: this._fromIconToName(identity.icon),
|
|
||||||
color: this._fromColorToName(identity.color),
|
|
||||||
userContextId: identity.userContextId,
|
|
||||||
hasHiddenTabs: !!this._identitiesState[identity.userContextId].hiddenTabs.length,
|
|
||||||
hasOpenTabs: !!this._identitiesState[identity.userContextId].openTabs
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
// In FF 50-51, the icon is the full path, in 52 and following
|
// In FF 50-51, the icon is the full path, in 52 and following
|
||||||
// releases, we have IDs to be used with a svg file. In this function
|
// releases, we have IDs to be used with a svg file. In this function
|
||||||
// we map URLs to svg IDs.
|
// we map URLs to svg IDs.
|
||||||
|
@ -433,10 +437,6 @@ const ContainerService = {
|
||||||
|
|
||||||
// Helper methods for converting icons to names and names to icons.
|
// Helper methods for converting icons to names and names to icons.
|
||||||
|
|
||||||
_fromNameToIcon(name) {
|
|
||||||
return this._fromNameOrIcon(name, "image", "");
|
|
||||||
},
|
|
||||||
|
|
||||||
_fromIconToName(icon) {
|
_fromIconToName(icon) {
|
||||||
return this._fromNameOrIcon(icon, "name", "circle");
|
return this._fromNameOrIcon(icon, "name", "circle");
|
||||||
},
|
},
|
||||||
|
@ -456,22 +456,31 @@ const ContainerService = {
|
||||||
return parseInt(viewFor(tab).getAttribute("usercontextid") || 0, 10);
|
return parseInt(viewFor(tab).getAttribute("usercontextid") || 0, 10);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createTabObject(tab) {
|
async _createTabObject(tab) {
|
||||||
|
let url;
|
||||||
|
try {
|
||||||
|
url = await getFavicon(tab.url);
|
||||||
|
} catch (e) {
|
||||||
|
url = "";
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
title: tab.title,
|
title: tab.title,
|
||||||
url: tab.url,
|
url: tab.url,
|
||||||
|
favicon: url,
|
||||||
id: tab.id,
|
id: tab.id,
|
||||||
active: true,
|
active: true,
|
||||||
pinned: tabsUtils.isPinned(viewFor(tab))
|
pinned: tabsUtils.isPinned(viewFor(tab))
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
_containerTabIterator(userContextId, cb) {
|
_matchTabsByContainer(userContextId) {
|
||||||
for (let tab of tabs) { // eslint-disable-line prefer-const
|
const matchedTabs = [];
|
||||||
|
for (const tab of tabs) {
|
||||||
if (userContextId === this._getUserContextIdFromTab(tab)) {
|
if (userContextId === this._getUserContextIdFromTab(tab)) {
|
||||||
cb(tab);
|
matchedTabs.push(tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return matchedTabs;
|
||||||
},
|
},
|
||||||
|
|
||||||
_createIdentityState() {
|
_createIdentityState() {
|
||||||
|
@ -492,10 +501,7 @@ const ContainerService = {
|
||||||
},
|
},
|
||||||
|
|
||||||
_remapTabsFromUserContextId(userContextId) {
|
_remapTabsFromUserContextId(userContextId) {
|
||||||
this._identitiesState[userContextId].openTabs = 0;
|
this._identitiesState[userContextId].openTabs = this._matchTabsByContainer(userContextId).length;
|
||||||
this._containerTabIterator(userContextId, () => {
|
|
||||||
++this._identitiesState[userContextId].openTabs;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_remapTab(tab) {
|
_remapTab(tab) {
|
||||||
|
@ -509,30 +515,25 @@ const ContainerService = {
|
||||||
return userContextId in this._identitiesState;
|
return userContextId in this._identitiesState;
|
||||||
},
|
},
|
||||||
|
|
||||||
_closeTabs(tabsToClose) {
|
async _closeTabs(tabsToClose) {
|
||||||
// We create a new tab only if the current operation closes all the
|
// We create a new tab only if the current operation closes all the
|
||||||
// existing ones.
|
// existing ones.
|
||||||
let promise;
|
if (tabs.length === tabsToClose.length) {
|
||||||
if (tabs.length !== tabsToClose.length) {
|
await this.openTab({});
|
||||||
promise = Promise.resolve(null);
|
|
||||||
} else {
|
|
||||||
promise = this.openTab({});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.then(() => {
|
for (const tab of tabsToClose) {
|
||||||
for (let tab of tabsToClose) { // eslint-disable-line prefer-const
|
// after .close() window is null. Let's take it now.
|
||||||
// after .close() window is null. Let's take it now.
|
const window = viewFor(tab.window);
|
||||||
const window = viewFor(tab.window);
|
|
||||||
|
|
||||||
tab.close();
|
tab.close();
|
||||||
|
|
||||||
// forget about this tab. 0 is the index of the forgotten tab and 0
|
// forget about this tab. 0 is the index of the forgotten tab and 0
|
||||||
// means the last one.
|
// means the last one.
|
||||||
try {
|
try {
|
||||||
SessionStore.forgetClosedTab(window, 0);
|
SessionStore.forgetClosedTab(window, 0);
|
||||||
} catch(e) {} // eslint-disable-line no-empty
|
} catch (e) {} // eslint-disable-line no-empty
|
||||||
}
|
}
|
||||||
}).catch(() => null);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_recentBrowserWindow() {
|
_recentBrowserWindow() {
|
||||||
|
@ -559,6 +560,29 @@ const ContainerService = {
|
||||||
};
|
};
|
||||||
Object.assign(payload, args);
|
Object.assign(payload, args);
|
||||||
|
|
||||||
|
/* This is to masage the data whilst it is still active in the SDK side */
|
||||||
|
const containersCounts = this._containersCounts();
|
||||||
|
Object.keys(payload).forEach((keyName) => {
|
||||||
|
let value = payload[keyName];
|
||||||
|
if (value === LOOKUP_KEY) {
|
||||||
|
switch (keyName) {
|
||||||
|
case "clickedContainerTabCount":
|
||||||
|
value = this._containerTabCount(payload.userContextId);
|
||||||
|
break;
|
||||||
|
case "shownContainersCount":
|
||||||
|
value = containersCounts.shown;
|
||||||
|
break;
|
||||||
|
case "hiddenContainersCount":
|
||||||
|
value = containersCounts.hidden;
|
||||||
|
break;
|
||||||
|
case "totalContainersCount":
|
||||||
|
value = containersCounts.total;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
payload[keyName] = value;
|
||||||
|
});
|
||||||
|
|
||||||
this._sendEvent(payload);
|
this._sendEvent(payload);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -579,51 +603,46 @@ const ContainerService = {
|
||||||
|
|
||||||
// Tabs management
|
// Tabs management
|
||||||
|
|
||||||
hideTabs(args) {
|
async hideTabs(args) {
|
||||||
if (!("userContextId" in args)) {
|
if (!("userContextId" in args)) {
|
||||||
return Promise.reject("hideTabs must be called with userContextId argument.");
|
return new Error("hideTabs must be called with userContextId argument.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._remapTabsIfMissing(args.userContextId);
|
this._remapTabsIfMissing(args.userContextId);
|
||||||
if (!this._isKnownContainer(args.userContextId)) {
|
if (!this._isKnownContainer(args.userContextId)) {
|
||||||
return Promise.resolve(null);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const containersCounts = this._containersCounts();
|
|
||||||
this.sendTelemetryPayload({
|
this.sendTelemetryPayload({
|
||||||
"event": "hide-tabs",
|
"event": "hide-tabs",
|
||||||
"userContextId": args.userContextId,
|
"userContextId": args.userContextId,
|
||||||
"clickedContainerTabCount": this._containerTabCount(args.userContextId),
|
"clickedContainerTabCount": LOOKUP_KEY,
|
||||||
"shownContainersCount": containersCounts.shown,
|
"shownContainersCount": LOOKUP_KEY,
|
||||||
"hiddenContainersCount": containersCounts.hidden,
|
"hiddenContainersCount": LOOKUP_KEY,
|
||||||
"totalContainersCount": containersCounts.total
|
"totalContainersCount": LOOKUP_KEY
|
||||||
});
|
});
|
||||||
|
|
||||||
const tabsToClose = [];
|
const tabsToClose = [];
|
||||||
|
|
||||||
this._containerTabIterator(args.userContextId, tab => {
|
const tabObjects = await Promise.all(this._matchTabsByContainer(args.userContextId).map((tab) => {
|
||||||
const object = this._createTabObject(tab);
|
tabsToClose.push(tab);
|
||||||
|
return this._createTabObject(tab);
|
||||||
|
}));
|
||||||
|
|
||||||
|
tabObjects.forEach((object) => {
|
||||||
// This tab is going to be closed. Let's mark this tabObject as
|
// This tab is going to be closed. Let's mark this tabObject as
|
||||||
// non-active.
|
// non-active.
|
||||||
object.active = false;
|
object.active = false;
|
||||||
|
|
||||||
getFavicon(object.url).then(url => {
|
|
||||||
object.favicon = url;
|
|
||||||
}).catch(() => {
|
|
||||||
object.favicon = "";
|
|
||||||
});
|
|
||||||
|
|
||||||
this._identitiesState[args.userContextId].hiddenTabs.push(object);
|
this._identitiesState[args.userContextId].hiddenTabs.push(object);
|
||||||
tabsToClose.push(tab);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return this._closeTabs(tabsToClose).then(() => {
|
await this._closeTabs(tabsToClose);
|
||||||
return this._syncTabs();
|
|
||||||
});
|
return this._syncTabs();
|
||||||
},
|
},
|
||||||
|
|
||||||
showTabs(args) {
|
async showTabs(args) {
|
||||||
if (!("userContextId" in args)) {
|
if (!("userContextId" in args)) {
|
||||||
return Promise.reject("showTabs must be called with userContextId argument.");
|
return Promise.reject("showTabs must be called with userContextId argument.");
|
||||||
}
|
}
|
||||||
|
@ -633,14 +652,13 @@ const ContainerService = {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
const containersCounts = this._containersCounts();
|
|
||||||
this.sendTelemetryPayload({
|
this.sendTelemetryPayload({
|
||||||
"event": "show-tabs",
|
"event": "show-tabs",
|
||||||
"userContextId": args.userContextId,
|
"userContextId": args.userContextId,
|
||||||
"clickedContainerTabCount": this._containerTabCount(args.userContextId),
|
"clickedContainerTabCount": LOOKUP_KEY,
|
||||||
"shownContainersCount": containersCounts.shown,
|
"shownContainersCount": LOOKUP_KEY,
|
||||||
"hiddenContainersCount": containersCounts.hidden,
|
"hiddenContainersCount": LOOKUP_KEY,
|
||||||
"totalContainersCount": containersCounts.total
|
"totalContainersCount": LOOKUP_KEY
|
||||||
});
|
});
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
@ -653,16 +671,14 @@ const ContainerService = {
|
||||||
userContextId: args.userContextId,
|
userContextId: args.userContextId,
|
||||||
url: object.url,
|
url: object.url,
|
||||||
nofocus: args.nofocus || false,
|
nofocus: args.nofocus || false,
|
||||||
window: args.window || null,
|
|
||||||
pinned: object.pinned,
|
pinned: object.pinned,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._identitiesState[args.userContextId].hiddenTabs = [];
|
this._identitiesState[args.userContextId].hiddenTabs = [];
|
||||||
|
|
||||||
return Promise.all(promises).then(() => {
|
await Promise.all(promises);
|
||||||
return this._syncTabs();
|
return this._syncTabs();
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
sortTabs() {
|
sortTabs() {
|
||||||
|
@ -692,7 +708,7 @@ const ContainerService = {
|
||||||
|
|
||||||
// Let's collect UCIs/tabs for this window.
|
// Let's collect UCIs/tabs for this window.
|
||||||
const map = new Map;
|
const map = new Map;
|
||||||
for (let tab of tabs) { // eslint-disable-line prefer-const
|
for (const tab of tabs) {
|
||||||
if (pinnedTabs && !tabsUtils.isPinned(tab)) {
|
if (pinnedTabs && !tabsUtils.isPinned(tab)) {
|
||||||
// We don't have, or we already handled all the pinned tabs.
|
// We don't have, or we already handled all the pinned tabs.
|
||||||
break;
|
break;
|
||||||
|
@ -716,44 +732,29 @@ const ContainerService = {
|
||||||
|
|
||||||
// Let's move tabs.
|
// Let's move tabs.
|
||||||
sortMap.forEach(tabs => {
|
sortMap.forEach(tabs => {
|
||||||
for (let tab of tabs) { // eslint-disable-line prefer-const
|
for (const tab of tabs) {
|
||||||
xulWindow.gBrowser.moveTabTo(tab, pos++);
|
xulWindow.gBrowser.moveTabTo(tab, pos++);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getTabs(args) {
|
async getTabs(args) {
|
||||||
if (!("userContextId" in args)) {
|
if (!("userContextId" in args)) {
|
||||||
return Promise.reject("getTabs must be called with userContextId argument.");
|
return new Error("getTabs must be called with userContextId argument.");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._remapTabsIfMissing(args.userContextId);
|
this._remapTabsIfMissing(args.userContextId);
|
||||||
if (!this._isKnownContainer(args.userContextId)) {
|
if (!this._isKnownContainer(args.userContextId)) {
|
||||||
return Promise.resolve([]);
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
const promises = [];
|
||||||
const list = [];
|
this._matchTabsByContainer(args.userContextId).forEach((tab) => {
|
||||||
this._containerTabIterator(args.userContextId, tab => {
|
promises.push(this._createTabObject(tab));
|
||||||
list.push(this._createTabObject(tab));
|
|
||||||
});
|
|
||||||
|
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
for (let object of list) { // eslint-disable-line prefer-const
|
|
||||||
promises.push(getFavicon(object.url).then(url => {
|
|
||||||
object.favicon = url;
|
|
||||||
}).catch(() => {
|
|
||||||
object.favicon = "";
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(promises).then(() => {
|
|
||||||
resolve(list.concat(this._identitiesState[args.userContextId].hiddenTabs));
|
|
||||||
}).catch((e) => {
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const list = await Promise.all(promises);
|
||||||
|
return list.concat(this._identitiesState[args.userContextId].hiddenTabs);
|
||||||
},
|
},
|
||||||
|
|
||||||
showTab(args) {
|
showTab(args) {
|
||||||
|
@ -763,7 +764,7 @@ const ContainerService = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let tab of tabs) { // eslint-disable-line prefer-const
|
for (const tab of tabs) {
|
||||||
if (tab.id === args.tabId) {
|
if (tab.id === args.tabId) {
|
||||||
tab.window.activate();
|
tab.window.activate();
|
||||||
tab.activate();
|
tab.activate();
|
||||||
|
@ -793,11 +794,7 @@ const ContainerService = {
|
||||||
"clickedContainerTabCount": this._containerTabCount(args.userContextId),
|
"clickedContainerTabCount": this._containerTabCount(args.userContextId),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Let's create a list of the tabs.
|
const list = this._matchTabsByContainer(args.userContextId);
|
||||||
const list = [];
|
|
||||||
this._containerTabIterator(args.userContextId, tab => {
|
|
||||||
list.push(tab);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
if (list.length === 0 &&
|
if (list.length === 0 &&
|
||||||
|
@ -840,74 +837,37 @@ const ContainerService = {
|
||||||
},
|
},
|
||||||
|
|
||||||
openTab(args) {
|
openTab(args) {
|
||||||
return new Promise(resolve => {
|
return this.triggerBackgroundCallback(args, "open-tab");
|
||||||
if ("window" in args && args.window) {
|
|
||||||
resolve(args.window);
|
|
||||||
} else {
|
|
||||||
this._recentBrowserWindow().then(browserWin => {
|
|
||||||
resolve(browserWin);
|
|
||||||
}).catch(() => {});
|
|
||||||
}
|
|
||||||
}).then(browserWin => {
|
|
||||||
const userContextId = ("userContextId" in args) ? args.userContextId : 0;
|
|
||||||
const source = ("source" in args) ? args.source : null;
|
|
||||||
const nofocus = ("nofocus" in args) ? args.nofocus : false;
|
|
||||||
|
|
||||||
// Only send telemetry for tabs opened by UI - i.e., not via showTabs
|
|
||||||
if (source && userContextId) {
|
|
||||||
this.sendTelemetryPayload({
|
|
||||||
"event": "open-tab",
|
|
||||||
"eventSource": source,
|
|
||||||
"userContextId": userContextId,
|
|
||||||
"clickedContainerTabCount": this._containerTabCount(userContextId)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let promise;
|
|
||||||
if (userContextId) {
|
|
||||||
promise = this.showTabs(args);
|
|
||||||
} else {
|
|
||||||
promise = Promise.resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise.then(() => {
|
|
||||||
const tab = browserWin.gBrowser.addTab(args.url || DEFAULT_TAB, { userContextId });
|
|
||||||
if (!nofocus) {
|
|
||||||
browserWin.gBrowser.selectedTab = tab;
|
|
||||||
browserWin.focusAndSelectUrlBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.pinned) {
|
|
||||||
browserWin.gBrowser.pinTab(tab);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}).catch(() => false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Identities management
|
// Identities management
|
||||||
|
queryIdentitiesState() {
|
||||||
queryIdentities() {
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const identities = [];
|
const identities = {};
|
||||||
|
|
||||||
ContextualIdentityProxy.getIdentities().forEach(identity => {
|
ContextualIdentityProxy.getIdentities().forEach(identity => {
|
||||||
this._remapTabsIfMissing(identity.userContextId);
|
this._remapTabsIfMissing(identity.userContextId);
|
||||||
const convertedIdentity = this._convert(identity);
|
const convertedIdentity = {
|
||||||
identities.push(convertedIdentity);
|
hasHiddenTabs: !!this._identitiesState[identity.userContextId].hiddenTabs.length,
|
||||||
|
hasOpenTabs: !!this._identitiesState[identity.userContextId].openTabs
|
||||||
|
};
|
||||||
|
|
||||||
|
identities[identity.userContextId] = convertedIdentity;
|
||||||
});
|
});
|
||||||
|
|
||||||
resolve(identities);
|
resolve(identities);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getIdentity(args) {
|
queryIdentities() {
|
||||||
if (!("userContextId" in args)) {
|
return new Promise(resolve => {
|
||||||
return Promise.reject("getIdentity must be called with userContextId argument.");
|
const identities = ContextualIdentityProxy.getIdentities();
|
||||||
}
|
identities.forEach(identity => {
|
||||||
|
this._remapTabsIfMissing(identity.userContextId);
|
||||||
|
});
|
||||||
|
|
||||||
const identity = ContextualIdentityProxy.getIdentityFromId(args.userContextId);
|
resolve(identities);
|
||||||
return Promise.resolve(identity ? this._convert(identity) : null);
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// Preferences
|
// Preferences
|
||||||
|
@ -974,26 +934,25 @@ const ContainerService = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const userContextId = ContainerService._getUserContextIdFromTab(tab);
|
const userContextId = ContainerService._getUserContextIdFromTab(tab);
|
||||||
return ContainerService.getIdentity({userContextId}).then(identity => {
|
const identity = ContextualIdentityProxy.getIdentityFromId(userContextId);
|
||||||
const hbox = viewFor(tab.window).document.getElementById("userContext-icons");
|
const hbox = viewFor(tab.window).document.getElementById("userContext-icons");
|
||||||
|
|
||||||
if (!identity) {
|
if (!identity) {
|
||||||
hbox.setAttribute("data-identity-color", "");
|
hbox.setAttribute("data-identity-color", "");
|
||||||
return;
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
hbox.setAttribute("data-identity-color", identity.color);
|
hbox.setAttribute("data-identity-color", identity.color);
|
||||||
|
|
||||||
const label = viewFor(tab.window).document.getElementById("userContext-label");
|
const label = viewFor(tab.window).document.getElementById("userContext-label");
|
||||||
label.setAttribute("value", identity.name);
|
label.setAttribute("value", identity.name);
|
||||||
label.style.color = ContainerService._fromNameToColor(identity.color);
|
label.style.color = ContainerService._fromNameToColor(identity.color);
|
||||||
|
|
||||||
const indicator = viewFor(tab.window).document.getElementById("userContext-indicator");
|
const indicator = viewFor(tab.window).document.getElementById("userContext-indicator");
|
||||||
indicator.setAttribute("data-identity-icon", identity.image);
|
indicator.setAttribute("data-identity-icon", identity.icon);
|
||||||
indicator.style.listStyleImage = "";
|
indicator.style.listStyleImage = "";
|
||||||
}).then(() => {
|
|
||||||
return this._restyleTab(tab);
|
return this._restyleTab(tab);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_restyleTab(tab) {
|
_restyleTab(tab) {
|
||||||
|
@ -1001,12 +960,11 @@ const ContainerService = {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
const userContextId = ContainerService._getUserContextIdFromTab(tab);
|
const userContextId = ContainerService._getUserContextIdFromTab(tab);
|
||||||
return ContainerService.getIdentity({userContextId}).then(identity => {
|
const identity = ContextualIdentityProxy.getIdentityFromId(userContextId);
|
||||||
if (!identity) {
|
if (!identity) {
|
||||||
return;
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
viewFor(tab).setAttribute("data-identity-color", identity.color);
|
return Promise.resolve(viewFor(tab).setAttribute("data-identity-color", identity.color));
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Uninstallation
|
// Uninstallation
|
||||||
|
@ -1065,7 +1023,7 @@ const ContainerService = {
|
||||||
const preInstalledIdentities = data.preInstalledIdentities;
|
const preInstalledIdentities = data.preInstalledIdentities;
|
||||||
ContextualIdentityProxy.getIdentities().forEach(identity => {
|
ContextualIdentityProxy.getIdentities().forEach(identity => {
|
||||||
if (!preInstalledIdentities.includes(identity.userContextId)) {
|
if (!preInstalledIdentities.includes(identity.userContextId)) {
|
||||||
ContextualIdentityProxy.remove(identity.userContextId);
|
ContextualIdentityService.remove(identity.userContextId);
|
||||||
} else {
|
} else {
|
||||||
// Let's cleanup all the cookies for this container.
|
// Let's cleanup all the cookies for this container.
|
||||||
Services.obs.notifyObservers(null, "clear-origin-attributes-data",
|
Services.obs.notifyObservers(null, "clear-origin-attributes-data",
|
||||||
|
@ -1203,7 +1161,7 @@ ContainerWindow.prototype = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_configurePlusButtonMenu() {
|
async _configurePlusButtonMenu() {
|
||||||
const mainPopupSetElement = this._window.document.getElementById("mainPopupSet");
|
const mainPopupSetElement = this._window.document.getElementById("mainPopupSet");
|
||||||
|
|
||||||
// Let's remove all the previous panels.
|
// Let's remove all the previous panels.
|
||||||
|
@ -1230,21 +1188,21 @@ ContainerWindow.prototype = {
|
||||||
this._cleanAllTimeouts();
|
this._cleanAllTimeouts();
|
||||||
});
|
});
|
||||||
|
|
||||||
return ContainerService.queryIdentities().then(identities => {
|
try {
|
||||||
|
const identities = await ContainerService.queryIdentities();
|
||||||
identities.forEach(identity => {
|
identities.forEach(identity => {
|
||||||
const menuItemElement = this._window.document.createElementNS(XUL_NS, "menuitem");
|
const menuItemElement = this._window.document.createElementNS(XUL_NS, "menuitem");
|
||||||
this._panelElement.appendChild(menuItemElement);
|
this._panelElement.appendChild(menuItemElement);
|
||||||
menuItemElement.className = "menuitem-iconic";
|
menuItemElement.className = "menuitem-iconic";
|
||||||
menuItemElement.setAttribute("label", identity.name);
|
menuItemElement.setAttribute("label", identity.name);
|
||||||
menuItemElement.setAttribute("data-usercontextid", identity.userContextId);
|
menuItemElement.setAttribute("data-usercontextid", identity.userContextId);
|
||||||
menuItemElement.setAttribute("data-identity-icon", identity.image);
|
menuItemElement.setAttribute("data-identity-icon", identity.icon);
|
||||||
menuItemElement.setAttribute("data-identity-color", identity.color);
|
menuItemElement.setAttribute("data-identity-color", identity.color);
|
||||||
|
|
||||||
menuItemElement.addEventListener("command", (e) => {
|
menuItemElement.addEventListener("command", (e) => {
|
||||||
ContainerService.openTab({
|
ContainerService.openTab({
|
||||||
userContextId: identity.userContextId,
|
userContextId: identity.userContextId,
|
||||||
source: "tab-bar",
|
source: "tab-bar"
|
||||||
window: this._window,
|
|
||||||
});
|
});
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
|
@ -1257,9 +1215,9 @@ ContainerWindow.prototype = {
|
||||||
|
|
||||||
this._panelElement.appendChild(menuItemElement);
|
this._panelElement.appendChild(menuItemElement);
|
||||||
});
|
});
|
||||||
}).catch(() => {
|
} catch (e) {
|
||||||
this.hidePanel();
|
this.hidePanel();
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_configureTabStyle() {
|
_configureTabStyle() {
|
||||||
|
@ -1280,8 +1238,7 @@ ContainerWindow.prototype = {
|
||||||
const userContextId = parseInt(e.target.getAttribute("data-usercontextid"), 10);
|
const userContextId = parseInt(e.target.getAttribute("data-usercontextid"), 10);
|
||||||
ContainerService.openTab({
|
ContainerService.openTab({
|
||||||
userContextId: userContextId,
|
userContextId: userContextId,
|
||||||
source: "file-menu",
|
source: "file-menu"
|
||||||
window: this._window,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1296,8 +1253,7 @@ ContainerWindow.prototype = {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return ContainerService.openTab({
|
return ContainerService.openTab({
|
||||||
userContextId,
|
userContextId,
|
||||||
source: "alltabs-menu",
|
source: "alltabs-menu"
|
||||||
window: this._window,
|
|
||||||
});
|
});
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
});
|
});
|
||||||
|
@ -1399,7 +1355,7 @@ ContainerWindow.prototype = {
|
||||||
menuitem.classList.add("menuitem-iconic");
|
menuitem.classList.add("menuitem-iconic");
|
||||||
menuitem.setAttribute("data-usercontextid", identity.userContextId);
|
menuitem.setAttribute("data-usercontextid", identity.userContextId);
|
||||||
menuitem.setAttribute("data-identity-color", identity.color);
|
menuitem.setAttribute("data-identity-color", identity.color);
|
||||||
menuitem.setAttribute("data-identity-icon", identity.image);
|
menuitem.setAttribute("data-identity-icon", identity.icon);
|
||||||
fragment.appendChild(menuitem);
|
fragment.appendChild(menuitem);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
const MAJOR_VERSIONS = ["2.3.0"];
|
const MAJOR_VERSIONS = ["2.3.0"];
|
||||||
|
const LOOKUP_KEY = "$ref";
|
||||||
|
|
||||||
const assignManager = {
|
const assignManager = {
|
||||||
CLOSEABLE_WINDOWS: new Set([
|
|
||||||
"about:startpage",
|
|
||||||
"about:newtab",
|
|
||||||
"about:home",
|
|
||||||
"about:blank"
|
|
||||||
]),
|
|
||||||
MENU_ASSIGN_ID: "open-in-this-container",
|
MENU_ASSIGN_ID: "open-in-this-container",
|
||||||
MENU_REMOVE_ID: "remove-open-in-this-container",
|
MENU_REMOVE_ID: "remove-open-in-this-container",
|
||||||
storageArea: {
|
storageArea: {
|
||||||
|
@ -133,14 +128,14 @@ const assignManager = {
|
||||||
We aim to open the new assigned container tab / warning prompt in it's own tab:
|
We aim to open the new assigned container tab / warning prompt in it's own tab:
|
||||||
- As the history won't span from one container to another it seems most sane to not try and reopen a tab on history.back()
|
- As the history won't span from one container to another it seems most sane to not try and reopen a tab on history.back()
|
||||||
- When users open a new tab themselves we want to make sure we don't end up with three tabs as per: https://github.com/mozilla/testpilot-containers/issues/421
|
- When users open a new tab themselves we want to make sure we don't end up with three tabs as per: https://github.com/mozilla/testpilot-containers/issues/421
|
||||||
If we are coming from an internal url that are used for the new tab page (CLOSEABLE_WINDOWS), we can safely close as user is unlikely losing history
|
If we are coming from an internal url that are used for the new tab page (NEW_TAB_PAGES), we can safely close as user is unlikely losing history
|
||||||
Detecting redirects on "new tab" opening actions is pretty hard as we don't get tab history:
|
Detecting redirects on "new tab" opening actions is pretty hard as we don't get tab history:
|
||||||
- Redirects happen from Short URLs and tracking links that act as a gateway
|
- Redirects happen from Short URLs and tracking links that act as a gateway
|
||||||
- Extensions don't provide a way to history crawl for tabs, we could inject content scripts to do this
|
- Extensions don't provide a way to history crawl for tabs, we could inject content scripts to do this
|
||||||
however they don't run on about:blank so this would likely be just as hacky.
|
however they don't run on about:blank so this would likely be just as hacky.
|
||||||
We capture the time the tab was created and close if it was within the timeout to try to capture pages which haven't had user interaction or history.
|
We capture the time the tab was created and close if it was within the timeout to try to capture pages which haven't had user interaction or history.
|
||||||
*/
|
*/
|
||||||
if (this.CLOSEABLE_WINDOWS.has(tab.url)
|
if (backgroundLogic.NEW_TAB_PAGES.has(tab.url)
|
||||||
|| (messageHandler.lastCreatedTab
|
|| (messageHandler.lastCreatedTab
|
||||||
&& messageHandler.lastCreatedTab.id === tab.id)) {
|
&& messageHandler.lastCreatedTab.id === tab.id)) {
|
||||||
browser.tabs.remove(tab.id);
|
browser.tabs.remove(tab.id);
|
||||||
|
@ -218,7 +213,7 @@ const assignManager = {
|
||||||
const loadPage = browser.extension.getURL("confirm-page.html");
|
const loadPage = browser.extension.getURL("confirm-page.html");
|
||||||
// If the user has explicitly checked "Never Ask Again" on the warning page we will send them straight there
|
// If the user has explicitly checked "Never Ask Again" on the warning page we will send them straight there
|
||||||
if (neverAsk) {
|
if (neverAsk) {
|
||||||
browser.tabs.create({url, cookieStoreId: `firefox-container-${userContextId}`, index});
|
browser.tabs.create({url, cookieStoreId: backgroundLogic.cookieStoreId(userContextId), index});
|
||||||
backgroundLogic.sendTelemetryPayload({
|
backgroundLogic.sendTelemetryPayload({
|
||||||
event: "auto-reload-page-in-container",
|
event: "auto-reload-page-in-container",
|
||||||
userContextId: userContextId,
|
userContextId: userContextId,
|
||||||
|
@ -229,7 +224,7 @@ const assignManager = {
|
||||||
userContextId: userContextId,
|
userContextId: userContextId,
|
||||||
});
|
});
|
||||||
const confirmUrl = `${loadPage}?url=${url}`;
|
const confirmUrl = `${loadPage}?url=${url}`;
|
||||||
browser.tabs.create({url: confirmUrl, cookieStoreId: `firefox-container-${userContextId}`, index}).then(() => {
|
browser.tabs.create({url: confirmUrl, cookieStoreId: backgroundLogic.cookieStoreId(userContextId), index}).then(() => {
|
||||||
// We don't want to sync this URL ever nor clutter the users history
|
// We don't want to sync this URL ever nor clutter the users history
|
||||||
browser.history.deleteUrl({url: confirmUrl});
|
browser.history.deleteUrl({url: confirmUrl});
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
|
@ -241,6 +236,13 @@ const assignManager = {
|
||||||
|
|
||||||
|
|
||||||
const backgroundLogic = {
|
const backgroundLogic = {
|
||||||
|
NEW_TAB_PAGES: new Set([
|
||||||
|
"about:startpage",
|
||||||
|
"about:newtab",
|
||||||
|
"about:home",
|
||||||
|
"about:blank"
|
||||||
|
]),
|
||||||
|
|
||||||
deleteContainer(userContextId) {
|
deleteContainer(userContextId) {
|
||||||
this.sendTelemetryPayload({
|
this.sendTelemetryPayload({
|
||||||
event: "delete-container",
|
event: "delete-container",
|
||||||
|
@ -291,6 +293,41 @@ const backgroundLogic = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openTab(options) {
|
||||||
|
let url = options.url || undefined;
|
||||||
|
const userContextId = ("userContextId" in options) ? options.userContextId : 0;
|
||||||
|
const active = ("nofocus" in options) ? options.nofocus : true;
|
||||||
|
const source = ("source" in options) ? options.source : null;
|
||||||
|
|
||||||
|
// Only send telemetry for tabs opened by UI - i.e., not via showTabs
|
||||||
|
if (source && userContextId) {
|
||||||
|
this.sendTelemetryPayload({
|
||||||
|
"event": "open-tab",
|
||||||
|
"eventSource": source,
|
||||||
|
"userContextId": userContextId,
|
||||||
|
"clickedContainerTabCount": LOOKUP_KEY
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Autofocus url bar will happen in 54: https://bugzilla.mozilla.org/show_bug.cgi?id=1295072
|
||||||
|
|
||||||
|
// We can't open new tab pages, so open a blank tab. Used in tab un-hide
|
||||||
|
if (this.NEW_TAB_PAGES.has(url)) {
|
||||||
|
url = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unhide all hidden tabs
|
||||||
|
browser.runtime.sendMessage({
|
||||||
|
method: "showTabs",
|
||||||
|
userContextId: options.userContextId
|
||||||
|
});
|
||||||
|
return browser.tabs.create({
|
||||||
|
url,
|
||||||
|
active,
|
||||||
|
pinned: options.pinned || false,
|
||||||
|
cookieStoreId: backgroundLogic.cookieStoreId(options.userContextId)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
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");
|
||||||
|
@ -317,6 +354,7 @@ const messageHandler = {
|
||||||
LAST_CREATED_TAB_TIMER: 2000,
|
LAST_CREATED_TAB_TIMER: 2000,
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
// Handles messages from webextension/js/popup.js
|
||||||
browser.runtime.onMessage.addListener((m) => {
|
browser.runtime.onMessage.addListener((m) => {
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
|
@ -327,6 +365,10 @@ const messageHandler = {
|
||||||
case "createOrUpdateContainer":
|
case "createOrUpdateContainer":
|
||||||
response = backgroundLogic.createOrUpdateContainer(m.message);
|
response = backgroundLogic.createOrUpdateContainer(m.message);
|
||||||
break;
|
break;
|
||||||
|
case "openTab":
|
||||||
|
// Same as open-tab for index.js
|
||||||
|
response = backgroundLogic.openTab(m.message);
|
||||||
|
break;
|
||||||
case "neverAsk":
|
case "neverAsk":
|
||||||
assignManager._neverAsk(m);
|
assignManager._neverAsk(m);
|
||||||
break;
|
break;
|
||||||
|
@ -341,6 +383,9 @@ const messageHandler = {
|
||||||
case "lightweight-theme-changed":
|
case "lightweight-theme-changed":
|
||||||
themeManager.update(m.message);
|
themeManager.update(m.message);
|
||||||
break;
|
break;
|
||||||
|
case "open-tab":
|
||||||
|
backgroundLogic.openTab(m.message);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled message type: ${m.message}`);
|
throw new Error(`Unhandled message type: ${m.message}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,13 +116,27 @@ const Logic = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
userContextId(cookieStoreId = "") {
|
||||||
|
const userContextId = cookieStoreId.replace("firefox-container-", "");
|
||||||
|
return (userContextId !== cookieStoreId) ? Number(userContextId) : false;
|
||||||
|
},
|
||||||
|
|
||||||
refreshIdentities() {
|
refreshIdentities() {
|
||||||
return browser.runtime.sendMessage({
|
return Promise.all([
|
||||||
method: "queryIdentities"
|
browser.contextualIdentities.query({}),
|
||||||
})
|
browser.runtime.sendMessage({
|
||||||
.then(identities => {
|
method: "queryIdentitiesState"
|
||||||
this._identities = identities;
|
})
|
||||||
});
|
]).then(([identities, state]) => {
|
||||||
|
this._identities = identities.map((identity) => {
|
||||||
|
const stateObject = state[Logic.userContextId(identity.cookieStoreId)];
|
||||||
|
if (stateObject) {
|
||||||
|
identity.hasOpenTabs = stateObject.hasOpenTabs;
|
||||||
|
identity.hasHiddenTabs = stateObject.hasHiddenTabs;
|
||||||
|
}
|
||||||
|
return identity;
|
||||||
|
});
|
||||||
|
}).catch((e) => {throw e;});
|
||||||
},
|
},
|
||||||
|
|
||||||
showPanel(panel, currentIdentity = null) {
|
showPanel(panel, currentIdentity = null) {
|
||||||
|
@ -371,7 +385,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
context.innerHTML = escaped`
|
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.icon}"
|
||||||
data-identity-color="${identity.color}">
|
data-identity-color="${identity.color}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -393,8 +407,10 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
|| e.type === "keydown") {
|
|| e.type === "keydown") {
|
||||||
browser.runtime.sendMessage({
|
browser.runtime.sendMessage({
|
||||||
method: "openTab",
|
method: "openTab",
|
||||||
userContextId: identity.userContextId,
|
message: {
|
||||||
source: "pop-up"
|
userContextId: Logic.userContextId(identity.cookieStoreId),
|
||||||
|
source: "pop-up"
|
||||||
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
window.close();
|
window.close();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
@ -437,7 +453,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: identity.userContextId
|
userContextId: Logic.userContextId(identity.cookieStoreId)
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
window.close();
|
window.close();
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
@ -467,7 +483,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
Logic.addEnterHandler(moveTabsEl, () => {
|
Logic.addEnterHandler(moveTabsEl, () => {
|
||||||
browser.runtime.sendMessage({
|
browser.runtime.sendMessage({
|
||||||
method: "moveTabsToWindow",
|
method: "moveTabsToWindow",
|
||||||
userContextId: Logic.currentIdentity().userContextId,
|
userContextId: Logic.userContextId(Logic.currentIdentity().cookieStoreId),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
window.close();
|
window.close();
|
||||||
}).catch((e) => { throw e; });
|
}).catch((e) => { throw e; });
|
||||||
|
@ -486,7 +502,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
document.getElementById("container-info-name").textContent = identity.name;
|
document.getElementById("container-info-name").textContent = identity.name;
|
||||||
|
|
||||||
const icon = document.getElementById("container-info-icon");
|
const icon = document.getElementById("container-info-icon");
|
||||||
icon.setAttribute("data-identity-icon", identity.image);
|
icon.setAttribute("data-identity-icon", identity.icon);
|
||||||
icon.setAttribute("data-identity-color", identity.color);
|
icon.setAttribute("data-identity-color", identity.color);
|
||||||
|
|
||||||
// Show or not the has-tabs section.
|
// Show or not the has-tabs section.
|
||||||
|
@ -509,7 +525,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: identity.userContextId,
|
userContextId: Logic.userContextId(identity.cookieStoreId),
|
||||||
}).then(this.buildInfoTable);
|
}).then(this.buildInfoTable);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -568,7 +584,7 @@ Logic.registerPanel(P_CONTAINERS_EDIT, {
|
||||||
<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"
|
||||||
data-identity-icon="${identity.image}"
|
data-identity-icon="${identity.icon}"
|
||||||
data-identity-color="${identity.color}">
|
data-identity-color="${identity.color}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -639,7 +655,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
return browser.runtime.sendMessage({
|
return browser.runtime.sendMessage({
|
||||||
method: "createOrUpdateContainer",
|
method: "createOrUpdateContainer",
|
||||||
message: {
|
message: {
|
||||||
userContextId: identity.userContextId || false,
|
userContextId: Logic.userContextId(identity.cookieStoreId) || 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,
|
||||||
|
@ -691,7 +707,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, {
|
||||||
colorInput.checked = colorInput.value === identity.color;
|
colorInput.checked = colorInput.value === identity.color;
|
||||||
});
|
});
|
||||||
[...document.querySelectorAll("[name='container-icon']")].forEach(iconInput => {
|
[...document.querySelectorAll("[name='container-icon']")].forEach(iconInput => {
|
||||||
iconInput.checked = iconInput.value === identity.image;
|
iconInput.checked = iconInput.value === identity.icon;
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
|
@ -717,7 +733,7 @@ Logic.registerPanel(P_CONTAINER_DELETE, {
|
||||||
if you want to do anything post delete do it in the background script.
|
if you want to do anything post delete do it in the background script.
|
||||||
Browser console currently warns about not listening also.
|
Browser console currently warns about not listening also.
|
||||||
*/
|
*/
|
||||||
Logic.removeIdentity(Logic.currentIdentity().userContextId).then(() => {
|
Logic.removeIdentity(Logic.userContextId(Logic.currentIdentity().cookieStoreId)).then(() => {
|
||||||
return Logic.refreshIdentities();
|
return Logic.refreshIdentities();
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
Logic.showPreviousPanel();
|
Logic.showPreviousPanel();
|
||||||
|
@ -735,7 +751,7 @@ Logic.registerPanel(P_CONTAINER_DELETE, {
|
||||||
document.getElementById("delete-container-name").textContent = identity.name;
|
document.getElementById("delete-container-name").textContent = identity.name;
|
||||||
|
|
||||||
const icon = document.getElementById("delete-container-icon");
|
const icon = document.getElementById("delete-container-icon");
|
||||||
icon.setAttribute("data-identity-icon", identity.image);
|
icon.setAttribute("data-identity-icon", identity.icon);
|
||||||
icon.setAttribute("data-identity-color", identity.color);
|
icon.setAttribute("data-identity-color", identity.color);
|
||||||
|
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
|
|
Loading…
Add table
Reference in a new issue