diff --git a/src/config/i18n.js b/src/config/i18n.js
index 33fd548..1f3b9d2 100644
--- a/src/config/i18n.js
+++ b/src/config/i18n.js
@@ -1184,6 +1184,21 @@ export const I18N = {
en: `Four finger tap`,
zh_TW: `四指輕觸`,
},
+ touch_tap_5: {
+ zh: `单指双击`,
+ en: `Double-click`,
+ zh_TW: `單指雙擊`,
+ },
+ touch_tap_6: {
+ zh: `单指三击`,
+ en: `Triple-click`,
+ zh_TW: `單指三擊`,
+ },
+ touch_tap_7: {
+ zh: `双指双击`,
+ en: `Two-finger double-click`,
+ zh_TW: `雙指雙擊`,
+ },
translate_blacklist: {
zh: `禁用翻译名单`,
en: `Translate Blacklist`,
diff --git a/src/config/msg.js b/src/config/msg.js
index f74f542..6d867a9 100644
--- a/src/config/msg.js
+++ b/src/config/msg.js
@@ -15,6 +15,7 @@ export const MSG_TRANS_GETRULE = "trans_getrule";
export const MSG_TRANS_PUTRULE = "trans_putrule";
export const MSG_TRANS_CURRULE = "trans_currule";
export const MSG_TRANSBOX_TOGGLE = "transbox_toggle";
+export const MSG_POPUP_TOGGLE = "popup_toggle";
export const MSG_MOUSEHOVER_TOGGLE = "mousehover_toggle";
export const MSG_TRANSINPUT_TOGGLE = "transinput_toggle";
export const MSG_CONTEXT_MENUS = "context_menus";
@@ -27,6 +28,8 @@ export const MSG_BUILTINAI_TRANSLATE = "builtinai_translte";
export const MSG_SET_LOGLEVEL = "set_loglevel";
export const MSG_CLEAR_CACHES = "clear_caches";
+export const EVENT_KISS = "event_kiss_translate";
+
export const MSG_XHR_DATA_YOUTUBE = "KISS_XHR_DATA_YOUTUBE";
// export const MSG_GLOBAL_VAR_FETCH = "KISS_GLOBAL_VAR_FETCH";
// export const MSG_GLOBAL_VAR_BACK = "KISS_GLOBAL_VAR_BACK";
diff --git a/src/config/setting.js b/src/config/setting.js
index c936b7a..44d8da7 100644
--- a/src/config/setting.js
+++ b/src/config/setting.js
@@ -166,7 +166,7 @@ export const DEFAULT_SETTING = {
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
inputRule: DEFAULT_INPUT_RULE, // 输入框设置
tranboxSetting: DEFAULT_TRANBOX_SETTING, // 划词翻译设置
- touchTranslate: 2, // 触屏翻译
+ touchTranslate: 2, // 触屏翻译 {5:单指双击,6:单指三击,7:双指双击}
blacklist: DEFAULT_BLACKLIST.join(",\n"), // 禁用翻译名单
csplist: DEFAULT_CSPLIST.join(",\n"), // 禁用CSP名单
orilist: DEFAULT_ORILIST.join(",\n"), // 禁用CSP名单
diff --git a/src/libs/fabManager.js b/src/libs/fabManager.js
index d2e7b45..25a44af 100644
--- a/src/libs/fabManager.js
+++ b/src/libs/fabManager.js
@@ -3,12 +3,16 @@ import { APP_CONSTS } from "../config";
import ContentFab from "../views/Action/ContentFab";
export class FabManager extends ShadowDomManager {
- constructor({ translator, popupManager, fabConfig }) {
+ constructor({ translator, processActions, fabConfig }) {
super({
id: APP_CONSTS.fabID,
className: "notranslate",
reactComponent: ContentFab,
- props: { translator, popupManager, fabConfig },
+ props: { translator, processActions, fabConfig },
});
+
+ if (!fabConfig?.isHide) {
+ this.show();
+ }
}
}
diff --git a/src/libs/popupManager.js b/src/libs/popupManager.js
index d9a9906..ba9cb1d 100644
--- a/src/libs/popupManager.js
+++ b/src/libs/popupManager.js
@@ -1,14 +1,26 @@
import ShadowDomManager from "./shadowDomManager";
-import { APP_CONSTS } from "../config";
+import { APP_CONSTS, EVENT_KISS, MSG_POPUP_TOGGLE } from "../config";
import Action from "../views/Action";
export class PopupManager extends ShadowDomManager {
- constructor({ translator }) {
+ constructor({ translator, processActions }) {
super({
id: APP_CONSTS.popupID,
className: "notranslate",
reactComponent: Action,
- props: { translator },
+ props: { translator, processActions },
});
}
+
+ toggle(props) {
+ if (this.isVisible) {
+ document.dispatchEvent(
+ new CustomEvent(EVENT_KISS, {
+ detail: { action: MSG_POPUP_TOGGLE },
+ })
+ );
+ } else {
+ this.show(props || this._props);
+ }
+ }
}
diff --git a/src/libs/touch.js b/src/libs/touch.js
index 4b0e066..5d0ee3d 100644
--- a/src/libs/touch.js
+++ b/src/libs/touch.js
@@ -1,12 +1,47 @@
-export function touchTapListener(fn, touchsLength) {
+export function touchTapListener(fn, options = {}) {
+ const config = {
+ taps: 2,
+ fingers: 1,
+ delay: 300,
+ ...options,
+ };
+
+ let maxTouches = 0;
+ let tapCount = 0;
+ let tapTimer = null;
+
+ const handleTouchStart = (e) => {
+ maxTouches = Math.max(maxTouches, e.touches.length);
+ };
+
const handleTouchend = (e) => {
- if (e.touches.length === touchsLength) {
- fn();
+ if (e.touches.length === 0) {
+ if (maxTouches === config.fingers) {
+ tapCount++;
+ clearTimeout(tapTimer);
+
+ if (tapCount === config.taps) {
+ fn(e);
+ tapCount = 0;
+ } else {
+ tapTimer = setTimeout(() => {
+ tapCount = 0;
+ }, config.delay);
+ }
+ } else {
+ tapCount = 0;
+ clearTimeout(tapTimer);
+ }
+ maxTouches = 0;
}
};
- document.addEventListener("touchstart", handleTouchend);
+ document.addEventListener("touchstart", handleTouchStart, { passive: true });
+ document.addEventListener("touchend", handleTouchend, { passive: true });
+
return () => {
- document.removeEventListener("touchstart", handleTouchend);
+ clearTimeout(tapTimer);
+ document.removeEventListener("touchstart", handleTouchStart);
+ document.removeEventListener("touchend", handleTouchend);
};
}
diff --git a/src/libs/translator.js b/src/libs/translator.js
index ad3e0da..76d46d2 100644
--- a/src/libs/translator.js
+++ b/src/libs/translator.js
@@ -1644,6 +1644,17 @@ export class Translator {
this.updateRule({ textStyle });
}
+ // 切换划词翻译
+ toggleTransbox() {
+ this.#setting.tranboxSetting.transOpen =
+ !this.#setting.tranboxSetting.transOpen;
+ }
+
+ // 切换输入框翻译
+ toggleInputTranslate() {
+ this.#setting.inputRule.transOpen = !this.#setting.inputRule.transOpen;
+ }
+
// 停止运行
stop() {
this.disable();
diff --git a/src/libs/translatorManager.js b/src/libs/translatorManager.js
index 8d8266c..66c2a56 100644
--- a/src/libs/translatorManager.js
+++ b/src/libs/translatorManager.js
@@ -4,9 +4,8 @@ import { InputTranslator } from "./inputTranslate";
import { TransboxManager } from "./tranbox";
import { shortcutRegister } from "./shortcut";
import { sendIframeMsg } from "./iframe";
-import { newI18n } from "../config";
+import { EVENT_KISS, newI18n } from "../config";
import { touchTapListener } from "./touch";
-import { debounce } from "./utils";
import { PopupManager } from "./popupManager";
import { FabManager } from "./fabManager";
import {
@@ -20,6 +19,7 @@ import {
MSG_TRANS_PUTRULE,
MSG_OPEN_TRANBOX,
MSG_TRANSBOX_TOGGLE,
+ MSG_POPUP_TOGGLE,
MSG_MOUSEHOVER_TOGGLE,
MSG_TRANSINPUT_TOGGLE,
} from "../config";
@@ -57,16 +57,15 @@ export default class TranslatorManager {
if (!isIframe) {
this._transboxManager = new TransboxManager(setting);
this._inputTranslator = new InputTranslator(setting);
- this._popupManager = new PopupManager({ translator: this._translator });
-
- if (fabConfig && !fabConfig.isHide) {
- this._fabManager = new FabManager({
- translator: this._translator,
- popupManager: this._popupManager,
- fabConfig,
- });
- this._fabManager.show();
- }
+ this._popupManager = new PopupManager({
+ translator: this._translator,
+ processActions: this.#processActions.bind(this),
+ });
+ this._fabManager = new FabManager({
+ translator: this._translator,
+ processActions: this.#processActions.bind(this),
+ fabConfig,
+ });
}
this.#windowMessageHandler = this.#handleWindowMessage.bind(this);
@@ -125,8 +124,8 @@ export default class TranslatorManager {
}
// 子模块
- this._popupManager?.hide();
- this._fabManager?.hide();
+ this._popupManager?.destroy();
+ this._fabManager?.destroy();
this._transboxManager?.disable();
this._inputTranslator?.disable();
this._translator.stop();
@@ -151,11 +150,39 @@ export default class TranslatorManager {
return;
}
- const handleTap = debounce(() => {
+ const handleTap = () => {
this.#processActions({ action: MSG_TRANS_TOGGLE });
- }, 300);
+ };
- this.#clearTouchListener = touchTapListener(handleTap, touchTranslate);
+ switch (touchTranslate) {
+ case 2:
+ case 3:
+ case 4:
+ this.#clearTouchListener = touchTapListener(handleTap, {
+ taps: 1,
+ fingers: touchTranslate,
+ });
+ break;
+ case 5:
+ this.#clearTouchListener = touchTapListener(handleTap, {
+ taps: 2,
+ fingers: 1,
+ });
+ break;
+ case 6:
+ this.#clearTouchListener = touchTapListener(handleTap, {
+ taps: 3,
+ fingers: 1,
+ });
+ break;
+ case 7:
+ this.#clearTouchListener = touchTapListener(handleTap, {
+ taps: 2,
+ fingers: 2,
+ });
+ break;
+ default:
+ }
}
#handleWindowMessage(event) {
@@ -182,7 +209,7 @@ export default class TranslatorManager {
this.#processActions({ action: MSG_TRANS_TOGGLE_STYLE })
),
shortcutRegister(shortcuts[OPT_SHORTCUT_POPUP], () =>
- this._popupManager.toggle()
+ this.#processActions({ action: MSG_POPUP_TOGGLE })
),
shortcutRegister(shortcuts[OPT_SHORTCUT_SETTING], () =>
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank")
@@ -210,7 +237,7 @@ export default class TranslatorManager {
),
GM.registerMenuCommand(
i18n("open_menu"),
- () => this._popupManager.toggle(),
+ () => this.#processActions({ action: MSG_POPUP_TOGGLE }),
"K"
),
GM.registerMenuCommand(
@@ -239,16 +266,25 @@ export default class TranslatorManager {
this._translator.updateRule(args);
break;
case MSG_OPEN_TRANBOX:
- this._transboxManager?.enable();
+ document.dispatchEvent(
+ new CustomEvent(EVENT_KISS, {
+ detail: { action: MSG_OPEN_TRANBOX },
+ })
+ );
+ break;
+ case MSG_POPUP_TOGGLE:
+ this._popupManager?.toggle();
break;
case MSG_TRANSBOX_TOGGLE:
this._transboxManager?.toggle();
+ this._translator.toggleTransbox();
break;
case MSG_MOUSEHOVER_TOGGLE:
this._translator.toggleMouseHover();
break;
case MSG_TRANSINPUT_TOGGLE:
this._inputTranslator?.toggle();
+ this._translator.toggleInputTranslate();
break;
default:
logger.info(`Message action is unavailable: ${action}`);
diff --git a/src/views/Action/ContentFab.js b/src/views/Action/ContentFab.js
index 4e66ca6..397fd38 100644
--- a/src/views/Action/ContentFab.js
+++ b/src/views/Action/ContentFab.js
@@ -4,14 +4,14 @@ import ThemeProvider from "../../hooks/Theme";
import Draggable from "./Draggable";
import { useState, useMemo, useCallback } from "react";
import { SettingProvider } from "../../hooks/Setting";
-import { MSG_TRANS_TOGGLE } from "../../config";
+import { MSG_TRANS_TOGGLE, MSG_POPUP_TOGGLE } from "../../config";
import { sendIframeMsg } from "../../libs/iframe";
import useWindowSize from "../../hooks/WindowSize";
export default function ContentFab({
translator,
fabConfig: { x: fabX, y: fabY, fabClickAction = 0 } = {},
- popupManager,
+ processActions,
}) {
const fabWidth = 40;
const windowSize = useWindowSize();
@@ -31,10 +31,10 @@ export default function ContentFab({
translator.toggle();
sendIframeMsg(MSG_TRANS_TOGGLE);
} else {
- popupManager.toggle();
+ processActions({ action: MSG_POPUP_TOGGLE });
}
}
- }, [moved, translator, popupManager, fabClickAction]);
+ }, [moved, translator, fabClickAction, processActions]);
const fabProps = useMemo(
() => ({
diff --git a/src/views/Action/index.js b/src/views/Action/index.js
index ac99dbd..3967a89 100644
--- a/src/views/Action/index.js
+++ b/src/views/Action/index.js
@@ -1,27 +1,59 @@
import ThemeProvider from "../../hooks/Theme";
import Draggable from "./Draggable";
-import { useEffect, useMemo, useCallback } from "react";
+import { useEffect, useMemo, useCallback, useState } from "react";
import { SettingProvider } from "../../hooks/Setting";
-import Popup from "../Popup";
import Header from "../Popup/Header";
import Box from "@mui/material/Box";
import Divider from "@mui/material/Divider";
import useWindowSize from "../../hooks/WindowSize";
+import { EVENT_KISS, MSG_OPEN_OPTIONS, MSG_POPUP_TOGGLE } from "../../config";
+import PopupCont from "../Popup/PopupCont";
+import { isExt } from "../../libs/client";
+import { sendBgMsg } from "../../libs/msg";
-export default function Action({ translator, onClose }) {
+export default function Action({ translator, processActions }) {
+ const [showPopup, setShowPopup] = useState(true);
+ const [rule, setRule] = useState(translator.rule);
+ const [setting, setSetting] = useState(translator.setting);
const windowSize = useWindowSize();
- const handleWindowClick = useCallback(() => {
- onClose();
- }, [onClose]);
+ const handleOpenSetting = useCallback(() => {
+ if (isExt) {
+ sendBgMsg(MSG_OPEN_OPTIONS);
+ } else {
+ window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
+ }
+ }, []);
useEffect(() => {
+ const handleWindowClick = () => {
+ setShowPopup(false);
+ };
window.addEventListener("click", handleWindowClick);
-
return () => {
window.removeEventListener("click", handleWindowClick);
};
- }, [handleWindowClick]);
+ }, []);
+
+ useEffect(() => {
+ const handleStatusUpdate = (event) => {
+ if (event.detail?.action === MSG_POPUP_TOGGLE) {
+ setShowPopup((pre) => !pre);
+ }
+ };
+
+ document.addEventListener(EVENT_KISS, handleStatusUpdate);
+ return () => {
+ document.removeEventListener(EVENT_KISS, handleStatusUpdate);
+ };
+ }, []);
+
+ useEffect(() => {
+ if (showPopup) {
+ setRule(translator.rule);
+ setSetting(translator.setting);
+ }
+ }, [showPopup, translator]);
const popProps = useMemo(() => {
const width = Math.min(windowSize.w, 360);
@@ -40,19 +72,35 @@ export default function Action({ translator, onClose }) {
return (
-
-
-
+ {showPopup && (
+
+ {
+ setShowPopup(false);
+ }}
+ />
+
+
+ }
+ >
+
+
- }
- >
-
-
+
+ )}
);
diff --git a/src/views/Options/Setting.js b/src/views/Options/Setting.js
index 7ce0159..7cc1ff1 100644
--- a/src/views/Options/Setting.js
+++ b/src/views/Options/Setting.js
@@ -273,7 +273,7 @@ export default function Settings() {
label={i18n("touch_translate_shortcut")}
onChange={handleChange}
>
- {[0, 2, 3, 4].map((item) => (
+ {[0, 2, 3, 4, 5, 6, 7].map((item) => (
diff --git a/src/views/Popup/PopupCont.js b/src/views/Popup/PopupCont.js
new file mode 100644
index 0000000..299d9db
--- /dev/null
+++ b/src/views/Popup/PopupCont.js
@@ -0,0 +1,422 @@
+import { useState, useEffect, useMemo } from "react";
+import Stack from "@mui/material/Stack";
+import MenuItem from "@mui/material/MenuItem";
+import FormControlLabel from "@mui/material/FormControlLabel";
+import Switch from "@mui/material/Switch";
+import Button from "@mui/material/Button";
+import Grid from "@mui/material/Grid";
+import { sendBgMsg, sendTabMsg, getCurTab } from "../../libs/msg";
+import { isExt } from "../../libs/client";
+import { useI18n } from "../../hooks/I18n";
+import TextField from "@mui/material/TextField";
+import {
+ MSG_TRANS_TOGGLE,
+ MSG_TRANS_PUTRULE,
+ MSG_SAVE_RULE,
+ MSG_COMMAND_SHORTCUTS,
+ MSG_TRANSBOX_TOGGLE,
+ MSG_MOUSEHOVER_TOGGLE,
+ MSG_TRANSINPUT_TOGGLE,
+ OPT_LANGS_FROM,
+ OPT_LANGS_TO,
+ OPT_STYLE_ALL,
+} from "../../config";
+import { saveRule } from "../../libs/rules";
+import { tryClearCaches } from "../../libs/cache";
+import { kissLog } from "../../libs/log";
+import { parseUrlPattern } from "../../libs/utils";
+
+export default function PopupCont({
+ rule,
+ setting,
+ setRule,
+ setSetting,
+ handleOpenSetting,
+ processActions,
+ isContent = false,
+}) {
+ const i18n = useI18n();
+ const [commands, setCommands] = useState({});
+
+ const handleTransToggle = async (e) => {
+ try {
+ setRule({ ...rule, transOpen: e.target.checked ? "true" : "false" });
+
+ if (!processActions) {
+ await sendTabMsg(MSG_TRANS_TOGGLE);
+ } else {
+ processActions({ action: MSG_TRANS_TOGGLE });
+ }
+ } catch (err) {
+ kissLog("toggle trans", err);
+ }
+ };
+
+ const handleTransboxToggle = async (e) => {
+ try {
+ setSetting((pre) => ({
+ ...pre,
+ tranboxSetting: { ...pre.tranboxSetting, transOpen: e.target.checked },
+ }));
+
+ if (!processActions) {
+ await sendTabMsg(MSG_TRANSBOX_TOGGLE);
+ } else {
+ processActions({ action: MSG_TRANSBOX_TOGGLE });
+ }
+ } catch (err) {
+ kissLog("toggle transbox", err);
+ }
+ };
+
+ const handleMousehoverToggle = async (e) => {
+ try {
+ setSetting((pre) => ({
+ ...pre,
+ mouseHoverSetting: {
+ ...pre.mouseHoverSetting,
+ useMouseHover: e.target.checked,
+ },
+ }));
+
+ if (!processActions) {
+ await sendTabMsg(MSG_MOUSEHOVER_TOGGLE);
+ } else {
+ processActions({ action: MSG_MOUSEHOVER_TOGGLE });
+ }
+ } catch (err) {
+ kissLog("toggle mousehover", err);
+ }
+ };
+
+ const handleInputTransToggle = async (e) => {
+ try {
+ setSetting((pre) => ({
+ ...pre,
+ inputRule: {
+ ...pre.inputRule,
+ transOpen: e.target.checked,
+ },
+ }));
+
+ if (!processActions) {
+ await sendTabMsg(MSG_TRANSINPUT_TOGGLE);
+ } else {
+ processActions({ action: MSG_TRANSINPUT_TOGGLE });
+ }
+ } catch (err) {
+ kissLog("toggle inputtrans", err);
+ }
+ };
+
+ const handleChange = async (e) => {
+ try {
+ const { name, value } = e.target;
+ setRule((pre) => ({ ...pre, [name]: value }));
+
+ if (!processActions) {
+ await sendTabMsg(MSG_TRANS_PUTRULE, { [name]: value });
+ } else {
+ processActions({ action: MSG_TRANS_PUTRULE, args: { [name]: value } });
+ }
+ } catch (err) {
+ kissLog("update rule", err);
+ }
+ };
+
+ const handleClearCache = () => {
+ tryClearCaches();
+ };
+
+ const handleSaveRule = async () => {
+ try {
+ let href = "";
+ if (!isContent) {
+ const tab = await getCurTab();
+ href = tab.url;
+ } else {
+ href = window.location?.href;
+ }
+
+ if (!href || typeof href !== "string") {
+ return;
+ }
+
+ const pattern = parseUrlPattern(href);
+ const curRule = { ...rule, pattern };
+ if (isExt && isContent) {
+ sendBgMsg(MSG_SAVE_RULE, curRule);
+ } else {
+ saveRule(curRule);
+ }
+ } catch (err) {
+ kissLog("save rule", err);
+ }
+ };
+
+ useEffect(() => {
+ (async () => {
+ try {
+ const commands = {};
+ if (isExt) {
+ const res = await sendBgMsg(MSG_COMMAND_SHORTCUTS);
+ res.forEach(({ name, shortcut }) => {
+ commands[name] = shortcut;
+ });
+ } else {
+ const shortcuts = setting.shortcuts;
+ if (shortcuts) {
+ Object.entries(shortcuts).forEach(([key, val]) => {
+ commands[key] = val.join("+");
+ });
+ }
+ }
+ setCommands(commands);
+ } catch (err) {
+ kissLog("query cmds", err);
+ }
+ })();
+ }, [setting.shortcuts]);
+
+ const optApis = useMemo(
+ () =>
+ setting.transApis
+ .filter((api) => !api.isDisabled)
+ .map((api) => ({
+ key: api.apiSlug,
+ name: api.apiName || api.apiSlug,
+ })),
+ [setting.transApis]
+ );
+
+ const tranboxEnabled = setting.tranboxSetting.transOpen;
+ const mouseHoverEnabled = setting.mouseHoverSetting.useMouseHover;
+ const inputTransEnabled = setting.inputRule.transOpen;
+
+ const {
+ transOpen,
+ apiSlug,
+ fromLang,
+ toLang,
+ textStyle,
+ autoScan,
+ transOnly,
+ hasRichText,
+ hasShadowroot,
+ } = rule;
+
+ return (
+
+
+
+
+ }
+ label={
+ commands["toggleTranslate"]
+ ? `${i18n("translate_alt")}(${commands["toggleTranslate"]})`
+ : i18n("translate_alt")
+ }
+ />
+
+
+
+ }
+ label={i18n("autoscan_alt")}
+ />
+
+
+
+ }
+ label={i18n("shadowroot_alt")}
+ />
+
+
+
+ }
+ label={i18n("richtext_alt")}
+ />
+
+
+
+ }
+ label={i18n("transonly_alt")}
+ />
+
+
+
+ }
+ label={i18n("selection_translate")}
+ />
+
+
+
+ }
+ label={i18n("mousehover_translate")}
+ />
+
+
+
+ }
+ label={i18n("input_translate")}
+ />
+
+
+
+
+ {optApis.map(({ key, name }) => (
+
+ ))}
+
+
+
+ {OPT_LANGS_FROM.map(([lang, name]) => (
+
+ ))}
+
+
+
+ {OPT_LANGS_TO.map(([lang, name]) => (
+
+ ))}
+
+
+
+ {OPT_STYLE_ALL.map((item) => (
+
+ ))}
+
+
+ {/* {OPT_STYLE_USE_COLOR.includes(textStyle) && (
+
+ )} */}
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/views/Popup/index.js b/src/views/Popup/index.js
index 9bc2447..c34fce4 100644
--- a/src/views/Popup/index.js
+++ b/src/views/Popup/index.js
@@ -1,181 +1,26 @@
-import { useState, useEffect, useMemo } from "react";
+import { useState, useEffect, useCallback } from "react";
import Box from "@mui/material/Box";
import Stack from "@mui/material/Stack";
-import MenuItem from "@mui/material/MenuItem";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import Switch from "@mui/material/Switch";
import Button from "@mui/material/Button";
-import Grid from "@mui/material/Grid";
-import { sendBgMsg, sendTabMsg, getCurTab } from "../../libs/msg";
+import { sendTabMsg } from "../../libs/msg";
import { browser } from "../../libs/browser";
-import { isExt } from "../../libs/client";
import { useI18n } from "../../hooks/I18n";
-import TextField from "@mui/material/TextField";
import Divider from "@mui/material/Divider";
import Header from "./Header";
-import {
- MSG_TRANS_TOGGLE,
- MSG_TRANS_GETRULE,
- MSG_TRANS_PUTRULE,
- MSG_OPEN_OPTIONS,
- MSG_SAVE_RULE,
- MSG_COMMAND_SHORTCUTS,
- MSG_TRANSBOX_TOGGLE,
- MSG_MOUSEHOVER_TOGGLE,
- MSG_TRANSINPUT_TOGGLE,
- OPT_LANGS_FROM,
- OPT_LANGS_TO,
- OPT_STYLE_ALL,
-} from "../../config";
-import { sendIframeMsg } from "../../libs/iframe";
-import { saveRule } from "../../libs/rules";
-import { tryClearCaches } from "../../libs/cache";
+import { MSG_TRANS_GETRULE } from "../../config";
import { kissLog } from "../../libs/log";
-import { parseUrlPattern } from "../../libs/utils";
+import PopupCont from "./PopupCont";
-// 插件popup没有参数
-// 网页弹框有
-export default function Popup({ translator }) {
+export default function Popup() {
const i18n = useI18n();
- const [rule, setRule] = useState(translator?.rule);
- const [setting, setSetting] = useState(translator?.setting);
- const [commands, setCommands] = useState({});
+ const [rule, setRule] = useState(null);
+ const [setting, setSetting] = useState(null);
- const handleOpenSetting = () => {
- if (!translator) {
- browser?.runtime.openOptionsPage();
- } else if (isExt) {
- sendBgMsg(MSG_OPEN_OPTIONS);
- } else {
- window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
- }
- };
-
- const handleTransToggle = async (e) => {
- try {
- setRule({ ...rule, transOpen: e.target.checked ? "true" : "false" });
-
- if (!translator) {
- await sendTabMsg(MSG_TRANS_TOGGLE);
- } else {
- translator.toggle();
- sendIframeMsg(MSG_TRANS_TOGGLE);
- }
- } catch (err) {
- kissLog("toggle trans", err);
- }
- };
-
- const handleTransboxToggle = async (e) => {
- try {
- setSetting((pre) => ({
- ...pre,
- tranboxSetting: { ...pre.tranboxSetting, transOpen: e.target.checked },
- }));
-
- if (!translator) {
- await sendTabMsg(MSG_TRANSBOX_TOGGLE);
- } else {
- translator.toggleTransbox();
- sendIframeMsg(MSG_TRANSBOX_TOGGLE);
- }
- } catch (err) {
- kissLog("toggle transbox", err);
- }
- };
-
- const handleMousehoverToggle = async (e) => {
- try {
- setSetting((pre) => ({
- ...pre,
- mouseHoverSetting: {
- ...pre.mouseHoverSetting,
- useMouseHover: e.target.checked,
- },
- }));
-
- if (!translator) {
- await sendTabMsg(MSG_MOUSEHOVER_TOGGLE);
- } else {
- translator.toggleMouseHover();
- sendIframeMsg(MSG_MOUSEHOVER_TOGGLE);
- }
- } catch (err) {
- kissLog("toggle mousehover", err);
- }
- };
-
- const handleInputTransToggle = async (e) => {
- try {
- setSetting((pre) => ({
- ...pre,
- inputRule: {
- ...pre.inputRule,
- transOpen: e.target.checked,
- },
- }));
-
- if (!translator) {
- await sendTabMsg(MSG_TRANSINPUT_TOGGLE);
- } else {
- translator.toggleInputTranslate();
- sendIframeMsg(MSG_TRANSINPUT_TOGGLE);
- }
- } catch (err) {
- kissLog("toggle inputtrans", err);
- }
- };
-
- const handleChange = async (e) => {
- try {
- const { name, value } = e.target;
- setRule((pre) => ({ ...pre, [name]: value }));
-
- if (!translator) {
- await sendTabMsg(MSG_TRANS_PUTRULE, { [name]: value });
- } else {
- translator.updateRule({ [name]: value });
- sendIframeMsg(MSG_TRANS_PUTRULE, { [name]: value });
- }
- } catch (err) {
- kissLog("update rule", err);
- }
- };
-
- const handleClearCache = () => {
- tryClearCaches();
- };
-
- const handleSaveRule = async () => {
- try {
- let href = "";
- if (!translator) {
- const tab = await getCurTab();
- href = tab.url;
- } else {
- href = window.location?.href;
- }
-
- if (!href || typeof href !== "string") {
- return;
- }
-
- const pattern = parseUrlPattern(href);
- const curRule = { ...rule, pattern };
- if (isExt && translator) {
- sendBgMsg(MSG_SAVE_RULE, curRule);
- } else {
- saveRule(curRule);
- }
- } catch (err) {
- kissLog("save rule", err);
- }
- };
+ const handleOpenSetting = useCallback(() => {
+ browser?.runtime.openOptionsPage();
+ }, []);
useEffect(() => {
- if (translator) {
- return;
- }
(async () => {
try {
const res = await sendTabMsg(MSG_TRANS_GETRULE);
@@ -187,297 +32,27 @@ export default function Popup({ translator }) {
kissLog("query rule", err);
}
})();
- }, [translator]);
+ }, []);
- useEffect(() => {
- (async () => {
- try {
- const commands = {};
- if (isExt) {
- const res = await sendBgMsg(MSG_COMMAND_SHORTCUTS);
- res.forEach(({ name, shortcut }) => {
- commands[name] = shortcut;
- });
- } else {
- const shortcuts = translator.setting.shortcuts;
- if (shortcuts) {
- Object.entries(shortcuts).forEach(([key, val]) => {
- commands[key] = val.join("+");
- });
- }
- }
- setCommands(commands);
- } catch (err) {
- kissLog("query cmds", err);
- }
- })();
- }, [translator]);
-
- const optApis = useMemo(
- () =>
- setting?.transApis
- .filter((api) => !api.isDisabled)
- .map((api) => ({
- key: api.apiSlug,
- name: api.apiName || api.apiSlug,
- })),
- [setting]
- );
-
- const tranboxEnabled = setting?.tranboxSetting.transOpen;
- const mouseHoverEnabled = setting?.mouseHoverSetting.useMouseHover;
- const inputTransEnabled = setting?.inputRule.transOpen;
-
- if (!rule) {
- return (
-
- {!translator && (
- <>
-
-
- >
- )}
+ return (
+
+
+
+ {rule && setting ? (
+
+ ) : (
-
- );
- }
-
- const {
- transOpen,
- apiSlug,
- fromLang,
- toLang,
- textStyle,
- autoScan,
- transOnly,
- hasRichText,
- hasShadowroot,
- } = rule;
-
- return (
-
- {!translator && (
- <>
-
-
- >
)}
-
-
-
-
- }
- label={
- commands["toggleTranslate"]
- ? `${i18n("translate_alt")}(${commands["toggleTranslate"]})`
- : i18n("translate_alt")
- }
- />
-
-
-
- }
- label={i18n("autoscan_alt")}
- />
-
-
-
- }
- label={i18n("shadowroot_alt")}
- />
-
-
-
- }
- label={i18n("richtext_alt")}
- />
-
-
-
- }
- label={i18n("transonly_alt")}
- />
-
-
-
- }
- label={i18n("selection_translate")}
- />
-
-
-
- }
- label={i18n("mousehover_translate")}
- />
-
-
-
- }
- label={i18n("input_translate")}
- />
-
-
-
-
- {optApis.map(({ key, name }) => (
-
- ))}
-
-
-
- {OPT_LANGS_FROM.map(([lang, name]) => (
-
- ))}
-
-
-
- {OPT_LANGS_TO.map(([lang, name]) => (
-
- ))}
-
-
-
- {OPT_STYLE_ALL.map((item) => (
-
- ))}
-
-
- {/* {OPT_STYLE_USE_COLOR.includes(textStyle) && (
-
- )} */}
-
-
-
-
-
-
-
);
}
diff --git a/src/views/Selection/TranBox.js b/src/views/Selection/TranBox.js
index 2b929c8..c3c9f4b 100644
--- a/src/views/Selection/TranBox.js
+++ b/src/views/Selection/TranBox.js
@@ -20,7 +20,7 @@ import { isMobile } from "../../libs/mobile";
import TranForm from "./TranForm.js";
function Header({
- setShowPopup,
+ setShowBox,
simpleStyle,
setSimpleStyle,
hideClickAway,
@@ -98,7 +98,7 @@ function Header({
{
- setShowPopup(false);
+ setShowBox(false);
}}
>
@@ -111,6 +111,7 @@ function Header({
}
export default function TranBox({
+ showBox,
text,
setText,
setShowBox,
@@ -134,43 +135,45 @@ export default function TranBox({
return (
-
- }
- onClick={(e) => e.stopPropagation()}
- onMouseEnter={() => setMouseHover(true)}
- onMouseLeave={() => setMouseHover(false)}
- >
-
-
-
-
+ {showBox && (
+
+ }
+ onClick={(e) => e.stopPropagation()}
+ onMouseEnter={() => setMouseHover(true)}
+ onMouseLeave={() => setMouseHover(false)}
+ >
+
+
+
+
+ )}
);
diff --git a/src/views/Selection/index.js b/src/views/Selection/index.js
index c3d0bef..b54f827 100644
--- a/src/views/Selection/index.js
+++ b/src/views/Selection/index.js
@@ -10,6 +10,7 @@ import {
OPT_TRANBOX_TRIGGER_CLICK,
OPT_TRANBOX_TRIGGER_HOVER,
OPT_TRANBOX_TRIGGER_SELECT,
+ EVENT_KISS,
} from "../../config";
import { isMobile } from "../../libs/mobile";
import { kissLog } from "../../libs/log";
@@ -167,12 +168,26 @@ export default function Slection({
};
}, [tranboxShortcut, handleTranbox]);
+ const handleToggle = useCallback(() => {
+ if (showBox) {
+ setShowBox(false);
+ } else {
+ handleTranbox();
+ }
+ }, [showBox, handleTranbox]);
+
useEffect(() => {
- window.addEventListener(MSG_OPEN_TRANBOX, handleTranbox);
- return () => {
- window.removeEventListener(MSG_OPEN_TRANBOX, handleTranbox);
+ const handleStatusUpdate = (event) => {
+ if (event.detail?.action === MSG_OPEN_TRANBOX) {
+ handleToggle();
+ }
};
- }, [handleTranbox]);
+
+ document.addEventListener(EVENT_KISS, handleStatusUpdate);
+ return () => {
+ document.removeEventListener(EVENT_KISS, handleStatusUpdate);
+ };
+ }, [handleToggle]);
useEffect(() => {
if (!isGm) {
@@ -217,8 +232,9 @@ export default function Slection({
return (
<>
- {showBox && (
+ {
- )}
+ }
{showBtn && (