diff --git a/package.json b/package.json index ec79030..0a6d674 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "firefox:web": "vite build --watch", "firefox:preview": "vite preview", "firefox:build": "tsup src/background src/content --format iife --out-dir extension/dist --no-splitting", - "firefox:open": "npm run wait && web-ext run --start-url \"about:debugging#/runtime/this-firefox\" --source-dir ./extension/ --no-reload --browser-console", + "firefox:open": "npm run wait && web-ext run --start-url \"about:debugging#/runtime/this-firefox\" --source-dir ./extension/ --browser-console", "build:chrome": "run-s clear build:web build:prepare build:js", "build:firefox": "run-s clear build:web 'build:prepare -- --firefox' build:js", "build:prepare": "esno scripts/prepare.ts build", diff --git a/packageOld.json b/packageOld.json deleted file mode 100644 index 5419438..0000000 --- a/packageOld.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "superkeys", - "displayName": "SuperKeys", - "description": "_THIS EXTENSION IS IN BETA_ Superkeys allow users to add short keys for websites and make search query in those sites.", - "version": "1.0.0", - "private": true, - "scripts": { - "dev": "FIREFOX=true run-p dev:* open:firefox", - "run:chrome": "run-p build:watch preview open:chrome", - "dev:prepare": "esno scripts/prepare.ts dev", - "dev:web": "vite", - "dev:js": "npm run build:js -- --watch .", - "build": "run-s clear build:web build:prepare build:js", - "build:prepare": "esno scripts/prepare.ts build", - "build:web": "vite build", - "build:js": "tsup src/background src/content --format iife --out-dir extension/dist --no-splitting", - "build:watch": "vite build --watch", - "clear": "rimraf extension/dist", - "build:firefox": "FIREFOX=true run-s clear build:web build:prepare build:js", - "prod": "run-s clear build:web build:prepare build:js && cd extension && web-ext build --overwrite-dest", - "prod:firefox": "FIREFOX=true npm run prod", - "wait-ext": "wait-on http://localhost:4173/options/index.html", - "open:firefox": "npm run wait-ext && npm run web-ext run --start-url \"about:debugging#/runtime/this-firefox\" --source-dir ./extension/", - "open:chrome": "npm run wait-ext && npm run wait-ext && web-ext run -t chromium --start-url \"https://stackoverflow.com\" --source-dir ./extension/", - "preview": "vite preview" - }, - "devDependencies": { - "@iconify/react": "^3.2.2", - "@preact/preset-vite": "^2.1.0", - "@types/chrome": "^0.0.191", - "@types/fs-extra": "^9.0.12", - "@types/node": "^16.4.1", - "@types/webextension-polyfill": "^0.9.0", - "autoprefixer": "^10.4.7", - "chokidar": "^3.5.2", - "cross-env": "^7.0.3", - "esno": "^0.8.0", - "fs-extra": "^10.0.0", - "kolorist": "^1.5.0", - "npm-run-all": "^4.1.5", - "postcss": "^8.4.14", - "preact": "^10.5.14", - "rimraf": "^3.0.2", - "tailwindcss": "^3.1.2", - "tsup": "^4.12.5", - "typescript": "^4.3.5", - "vite": "^2.4.3", - "wait-on": "^6.0.1", - "web-ext": "^7.0.0", - "webext-bridge": "^4.0.0", - "webextension-polyfill": "^0.9.0", - "webextension-polyfill-ts": "^0.26.0" - }, - "dependencies": { - "daisyui": "^2.15.3", - "prettier": "^2.6.2", - "react-drag-drop-files": "^2.3.7", - "react-hook-form": "^7.32.0", - "react-simple-flex-grid": "^1.3.21" - } -} diff --git a/src/background/events.ts b/src/background/events.ts new file mode 100644 index 0000000..fa8685f --- /dev/null +++ b/src/background/events.ts @@ -0,0 +1,40 @@ +import browser from "webextension-polyfill"; +import { KEY_PREFIX } from "../constants"; +import { StorageChange } from "../types"; + + + +export const handleStorageChange = async (changes: { + [index: string]: StorageChange +}) => { + { + const changedArray: StorageChange[] = Object.values(changes) + + if(!changedArray?.length) return null; + + changedArray.forEach(({oldValue, newValue}: StorageChange) => { + // ADD KEY + if(!oldValue && newValue) { + console.log({'create': true, oldValue, newValue}); + browser.contextMenus.create({ + title: `Search on ${newValue.url}`, + contexts: ["selection"], + id: `${KEY_PREFIX}-${newValue.id}`, + }); + } + // REMOVE KEY + else if (oldValue && !newValue){ + console.log({'REMOVE': true, oldValue, newValue}); + browser.contextMenus.remove(oldValue.id); + } + // EDIT KEY + else if (oldValue && newValue){ + console.log({'EDIT': true, oldValue, newValue}); + browser.contextMenus.update(oldValue.id, { + title: `Search on ${newValue.url}`, + contexts: ["selection"], + }); + } + }) + } +} \ No newline at end of file diff --git a/src/background/index.ts b/src/background/index.ts index d93a6bb..d2e7278 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,50 +1,70 @@ -import browser from "webextension-polyfill"; +import browser, { Menus } from "webextension-polyfill"; import { keyLists } from "./superkey.db.json"; +import { handleStorageChange } from "./events"; +import { KEY_PREFIX } from "../constants"; -const KEY_PREFIX = "superkey"; +interface IDefaultMenu extends Menus.CreateCreatePropertiesType{ + // for future +} + +const DEFAULT_CONTEXT_MENUS: IDefaultMenu[] = [ + { + title: `Manage Keys`, + contexts: ["all"], + id: `addNew`, + } +] + +const handleDefaultMenuClick = async (id: string) => { + const defaultKey = DEFAULT_CONTEXT_MENUS.find(each => each.id === id) + let urlToGo:string = ''; + if(defaultKey?.id === 'addNew') + urlToGo = browser.runtime.getURL('dist/options/index.html') + + return urlToGo && browser.tabs.create({ + url: urlToGo, + }); +} -function handleSearch(info: any, tab: any) { +async function handleSearch(info: any, tab: any) { const [keyPrefix, indexKey] = info.menuItemId.split("-"); - if (keyPrefix !== KEY_PREFIX || !info.selectionText) return; + if (keyPrefix !== KEY_PREFIX) return; + + await handleDefaultMenuClick(indexKey) + + if(!info.index) return; browser.storage.sync.get(indexKey).then((item) => { const keyItem = item[indexKey]; - browser.tabs.create({ + return keyItem && browser.tabs.create({ url: `${keyItem.queryUrl}=${encodeURI(info.selectionText)}`, }); }); } browser.runtime.onInstalled.addListener(async () => { + // CLEAN ALL CONTEXT MENU BEFORE ADDING/RESETTING ALL KEYS + await browser.contextMenus.removeAll() + + // Add Default Menus + DEFAULT_CONTEXT_MENUS.forEach(({title,contexts,id }:Menus.CreateCreatePropertiesType) => + browser.contextMenus.create({ + title,contexts,id: `${KEY_PREFIX}-${id}` + })) + + // Add User Keys keyLists.forEach((keyItem, index) => { const indexKey = index + 1; browser.storage.sync // @ts-ignore .set({ [indexKey]: { id: indexKey, ...keyItem } }) // TODO: Test carefully. .then(() => browser.runtime.openOptionsPage()); - - // context menu - if (keyItem.queryUrl) { - browser.contextMenus.create({ - title: `Search on ${keyItem.url}`, - contexts: ["selection"], - id: `${KEY_PREFIX}-${indexKey}`, - }); - } + // This will trigger handleStorageChange }); }); browser.contextMenus.onClicked.addListener(handleSearch); -browser.storage.onChanged.addListener(function (changes) { - const { newValue } = Object.values(changes)?.[0] || {}; - - if (newValue.queryUrl) - browser.contextMenus.create({ - title: `Search on ${newValue.url}`, - contexts: ["selection"], - id: `${KEY_PREFIX}-${newValue.id}`, - }); -}); +browser.storage.onChanged.addListener(handleStorageChange); diff --git a/src/components/autocomplete/suggestions.tsx b/src/components/autocomplete/suggestions.tsx index 94f369e..168f12b 100644 --- a/src/components/autocomplete/suggestions.tsx +++ b/src/components/autocomplete/suggestions.tsx @@ -112,9 +112,7 @@ const Suggestions: FunctionComponent = ({ className="ml-2 badge badge-accent badge-outline text-xs cursor-pointer hover:bg-accent hover:text-gray-100 hover:border-none" onClick={() => window.open( - browser.runtime.getURL( - "features/options/index.html#add-key-modal" - ) + browser.runtime.getURL('dist/options/index.html#add-key-modal') ) } > diff --git a/src/components/autocomplete/use-autocomplete.tsx b/src/components/autocomplete/use-autocomplete.tsx index 66fa93f..478d7d1 100644 --- a/src/components/autocomplete/use-autocomplete.tsx +++ b/src/components/autocomplete/use-autocomplete.tsx @@ -57,7 +57,7 @@ export const useAutocomplete = () => { const handleChange = useCallback( async (e: Event) => { const target = e.currentTarget as HTMLInputElement; - const userInput = target.value; + const userInput = target.value?.toLowerCase(); let newFilteredSuggestions: ISuperKeyOptional[] = []; if (isSearchingBookmarks(userInput)) { diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..5bd9f12 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1 @@ +export const KEY_PREFIX = "superkey"; \ No newline at end of file diff --git a/src/manifest.ts b/src/manifest.ts index 19c6f02..6cadfc8 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -21,7 +21,7 @@ export async function getManifest(isFirefoxInArg: boolean = false) { const shortCut = { [`_execute${isFirefoxInArg ? "_browser" : ""}_action`]: { suggested_key: { - windows: "Alt+Space", + windows: "Ctrl+Space", mac: "Alt+Space", }, }, diff --git a/src/types.ts b/src/types.ts index b287203..b2011d2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -34,3 +34,17 @@ export interface ISearchHandler { keyItem: ISuperKeyOptional | null; value?: string; } + +export interface StorageChange { + /** + * The old value of the item, if there was an old value. + * Optional. + */ + oldValue?: any; + + /** + * The new value of the item, if there is a new value. + * Optional. + */ + newValue?: any; +}