This commit is contained in:
Brad Sharp 2025-02-25 17:37:23 +01:00 committed by GitHub
commit c67f473927
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 275 additions and 5 deletions

107
src/css/select-page.css Normal file
View file

@ -0,0 +1,107 @@
/* General Rules and Resets */
.title {
background-image: none;
}
main {
background: url(/img/onboarding-4.png) no-repeat;
background-position: 200px 0;
background-size: 120px;
margin-inline-start: -350px;
padding-inline-start: 350px;
}
@media only screen and (max-width: 900px) {
main {
background: none;
}
/* for a mid sized window we have enough for this but not our image */
.title {
background-image: url('chrome://global/skin/icons/info.svg');
}
}
html {
box-sizing: border-box;
font: message-box;
}
#redirect-url,
#redirect-origin {
font-weight: bold;
/* max-inline-size is needed to force this text smaller than the layout at a mid-sized window */
max-inline-size: 40rem;
word-break: break-all;
}
#redirect-url {
background: #efedf0; /* Grey 20 */
border-radius: 2px;
line-height: 1.5;
padding-block-end: 0.5rem;
padding-block-start: 0.5rem;
padding-inline-end: 0.5rem;
padding-inline-start: 0.5rem;
}
/* stylelint-disable media-feature-name-no-unknown */
@media (prefers-color-scheme: dark) {
#redirect-url {
background: #38383d; /* Grey 70 */
color: #eee; /* White 20 */
}
}
/* stylelint-enable */
#redirect-url img {
block-size: 16px;
inline-size: 16px;
margin-inline-end: 6px;
offset-block-start: 3px;
position: relative;
}
dfn {
font-style: normal;
}
.check-label {
align-items: center;
display: flex;
}
#redirect-identities {
display: flex;
flex-wrap: wrap;
gap: 7.5px;
}
#redirect-identities button {
flex-grow: 1;
flex-basis: 180px;
margin: 0;
padding: 7.5px;
height: 60px;
display: flex;
align-items: center;
gap: 7.5px;
}
#redirect-identities button .primary {
flex-grow: 2;
flex-basis: 360px;
}
#redirect-identities button img {
position: relative;
width: 30px;
height: 30px;
filter: url('/img/filters.svg#fill');
}
#redirect-identities button label {
position: relative;
flex-grow: 1;
}

View file

@ -56,6 +56,11 @@ window.assignManager = {
return !!replaceTabEnabled; return !!replaceTabEnabled;
}, },
async getContainerPromptEnabled() {
const { containerPromptEnabled } = await browser.storage.local.get("containerPromptEnabled");
return !!containerPromptEnabled;
},
getByUrlKey(siteStoreKey) { getByUrlKey(siteStoreKey) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.area.get([siteStoreKey]).then((storageResponse) => { this.area.get([siteStoreKey]).then((storageResponse) => {
@ -265,13 +270,18 @@ window.assignManager = {
const siteIsolatedReloadInDefault = const siteIsolatedReloadInDefault =
await this._maybeSiteIsolatedReloadInDefault(siteSettings, tab); await this._maybeSiteIsolatedReloadInDefault(siteSettings, tab);
if (!siteIsolatedReloadInDefault) { // The site is not associated with a container and a container is not already
if (!siteSettings // being used to access it. In this case, we want to prompt the user to select
|| userContextId === siteSettings.userContextId // a container before continuing.
|| this.storageArea.isExempted(options.url, tab.id)) { const containerPromptEnabled = await this.storageArea.getContainerPromptEnabled();
const promptReloadInContainer = containerPromptEnabled && !siteSettings && !userContextId;
if (!siteIsolatedReloadInDefault && !promptReloadInContainer) {
if (!siteSettings || userContextId === siteSettings.userContextId || this.storageArea.isExempted(options.url, tab.id)) {
return {}; return {};
} }
} }
const replaceTabEnabled = await this.storageArea.getReplaceTabEnabled(); const replaceTabEnabled = await this.storageArea.getReplaceTabEnabled();
const removeTab = backgroundLogic.NEW_TAB_PAGES.has(tab.url) const removeTab = backgroundLogic.NEW_TAB_PAGES.has(tab.url)
|| (messageHandler.lastCreatedTab || (messageHandler.lastCreatedTab
@ -321,7 +331,15 @@ window.assignManager = {
} }
} }
if (siteIsolatedReloadInDefault) { if (promptReloadInContainer)
{
this.promptReloadPageInContainer(
options.url,
tab.index + 1,
tab.active,
openTabId
);
} else if (siteIsolatedReloadInDefault) {
this.reloadPageInDefaultContainer( this.reloadPageInDefaultContainer(
options.url, options.url,
tab.index + 1, tab.index + 1,
@ -339,6 +357,7 @@ window.assignManager = {
openTabId openTabId
); );
} }
this.calculateContextMenu(tab); this.calculateContextMenu(tab);
/* Removal of existing tabs: /* Removal of existing tabs:
@ -749,6 +768,22 @@ window.assignManager = {
browser.tabs.create({url, cookieStoreId, index, active, openerTabId}); browser.tabs.create({url, cookieStoreId, index, active, openerTabId});
}, },
promptReloadPageInContainer(url, index, active, openerTabId = null) {
const loadPage = browser.runtime.getURL("select-page.html");
let confirmUrl = `${loadPage}?url=${this.encodeURLProperty(url)}`;
return browser.tabs.create({
url: confirmUrl,
openerTabId,
index,
active
}).then(async () => {
// We don't want to sync this URL ever nor clutter the users history
browser.history.deleteUrl({url: confirmUrl});
}).catch((e) => {
throw e;
});
},
reloadPageInContainer(url, currentUserContextId, userContextId, index, active, neverAsk = false, openerTabId = null) { reloadPageInContainer(url, currentUserContextId, userContextId, index, active, neverAsk = false, openerTabId = null) {
const cookieStoreId = backgroundLogic.cookieStoreId(userContextId); const cookieStoreId = backgroundLogic.cookieStoreId(userContextId);
const loadPage = browser.runtime.getURL("confirm-page.html"); const loadPage = browser.runtime.getURL("confirm-page.html");

View file

@ -53,6 +53,11 @@ async function enableDisableReplaceTab() {
await browser.storage.local.set({replaceTabEnabled: !!checkbox.checked}); await browser.storage.local.set({replaceTabEnabled: !!checkbox.checked});
} }
async function enableDisableContainerPrompt() {
const checkbox = document.querySelector("#containerPromptCheck");
await browser.storage.local.set({containerPromptEnabled: !!checkbox.checked});
}
async function changeTheme(event) { async function changeTheme(event) {
const theme = event.currentTarget; const theme = event.currentTarget;
await browser.storage.local.set({currentTheme: theme.value}); await browser.storage.local.set({currentTheme: theme.value});
@ -62,10 +67,12 @@ async function changeTheme(event) {
async function setupOptions() { async function setupOptions() {
const { syncEnabled } = await browser.storage.local.get("syncEnabled"); const { syncEnabled } = await browser.storage.local.get("syncEnabled");
const { replaceTabEnabled } = await browser.storage.local.get("replaceTabEnabled"); const { replaceTabEnabled } = await browser.storage.local.get("replaceTabEnabled");
const { containerPromptEnabled } = await browser.storage.local.get("containerPromptEnabled");
const { currentThemeId } = await browser.storage.local.get("currentThemeId"); const { currentThemeId } = await browser.storage.local.get("currentThemeId");
document.querySelector("#syncCheck").checked = !!syncEnabled; document.querySelector("#syncCheck").checked = !!syncEnabled;
document.querySelector("#replaceTabCheck").checked = !!replaceTabEnabled; document.querySelector("#replaceTabCheck").checked = !!replaceTabEnabled;
document.querySelector("#containerPromptCheck").checked = !!containerPromptEnabled;
document.querySelector("#changeTheme").selectedIndex = currentThemeId; document.querySelector("#changeTheme").selectedIndex = currentThemeId;
setupContainerShortcutSelects(); setupContainerShortcutSelects();
} }
@ -123,6 +130,7 @@ browser.permissions.onRemoved.addListener(resetPermissionsUi);
document.addEventListener("DOMContentLoaded", setupOptions); document.addEventListener("DOMContentLoaded", setupOptions);
document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync); document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync);
document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab); document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab);
document.querySelector("#containerPromptCheck").addEventListener( "change", enableDisableContainerPrompt);
document.querySelector("#changeTheme").addEventListener( "change", changeTheme); document.querySelector("#changeTheme").addEventListener( "change", changeTheme);
maybeShowPermissionsWarningIcon(); maybeShowPermissionsWarningIcon();

83
src/js/select-page.js Normal file
View file

@ -0,0 +1,83 @@
async function load() {
const searchParams = new URL(window.location).searchParams;
const redirectUrl = searchParams.get("url");
const redirectUrlElement = document.getElementById("redirect-url");
redirectUrlElement.textContent = redirectUrl;
appendFavicon(redirectUrl, redirectUrlElement);
const identities = await browser.contextualIdentities.query({});
const redirectFormElement = document.getElementById("redirect-identities");
identities.forEach(identity => {
const cookieStoreId = identity.cookieStoreId;
var containerButtonElement = document.createElement("button");
containerButtonElement.classList.add("button");
containerButtonElement.id = "container-" + identity.name;
containerButtonElement.setAttribute("container-id", cookieStoreId);
containerButtonElement.addEventListener("click", e => {
e.preventDefault();
selectContainer(redirectUrl, identity)
})
var containerIconElement = document.createElement("img");
containerIconElement.src = identity.iconUrl;
containerIconElement.alt = identity.icon;
containerIconElement.style.fill = identity.colorCode;
var containerLabelElement = document.createElement("label");
containerLabelElement.textContent = identity.name;
containerButtonElement.appendChild(containerIconElement);
containerButtonElement.appendChild(containerLabelElement);
redirectFormElement.appendChild(containerButtonElement);
})
document.querySelectorAll("[data-message-id]").forEach(el => {
const elementData = el.dataset;
el.textContent = browser.i18n.getMessage(elementData.messageId);
});
}
function appendFavicon(pageUrl, redirectUrlElement) {
const origin = new URL(pageUrl).origin;
const favIconElement = Utils.createFavIconElement(`${origin}/favicon.ico`);
redirectUrlElement.prepend(favIconElement);
}
function getCurrentTab() {
return browser.tabs.query({
active: true,
windowId: browser.windows.WINDOW_ID_CURRENT
});
}
load();
function selectContainer(redirectUrl, identity){
const neverAsk = document.getElementById("never-ask").checked;
if (neverAsk) {
assignContainer(redirectUrl, identity);
}
openInContainer(redirectUrl, identity.cookieStoreId);
}
async function openInContainer(redirectUrl, cookieStoreId) {
const tab = await getCurrentTab();
await browser.tabs.create({
index: tab[0].index + 1,
cookieStoreId,
url: redirectUrl
});
if (tab.length > 0) {
browser.tabs.remove(tab[0].id);
}
}
async function assignContainer(redirectUrl, identity) {
const currentTab = await Utils.currentTab();
const assignedUserContextId = Utils.userContextId(identity.cookieStoreId);
await Utils.setOrRemoveAssignment(
null,
redirectUrl,
assignedUserContextId,
false
);
}

View file

@ -57,6 +57,11 @@
<span class="bold" data-i18n-message-id="replaceTab"></span> <span class="bold" data-i18n-message-id="replaceTab"></span>
</label> </label>
<p><em data-i18n-message-id="replaceTabDescription"></em></p> <p><em data-i18n-message-id="replaceTabDescription"></em></p>
<label>
<input type="checkbox" id="containerPromptCheck">
<span class="bold" data-i18n-message-id="containerPrompt"></span>
</label>
<p><em data-i18n-message-id="containerPromptDescription"></em></p>
</div> </div>
<!-- <!--

32
src/select-page.html Normal file
View file

@ -0,0 +1,32 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title data-i18n-message-id="confirmNavigationTitle"></title>
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="chrome://browser/skin/aboutNetError.css" type="text/css" media="all" />
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="chrome://global/skin/aboutNetError.css" type="text/css" media="all" />
<script type="text/javascript" src="./js/i18n.js"></script>
<link rel="stylesheet" href="/css/select-page.css" />
</head>
<body>
<main>
<div class="title">
<h1 class="title-text" data-i18n-message-id="whichContainerDoYouWantToUse"></h1>
</div>
<form id="redirect-form">
<p data-message-id="noAssociatedContainer"></p>
<div id="redirect-url"></div>
<p data-i18n-message-id="whichContainerDoYouWantToOpen"></p>
<br />
<br />
<label for="never-ask" class="check-label">
<input id="never-ask" type="checkbox" />
<span data-i18n-message-id="rememberMyDecision"></span>
</label>
<br />
<div id="redirect-identities"></div>
</form>
</main>
<script src="js/utils.js"></script>
<script src="js/select-page.js"></script>
</body>
</html>