optimize Translator class & EVENT_KISS event

This commit is contained in:
Gabe Yuan
2023-08-09 13:22:10 +08:00
parent 5b38c38feb
commit 8bfd02bbc4
3 changed files with 69 additions and 57 deletions

View File

@@ -1,63 +1,26 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { useState } from "react"; import { useState } from "react";
import { transPool } from "../libs/pool"; import { transPool } from "../libs/pool";
import { browser } from "../libs/browser";
import { MSG_TRANS_PUTRULE, EVENT_KISS } from "../config";
import { detectLang } from "../libs"; import { detectLang } from "../libs";
import { isExt } from "../libs/browser";
/** /**
* 翻译hook * 翻译hook
* @param {*} q * @param {*} q
* @param {*} rule
* @returns * @returns
*/ */
export function useTranslate(q, initRule) { export function useTranslate(q, rule) {
const [text, setText] = useState(""); const [text, setText] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [sameLang, setSamelang] = useState(false); const [sameLang, setSamelang] = useState(false);
const [rule, setRule] = useState(initRule);
const { translator, fromLang, toLang, textStyle, bgColor } = rule; const { translator, fromLang, toLang } = rule;
const handleMessage = ({ action, args }) => {
if (action === MSG_TRANS_PUTRULE) {
setRule((pre) => ({ ...pre, ...args }));
}
return true;
};
const handleKissEvent = (e) => {
const action = e?.detail?.action;
const args = e?.detail?.args || {};
switch (action) {
case MSG_TRANS_PUTRULE:
setRule((pre) => ({ ...pre, ...args }));
break;
default:
// console.log(`[popup] kissEvent action skip: ${action}`);
}
};
useEffect(() => {
if (isExt) {
browser?.runtime.onMessage.addListener(handleMessage);
} else {
window.addEventListener(EVENT_KISS, handleKissEvent);
}
return () => {
if (isExt) {
browser?.runtime.onMessage.removeListener(handleMessage);
} else {
window.removeEventListener(EVENT_KISS, handleKissEvent);
}
};
}, []);
useEffect(() => { useEffect(() => {
(async () => { (async () => {
try { try {
setLoading(true); setLoading(true);
const deLang = await detectLang(q); const deLang = await detectLang(q);
if (toLang.includes(deLang)) { if (toLang.includes(deLang)) {
setSamelang(true); setSamelang(true);
@@ -79,5 +42,5 @@ export function useTranslate(q, initRule) {
})(); })();
}, [q, translator, fromLang, toLang]); }, [q, translator, fromLang, toLang]);
return { text, sameLang, loading, textStyle, bgColor }; return { text, sameLang, loading };
} }

View File

@@ -1,5 +1,11 @@
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import { APP_LCNAME, TRANS_MIN_LENGTH, TRANS_MAX_LENGTH } from "../config"; import {
APP_LCNAME,
TRANS_MIN_LENGTH,
TRANS_MAX_LENGTH,
EVENT_KISS,
MSG_TRANS_CURRULE,
} from "../config";
import { StoragesProvider } from "../hooks/Storage"; import { StoragesProvider } from "../hooks/Storage";
import { queryEls } from "."; import { queryEls } from ".";
import Content from "../views/Content"; import Content from "../views/Content";
@@ -28,7 +34,7 @@ export class Translator {
mutations.forEach((mutation) => { mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => { mutation.addedNodes.forEach((node) => {
try { try {
queryEls(this._rule.selector, node).forEach((el) => { queryEls(this.rule.selector, node).forEach((el) => {
this._interseObserver.observe(el); this._interseObserver.observe(el);
}); });
} catch (err) { } catch (err) {
@@ -39,26 +45,42 @@ export class Translator {
}); });
constructor(rule) { constructor(rule) {
this._rule = rule; this.rule = rule;
if (rule.transOpen === "true") { if (rule.transOpen === "true") {
this._register(); this._register();
} }
} }
get rule() { get rule() {
// console.log("get rule", this._rule);
return this._rule; return this._rule;
} }
set rule(rule) {
// console.log("set rule", rule);
this._rule = rule;
// 广播消息
window.dispatchEvent(
new CustomEvent(EVENT_KISS, {
detail: {
action: MSG_TRANS_CURRULE,
args: rule,
},
})
);
}
updateRule = (obj) => { updateRule = (obj) => {
this._rule = { ...this._rule, ...obj }; this.rule = { ...this.rule, ...obj };
}; };
toggle = () => { toggle = () => {
if (this._rule.transOpen === "true") { if (this.rule.transOpen === "true") {
this._rule = { ...this._rule, transOpen: "false" }; this.rule = { ...this.rule, transOpen: "false" };
this._unRegister(); this._unRegister();
} else { } else {
this._rule = { ...this._rule, transOpen: "true" }; this.rule = { ...this.rule, transOpen: "true" };
this._register(); this._register();
} }
}; };
@@ -71,7 +93,7 @@ export class Translator {
}); });
// 监听节点显示 // 监听节点显示
queryEls(this._rule.selector).forEach((el) => { queryEls(this.rule.selector).forEach((el) => {
this._interseObserver.observe(el); this._interseObserver.observe(el);
}); });
}; };
@@ -81,7 +103,7 @@ export class Translator {
this._mutaObserver.disconnect(); this._mutaObserver.disconnect();
// 解除节点显示监听 // 解除节点显示监听
queryEls(this._rule.selector).forEach((el) => queryEls(this.rule.selector).forEach((el) =>
this._interseObserver.unobserve(el) this._interseObserver.unobserve(el)
); );
@@ -90,14 +112,19 @@ export class Translator {
}; };
_render = (el) => { _render = (el) => {
// 含子元素
if (el.querySelector(this.rule.selector)) {
return;
}
// 已翻译
if (el.querySelector(APP_LCNAME)) { if (el.querySelector(APP_LCNAME)) {
return; return;
} }
// 除openai外保留code和a标签 // 太长或太短
const q = el.innerText.trim(); const q = el.innerText.trim();
if (!q || q.length < TRANS_MIN_LENGTH || q.length > TRANS_MAX_LENGTH) { if (!q || q.length < TRANS_MIN_LENGTH || q.length > TRANS_MAX_LENGTH) {
// 太长或太短不翻译
return; return;
} }
@@ -109,7 +136,7 @@ export class Translator {
const root = createRoot(span); const root = createRoot(span);
root.render( root.render(
<StoragesProvider> <StoragesProvider>
<Content q={q} rule={this._rule} /> <Content q={q} translator={this} />
</StoragesProvider> </StoragesProvider>
); );
}; };

View File

@@ -1,4 +1,4 @@
import { useMemo, useState } from "react"; import { useMemo, useState, useEffect } from "react";
import LoadingIcon from "./LoadingIcon"; import LoadingIcon from "./LoadingIcon";
import { import {
OPT_STYLE_LINE, OPT_STYLE_LINE,
@@ -8,12 +8,16 @@ import {
OPT_STYLE_FUZZY, OPT_STYLE_FUZZY,
OPT_STYLE_HIGHTLIGHT, OPT_STYLE_HIGHTLIGHT,
DEFAULT_COLOR, DEFAULT_COLOR,
EVENT_KISS,
MSG_TRANS_CURRULE,
} from "../../config"; } from "../../config";
import { useTranslate } from "../../hooks/Translate"; import { useTranslate } from "../../hooks/Translate";
export default function Content({ q, rule }) { export default function Content({ q, translator }) {
const [rule, setRule] = useState(translator.rule);
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
const { text, sameLang, loading, textStyle, bgColor } = useTranslate(q, rule); const { text, sameLang, loading } = useTranslate(q, rule);
const { textStyle, bgColor } = rule;
const handleMouseEnter = () => { const handleMouseEnter = () => {
setHover(true); setHover(true);
@@ -23,6 +27,24 @@ export default function Content({ q, rule }) {
setHover(false); setHover(false);
}; };
const handleKissEvent = (e) => {
const { action, args } = e.detail;
switch (action) {
case MSG_TRANS_CURRULE:
setRule(args);
break;
default:
// console.log(`[popup] kissEvent action skip: ${action}`);
}
};
useEffect(() => {
window.addEventListener(EVENT_KISS, handleKissEvent);
return () => {
window.removeEventListener(EVENT_KISS, handleKissEvent);
};
}, []);
const style = useMemo(() => { const style = useMemo(() => {
const lineColor = bgColor || ""; const lineColor = bgColor || "";
switch (textStyle) { switch (textStyle) {