add context menus
This commit is contained in:
@@ -34,6 +34,7 @@ A simple, open source [bilingual translation extension & Greasemonkey script](ht
|
|||||||
- `Alt+B` Open Translate Popup
|
- `Alt+B` Open Translate Popup
|
||||||
- `Alt+O` Open Options Page
|
- `Alt+O` Open Options Page
|
||||||
- `Alt+I` Input Box Translation
|
- `Alt+I` Input Box Translation
|
||||||
|
- `Alt+S` Translate Selected Text
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
- `Alt+B` 打开翻译弹窗
|
- `Alt+B` 打开翻译弹窗
|
||||||
- `Alt+O` 打开设置页面
|
- `Alt+O` 打开设置页面
|
||||||
- `Alt+I` 输入框翻译
|
- `Alt+I` 输入框翻译
|
||||||
|
- `Alt+S` 翻译选中文字
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,15 @@
|
|||||||
"message": "A simple bilingual translation extension & Greasemonkey script"
|
"message": "A simple bilingual translation extension & Greasemonkey script"
|
||||||
},
|
},
|
||||||
"toggle_translate": {
|
"toggle_translate": {
|
||||||
"message": "Toggle Translate"
|
"message": "Toggle Translate (Alt+Q)"
|
||||||
},
|
},
|
||||||
"toggle_style": {
|
"toggle_style": {
|
||||||
"message": "Toggle Style"
|
"message": "Toggle Style (Alt+C)"
|
||||||
},
|
},
|
||||||
"open_options": {
|
"open_options": {
|
||||||
"message": "Open Options"
|
"message": "Open Options (Alt+O)"
|
||||||
|
},
|
||||||
|
"translate_selected": {
|
||||||
|
"message": "Translate Selected Text (Alt+S)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,15 @@
|
|||||||
"message": "一个简约的双语对照翻译扩展 & 油猴脚本"
|
"message": "一个简约的双语对照翻译扩展 & 油猴脚本"
|
||||||
},
|
},
|
||||||
"toggle_translate": {
|
"toggle_translate": {
|
||||||
"message": "开启翻译"
|
"message": "开启翻译 (Alt+Q)"
|
||||||
},
|
},
|
||||||
"toggle_style": {
|
"toggle_style": {
|
||||||
"message": "切换样式"
|
"message": "切换样式 (Alt+C)"
|
||||||
},
|
},
|
||||||
"open_options": {
|
"open_options": {
|
||||||
"message": "打开设置"
|
"message": "打开设置 (Alt+O)"
|
||||||
|
},
|
||||||
|
"translate_selected": {
|
||||||
|
"message": "翻译选中文字 (Alt+S)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
"description": "__MSG_open_options__"
|
"description": "__MSG_open_options__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": ["<all_urls>", "storage"],
|
"permissions": ["<all_urls>", "storage", "contextMenus"],
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "images/logo16.png",
|
"16": "images/logo16.png",
|
||||||
"32": "images/logo32.png",
|
"32": "images/logo32.png",
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
"description": "__MSG_open_options__"
|
"description": "__MSG_open_options__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": ["storage"],
|
"permissions": ["storage", "contextMenus"],
|
||||||
"host_permissions": ["<all_urls>"],
|
"host_permissions": ["<all_urls>"],
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "images/logo16.png",
|
"16": "images/logo16.png",
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import {
|
|||||||
MSG_OPEN_OPTIONS,
|
MSG_OPEN_OPTIONS,
|
||||||
MSG_SAVE_RULE,
|
MSG_SAVE_RULE,
|
||||||
MSG_TRANS_TOGGLE_STYLE,
|
MSG_TRANS_TOGGLE_STYLE,
|
||||||
|
MSG_TRANSLATE_SELECTED,
|
||||||
CMD_TOGGLE_TRANSLATE,
|
CMD_TOGGLE_TRANSLATE,
|
||||||
CMD_TOGGLE_STYLE,
|
CMD_TOGGLE_STYLE,
|
||||||
CMD_OPEN_OPTIONS,
|
CMD_OPEN_OPTIONS,
|
||||||
|
CMD_TRANSLATE_SELECTED,
|
||||||
} from "./config";
|
} from "./config";
|
||||||
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
||||||
import { trySyncSettingAndRules } from "./libs/sync";
|
import { trySyncSettingAndRules } from "./libs/sync";
|
||||||
@@ -26,14 +28,34 @@ globalThis.ContextType = "BACKGROUND";
|
|||||||
*/
|
*/
|
||||||
browser.runtime.onInstalled.addListener(() => {
|
browser.runtime.onInstalled.addListener(() => {
|
||||||
tryInitDefaultData();
|
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 () => {
|
browser.runtime.onStartup.addListener(async () => {
|
||||||
console.log("browser onStartup");
|
|
||||||
|
|
||||||
// 同步数据
|
// 同步数据
|
||||||
await trySyncSettingAndRules();
|
await trySyncSettingAndRules();
|
||||||
|
|
||||||
@@ -103,3 +125,21 @@ browser.commands.onCommand.addListener((command) => {
|
|||||||
default:
|
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:
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -547,6 +547,10 @@ export const I18N = {
|
|||||||
zh: `隐藏悬浮按钮`,
|
zh: `隐藏悬浮按钮`,
|
||||||
en: `Hide Fab Button`,
|
en: `Hide Fab Button`,
|
||||||
},
|
},
|
||||||
|
hide_tran_button: {
|
||||||
|
zh: `隐藏翻译按钮`,
|
||||||
|
en: `Hide Translate Button`,
|
||||||
|
},
|
||||||
show: {
|
show: {
|
||||||
zh: `显示`,
|
zh: `显示`,
|
||||||
en: `Show`,
|
en: `Show`,
|
||||||
@@ -631,6 +635,10 @@ export const I18N = {
|
|||||||
zh: `显示翻译框快捷键`,
|
zh: `显示翻译框快捷键`,
|
||||||
en: `Toggle Translate Box Shortcut`,
|
en: `Toggle Translate Box Shortcut`,
|
||||||
},
|
},
|
||||||
|
trigger_transel_shortcut: {
|
||||||
|
zh: `翻译选中文字快捷键`,
|
||||||
|
en: `Translate Selected Shortcut`,
|
||||||
|
},
|
||||||
tranbtn_offset_x: {
|
tranbtn_offset_x: {
|
||||||
zh: `翻译按钮偏移X(0-100)`,
|
zh: `翻译按钮偏移X(0-100)`,
|
||||||
en: `Translate Button Offset X (0-100)`,
|
en: `Translate Button Offset X (0-100)`,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export const STOKEY_WEBFIXCACHE_PREFIX = `${APP_NAME}_webfixcache_`;
|
|||||||
export const CMD_TOGGLE_TRANSLATE = "toggleTranslate";
|
export const CMD_TOGGLE_TRANSLATE = "toggleTranslate";
|
||||||
export const CMD_TOGGLE_STYLE = "toggleStyle";
|
export const CMD_TOGGLE_STYLE = "toggleStyle";
|
||||||
export const CMD_OPEN_OPTIONS = "openOptions";
|
export const CMD_OPEN_OPTIONS = "openOptions";
|
||||||
|
export const CMD_TRANSLATE_SELECTED = "translateSelected";
|
||||||
|
|
||||||
export const CLIENT_WEB = "web";
|
export const CLIENT_WEB = "web";
|
||||||
export const CLIENT_CHROME = "chrome";
|
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_SAVE_RULE = "save_rule";
|
||||||
export const MSG_TRANS_TOGGLE = "trans_toggle";
|
export const MSG_TRANS_TOGGLE = "trans_toggle";
|
||||||
export const MSG_TRANS_TOGGLE_STYLE = "trans_toggle_style";
|
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_GETRULE = "trans_getrule";
|
||||||
export const MSG_TRANS_PUTRULE = "trans_putrule";
|
export const MSG_TRANS_PUTRULE = "trans_putrule";
|
||||||
export const MSG_TRANS_CURRULE = "trans_currule";
|
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_TRANBOX_SHORTCUT = ["AltLeft", "KeyB"];
|
||||||
|
export const DEFAULT_TRANSEL_SHORTCUT = ["AltLeft", "KeyS"];
|
||||||
export const DEFAULT_TRANBOX_SETTING = {
|
export const DEFAULT_TRANBOX_SETTING = {
|
||||||
transOpen: true,
|
transOpen: true,
|
||||||
translator: OPT_TRANS_MICROSOFT,
|
translator: OPT_TRANS_MICROSOFT,
|
||||||
fromLang: "auto",
|
fromLang: "auto",
|
||||||
toLang: "zh-CN",
|
toLang: "zh-CN",
|
||||||
tranboxShortcut: DEFAULT_TRANBOX_SHORTCUT,
|
tranboxShortcut: DEFAULT_TRANBOX_SHORTCUT,
|
||||||
|
transelShortcut: DEFAULT_TRANSEL_SHORTCUT,
|
||||||
btnOffsetX: 10,
|
btnOffsetX: 10,
|
||||||
btnOffsetY: 10,
|
btnOffsetY: 10,
|
||||||
|
hideTranBtn: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 订阅列表
|
// 订阅列表
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { browser } from "./libs/browser";
|
|||||||
import {
|
import {
|
||||||
MSG_TRANS_TOGGLE,
|
MSG_TRANS_TOGGLE,
|
||||||
MSG_TRANS_TOGGLE_STYLE,
|
MSG_TRANS_TOGGLE_STYLE,
|
||||||
|
MSG_TRANSLATE_SELECTED,
|
||||||
MSG_TRANS_GETRULE,
|
MSG_TRANS_GETRULE,
|
||||||
MSG_TRANS_PUTRULE,
|
MSG_TRANS_PUTRULE,
|
||||||
} from "./config";
|
} from "./config";
|
||||||
@@ -35,6 +36,9 @@ function runtimeListener(translator) {
|
|||||||
translator.updateRule(args);
|
translator.updateRule(args);
|
||||||
sendIframeMsg(MSG_TRANS_PUTRULE, args);
|
sendIframeMsg(MSG_TRANS_PUTRULE, args);
|
||||||
break;
|
break;
|
||||||
|
case MSG_TRANSLATE_SELECTED:
|
||||||
|
window.dispatchEvent(new CustomEvent(MSG_TRANSLATE_SELECTED));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return { error: `message action is unavailable: ${action}` };
|
return { error: `message action is unavailable: ${action}` };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ import Stack from "@mui/material/Stack";
|
|||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import { useI18n } from "../../hooks/I18n";
|
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 ShortcutInput from "./ShortcutInput";
|
||||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||||
import Switch from "@mui/material/Switch";
|
import Switch from "@mui/material/Switch";
|
||||||
@@ -39,14 +44,23 @@ export default function Tranbox() {
|
|||||||
[updateTranbox]
|
[updateTranbox]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleShortcutTransel = useCallback(
|
||||||
|
(val) => {
|
||||||
|
updateTranbox({ transelShortcut: val });
|
||||||
|
},
|
||||||
|
[updateTranbox]
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
transOpen,
|
transOpen,
|
||||||
translator,
|
translator,
|
||||||
fromLang,
|
fromLang,
|
||||||
toLang,
|
toLang,
|
||||||
tranboxShortcut,
|
tranboxShortcut,
|
||||||
|
transelShortcut = DEFAULT_TRANSEL_SHORTCUT,
|
||||||
btnOffsetX,
|
btnOffsetX,
|
||||||
btnOffsetY,
|
btnOffsetY,
|
||||||
|
hideTranBtn = false,
|
||||||
} = tranboxSetting;
|
} = tranboxSetting;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -129,11 +143,29 @@ export default function Tranbox() {
|
|||||||
onChange={handleChange}
|
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
|
<ShortcutInput
|
||||||
value={tranboxShortcut}
|
value={tranboxShortcut}
|
||||||
onChange={handleShortcutInput}
|
onChange={handleShortcutInput}
|
||||||
label={i18n("trigger_tranbox_shortcut")}
|
label={i18n("trigger_tranbox_shortcut")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ShortcutInput
|
||||||
|
value={transelShortcut}
|
||||||
|
onChange={handleShortcutTransel}
|
||||||
|
label={i18n("trigger_transel_shortcut")}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import TranBtn from "./TranBtn";
|
import TranBtn from "./TranBtn";
|
||||||
import TranBox from "./TranBox";
|
import TranBox from "./TranBox";
|
||||||
import { shortcutRegister } from "../../libs/shortcut";
|
import { shortcutRegister } from "../../libs/shortcut";
|
||||||
import { sleep } from "../../libs/utils";
|
import { sleep } from "../../libs/utils";
|
||||||
|
import { MSG_TRANSLATE_SELECTED, DEFAULT_TRANSEL_SHORTCUT } from "../../config";
|
||||||
|
|
||||||
export default function Slection({ tranboxSetting, transApis }) {
|
export default function Slection({ tranboxSetting, transApis }) {
|
||||||
const [showBox, setShowBox] = useState(false);
|
const [showBox, setShowBox] = useState(false);
|
||||||
@@ -16,36 +17,47 @@ export default function Slection({ tranboxSetting, transApis }) {
|
|||||||
y: (window.innerHeight - 400) / 2,
|
y: (window.innerHeight - 400) / 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleMouseup(e) {
|
const handleClick = (e) => {
|
||||||
await sleep(10);
|
e.stopPropagation();
|
||||||
|
|
||||||
|
setShowBtn(false);
|
||||||
|
setText(selectedText);
|
||||||
|
setShowBox(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTranSelected = useCallback(() => {
|
||||||
|
setShowBtn(false);
|
||||||
|
|
||||||
const selectedText = window.getSelection()?.toString()?.trim() || "";
|
const selectedText = window.getSelection()?.toString()?.trim() || "";
|
||||||
if (!selectedText) {
|
if (!selectedText) {
|
||||||
setShowBtn(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelText(selectedText);
|
setSelText(selectedText);
|
||||||
setShowBtn(true);
|
|
||||||
setPosition({ x: e.clientX, y: e.clientY });
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleClick = (e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setShowBtn(false);
|
|
||||||
|
|
||||||
setText(selectedText);
|
setText(selectedText);
|
||||||
if (!showBox) {
|
setShowBox(true);
|
||||||
setShowBox(true);
|
}, []);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
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);
|
window.addEventListener("mouseup", handleMouseup);
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("mouseup", handleMouseup);
|
window.removeEventListener("mouseup", handleMouseup);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [tranboxSetting.hideTranBtn]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const clearShortcut = shortcutRegister(
|
const clearShortcut = shortcutRegister(
|
||||||
@@ -58,7 +70,25 @@ export default function Slection({ tranboxSetting, transApis }) {
|
|||||||
return () => {
|
return () => {
|
||||||
clearShortcut();
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
Reference in New Issue
Block a user