From 433e8118215105c498438c5505253d867ae6e8d2 Mon Sep 17 00:00:00 2001 From: Gabe Yuan Date: Tue, 21 Nov 2023 11:20:05 +0800 Subject: [PATCH] add context menus --- README.en.md | 1 + README.md | 1 + public/_locales/en/messages.json | 9 ++-- public/_locales/zh_CN/messages.json | 9 ++-- public/manifest.firefox.json | 2 +- public/manifest.json | 2 +- src/background.js | 44 ++++++++++++++++++- src/config/i18n.js | 8 ++++ src/config/index.js | 5 +++ src/content.js | 4 ++ src/views/Options/Tranbox.js | 34 ++++++++++++++- src/views/Selection/index.js | 66 +++++++++++++++++++++-------- 12 files changed, 156 insertions(+), 29 deletions(-) diff --git a/README.en.md b/README.en.md index 80628bb..ef11017 100644 --- a/README.en.md +++ b/README.en.md @@ -34,6 +34,7 @@ A simple, open source [bilingual translation extension & Greasemonkey script](ht - `Alt+B` Open Translate Popup - `Alt+O` Open Options Page - `Alt+I` Input Box Translation + - `Alt+S` Translate Selected Text ## Install diff --git a/README.md b/README.md index 45f4ee9..6821954 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ - `Alt+B` 打开翻译弹窗 - `Alt+O` 打开设置页面 - `Alt+I` 输入框翻译 + - `Alt+S` 翻译选中文字 ## 安装 diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index de6e6e1..73541a1 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -6,12 +6,15 @@ "message": "A simple bilingual translation extension & Greasemonkey script" }, "toggle_translate": { - "message": "Toggle Translate" + "message": "Toggle Translate (Alt+Q)" }, "toggle_style": { - "message": "Toggle Style" + "message": "Toggle Style (Alt+C)" }, "open_options": { - "message": "Open Options" + "message": "Open Options (Alt+O)" + }, + "translate_selected": { + "message": "Translate Selected Text (Alt+S)" } } diff --git a/public/_locales/zh_CN/messages.json b/public/_locales/zh_CN/messages.json index ce02f53..dded20b 100644 --- a/public/_locales/zh_CN/messages.json +++ b/public/_locales/zh_CN/messages.json @@ -6,12 +6,15 @@ "message": "一个简约的双语对照翻译扩展 & 油猴脚本" }, "toggle_translate": { - "message": "开启翻译" + "message": "开启翻译 (Alt+Q)" }, "toggle_style": { - "message": "切换样式" + "message": "切换样式 (Alt+C)" }, "open_options": { - "message": "打开设置" + "message": "打开设置 (Alt+O)" + }, + "translate_selected": { + "message": "翻译选中文字 (Alt+S)" } } diff --git a/public/manifest.firefox.json b/public/manifest.firefox.json index 6000191..34f05fe 100644 --- a/public/manifest.firefox.json +++ b/public/manifest.firefox.json @@ -41,7 +41,7 @@ "description": "__MSG_open_options__" } }, - "permissions": ["", "storage"], + "permissions": ["", "storage", "contextMenus"], "icons": { "16": "images/logo16.png", "32": "images/logo32.png", diff --git a/public/manifest.json b/public/manifest.json index 7a06cc1..416065e 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -42,7 +42,7 @@ "description": "__MSG_open_options__" } }, - "permissions": ["storage"], + "permissions": ["storage", "contextMenus"], "host_permissions": [""], "icons": { "16": "images/logo16.png", diff --git a/src/background.js b/src/background.js index 0d8ea87..687b34e 100644 --- a/src/background.js +++ b/src/background.js @@ -7,9 +7,11 @@ import { MSG_OPEN_OPTIONS, MSG_SAVE_RULE, MSG_TRANS_TOGGLE_STYLE, + MSG_TRANSLATE_SELECTED, CMD_TOGGLE_TRANSLATE, CMD_TOGGLE_STYLE, CMD_OPEN_OPTIONS, + CMD_TRANSLATE_SELECTED, } from "./config"; import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage"; import { trySyncSettingAndRules } from "./libs/sync"; @@ -26,14 +28,34 @@ globalThis.ContextType = "BACKGROUND"; */ browser.runtime.onInstalled.addListener(() => { tryInitDefaultData(); + + // 右键菜单 + browser.contextMenus.create({ + id: CMD_TRANSLATE_SELECTED, + title: browser.i18n.getMessage("translate_selected"), + contexts: ["selection"], + }); + browser.contextMenus.create({ + id: CMD_TOGGLE_TRANSLATE, + title: browser.i18n.getMessage("toggle_translate"), + contexts: ["all"], + }); + browser.contextMenus.create({ + id: CMD_TOGGLE_STYLE, + title: browser.i18n.getMessage("toggle_style"), + contexts: ["all"], + }); + browser.contextMenus.create({ + id: CMD_OPEN_OPTIONS, + title: browser.i18n.getMessage("open_options"), + contexts: ["all"], + }); }); /** * 浏览器启动 */ browser.runtime.onStartup.addListener(async () => { - console.log("browser onStartup"); - // 同步数据 await trySyncSettingAndRules(); @@ -103,3 +125,21 @@ browser.commands.onCommand.addListener((command) => { default: } }); + +browser.contextMenus.onClicked.addListener(({ menuItemId }) => { + switch (menuItemId) { + case CMD_TOGGLE_TRANSLATE: + sendTabMsg(MSG_TRANS_TOGGLE); + break; + case CMD_TOGGLE_STYLE: + sendTabMsg(MSG_TRANS_TOGGLE_STYLE); + break; + case CMD_TRANSLATE_SELECTED: + sendTabMsg(MSG_TRANSLATE_SELECTED); + break; + case CMD_OPEN_OPTIONS: + browser.runtime.openOptionsPage(); + break; + default: + } +}); diff --git a/src/config/i18n.js b/src/config/i18n.js index deb5a31..26aa060 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -547,6 +547,10 @@ export const I18N = { zh: `隐藏悬浮按钮`, en: `Hide Fab Button`, }, + hide_tran_button: { + zh: `隐藏翻译按钮`, + en: `Hide Translate Button`, + }, show: { zh: `显示`, en: `Show`, @@ -631,6 +635,10 @@ export const I18N = { zh: `显示翻译框快捷键`, en: `Toggle Translate Box Shortcut`, }, + trigger_transel_shortcut: { + zh: `翻译选中文字快捷键`, + en: `Translate Selected Shortcut`, + }, tranbtn_offset_x: { zh: `翻译按钮偏移X(0-100)`, en: `Translate Button Offset X (0-100)`, diff --git a/src/config/index.js b/src/config/index.js index 79da443..68f02a1 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -33,6 +33,7 @@ export const STOKEY_WEBFIXCACHE_PREFIX = `${APP_NAME}_webfixcache_`; export const CMD_TOGGLE_TRANSLATE = "toggleTranslate"; export const CMD_TOGGLE_STYLE = "toggleStyle"; export const CMD_OPEN_OPTIONS = "openOptions"; +export const CMD_TRANSLATE_SELECTED = "translateSelected"; export const CLIENT_WEB = "web"; export const CLIENT_CHROME = "chrome"; @@ -58,6 +59,7 @@ export const MSG_OPEN_OPTIONS = "open_options"; export const MSG_SAVE_RULE = "save_rule"; export const MSG_TRANS_TOGGLE = "trans_toggle"; export const MSG_TRANS_TOGGLE_STYLE = "trans_toggle_style"; +export const MSG_TRANSLATE_SELECTED = "translate_selected"; export const MSG_TRANS_GETRULE = "trans_getrule"; export const MSG_TRANS_PUTRULE = "trans_putrule"; export const MSG_TRANS_CURRULE = "trans_currule"; @@ -334,14 +336,17 @@ export const DEFAULT_INPUT_RULE = { // 划词翻译 export const DEFAULT_TRANBOX_SHORTCUT = ["AltLeft", "KeyB"]; +export const DEFAULT_TRANSEL_SHORTCUT = ["AltLeft", "KeyS"]; export const DEFAULT_TRANBOX_SETTING = { transOpen: true, translator: OPT_TRANS_MICROSOFT, fromLang: "auto", toLang: "zh-CN", tranboxShortcut: DEFAULT_TRANBOX_SHORTCUT, + transelShortcut: DEFAULT_TRANSEL_SHORTCUT, btnOffsetX: 10, btnOffsetY: 10, + hideTranBtn: false, }; // 订阅列表 diff --git a/src/content.js b/src/content.js index d8fffe0..1be7733 100644 --- a/src/content.js +++ b/src/content.js @@ -2,6 +2,7 @@ import { browser } from "./libs/browser"; import { MSG_TRANS_TOGGLE, MSG_TRANS_TOGGLE_STYLE, + MSG_TRANSLATE_SELECTED, MSG_TRANS_GETRULE, MSG_TRANS_PUTRULE, } from "./config"; @@ -35,6 +36,9 @@ function runtimeListener(translator) { translator.updateRule(args); sendIframeMsg(MSG_TRANS_PUTRULE, args); break; + case MSG_TRANSLATE_SELECTED: + window.dispatchEvent(new CustomEvent(MSG_TRANSLATE_SELECTED)); + break; default: return { error: `message action is unavailable: ${action}` }; } diff --git a/src/views/Options/Tranbox.js b/src/views/Options/Tranbox.js index 1cf7591..69bb57f 100644 --- a/src/views/Options/Tranbox.js +++ b/src/views/Options/Tranbox.js @@ -3,7 +3,12 @@ import Stack from "@mui/material/Stack"; import TextField from "@mui/material/TextField"; import MenuItem from "@mui/material/MenuItem"; import { useI18n } from "../../hooks/I18n"; -import { OPT_TRANS_ALL, OPT_LANGS_FROM, OPT_LANGS_TO } from "../../config"; +import { + OPT_TRANS_ALL, + OPT_LANGS_FROM, + OPT_LANGS_TO, + DEFAULT_TRANSEL_SHORTCUT, +} from "../../config"; import ShortcutInput from "./ShortcutInput"; import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; @@ -39,14 +44,23 @@ export default function Tranbox() { [updateTranbox] ); + const handleShortcutTransel = useCallback( + (val) => { + updateTranbox({ transelShortcut: val }); + }, + [updateTranbox] + ); + const { transOpen, translator, fromLang, toLang, tranboxShortcut, + transelShortcut = DEFAULT_TRANSEL_SHORTCUT, btnOffsetX, btnOffsetY, + hideTranBtn = false, } = tranboxSetting; return ( @@ -129,11 +143,29 @@ export default function Tranbox() { onChange={handleChange} /> + + {i18n("show")} + {i18n("hide")} + + + + ); diff --git a/src/views/Selection/index.js b/src/views/Selection/index.js index da15045..49ebc75 100644 --- a/src/views/Selection/index.js +++ b/src/views/Selection/index.js @@ -1,8 +1,9 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import TranBtn from "./TranBtn"; import TranBox from "./TranBox"; import { shortcutRegister } from "../../libs/shortcut"; import { sleep } from "../../libs/utils"; +import { MSG_TRANSLATE_SELECTED, DEFAULT_TRANSEL_SHORTCUT } from "../../config"; export default function Slection({ tranboxSetting, transApis }) { const [showBox, setShowBox] = useState(false); @@ -16,36 +17,47 @@ export default function Slection({ tranboxSetting, transApis }) { y: (window.innerHeight - 400) / 2, }); - async function handleMouseup(e) { - await sleep(10); + const handleClick = (e) => { + e.stopPropagation(); + + setShowBtn(false); + setText(selectedText); + setShowBox(true); + }; + + const handleTranSelected = useCallback(() => { + setShowBtn(false); const selectedText = window.getSelection()?.toString()?.trim() || ""; if (!selectedText) { - setShowBtn(false); return; } setSelText(selectedText); - setShowBtn(true); - setPosition({ x: e.clientX, y: e.clientY }); - } - - const handleClick = (e) => { - e.stopPropagation(); - setShowBtn(false); - setText(selectedText); - if (!showBox) { - setShowBox(true); - } - }; + setShowBox(true); + }, []); useEffect(() => { + async function handleMouseup(e) { + await sleep(10); + + const selectedText = window.getSelection()?.toString()?.trim() || ""; + setSelText(selectedText); + if (!selectedText) { + setShowBtn(false); + return; + } + + !tranboxSetting.hideTranBtn && setShowBtn(true); + setPosition({ x: e.clientX, y: e.clientY }); + } + window.addEventListener("mouseup", handleMouseup); return () => { window.removeEventListener("mouseup", handleMouseup); }; - }, []); + }, [tranboxSetting.hideTranBtn]); useEffect(() => { const clearShortcut = shortcutRegister( @@ -58,7 +70,25 @@ export default function Slection({ tranboxSetting, transApis }) { return () => { clearShortcut(); }; - }, [tranboxSetting.tranboxShortcut, setShowBox]); + }, [tranboxSetting.tranboxShortcut]); + + useEffect(() => { + const clearShortcut = shortcutRegister( + tranboxSetting.transelShortcut || DEFAULT_TRANSEL_SHORTCUT, + handleTranSelected + ); + + return () => { + clearShortcut(); + }; + }, [tranboxSetting.transelShortcut, handleTranSelected]); + + useEffect(() => { + window.addEventListener(MSG_TRANSLATE_SELECTED, handleTranSelected); + return () => { + window.removeEventListener(MSG_TRANSLATE_SELECTED, handleTranSelected); + }; + }, [handleTranSelected]); return ( <>