diff --git a/package.json b/package.json index 79c427b..0c71f2d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "toggle-experiment", "displayName": "Toggle Experiment", "description": "A browser extension to inject the LocalStorage of a website for Optimizely experiments.", - "version": "0.7.0", + "version": "0.8.0", "author": "Aaron van den Berg", "homepage": "https://aaronvandenberg.nl/", "scripts": { diff --git a/src/background.ts b/src/background.ts new file mode 100644 index 0000000..37eb078 --- /dev/null +++ b/src/background.ts @@ -0,0 +1,47 @@ +import { setLocalStorageValue } from "~local-storage-injector"; + +const broadcastChannel = new BroadcastChannel('broadcastChannel'); + +broadcastChannel.onmessage = (event) => { + const { data } = event; + const { history, localStorageKey } = data; + + // set the localStorageKey to the one that was sent from the content script + if (localStorageKey) { + chrome.storage.local.set({ + "localStorageKey": localStorageKey, + }, function () { + console.log(`localStorageKey is set to '${localStorageKey}'`); + }); + } + + if(history?.length > 1) { + // first remove all the context menus + chrome.contextMenus.removeAll(); + + // then create the new ones + history.forEach((item) => { + chrome.contextMenus.create({ + id: item.key, + title: `${item.name} (${item.key})`, + type: "normal", + contexts: ["all"], + }); + }) + } else { + chrome.contextMenus.removeAll(); + } +} + +chrome.contextMenus.onClicked.addListener(async (info, tabs) => { + chrome.storage.local.get(['localStorageKey'], async function(result) { + await chrome.scripting.executeScript( + { + target: { tabId: tabs.id }, + world: "MAIN", // MAIN in order to access the window object + func: setLocalStorageValue, + args: [result.localStorageKey, info.menuItemId] + } + ) + }); +}); diff --git a/src/components/HistoryItems.tsx b/src/components/HistoryItems.tsx index 220d34c..b2c3721 100644 --- a/src/components/HistoryItems.tsx +++ b/src/components/HistoryItems.tsx @@ -39,24 +39,19 @@ interface HistoryItemsProps { export function HistoryItems({ links, active }: HistoryItemsProps) { const { classes, cx } = useStyles(); const { localStorageKey, setLocalStorageValue } = useStore(state => state); - + const saveToLocalStorage = (value) => { setLocalStorageValue(value); - + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { updateLocalStorageValue(tabs[0].id, localStorageKey, value); }); }; - - const setHistoryValue = (e, itemKey) => { - e.preventDefault(); - saveToLocalStorage(itemKey); - } const items = links.map((item) => ( component="a" - onClick={(event) => setHistoryValue(event, item.key)} + onClick={() => saveToLocalStorage(item.key)} key={item.key} className={cx(classes.link, { [classes.linkActive]: active === item.key })} > @@ -72,4 +67,4 @@ export function HistoryItems({ links, active }: HistoryItemsProps) { {items} ); -} \ No newline at end of file +} diff --git a/src/components/SearchItem.tsx b/src/components/SearchItem.tsx index a565d85..fc28fd8 100644 --- a/src/components/SearchItem.tsx +++ b/src/components/SearchItem.tsx @@ -4,7 +4,9 @@ import { IconPlayerPlay, IconPlayerPause, IconPencil, IconQuestionMark, IconExte import useStore from "~store/useStore"; import { updateLocalStorageValue } from "~handlers/localStorageHandlers"; import { Storage } from "@plasmohq/storage"; -import type { HistoryItems } from '~types/types'; +import type { HistoryItems } from "~types/types"; + +const broadcastChannel = new BroadcastChannel("broadcastChannel"); const useStyles = createStyles((theme) => ({ card: { @@ -29,7 +31,7 @@ interface SearchItemProps { }; } -const storage = new Storage() +const storage = new Storage(); const SearchItem = ({ experiment }: SearchItemProps) => { const { classes } = useStyles(); @@ -66,23 +68,26 @@ const SearchItem = ({ experiment }: SearchItemProps) => { const addHistoryItem = async (newItem: HistoryItems) => { const maxHistoryItems = 3; const historyItemsLocalStorage = await storage.get("history"); - const newHistoryItems = historyItemsLocalStorage ? JSON.parse(historyItemsLocalStorage) : [] + const newHistoryItems = historyItemsLocalStorage ? JSON.parse(historyItemsLocalStorage) : []; - if(newHistoryItems.find((item: { key: string; }) => item.key === newItem.key)) { + if (newHistoryItems.find((item: { key: string; }) => item.key === newItem.key)) { return; } - if(newHistoryItems.length === maxHistoryItems) { + if (newHistoryItems.length >= maxHistoryItems) { newHistoryItems.shift(); } newHistoryItems.push(newItem); setHistoryItems(newHistoryItems); - } + + // Broadcast history to service worker + broadcastChannel.postMessage({ history: newHistoryItems }); + }; const saveToLocalStorage = (value, experimentName) => { setLocalStorageValue(value); - addHistoryItem({name: experimentName, key: value}); + addHistoryItem({ name: experimentName, key: value }); chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { updateLocalStorageValue(tabs[0].id, localStorageKey, value); @@ -141,7 +146,9 @@ const SearchItem = ({ experiment }: SearchItemProps) => { - + Optimizely diff --git a/src/components/settings/LocalStorageInputField.tsx b/src/components/settings/LocalStorageInputField.tsx index e3e7402..b242978 100644 --- a/src/components/settings/LocalStorageInputField.tsx +++ b/src/components/settings/LocalStorageInputField.tsx @@ -1,15 +1,27 @@ import { TextInput } from "@mantine/core"; import useStore from "~store/useStore"; +const broadcastChannel = new BroadcastChannel("broadcastChannel"); + const LocalStorageField = () => { - const { localStorageKey, setLocalStorageKey } = useStore(state => state); + const { localStorageKey, setLocalStorageKey, historyItems } = useStore(state => state); + + const handleChange = (value) => { + setLocalStorageKey(value) + + // Broadcast localStorageKey to service worker + broadcastChannel.postMessage({ + history: historyItems, + localStorageKey: value, + }); + } return ( setLocalStorageKey(e.target.value)} + onChange={(e) => handleChange(e.target.value)} mb="lg" /> ); diff --git a/src/popup/index.tsx b/src/popup/index.tsx index 821cfdc..9904a42 100644 --- a/src/popup/index.tsx +++ b/src/popup/index.tsx @@ -1,36 +1,53 @@ import { useEffect } from "react"; -import { Storage } from "@plasmohq/storage" +import { Storage } from "@plasmohq/storage"; import useStore from "~store/useStore"; import HomeScreen from "~screens/Home"; -import History from "~screens/History" +import History from "~screens/History"; import Settings from "~screens/Settings"; import Search from "~screens/Search"; import type { Screen } from "~types/types"; import ConnectOptimizely from "~screens/ConnectOptimizely"; -const storage = new Storage() +const storage = new Storage(); +const broadcastChannel = new BroadcastChannel("broadcastChannel"); function IndexPopup() { - const {setLocalStorageValue, screen, setLocalStorageKey, setOptimizelyAccessToken, setOptimizelyProjectId, setScreen} = useStore(state => state); + const { + setLocalStorageValue, + screen, + setLocalStorageKey, + setOptimizelyAccessToken, + setOptimizelyProjectId, + setScreen, + setHistoryItems + } = useStore(state => state); useEffect(() => { - const load = async () => { + const setInitialData = async () => { const key = await storage.get("localStorageKey"); const value = await storage.get("localStorageValue"); const defaultScreen = await storage.get("defaultScreen"); const optimizelyAccessToken = await storage.get("optimizelyAccessToken"); const optimizelyProjectId = await storage.get("optimizelyProjectId"); + const history = await storage.get("history"); setLocalStorageKey(key ?? "optimizelyNonLoggedInUser"); setLocalStorageValue(value ?? ""); setOptimizelyAccessToken(optimizelyAccessToken ?? ""); setOptimizelyProjectId(optimizelyProjectId ?? null); setScreen(defaultScreen ?? "home"); - } - load(); + setHistoryItems(history ? JSON.parse(history) : []); + + // Broadcast history and localStorageKey to service worker + broadcastChannel.postMessage({ + history: history ? JSON.parse(history) : null, + localStorageKey: key ?? "optimizelyNonLoggedInUser", + }); + }; + setInitialData(); }, []); return ( -
+
{screen === "home" && } {screen === "history" && } {screen === "settings" && } diff --git a/src/screens/History.tsx b/src/screens/History.tsx index 67a825b..6ace624 100644 --- a/src/screens/History.tsx +++ b/src/screens/History.tsx @@ -1,6 +1,5 @@ -import { useEffect, useState } from "react"; import Header from "~components/Header"; -import { Anchor, Card, Center, Button, Container } from "@mantine/core"; +import { Card, Center, Button, Container } from "@mantine/core"; import { IconTrash } from "@tabler/icons-react"; import { Storage } from "@plasmohq/storage"; import useStore from "~store/useStore"; @@ -8,28 +7,18 @@ import useStore from "~store/useStore"; import { HistoryItems } from "~components/HistoryItems"; const storage = new Storage(); +const broadcastChannel = new BroadcastChannel('broadcastChannel'); const History = () => { - const [historyItems, setHistoryItems] = useState([]); - const { localStorageValue } = useStore(state => state); - - useEffect(() => { - const load = async () => { - const historyLocalStorage = await storage.get("history"); - if (historyLocalStorage) { - const historyItemArray = JSON.parse(historyLocalStorage); - if (historyItemArray?.length > 0) { - setHistoryItems(historyItemArray); - } - } - }; - load(); - }, []); + const { localStorageValue, historyItems, setHistoryItems } = useStore(state => state); const clearHistory = async (e) => { e.preventDefault(); setHistoryItems([]); await storage.remove("history"); + + // broadcast to service worker + broadcastChannel.postMessage({ history: null }); }; return ( @@ -52,11 +41,6 @@ const History = () => { -
- - GitHub - -
);