259 lines
6.8 KiB
JavaScript
259 lines
6.8 KiB
JavaScript
|
|
import { browser } from "./browser";
|
||
|
|
import { Translator } from "./translator";
|
||
|
|
import { InputTranslator } from "./inputTranslate";
|
||
|
|
import { TransboxManager } from "./tranbox";
|
||
|
|
import { shortcutRegister } from "./shortcut";
|
||
|
|
import { sendIframeMsg } from "./iframe";
|
||
|
|
import { newI18n } from "../config";
|
||
|
|
import { touchTapListener } from "./touch";
|
||
|
|
import { debounce } from "./utils";
|
||
|
|
import { PopupManager } from "./popupManager";
|
||
|
|
import { FabManager } from "./fabManager";
|
||
|
|
import {
|
||
|
|
OPT_SHORTCUT_TRANSLATE,
|
||
|
|
OPT_SHORTCUT_STYLE,
|
||
|
|
OPT_SHORTCUT_POPUP,
|
||
|
|
OPT_SHORTCUT_SETTING,
|
||
|
|
MSG_TRANS_TOGGLE,
|
||
|
|
MSG_TRANS_TOGGLE_STYLE,
|
||
|
|
MSG_TRANS_GETRULE,
|
||
|
|
MSG_TRANS_PUTRULE,
|
||
|
|
MSG_OPEN_TRANBOX,
|
||
|
|
MSG_TRANSBOX_TOGGLE,
|
||
|
|
MSG_MOUSEHOVER_TOGGLE,
|
||
|
|
MSG_TRANSINPUT_TOGGLE,
|
||
|
|
} from "../config";
|
||
|
|
import { logger } from "./log";
|
||
|
|
|
||
|
|
export default class TranslatorManager {
|
||
|
|
#clearShortcuts = [];
|
||
|
|
#menuCommandIds = [];
|
||
|
|
#clearTouchListener = null;
|
||
|
|
#isActive = false;
|
||
|
|
#isUserscript;
|
||
|
|
#isIframe;
|
||
|
|
|
||
|
|
#windowMessageHandler = null;
|
||
|
|
#browserMessageHandler = null;
|
||
|
|
|
||
|
|
_translator;
|
||
|
|
_transboxManager;
|
||
|
|
_inputTranslator;
|
||
|
|
_popupManager;
|
||
|
|
_fabManager;
|
||
|
|
|
||
|
|
constructor({ setting, rule, fabConfig, favWords, isIframe, isUserscript }) {
|
||
|
|
this.#isIframe = isIframe;
|
||
|
|
this.#isUserscript = isUserscript;
|
||
|
|
|
||
|
|
this._translator = new Translator({
|
||
|
|
rule,
|
||
|
|
setting,
|
||
|
|
favWords,
|
||
|
|
isUserscript,
|
||
|
|
isIframe,
|
||
|
|
});
|
||
|
|
|
||
|
|
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.#windowMessageHandler = this.#handleWindowMessage.bind(this);
|
||
|
|
this.#browserMessageHandler = this.#handleBrowserMessage.bind(this);
|
||
|
|
}
|
||
|
|
|
||
|
|
start() {
|
||
|
|
if (this.#isActive) {
|
||
|
|
logger.info("TranslatorManager is already started.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.#setupMessageListeners();
|
||
|
|
this.#setupTouchOperations();
|
||
|
|
|
||
|
|
if (!this.#isIframe && this.#isUserscript) {
|
||
|
|
this.#registerShortcuts();
|
||
|
|
this.#registerMenus();
|
||
|
|
}
|
||
|
|
|
||
|
|
this.#isActive = true;
|
||
|
|
logger.info("TranslatorManager started.");
|
||
|
|
}
|
||
|
|
|
||
|
|
stop() {
|
||
|
|
if (!this.#isActive) {
|
||
|
|
logger.info("TranslatorManager is not running.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 移除消息监听器
|
||
|
|
if (this.#isUserscript) {
|
||
|
|
window.removeEventListener("message", this.#windowMessageHandler);
|
||
|
|
} else if (
|
||
|
|
browser.runtime.onMessage.hasListener(this.#browserMessageHandler)
|
||
|
|
) {
|
||
|
|
browser.runtime.onMessage.removeListener(this.#browserMessageHandler);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 已注册的快捷键
|
||
|
|
this.#clearShortcuts.forEach((clear) => clear());
|
||
|
|
this.#clearShortcuts = [];
|
||
|
|
|
||
|
|
// 触屏
|
||
|
|
if (this.#clearTouchListener) {
|
||
|
|
this.#clearTouchListener();
|
||
|
|
this.#clearTouchListener = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 油猴菜单
|
||
|
|
if (globalThis.GM && this.#menuCommandIds.length > 0) {
|
||
|
|
this.#menuCommandIds.forEach((id) =>
|
||
|
|
globalThis.GM.unregisterMenuCommand(id)
|
||
|
|
);
|
||
|
|
this.#menuCommandIds = [];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 子模块
|
||
|
|
this._popupManager?.hide();
|
||
|
|
this._fabManager?.hide();
|
||
|
|
this._transboxManager?.disable();
|
||
|
|
this._inputTranslator?.disable();
|
||
|
|
this._translator.stop();
|
||
|
|
|
||
|
|
this.#isActive = false;
|
||
|
|
logger.info("TranslatorManager stopped.");
|
||
|
|
}
|
||
|
|
|
||
|
|
#setupMessageListeners() {
|
||
|
|
if (this.#isUserscript) {
|
||
|
|
window.addEventListener("message", this.#windowMessageHandler);
|
||
|
|
} else {
|
||
|
|
browser.runtime.onMessage.addListener(this.#browserMessageHandler);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#setupTouchOperations() {
|
||
|
|
if (this.#isIframe) return;
|
||
|
|
|
||
|
|
const { touchTranslate = 2 } = this._translator.setting;
|
||
|
|
if (touchTranslate === 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleTap = debounce(() => {
|
||
|
|
this.#processActions({ action: MSG_TRANS_TOGGLE });
|
||
|
|
}, 300);
|
||
|
|
|
||
|
|
this.#clearTouchListener = touchTapListener(handleTap, touchTranslate);
|
||
|
|
}
|
||
|
|
|
||
|
|
#handleWindowMessage(event) {
|
||
|
|
this.#processActions(event.data);
|
||
|
|
}
|
||
|
|
|
||
|
|
#handleBrowserMessage(message, sender, sendResponse) {
|
||
|
|
const result = this.#processActions(message);
|
||
|
|
const response = result || {
|
||
|
|
rule: this._translator.rule,
|
||
|
|
setting: this._translator.setting,
|
||
|
|
};
|
||
|
|
sendResponse(response);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
#registerShortcuts() {
|
||
|
|
const { shortcuts } = this._translator.setting;
|
||
|
|
this.#clearShortcuts = [
|
||
|
|
shortcutRegister(shortcuts[OPT_SHORTCUT_TRANSLATE], () =>
|
||
|
|
this.#processActions({ action: MSG_TRANS_TOGGLE })
|
||
|
|
),
|
||
|
|
shortcutRegister(shortcuts[OPT_SHORTCUT_STYLE], () =>
|
||
|
|
this.#processActions({ action: MSG_TRANS_TOGGLE_STYLE })
|
||
|
|
),
|
||
|
|
shortcutRegister(shortcuts[OPT_SHORTCUT_POPUP], () =>
|
||
|
|
this._popupManager.toggle()
|
||
|
|
),
|
||
|
|
shortcutRegister(shortcuts[OPT_SHORTCUT_SETTING], () =>
|
||
|
|
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank")
|
||
|
|
),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
#registerMenus() {
|
||
|
|
if (!globalThis.GM) return;
|
||
|
|
const { contextMenuType, uiLang } = this._translator.setting;
|
||
|
|
if (contextMenuType === 0) return;
|
||
|
|
|
||
|
|
const i18n = newI18n(uiLang || "zh");
|
||
|
|
const GM = globalThis.GM;
|
||
|
|
this.#menuCommandIds = [
|
||
|
|
GM.registerMenuCommand(
|
||
|
|
i18n("translate_switch"),
|
||
|
|
() => this.#processActions({ action: MSG_TRANS_TOGGLE }),
|
||
|
|
"Q"
|
||
|
|
),
|
||
|
|
GM.registerMenuCommand(
|
||
|
|
i18n("toggle_style"),
|
||
|
|
() => this.#processActions({ action: MSG_TRANS_TOGGLE_STYLE }),
|
||
|
|
"C"
|
||
|
|
),
|
||
|
|
GM.registerMenuCommand(
|
||
|
|
i18n("open_menu"),
|
||
|
|
() => this._popupManager.toggle(),
|
||
|
|
"K"
|
||
|
|
),
|
||
|
|
GM.registerMenuCommand(
|
||
|
|
i18n("open_setting"),
|
||
|
|
() => window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank"),
|
||
|
|
"O"
|
||
|
|
),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
#processActions({ action, args } = {}) {
|
||
|
|
if (this.#isUserscript) {
|
||
|
|
sendIframeMsg(action);
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (action) {
|
||
|
|
case MSG_TRANS_TOGGLE:
|
||
|
|
this._translator.toggle();
|
||
|
|
break;
|
||
|
|
case MSG_TRANS_TOGGLE_STYLE:
|
||
|
|
this._translator.toggleStyle();
|
||
|
|
break;
|
||
|
|
case MSG_TRANS_GETRULE:
|
||
|
|
break;
|
||
|
|
case MSG_TRANS_PUTRULE:
|
||
|
|
this._translator.updateRule(args);
|
||
|
|
break;
|
||
|
|
case MSG_OPEN_TRANBOX:
|
||
|
|
this._transboxManager?.enable();
|
||
|
|
break;
|
||
|
|
case MSG_TRANSBOX_TOGGLE:
|
||
|
|
this._transboxManager?.toggle();
|
||
|
|
break;
|
||
|
|
case MSG_MOUSEHOVER_TOGGLE:
|
||
|
|
this._translator.toggleMouseHover();
|
||
|
|
break;
|
||
|
|
case MSG_TRANSINPUT_TOGGLE:
|
||
|
|
this._inputTranslator?.toggle();
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
logger.info(`Message action is unavailable: ${action}`);
|
||
|
|
return { error: `Message action is unavailable: ${action}` };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|