Compare commits

..

4 Commits

5 changed files with 126 additions and 2 deletions

View File

@ -0,0 +1,56 @@
import browser from 'webextension-polyfill';
import {updateBadge} from '../utilities/badge.js';
type ContextMenu = browser.Menus.CreateCreatePropertiesType;
export function getContextMenus(): ContextMenu[] {
const actionContext =
import.meta.env.VITE_BROWSER === 'chromium' ? 'action' : 'browser_action';
const contextMenus: ContextMenu[] = [
{
id: 're-nav-toggle-redirects',
title: 'Toggle all redirects',
contexts: [actionContext],
},
];
return contextMenus;
}
export async function initializeContextMenus(): Promise<void> {
const contextMenus = getContextMenus();
await browser.contextMenus.removeAll();
for (const contextMenu of contextMenus) {
browser.contextMenus.create(contextMenu, contextCreated);
}
}
function contextCreated(): void {
const error = browser.runtime.lastError;
if (error !== null && error !== undefined) {
console.error('Re-Nav', error.message);
}
}
export async function contextClicked(
contextMenuIds: Set<string>,
info: browser.Menus.OnClickData,
tab?: browser.Tabs.Tab,
): Promise<void> {
const id = info.menuItemId.toString();
if (!contextMenuIds.has(id)) {
return;
}
if (id === 're-nav-toggle-redirects') {
const state = await browser.storage.local.get({redirectsEnabled: true});
const redirectsEnabled = !(state.redirectsEnabled as boolean);
await browser.storage.local.set({redirectsEnabled});
await updateBadge(redirectsEnabled);
}
}

View File

@ -1,6 +1,12 @@
import browser from 'webextension-polyfill'; import browser from 'webextension-polyfill';
import storage from '../redirect/storage.js'; import storage from '../redirect/storage.js';
import {updateBadge} from '../utilities/badge.js';
import {
contextClicked,
getContextMenus,
initializeContextMenus,
} from './context-menus.js';
async function browserActionClicked() { async function browserActionClicked() {
await browser.runtime.openOptionsPage(); await browser.runtime.openOptionsPage();
@ -10,15 +16,30 @@ if (import.meta.env.VITE_BROWSER === 'chromium') {
browser.action.onClicked.addListener(browserActionClicked); browser.action.onClicked.addListener(browserActionClicked);
} else { } else {
browser.browserAction.onClicked.addListener(browserActionClicked); browser.browserAction.onClicked.addListener(browserActionClicked);
void initializeContextMenus();
} }
browser.runtime.onInstalled.addListener(async () => { browser.runtime.onInstalled.addListener(async () => {
await initializeContextMenus();
await updateBadge();
if (import.meta.env.DEV) { if (import.meta.env.DEV) {
await browser.runtime.openOptionsPage(); await browser.runtime.openOptionsPage();
} }
}); });
browser.runtime.onStartup.addListener(async () => {
await updateBadge();
});
browser.webNavigation.onBeforeNavigate.addListener(async (details) => { browser.webNavigation.onBeforeNavigate.addListener(async (details) => {
const {redirectsEnabled} = await browser.storage.local.get({
redirectsEnabled: true,
});
if (redirectsEnabled === false) {
return;
}
if (!details.url.startsWith('http') || details.frameId > 0) { if (!details.url.startsWith('http') || details.frameId > 0) {
return; return;
} }
@ -29,6 +50,10 @@ browser.webNavigation.onBeforeNavigate.addListener(async (details) => {
return; return;
} }
const tab = await browser.tabs.query({active: true, lastFocusedWindow: true});
const currentTabUrl =
tab[0]?.url === undefined ? undefined : new URL(tab[0].url);
const url = new URL(details.url); const url = new URL(details.url);
const {latestUrl} = await browser.storage.local.get('latestUrl'); const {latestUrl} = await browser.storage.local.get('latestUrl');
if (redirectDelta < 30_000 && url.href === latestUrl) { if (redirectDelta < 30_000 && url.href === latestUrl) {
@ -41,6 +66,15 @@ browser.webNavigation.onBeforeNavigate.addListener(async (details) => {
} }
if (redirect.isMatch(url)) { if (redirect.isMatch(url)) {
// Don't redirect if the URL before going to a new page is also a match.
// This will happen when the user is already on a website that has a
// redirect, but for whatever reason hasn't redirected. So it's safe to
// assume that they want to stay on this website, rather than get
// redirected.
if (currentTabUrl !== undefined && redirect.isMatch(currentTabUrl)) {
break;
}
const redirectedUrl = redirect.redirect(url); const redirectedUrl = redirect.redirect(url);
await browser.tabs.update(details.tabId, {url: redirectedUrl.href}); await browser.tabs.update(details.tabId, {url: redirectedUrl.href});
await browser.storage.local.set({ await browser.storage.local.set({
@ -51,3 +85,12 @@ browser.webNavigation.onBeforeNavigate.addListener(async (details) => {
} }
} }
}); });
browser.contextMenus.onClicked.addListener(async (info, tab) => {
const contextMenus = getContextMenus();
const contextMenuIds = new Set<string>(
contextMenus.map(({id}) => id ?? 're-nav-unknown'),
);
await contextClicked(contextMenuIds, info, tab);
});

View File

@ -7,7 +7,7 @@ export default function createManifest(
name: 'Re-Nav', name: 'Re-Nav',
description: 'Navigation redirects for the masses.', description: 'Navigation redirects for the masses.',
version: '0.1.1', version: '0.1.1',
permissions: ['storage', 'webNavigation'], permissions: ['contextMenus', 'storage', 'tabs', 'webNavigation'],
options_ui: { options_ui: {
page: 'options/index.html', page: 'options/index.html',
open_in_tab: true, open_in_tab: true,

View File

@ -68,7 +68,7 @@ export class PageMain extends Component<Props, State> {
id: await storage.nextRedirectId(), id: await storage.nextRedirectId(),
matcherType: 'hostname', matcherType: 'hostname',
matcherValue: 'example.com', matcherValue: 'example.com',
redirectType: 'simple', redirectType: 'hostname',
redirectValue: 'example.org', redirectValue: 'example.org',
}); });
await storage.savePrepared(await storage.prepareForStorage(redirect)); await storage.savePrepared(await storage.prepareForStorage(redirect));

25
source/utilities/badge.ts Normal file
View File

@ -0,0 +1,25 @@
import browser from 'webextension-polyfill';
export async function updateBadge(redirectsEnabled?: boolean): Promise<void> {
if (redirectsEnabled === undefined) {
const state = await browser.storage.local.get({redirectsEnabled: true});
redirectsEnabled = state.redirectsEnabled as boolean;
}
let action: browser.Action.Static = browser.browserAction;
if (import.meta.env.VITE_BROWSER === 'chromium') {
action = browser.action;
}
await action.setBadgeText({
text: redirectsEnabled ? '' : '✗',
});
await action.setBadgeBackgroundColor({
color: '#f99fb1',
});
if (import.meta.env.VITE_BROWSER === 'firefox') {
action.setBadgeTextColor({color: '#2a2041'});
}
}