Skip to content

Commit 4204f22

Browse files
authored
Merge pull request #41 from aaron5670/feature/service-worker-with-context-menu
Feature: Added service worker that listens to a dynamic ContextMenu
2 parents c254c03 + 25ae974 commit 4204f22

File tree

7 files changed

+112
-50
lines changed

7 files changed

+112
-50
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "toggle-experiment",
33
"displayName": "Toggle Experiment",
44
"description": "A browser extension to inject the LocalStorage of a website for Optimizely experiments.",
5-
"version": "0.7.0",
5+
"version": "0.8.0",
66
"author": "Aaron van den Berg",
77
"homepage": "https://aaronvandenberg.nl/",
88
"scripts": {

src/background.ts

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { setLocalStorageValue } from "~local-storage-injector";
2+
3+
const broadcastChannel = new BroadcastChannel('broadcastChannel');
4+
5+
broadcastChannel.onmessage = (event) => {
6+
const { data } = event;
7+
const { history, localStorageKey } = data;
8+
9+
// set the localStorageKey to the one that was sent from the content script
10+
if (localStorageKey) {
11+
chrome.storage.local.set({
12+
"localStorageKey": localStorageKey,
13+
}, function () {
14+
console.log(`localStorageKey is set to '${localStorageKey}'`);
15+
});
16+
}
17+
18+
if(history?.length > 1) {
19+
// first remove all the context menus
20+
chrome.contextMenus.removeAll();
21+
22+
// then create the new ones
23+
history.forEach((item) => {
24+
chrome.contextMenus.create({
25+
id: item.key,
26+
title: `${item.name} (${item.key})`,
27+
type: "normal",
28+
contexts: ["all"],
29+
});
30+
})
31+
} else {
32+
chrome.contextMenus.removeAll();
33+
}
34+
}
35+
36+
chrome.contextMenus.onClicked.addListener(async (info, tabs) => {
37+
chrome.storage.local.get(['localStorageKey'], async function(result) {
38+
await chrome.scripting.executeScript(
39+
{
40+
target: { tabId: tabs.id },
41+
world: "MAIN", // MAIN in order to access the window object
42+
func: setLocalStorageValue,
43+
args: [result.localStorageKey, info.menuItemId]
44+
}
45+
)
46+
});
47+
});

src/components/HistoryItems.tsx

+4-9
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,19 @@ interface HistoryItemsProps {
3939
export function HistoryItems({ links, active }: HistoryItemsProps) {
4040
const { classes, cx } = useStyles();
4141
const { localStorageKey, setLocalStorageValue } = useStore(state => state);
42-
42+
4343
const saveToLocalStorage = (value) => {
4444
setLocalStorageValue(value);
45-
45+
4646
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
4747
updateLocalStorageValue(tabs[0].id, localStorageKey, value);
4848
});
4949
};
50-
51-
const setHistoryValue = (e, itemKey) => {
52-
e.preventDefault();
53-
saveToLocalStorage(itemKey);
54-
}
5550

5651
const items = links.map((item) => (
5752
<Box<'a'>
5853
component="a"
59-
onClick={(event) => setHistoryValue(event, item.key)}
54+
onClick={() => saveToLocalStorage(item.key)}
6055
key={item.key}
6156
className={cx(classes.link, { [classes.linkActive]: active === item.key })}
6257
>
@@ -72,4 +67,4 @@ export function HistoryItems({ links, active }: HistoryItemsProps) {
7267
{items}
7368
</>
7469
);
75-
}
70+
}

src/components/SearchItem.tsx

+15-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import { IconPlayerPlay, IconPlayerPause, IconPencil, IconQuestionMark, IconExte
44
import useStore from "~store/useStore";
55
import { updateLocalStorageValue } from "~handlers/localStorageHandlers";
66
import { Storage } from "@plasmohq/storage";
7-
import type { HistoryItems } from '~types/types';
7+
import type { HistoryItems } from "~types/types";
8+
9+
const broadcastChannel = new BroadcastChannel("broadcastChannel");
810

911
const useStyles = createStyles((theme) => ({
1012
card: {
@@ -29,7 +31,7 @@ interface SearchItemProps {
2931
};
3032
}
3133

32-
const storage = new Storage()
34+
const storage = new Storage();
3335

3436
const SearchItem = ({ experiment }: SearchItemProps) => {
3537
const { classes } = useStyles();
@@ -66,23 +68,26 @@ const SearchItem = ({ experiment }: SearchItemProps) => {
6668
const addHistoryItem = async (newItem: HistoryItems) => {
6769
const maxHistoryItems = 3;
6870
const historyItemsLocalStorage = await storage.get("history");
69-
const newHistoryItems = historyItemsLocalStorage ? JSON.parse(historyItemsLocalStorage) : []
71+
const newHistoryItems = historyItemsLocalStorage ? JSON.parse(historyItemsLocalStorage) : [];
7072

71-
if(newHistoryItems.find((item: { key: string; }) => item.key === newItem.key)) {
73+
if (newHistoryItems.find((item: { key: string; }) => item.key === newItem.key)) {
7274
return;
7375
}
7476

75-
if(newHistoryItems.length === maxHistoryItems) {
77+
if (newHistoryItems.length >= maxHistoryItems) {
7678
newHistoryItems.shift();
7779
}
7880

7981
newHistoryItems.push(newItem);
8082
setHistoryItems(newHistoryItems);
81-
}
83+
84+
// Broadcast history to service worker
85+
broadcastChannel.postMessage({ history: newHistoryItems });
86+
};
8287

8388
const saveToLocalStorage = (value, experimentName) => {
8489
setLocalStorageValue(value);
85-
addHistoryItem({name: experimentName, key: value});
90+
addHistoryItem({ name: experimentName, key: value });
8691

8792
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
8893
updateLocalStorageValue(tabs[0].id, localStorageKey, value);
@@ -141,7 +146,9 @@ const SearchItem = ({ experiment }: SearchItemProps) => {
141146
</Text>
142147
</Group>
143148
<Text>
144-
<Anchor href={`https://app.optimizely.com/v2/projects/${experiment.project_id}/experiments/${experiment.id}`} target="_blank">
149+
<Anchor
150+
href={`https://app.optimizely.com/v2/projects/${experiment.project_id}/experiments/${experiment.id}`}
151+
target="_blank">
145152
<IconExternalLink size={18} stroke={1.5} style={{ marginBottom: -4 }} /> Optimizely
146153
</Anchor>
147154
</Text>

src/components/settings/LocalStorageInputField.tsx

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
import { TextInput } from "@mantine/core";
22
import useStore from "~store/useStore";
33

4+
const broadcastChannel = new BroadcastChannel("broadcastChannel");
5+
46
const LocalStorageField = () => {
5-
const { localStorageKey, setLocalStorageKey } = useStore(state => state);
7+
const { localStorageKey, setLocalStorageKey, historyItems } = useStore(state => state);
8+
9+
const handleChange = (value) => {
10+
setLocalStorageKey(value)
11+
12+
// Broadcast localStorageKey to service worker
13+
broadcastChannel.postMessage({
14+
history: historyItems,
15+
localStorageKey: value,
16+
});
17+
}
618

719
return (
820
<TextInput
921
label="LocalStorage key"
1022
description="Default value: optimizelyNonLoggedInUser"
1123
value={localStorageKey}
12-
onChange={(e) => setLocalStorageKey(e.target.value)}
24+
onChange={(e) => handleChange(e.target.value)}
1325
mb="lg"
1426
/>
1527
);

src/popup/index.tsx

+25-8
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,53 @@
11
import { useEffect } from "react";
2-
import { Storage } from "@plasmohq/storage"
2+
import { Storage } from "@plasmohq/storage";
33
import useStore from "~store/useStore";
44
import HomeScreen from "~screens/Home";
5-
import History from "~screens/History"
5+
import History from "~screens/History";
66
import Settings from "~screens/Settings";
77
import Search from "~screens/Search";
88
import type { Screen } from "~types/types";
99
import ConnectOptimizely from "~screens/ConnectOptimizely";
1010

11-
const storage = new Storage()
11+
const storage = new Storage();
12+
const broadcastChannel = new BroadcastChannel("broadcastChannel");
1213

1314
function IndexPopup() {
14-
const {setLocalStorageValue, screen, setLocalStorageKey, setOptimizelyAccessToken, setOptimizelyProjectId, setScreen} = useStore(state => state);
15+
const {
16+
setLocalStorageValue,
17+
screen,
18+
setLocalStorageKey,
19+
setOptimizelyAccessToken,
20+
setOptimizelyProjectId,
21+
setScreen,
22+
setHistoryItems
23+
} = useStore(state => state);
1524

1625
useEffect(() => {
17-
const load = async () => {
26+
const setInitialData = async () => {
1827
const key = await storage.get("localStorageKey");
1928
const value = await storage.get("localStorageValue");
2029
const defaultScreen = await storage.get<Screen | null>("defaultScreen");
2130
const optimizelyAccessToken = await storage.get("optimizelyAccessToken");
2231
const optimizelyProjectId = await storage.get("optimizelyProjectId");
32+
const history = await storage.get("history");
2333
setLocalStorageKey(key ?? "optimizelyNonLoggedInUser");
2434
setLocalStorageValue(value ?? "");
2535
setOptimizelyAccessToken(optimizelyAccessToken ?? "");
2636
setOptimizelyProjectId(optimizelyProjectId ?? null);
2737
setScreen(defaultScreen ?? "home");
28-
}
29-
load();
38+
setHistoryItems(history ? JSON.parse(history) : []);
39+
40+
// Broadcast history and localStorageKey to service worker
41+
broadcastChannel.postMessage({
42+
history: history ? JSON.parse(history) : null,
43+
localStorageKey: key ?? "optimizelyNonLoggedInUser",
44+
});
45+
};
46+
setInitialData();
3047
}, []);
3148

3249
return (
33-
<div style={{width: 350}}>
50+
<div style={{ width: 350 }}>
3451
{screen === "home" && <HomeScreen />}
3552
{screen === "history" && <History />}
3653
{screen === "settings" && <Settings />}

src/screens/History.tsx

+6-22
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,24 @@
1-
import { useEffect, useState } from "react";
21
import Header from "~components/Header";
3-
import { Anchor, Card, Center, Button, Container } from "@mantine/core";
2+
import { Card, Center, Button, Container } from "@mantine/core";
43
import { IconTrash } from "@tabler/icons-react";
54
import { Storage } from "@plasmohq/storage";
65
import useStore from "~store/useStore";
76

87
import { HistoryItems } from "~components/HistoryItems";
98

109
const storage = new Storage();
10+
const broadcastChannel = new BroadcastChannel('broadcastChannel');
1111

1212
const History = () => {
13-
const [historyItems, setHistoryItems] = useState([]);
14-
const { localStorageValue } = useStore(state => state);
15-
16-
useEffect(() => {
17-
const load = async () => {
18-
const historyLocalStorage = await storage.get("history");
19-
if (historyLocalStorage) {
20-
const historyItemArray = JSON.parse(historyLocalStorage);
21-
if (historyItemArray?.length > 0) {
22-
setHistoryItems(historyItemArray);
23-
}
24-
}
25-
};
26-
load();
27-
}, []);
13+
const { localStorageValue, historyItems, setHistoryItems } = useStore(state => state);
2814

2915
const clearHistory = async (e) => {
3016
e.preventDefault();
3117
setHistoryItems([]);
3218
await storage.remove("history");
19+
20+
// broadcast to service worker
21+
broadcastChannel.postMessage({ history: null });
3322
};
3423

3524
return (
@@ -52,11 +41,6 @@ const History = () => {
5241
</Button>
5342
</Center>
5443
</Container>
55-
<Center>
56-
<Anchor href="https://github.com/aaron5670/toggle-experiments-extension" target="_blank" mt="md">
57-
GitHub
58-
</Anchor>
59-
</Center>
6044
</Card>
6145
</>
6246
);

0 commit comments

Comments
 (0)