Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to ask which container a page should be open in when it has no site assigned to it #2530

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/css/select-page.css
Original file line number Diff line number Diff line change
@@ -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;
}
45 changes: 40 additions & 5 deletions src/js/background/assignManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ window.assignManager = {
return !!replaceTabEnabled;
},

async getContainerPromptEnabled() {
const { containerPromptEnabled } = await browser.storage.local.get("containerPromptEnabled");
return !!containerPromptEnabled;
},

getByUrlKey(siteStoreKey) {
return new Promise((resolve, reject) => {
this.area.get([siteStoreKey]).then((storageResponse) => {
Expand Down Expand Up @@ -258,13 +263,18 @@ window.assignManager = {
const siteIsolatedReloadInDefault =
await this._maybeSiteIsolatedReloadInDefault(siteSettings, tab);

if (!siteIsolatedReloadInDefault) {
if (!siteSettings
|| userContextId === siteSettings.userContextId
|| this.storageArea.isExempted(options.url, tab.id)) {
// The site is not associated with a container and a container is not already
// being used to access it. In this case, we want to prompt the user to select
// a container before continuing.
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 {};
}
}

const replaceTabEnabled = await this.storageArea.getReplaceTabEnabled();
const removeTab = backgroundLogic.NEW_TAB_PAGES.has(tab.url)
|| (messageHandler.lastCreatedTab
Expand Down Expand Up @@ -314,7 +324,15 @@ window.assignManager = {
}
}

if (siteIsolatedReloadInDefault) {
if (promptReloadInContainer)
{
this.promptReloadPageInContainer(
options.url,
tab.index + 1,
tab.active,
openTabId
);
} else if (siteIsolatedReloadInDefault) {
this.reloadPageInDefaultContainer(
options.url,
tab.index + 1,
Expand All @@ -332,6 +350,7 @@ window.assignManager = {
openTabId
);
}

this.calculateContextMenu(tab);

/* Removal of existing tabs:
Expand Down Expand Up @@ -732,6 +751,22 @@ window.assignManager = {
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) {
const cookieStoreId = backgroundLogic.cookieStoreId(userContextId);
const loadPage = browser.runtime.getURL("confirm-page.html");
Expand Down
8 changes: 8 additions & 0 deletions src/js/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ async function enableDisableReplaceTab() {
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) {
const theme = event.currentTarget;
await browser.storage.local.set({currentTheme: theme.value});
Expand All @@ -62,10 +67,12 @@ async function changeTheme(event) {
async function setupOptions() {
const { syncEnabled } = await browser.storage.local.get("syncEnabled");
const { replaceTabEnabled } = await browser.storage.local.get("replaceTabEnabled");
const { containerPromptEnabled } = await browser.storage.local.get("containerPromptEnabled");
const { currentThemeId } = await browser.storage.local.get("currentThemeId");

document.querySelector("#syncCheck").checked = !!syncEnabled;
document.querySelector("#replaceTabCheck").checked = !!replaceTabEnabled;
document.querySelector("#containerPromptCheck").checked = !!containerPromptEnabled;
document.querySelector("#changeTheme").selectedIndex = currentThemeId;
setupContainerShortcutSelects();
}
Expand Down Expand Up @@ -123,6 +130,7 @@ browser.permissions.onRemoved.addListener(resetPermissionsUi);
document.addEventListener("DOMContentLoaded", setupOptions);
document.querySelector("#syncCheck").addEventListener( "change", enableDisableSync);
document.querySelector("#replaceTabCheck").addEventListener( "change", enableDisableReplaceTab);
document.querySelector("#containerPromptCheck").addEventListener( "change", enableDisableContainerPrompt);
document.querySelector("#changeTheme").addEventListener( "change", changeTheme);

maybeShowPermissionsWarningIcon();
Expand Down
83 changes: 83 additions & 0 deletions src/js/select-page.js
Original file line number Diff line number Diff line change
@@ -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
);
}
5 changes: 5 additions & 0 deletions src/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ <h3 data-i18n-message-id="tabBehavior"></h3>
<span class="bold" data-i18n-message-id="replaceTab"></span>
</label>
<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>

<!--
Expand Down
32 changes: 32 additions & 0 deletions src/select-page.html
Original file line number Diff line number Diff line change
@@ -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>