219 lines
6.2 KiB
JavaScript
219 lines
6.2 KiB
JavaScript
/*
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
'use strict';
|
|
|
|
import EventListenerManager from '/extlib/EventListenerManager.js';
|
|
|
|
import {
|
|
configs,
|
|
log as internalLogger,
|
|
isWindows,
|
|
} from './common.js';
|
|
import * as ApiTabs from '/common/api-tabs.js';
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
function log(...args) {
|
|
internalLogger('common/contextual-identities', ...args);
|
|
}
|
|
|
|
const mContextualIdentities = new Map();
|
|
let mIsObserving = false;
|
|
|
|
export function get(id) {
|
|
return mContextualIdentities.get(id);
|
|
}
|
|
|
|
export function getIdFromName(name) {
|
|
for (const identity of mContextualIdentities.values()) {
|
|
if (identity.name.toLowerCase() == name.toLowerCase())
|
|
return identity.cookieStoreId;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Respect container type stored by Container Bookmarks
|
|
// https://addons.mozilla.org/firefox/addon/container-bookmarks/
|
|
export function getIdFromBookmark(bookmark) {
|
|
const containerMatcher = new RegExp(`#${configs.containerRedirectKey}-(.+)$`);
|
|
const matchedContainer = bookmark.url.match(containerMatcher);
|
|
if (!matchedContainer)
|
|
return {};
|
|
|
|
const idPart = matchedContainer[matchedContainer.length-1];
|
|
const url = bookmark.url.replace(containerMatcher, '');
|
|
|
|
// old method
|
|
const identity = mContextualIdentities.get(decodeURIComponent(idPart));
|
|
if (identity) {
|
|
return {
|
|
cookieStoreId: identity.cookieStoreId,
|
|
url,
|
|
};
|
|
}
|
|
|
|
for (const [cookieStoreId, identity] of mContextualIdentities.entries()) {
|
|
if (idPart != encodeURIComponent(identity.name.toLowerCase().replace(/\s/g, '-')))
|
|
continue;
|
|
return {
|
|
cookieStoreId,
|
|
url,
|
|
};
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
export function getColorInfo() {
|
|
const colors = {};
|
|
const customColors = [];
|
|
forEach(identity => {
|
|
if (!identity.colorCode)
|
|
return;
|
|
let colorValue = identity.colorCode;
|
|
if (identity.color) {
|
|
const customColor = `--contextual-identity-color-${identity.color}`;
|
|
customColors.push(`${customColor}: ${identity.colorCode};`);
|
|
colorValue = `var(${customColor})`;
|
|
}
|
|
colors[identity.cookieStoreId] = colorValue;
|
|
});
|
|
|
|
return {
|
|
colors,
|
|
colorDeclarations: customColors.length > 0 ? `:root { ${customColors.join('\n')} }` : ''
|
|
};
|
|
}
|
|
|
|
export function getCount() {
|
|
return mContextualIdentities.size;
|
|
}
|
|
|
|
export function forEach(callback) {
|
|
for (const identity of mContextualIdentities.values()) {
|
|
callback(identity);
|
|
}
|
|
}
|
|
|
|
if (browser.contextualIdentities) { // already granted
|
|
browser.contextualIdentities.onCreated.addListener(onContextualIdentityCreated);
|
|
browser.contextualIdentities.onRemoved.addListener(onContextualIdentityRemoved);
|
|
browser.contextualIdentities.onUpdated.addListener(onContextualIdentityUpdated);
|
|
mIsObserving = true;
|
|
}
|
|
|
|
export function startObserve() {
|
|
if (!browser.contextualIdentities ||
|
|
mIsObserving)
|
|
return;
|
|
mIsObserving = true;
|
|
browser.contextualIdentities.onCreated.addListener(onContextualIdentityCreated);
|
|
browser.contextualIdentities.onRemoved.addListener(onContextualIdentityRemoved);
|
|
browser.contextualIdentities.onUpdated.addListener(onContextualIdentityUpdated);
|
|
}
|
|
|
|
export function endObserve() {
|
|
if (!browser.contextualIdentities ||
|
|
!mIsObserving)
|
|
return;
|
|
browser.contextualIdentities.onCreated.removeListener(onContextualIdentityCreated);
|
|
browser.contextualIdentities.onRemoved.removeListener(onContextualIdentityRemoved);
|
|
browser.contextualIdentities.onUpdated.removeListener(onContextualIdentityUpdated);
|
|
}
|
|
|
|
export async function init() {
|
|
if (!browser.contextualIdentities)
|
|
return;
|
|
const identities = await browser.contextualIdentities.query({}).catch(ApiTabs.createErrorHandler());
|
|
for (const identity of identities) {
|
|
mContextualIdentities.set(identity.cookieStoreId, fixupIcon(identity));
|
|
}
|
|
}
|
|
|
|
function fixupIcon(identity) {
|
|
if (identity.icon && identity.color)
|
|
identity.iconUrl = `/resources/icons/contextual-identities/${identity.icon}.svg#${safeColor(identity.color)}`;
|
|
return identity;
|
|
}
|
|
|
|
const mDarkModeMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
|
mDarkModeMedia.addListener(async _event => {
|
|
await init();
|
|
forEach(identity => onContextualIdentityUpdated({ contextualIdentity: identity }));
|
|
});
|
|
|
|
function safeColor(color) {
|
|
switch (color) {
|
|
case 'blue':
|
|
case 'turquoise':
|
|
case 'green':
|
|
case 'yellow':
|
|
case 'orange':
|
|
case 'red':
|
|
case 'pink':
|
|
case 'purple':
|
|
return color;
|
|
|
|
case 'toolbar':
|
|
default:
|
|
return !isWindows() && mDarkModeMedia.matches ? 'toolbar-dark' : 'toolbar-light';
|
|
}
|
|
}
|
|
|
|
export const onUpdated = new EventListenerManager();
|
|
|
|
function onContextualIdentityCreated(createdInfo) {
|
|
if (!mIsObserving)
|
|
return;
|
|
|
|
const identity = createdInfo.contextualIdentity;
|
|
mContextualIdentities.set(identity.cookieStoreId, fixupIcon(identity));
|
|
onUpdated.dispatch();
|
|
}
|
|
|
|
function onContextualIdentityRemoved(removedInfo) {
|
|
if (!mIsObserving)
|
|
return;
|
|
|
|
const identity = removedInfo.contextualIdentity;
|
|
delete mContextualIdentities.delete(identity.cookieStoreId);
|
|
onUpdated.dispatch();
|
|
}
|
|
|
|
function onContextualIdentityUpdated(updatedInfo) {
|
|
if (!mIsObserving)
|
|
return;
|
|
|
|
const identity = updatedInfo.contextualIdentity;
|
|
mContextualIdentities.set(identity.cookieStoreId, fixupIcon(identity));
|
|
onUpdated.dispatch();
|
|
}
|
|
|
|
|
|
export function generateMenuItems({ hasDefault } = {}) {
|
|
const fragment = document.createDocumentFragment();
|
|
|
|
if (hasDefault) {
|
|
const defaultCotnainerItem = document.createElement('li');
|
|
defaultCotnainerItem.dataset.value = 'firefox-default';
|
|
defaultCotnainerItem.textContent = browser.i18n.getMessage('tabbar_newTabWithContexualIdentity_default');
|
|
fragment.appendChild(defaultCotnainerItem);
|
|
|
|
const separator = document.createElement('li');
|
|
separator.classList.add('separator');
|
|
fragment.appendChild(separator);
|
|
}
|
|
|
|
forEach(identity => {
|
|
const item = document.createElement('li');
|
|
item.dataset.value = identity.cookieStoreId;
|
|
item.textContent = identity.name;
|
|
item.dataset.icon = identity.iconUrl;
|
|
fragment.appendChild(item);
|
|
});
|
|
|
|
return fragment;
|
|
}
|