add context menus

This commit is contained in:
Gabe Yuan
2023-11-21 11:20:05 +08:00
parent df4cfc0fbc
commit 433e811821
12 changed files with 156 additions and 29 deletions

View File

@@ -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

View File

@@ -34,6 +34,7 @@
- `Alt+B` 打开翻译弹窗
- `Alt+O` 打开设置页面
- `Alt+I` 输入框翻译
- `Alt+S` 翻译选中文字
## 安装

View File

@@ -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)"
}
}

View File

@@ -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)"
}
}

View File

@@ -41,7 +41,7 @@
"description": "__MSG_open_options__"
}
},
"permissions": ["<all_urls>", "storage"],
"permissions": ["<all_urls>", "storage", "contextMenus"],
"icons": {
"16": "images/logo16.png",
"32": "images/logo32.png",

View File

@@ -42,7 +42,7 @@
"description": "__MSG_open_options__"
}
},
"permissions": ["storage"],
"permissions": ["storage", "contextMenus"],
"host_permissions": ["<all_urls>"],
"icons": {
"16": "images/logo16.png",

View File

@@ -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:
}
});

View File

@@ -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: `翻译按钮偏移X0-100`,
en: `Translate Button Offset X (0-100)`,

View File

@@ -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,
};
// 订阅列表

View File

@@ -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}` };
}

View File

@@ -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}
/>
<TextField
select
size="small"
name="hideTranBtn"
value={hideTranBtn}
label={i18n("hide_tran_button")}
onChange={handleChange}
>
<MenuItem value={false}>{i18n("show")}</MenuItem>
<MenuItem value={true}>{i18n("hide")}</MenuItem>
</TextField>
<ShortcutInput
value={tranboxShortcut}
onChange={handleShortcutInput}
label={i18n("trigger_tranbox_shortcut")}
/>
<ShortcutInput
value={transelShortcut}
onChange={handleShortcutTransel}
label={i18n("trigger_transel_shortcut")}
/>
</Stack>
</Box>
);

View File

@@ -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,
});
const handleClick = (e) => {
e.stopPropagation();
setShowBtn(false);
setText(selectedText);
setShowBox(true);
};
const handleTranSelected = useCallback(() => {
setShowBtn(false);
const selectedText = window.getSelection()?.toString()?.trim() || "";
if (!selectedText) {
return;
}
setSelText(selectedText);
setText(selectedText);
setShowBox(true);
}, []);
useEffect(() => {
async function handleMouseup(e) {
await sleep(10);
const selectedText = window.getSelection()?.toString()?.trim() || "";
setSelText(selectedText);
if (!selectedText) {
setShowBtn(false);
return;
}
setSelText(selectedText);
setShowBtn(true);
!tranboxSetting.hideTranBtn && setShowBtn(true);
setPosition({ x: e.clientX, y: e.clientY });
}
const handleClick = (e) => {
e.stopPropagation();
setShowBtn(false);
setText(selectedText);
if (!showBox) {
setShowBox(true);
}
};
useEffect(() => {
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 (
<>