feat: move settings to rule
This commit is contained in:
2
.env
2
.env
@@ -17,8 +17,6 @@ REACT_APP_RULESURL=https://fishjar.github.io/kiss-rules/kiss-rules.json
|
|||||||
REACT_APP_RULESURL_ON=https://fishjar.github.io/kiss-rules/kiss-rules-on.json
|
REACT_APP_RULESURL_ON=https://fishjar.github.io/kiss-rules/kiss-rules-on.json
|
||||||
REACT_APP_RULESURL_OFF=https://fishjar.github.io/kiss-rules/kiss-rules-off.json
|
REACT_APP_RULESURL_OFF=https://fishjar.github.io/kiss-rules/kiss-rules-off.json
|
||||||
|
|
||||||
REACT_APP_WEBFIXURL=https://fishjar.github.io/kiss-rules/kiss-webfix.json
|
|
||||||
|
|
||||||
REACT_APP_VERSIONFILE=https://fishjar.github.io/kiss-translator/version.txt
|
REACT_APP_VERSIONFILE=https://fishjar.github.io/kiss-translator/version.txt
|
||||||
REACT_APP_VERSIONFILE2=https://kiss-translator.rayjar.com/version.txt
|
REACT_APP_VERSIONFILE2=https://kiss-translator.rayjar.com/version.txt
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,6 @@ A simple, open source [bilingual translation extension & Greasemonkey script](ht
|
|||||||
- Community subscription rules: [https://github.com/fishjar/kiss-rules](https://github.com/fishjar/kiss-rules)
|
- Community subscription rules: [https://github.com/fishjar/kiss-rules](https://github.com/fishjar/kiss-rules)
|
||||||
- Provides the latest and most complete list of subscription rules maintained by the community.
|
- Provides the latest and most complete list of subscription rules maintained by the community.
|
||||||
- Help with rules-related issues.
|
- Help with rules-related issues.
|
||||||
- Web page correction script: [https://github.com/fishjar/kiss-webfixer](https://github.com/fishjar/kiss-webfixer)
|
|
||||||
- Fixed scripts for some special sites.
|
|
||||||
- So that the translation software can get better display effect.
|
|
||||||
- Translation interface agent: [https://github.com/fishjar/kiss-proxy](https://github.com/fishjar/kiss-proxy)
|
- Translation interface agent: [https://github.com/fishjar/kiss-proxy](https://github.com/fishjar/kiss-proxy)
|
||||||
- If you encounter network problems when accessing a certain translation interface, this proxy service may help you.
|
- If you encounter network problems when accessing a certain translation interface, this proxy service may help you.
|
||||||
- Deploy and manage by yourself.
|
- Deploy and manage by yourself.
|
||||||
|
|||||||
@@ -62,9 +62,6 @@
|
|||||||
- 社区订阅规则: [https://github.com/fishjar/kiss-rules](https://github.com/fishjar/kiss-rules)
|
- 社区订阅规则: [https://github.com/fishjar/kiss-rules](https://github.com/fishjar/kiss-rules)
|
||||||
- 提供社区维护的,最新最全的订阅规则列表。
|
- 提供社区维护的,最新最全的订阅规则列表。
|
||||||
- 求助规则相关的问题。
|
- 求助规则相关的问题。
|
||||||
- 网页修正脚本: [https://github.com/fishjar/kiss-webfixer](https://github.com/fishjar/kiss-webfixer)
|
|
||||||
- 针对一些特殊网站的修正脚本。
|
|
||||||
- 以便翻译软件得到更好的展示效果。
|
|
||||||
- 翻译接口代理: [https://github.com/fishjar/kiss-proxy](https://github.com/fishjar/kiss-proxy)
|
- 翻译接口代理: [https://github.com/fishjar/kiss-proxy](https://github.com/fishjar/kiss-proxy)
|
||||||
- 如果访问某个翻译接口遇到网络问题,这个代理服务也许可以帮到你。
|
- 如果访问某个翻译接口遇到网络问题,这个代理服务也许可以帮到你。
|
||||||
- 自己部署,自己管理。
|
- 自己部署,自己管理。
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { touchTapListener } from "./libs/touch";
|
|||||||
import { debounce, genEventName } from "./libs/utils";
|
import { debounce, genEventName } from "./libs/utils";
|
||||||
import { handlePing, injectScript } from "./libs/gm";
|
import { handlePing, injectScript } from "./libs/gm";
|
||||||
import { browser } from "./libs/browser";
|
import { browser } from "./libs/browser";
|
||||||
import { matchFixer } from "./libs/webfix";
|
|
||||||
import { matchRule } from "./libs/rules";
|
import { matchRule } from "./libs/rules";
|
||||||
import { trySyncAllSubRules } from "./libs/subRules";
|
import { trySyncAllSubRules } from "./libs/subRules";
|
||||||
import { isInBlacklist } from "./libs/blacklist";
|
import { isInBlacklist } from "./libs/blacklist";
|
||||||
@@ -223,12 +222,9 @@ export async function run(isUserscript = false) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 不规范网页修复
|
|
||||||
const fixerSetting = await matchFixer(href, setting);
|
|
||||||
|
|
||||||
// 翻译网页
|
// 翻译网页
|
||||||
const rule = await matchRule(href, setting);
|
const rule = await matchRule(href, setting);
|
||||||
const translator = new Translator(rule, setting, fixerSetting);
|
const translator = new Translator(rule, setting);
|
||||||
|
|
||||||
// 适配iframe
|
// 适配iframe
|
||||||
if (isIframe) {
|
if (isIframe) {
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ export const I18N = {
|
|||||||
zh: `翻译时机`,
|
zh: `翻译时机`,
|
||||||
en: `Translate Timing`,
|
en: `Translate Timing`,
|
||||||
},
|
},
|
||||||
mk_disable: {
|
mk_pagescroll: {
|
||||||
zh: `滚动加载翻译(推荐)`,
|
zh: `滚动加载翻译(推荐)`,
|
||||||
en: `Rolling Loading (Suggested)`,
|
en: `Rolling Loading (Suggested)`,
|
||||||
},
|
},
|
||||||
@@ -408,11 +408,11 @@ export const I18N = {
|
|||||||
en: `0. Supports regular expression matching. 1. Separate multiple terms with newlines or semicolons ";". 2. Terms and translations are separated by English commas ",". 3. If there is no translation, the term will be deemed not to be translated. 4. Leave blank to adopt the global setting.`,
|
en: `0. Supports regular expression matching. 1. Separate multiple terms with newlines or semicolons ";". 2. Terms and translations are separated by English commas ",". 3. If there is no translation, the term will be deemed not to be translated. 4. Leave blank to adopt the global setting.`,
|
||||||
},
|
},
|
||||||
selector_style: {
|
selector_style: {
|
||||||
zh: `选择器样式`,
|
zh: `选择器节点样式`,
|
||||||
en: `Selector Style`,
|
en: `Selector Style`,
|
||||||
},
|
},
|
||||||
selector_parent_style: {
|
selector_parent_style: {
|
||||||
zh: `选择器父样式`,
|
zh: `选择器父节点样式`,
|
||||||
en: `Selector Parent Style`,
|
en: `Selector Parent Style`,
|
||||||
},
|
},
|
||||||
inject_js: {
|
inject_js: {
|
||||||
@@ -787,4 +787,8 @@ export const I18N = {
|
|||||||
zh: `更多`,
|
zh: `更多`,
|
||||||
en: `More`,
|
en: `More`,
|
||||||
},
|
},
|
||||||
|
fixer_selector: {
|
||||||
|
zh: `修复函数选择器`,
|
||||||
|
en: `Fixer Selector`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,12 +24,10 @@ export const STOKEY_MSAUTH = `${APP_NAME}_msauth`;
|
|||||||
export const STOKEY_BDAUTH = `${APP_NAME}_bdauth`;
|
export const STOKEY_BDAUTH = `${APP_NAME}_bdauth`;
|
||||||
export const STOKEY_SETTING = `${APP_NAME}_setting`;
|
export const STOKEY_SETTING = `${APP_NAME}_setting`;
|
||||||
export const STOKEY_RULES = `${APP_NAME}_rules`;
|
export const STOKEY_RULES = `${APP_NAME}_rules`;
|
||||||
export const STOKEY_WFRULES = `${APP_NAME}_webfix_rules`;
|
|
||||||
export const STOKEY_WORDS = `${APP_NAME}_words`;
|
export const STOKEY_WORDS = `${APP_NAME}_words`;
|
||||||
export const STOKEY_SYNC = `${APP_NAME}_sync`;
|
export const STOKEY_SYNC = `${APP_NAME}_sync`;
|
||||||
export const STOKEY_FAB = `${APP_NAME}_fab`;
|
export const STOKEY_FAB = `${APP_NAME}_fab`;
|
||||||
export const STOKEY_RULESCACHE_PREFIX = `${APP_NAME}_rulescache_`;
|
export const STOKEY_RULESCACHE_PREFIX = `${APP_NAME}_rulescache_`;
|
||||||
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";
|
||||||
@@ -44,7 +42,6 @@ export const CLIENT_USERSCRIPT = "userscript";
|
|||||||
export const CLIENT_EXTS = [CLIENT_CHROME, CLIENT_EDGE, CLIENT_FIREFOX];
|
export const CLIENT_EXTS = [CLIENT_CHROME, CLIENT_EDGE, CLIENT_FIREFOX];
|
||||||
|
|
||||||
export const KV_RULES_KEY = "kiss-rules.json";
|
export const KV_RULES_KEY = "kiss-rules.json";
|
||||||
export const KV_WFRULES_KEY = "kiss-webfix.json";
|
|
||||||
export const KV_WORDS_KEY = "kiss-words.json";
|
export const KV_WORDS_KEY = "kiss-words.json";
|
||||||
export const KV_RULES_SHARE_KEY = "kiss-rules-share.json";
|
export const KV_RULES_SHARE_KEY = "kiss-rules-share.json";
|
||||||
export const KV_SETTING_KEY = "kiss-setting.json";
|
export const KV_SETTING_KEY = "kiss-setting.json";
|
||||||
@@ -300,19 +297,19 @@ export const OPT_STYLE_USE_COLOR = [
|
|||||||
OPT_STYLE_BLOCKQUOTE,
|
OPT_STYLE_BLOCKQUOTE,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const OPT_MOUSEKEY_DISABLE = "mk_disable"; // 滚动加载翻译
|
export const OPT_TIMING_PAGESCROLL = "mk_pagescroll"; // 滚动加载翻译
|
||||||
export const OPT_MOUSEKEY_PAGEOPEN = "mk_pageopen"; // 直接翻译到底
|
export const OPT_TIMING_PAGEOPEN = "mk_pageopen"; // 直接翻译到底
|
||||||
export const OPT_MOUSEKEY_MOUSEOVER = "mk_mouseover";
|
export const OPT_TIMING_MOUSEOVER = "mk_mouseover";
|
||||||
export const OPT_MOUSEKEY_CONTROL = "mk_ctrlKey";
|
export const OPT_TIMING_CONTROL = "mk_ctrlKey";
|
||||||
export const OPT_MOUSEKEY_SHIFT = "mk_shiftKey";
|
export const OPT_TIMING_SHIFT = "mk_shiftKey";
|
||||||
export const OPT_MOUSEKEY_ALT = "mk_altKey";
|
export const OPT_TIMING_ALT = "mk_altKey";
|
||||||
export const OPT_MOUSEKEY_ALL = [
|
export const OPT_TIMING_ALL = [
|
||||||
OPT_MOUSEKEY_DISABLE,
|
OPT_TIMING_PAGESCROLL,
|
||||||
OPT_MOUSEKEY_PAGEOPEN,
|
OPT_TIMING_PAGEOPEN,
|
||||||
OPT_MOUSEKEY_MOUSEOVER,
|
OPT_TIMING_MOUSEOVER,
|
||||||
OPT_MOUSEKEY_CONTROL,
|
OPT_TIMING_CONTROL,
|
||||||
OPT_MOUSEKEY_SHIFT,
|
OPT_TIMING_SHIFT,
|
||||||
OPT_MOUSEKEY_ALT,
|
OPT_TIMING_ALT,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_FETCH_LIMIT = 10; // 默认最大任务数量
|
export const DEFAULT_FETCH_LIMIT = 10; // 默认最大任务数量
|
||||||
@@ -325,24 +322,34 @@ export const PROMPT_PLACE_TEXT = "{{text}}"; // 占位符
|
|||||||
export const DEFAULT_COLOR = "#209CEE"; // 默认高亮背景色/线条颜色
|
export const DEFAULT_COLOR = "#209CEE"; // 默认高亮背景色/线条颜色
|
||||||
|
|
||||||
export const DEFAULT_TRANS_TAG = "font";
|
export const DEFAULT_TRANS_TAG = "font";
|
||||||
|
export const DEFAULT_SELECT_STYLE =
|
||||||
|
"-webkit-line-clamp: unset; max-height: none; height: auto;";
|
||||||
|
|
||||||
// 全局规则
|
// 全局规则
|
||||||
export const GLOBLA_RULE = {
|
export const GLOBLA_RULE = {
|
||||||
pattern: "*",
|
pattern: "*", // 匹配网址
|
||||||
selector: DEFAULT_SELECTOR,
|
selector: DEFAULT_SELECTOR, // 选择器
|
||||||
keepSelector: DEFAULT_KEEP_SELECTOR,
|
keepSelector: DEFAULT_KEEP_SELECTOR, // 保留元素选择器
|
||||||
terms: "",
|
terms: "", // 专业术语
|
||||||
translator: OPT_TRANS_MICROSOFT,
|
translator: OPT_TRANS_MICROSOFT, // 翻译服务
|
||||||
fromLang: "auto",
|
fromLang: "auto", // 源语言
|
||||||
toLang: "zh-CN",
|
toLang: "zh-CN", // 目标语言
|
||||||
textStyle: OPT_STYLE_DASHLINE,
|
textStyle: OPT_STYLE_DASHLINE, // 译文样式
|
||||||
transOpen: "false",
|
transOpen: "false", // 开启翻译
|
||||||
bgColor: "",
|
bgColor: "", // 译文颜色
|
||||||
textDiyStyle: "",
|
textDiyStyle: "", // 自定义译文样式
|
||||||
selectStyle: "-webkit-line-clamp: unset; max-height: none; height: auto;",
|
selectStyle: DEFAULT_SELECT_STYLE, // 选择器节点样式
|
||||||
parentStyle: "-webkit-line-clamp: unset; max-height: none; height: auto;",
|
parentStyle: DEFAULT_SELECT_STYLE, // 选择器父节点样式
|
||||||
injectJs: "",
|
injectJs: "", // 注入JS
|
||||||
injectCss: "",
|
injectCss: "", // 注入CSS
|
||||||
|
transOnly: "false", // 是否仅显示译文
|
||||||
|
transTiming: OPT_TIMING_PAGESCROLL, // 翻译时机/鼠标悬停翻译
|
||||||
|
transTag: DEFAULT_TRANS_TAG, // 译文元素标签
|
||||||
|
transTitle: "false", // 是否同时翻译页面标题
|
||||||
|
detectRemote: "false", // 是否使用远程语言检测
|
||||||
|
skipLangs: [], // 不翻译的语言
|
||||||
|
fixerSelector: "", // 修复函数选择器
|
||||||
|
fixerFunc: "-", // 修复函数
|
||||||
};
|
};
|
||||||
|
|
||||||
// 输入框翻译
|
// 输入框翻译
|
||||||
@@ -458,23 +465,24 @@ export const DEFAULT_SETTING = {
|
|||||||
newlineLength: TRANS_NEWLINE_LENGTH,
|
newlineLength: TRANS_NEWLINE_LENGTH,
|
||||||
clearCache: false, // 是否在浏览器下次启动时清除缓存
|
clearCache: false, // 是否在浏览器下次启动时清除缓存
|
||||||
injectRules: true, // 是否注入订阅规则
|
injectRules: true, // 是否注入订阅规则
|
||||||
injectWebfix: true, // 是否注入修复补丁
|
// injectWebfix: true, // 是否注入修复补丁(作废)
|
||||||
detectRemote: false, // 是否使用远程语言检测
|
// detectRemote: false, // 是否使用远程语言检测(移至rule,作废)
|
||||||
contextMenus: true, // 是否添加右键菜单(作废)
|
// contextMenus: true, // 是否添加右键菜单(作废)
|
||||||
contextMenuType: 1, // 右键菜单类型(0不显示,1简单菜单,2多级菜单)
|
contextMenuType: 1, // 右键菜单类型(0不显示,1简单菜单,2多级菜单)
|
||||||
transTag: DEFAULT_TRANS_TAG, // 译文元素标签
|
// transTag: DEFAULT_TRANS_TAG, // 译文元素标签(移至rule,作废)
|
||||||
transOnly: false, // 是否仅显示译文
|
// transOnly: false, // 是否仅显示译文(移至rule,作废)
|
||||||
transTitle: false, // 是否同时翻译页面标题
|
// transTitle: false, // 是否同时翻译页面标题(移至rule,作废)
|
||||||
subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表
|
subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表
|
||||||
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
|
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
|
||||||
transApis: DEFAULT_TRANS_APIS, // 翻译接口
|
transApis: DEFAULT_TRANS_APIS, // 翻译接口
|
||||||
mouseKey: OPT_MOUSEKEY_DISABLE, // 翻译时机/鼠标悬停翻译
|
// mouseKey: OPT_TIMING_PAGESCROLL, // 翻译时机/鼠标悬停翻译(移至rule,作废)
|
||||||
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
|
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
|
||||||
inputRule: DEFAULT_INPUT_RULE, // 输入框设置
|
inputRule: DEFAULT_INPUT_RULE, // 输入框设置
|
||||||
tranboxSetting: DEFAULT_TRANBOX_SETTING, // 划词翻译设置
|
tranboxSetting: DEFAULT_TRANBOX_SETTING, // 划词翻译设置
|
||||||
touchTranslate: 2, // 触屏翻译
|
touchTranslate: 2, // 触屏翻译
|
||||||
blacklist: DEFAULT_BLACKLIST.join(",\n"), // 禁用翻译名单
|
blacklist: DEFAULT_BLACKLIST.join(",\n"), // 禁用翻译名单
|
||||||
disableLangs: [], // 不翻译的语言
|
// disableLangs: [], // 不翻译的语言(移至rule,作废)
|
||||||
|
transInterval: 500, // 翻译间隔时间
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_RULES = [GLOBLA_RULE];
|
export const DEFAULT_RULES = [GLOBLA_RULE];
|
||||||
|
|||||||
@@ -7,21 +7,29 @@ export const REMAIN_KEY = "-";
|
|||||||
export const SHADOW_KEY = ">>>";
|
export const SHADOW_KEY = ">>>";
|
||||||
|
|
||||||
export const DEFAULT_RULE = {
|
export const DEFAULT_RULE = {
|
||||||
pattern: "",
|
pattern: "", // 匹配网址
|
||||||
selector: "",
|
selector: "", // 选择器
|
||||||
keepSelector: "",
|
keepSelector: "", // 保留元素选择器
|
||||||
terms: "",
|
terms: "", // 专业术语
|
||||||
translator: GLOBAL_KEY,
|
translator: GLOBAL_KEY, // 翻译服务
|
||||||
fromLang: GLOBAL_KEY,
|
fromLang: GLOBAL_KEY, // 源语言
|
||||||
toLang: GLOBAL_KEY,
|
toLang: GLOBAL_KEY, // 目标语言
|
||||||
textStyle: GLOBAL_KEY,
|
textStyle: GLOBAL_KEY, // 译文样式
|
||||||
transOpen: GLOBAL_KEY,
|
transOpen: GLOBAL_KEY, // 开启翻译
|
||||||
bgColor: "",
|
bgColor: "", // 译文颜色
|
||||||
textDiyStyle: "",
|
textDiyStyle: "", // 自定义译文样式
|
||||||
selectStyle: "",
|
selectStyle: "", // 选择器节点样式
|
||||||
parentStyle: "",
|
parentStyle: "", // 选择器父节点样式
|
||||||
injectJs: "",
|
injectJs: "", // 注入JS
|
||||||
injectCss: "",
|
injectCss: "", // 注入CSS
|
||||||
|
transOnly: GLOBAL_KEY, // 是否仅显示译文
|
||||||
|
transTiming: GLOBAL_KEY, // 翻译时机/鼠标悬停翻译
|
||||||
|
transTag: GLOBAL_KEY, // 译文元素标签
|
||||||
|
transTitle: GLOBAL_KEY, // 是否同时翻译页面标题
|
||||||
|
detectRemote: GLOBAL_KEY, // 是否使用远程语言检测
|
||||||
|
skipLangs: [], // 不翻译的语言
|
||||||
|
fixerSelector: "", // 修复函数选择器
|
||||||
|
fixerFunc: GLOBAL_KEY, // 修复函数
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_DIY_STYLE = `color: #666;
|
const DEFAULT_DIY_STYLE = `color: #666;
|
||||||
@@ -251,9 +259,6 @@ const RULES_MAP = {
|
|||||||
"randomnerdtutorials.com": {
|
"randomnerdtutorials.com": {
|
||||||
selector: `article ${DEFAULT_SELECTOR}`,
|
selector: `article ${DEFAULT_SELECTOR}`,
|
||||||
},
|
},
|
||||||
"forum.arduino.cc": {
|
|
||||||
selector: `.top-row>.title, .featured-topic>.title, .link-top-line>.title, .category-description, .topic-excerpt, .fancy-title, .cooked ${DEFAULT_SELECTOR}`,
|
|
||||||
},
|
|
||||||
"notebooks.githubusercontent.com/view/ipynb": {
|
"notebooks.githubusercontent.com/view/ipynb": {
|
||||||
selector: `#notebook-container ${DEFAULT_SELECTOR}`,
|
selector: `#notebook-container ${DEFAULT_SELECTOR}`,
|
||||||
keepSelector: `code, img, svg`,
|
keepSelector: `code, img, svg`,
|
||||||
@@ -276,6 +281,8 @@ export const BUILTIN_RULES = Object.entries(RULES_MAP)
|
|||||||
selectStyle = "",
|
selectStyle = "",
|
||||||
parentStyle = "",
|
parentStyle = "",
|
||||||
injectCss = "",
|
injectCss = "",
|
||||||
|
fixerSelector = "",
|
||||||
|
fixerFunc = GLOBAL_KEY,
|
||||||
},
|
},
|
||||||
]) => ({
|
]) => ({
|
||||||
...DEFAULT_RULE,
|
...DEFAULT_RULE,
|
||||||
@@ -286,5 +293,7 @@ export const BUILTIN_RULES = Object.entries(RULES_MAP)
|
|||||||
selectStyle,
|
selectStyle,
|
||||||
parentStyle,
|
parentStyle,
|
||||||
injectCss,
|
injectCss,
|
||||||
|
fixerSelector,
|
||||||
|
fixerFunc,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function useTranslate(q, rule, setting) {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [sameLang, setSamelang] = useState(false);
|
const [sameLang, setSamelang] = useState(false);
|
||||||
|
|
||||||
const { translator, fromLang, toLang } = rule;
|
const { translator, fromLang, toLang, detectRemote, skipLangs = [] } = rule;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
@@ -29,12 +29,8 @@ export function useTranslate(q, rule, setting) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deLang = await tryDetectLang(q, setting.detectRemote);
|
const deLang = await tryDetectLang(q, detectRemote === "true");
|
||||||
const disableLangs = setting.disableLangs || [];
|
if (deLang && (toLang.includes(deLang) || skipLangs.includes(deLang))) {
|
||||||
if (
|
|
||||||
deLang &&
|
|
||||||
(toLang.includes(deLang) || disableLangs.includes(deLang))
|
|
||||||
) {
|
|
||||||
setSamelang(true);
|
setSamelang(true);
|
||||||
} else {
|
} else {
|
||||||
const [trText, isSame] = await apiTranslate({
|
const [trText, isSame] = await apiTranslate({
|
||||||
@@ -54,7 +50,7 @@ export function useTranslate(q, rule, setting) {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [q, translator, fromLang, toLang, setting]);
|
}, [q, translator, fromLang, toLang, detectRemote, skipLangs, setting]);
|
||||||
|
|
||||||
return { text, sameLang, loading };
|
return { text, sameLang, loading };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
import { STOKEY_WFRULES, KV_WFRULES_KEY } from "../config";
|
|
||||||
import { useStorage } from "./Storage";
|
|
||||||
import { trySyncWebfixRules } from "../libs/sync";
|
|
||||||
import { useCallback } from "react";
|
|
||||||
import { useSyncMeta } from "./Sync";
|
|
||||||
|
|
||||||
const DEFAULT_WFRULES = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修复规则 hook
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function useWebfixRules() {
|
|
||||||
const { data: list, save } = useStorage(STOKEY_WFRULES, DEFAULT_WFRULES);
|
|
||||||
const { updateSyncMeta } = useSyncMeta();
|
|
||||||
|
|
||||||
const updateRules = useCallback(
|
|
||||||
async (rules) => {
|
|
||||||
await save(rules);
|
|
||||||
await updateSyncMeta(KV_WFRULES_KEY);
|
|
||||||
trySyncWebfixRules();
|
|
||||||
},
|
|
||||||
[save, updateSyncMeta]
|
|
||||||
);
|
|
||||||
|
|
||||||
const add = useCallback(
|
|
||||||
async (rule) => {
|
|
||||||
const rules = [...list];
|
|
||||||
if (rules.map((item) => item.pattern).includes(rule.pattern)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rules.unshift(rule);
|
|
||||||
await updateRules(rules);
|
|
||||||
},
|
|
||||||
[list, updateRules]
|
|
||||||
);
|
|
||||||
|
|
||||||
const del = useCallback(
|
|
||||||
async (pattern) => {
|
|
||||||
let rules = [...list];
|
|
||||||
rules = rules.filter((item) => item.pattern !== pattern);
|
|
||||||
await updateRules(rules);
|
|
||||||
},
|
|
||||||
[list, updateRules]
|
|
||||||
);
|
|
||||||
|
|
||||||
const put = useCallback(
|
|
||||||
async (pattern, obj) => {
|
|
||||||
const rules = [...list];
|
|
||||||
const rule = rules.find((r) => r.pattern === pattern);
|
|
||||||
rule && Object.assign(rule, obj);
|
|
||||||
await updateRules(rules);
|
|
||||||
},
|
|
||||||
[list, updateRules]
|
|
||||||
);
|
|
||||||
|
|
||||||
return { list, add, del, put };
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { isMatch } from "./utils";
|
import { isMatch } from "./utils";
|
||||||
import { DEFAULT_BLACKLIST } from "../config";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查是否在黑名单中
|
* 检查是否在黑名单中
|
||||||
@@ -7,7 +6,5 @@ import { DEFAULT_BLACKLIST } from "../config";
|
|||||||
* @param {*} param1
|
* @param {*} param1
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const isInBlacklist = (
|
export const isInBlacklist = (href, { blacklist }) =>
|
||||||
href,
|
blacklist.split(/\n|,/).some((url) => isMatch(href, url.trim()));
|
||||||
{ blacklist = DEFAULT_BLACKLIST.join(",\n") }
|
|
||||||
) => blacklist.split(/\n|,/).some((url) => isMatch(href, url.trim()));
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import { genEventName, removeEndchar, matchInputStr, sleep } from "./utils";
|
import { genEventName, removeEndchar, matchInputStr, sleep } from "./utils";
|
||||||
import { stepShortcutRegister } from "./shortcut";
|
import { stepShortcutRegister } from "./shortcut";
|
||||||
import { apiTranslate } from "../apis";
|
import { apiTranslate } from "../apis";
|
||||||
import { tryDetectLang } from ".";
|
|
||||||
import { loadingSvg } from "./svg";
|
import { loadingSvg } from "./svg";
|
||||||
|
|
||||||
function isInputNode(node) {
|
function isInputNode(node) {
|
||||||
@@ -83,7 +82,7 @@ function removeLoading(node, loadingId) {
|
|||||||
/**
|
/**
|
||||||
* 输入框翻译
|
* 输入框翻译
|
||||||
*/
|
*/
|
||||||
export default function inputTranslate ({
|
export default function inputTranslate({
|
||||||
inputRule: {
|
inputRule: {
|
||||||
transOpen,
|
transOpen,
|
||||||
triggerShortcut,
|
triggerShortcut,
|
||||||
@@ -95,7 +94,6 @@ export default function inputTranslate ({
|
|||||||
transSign,
|
transSign,
|
||||||
} = DEFAULT_INPUT_RULE,
|
} = DEFAULT_INPUT_RULE,
|
||||||
transApis,
|
transApis,
|
||||||
detectRemote,
|
|
||||||
}) {
|
}) {
|
||||||
if (!transOpen) {
|
if (!transOpen) {
|
||||||
return;
|
return;
|
||||||
@@ -156,11 +154,6 @@ export default function inputTranslate ({
|
|||||||
try {
|
try {
|
||||||
addLoading(node, loadingId);
|
addLoading(node, loadingId);
|
||||||
|
|
||||||
const deLang = await tryDetectLang(text, detectRemote);
|
|
||||||
if (deLang && toLang.includes(deLang)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [trText, isSame] = await apiTranslate({
|
const [trText, isSame] = await apiTranslate({
|
||||||
translator,
|
translator,
|
||||||
text,
|
text,
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import {
|
|||||||
OPT_STYLE_ALL,
|
OPT_STYLE_ALL,
|
||||||
OPT_LANGS_FROM,
|
OPT_LANGS_FROM,
|
||||||
OPT_LANGS_TO,
|
OPT_LANGS_TO,
|
||||||
|
OPT_TIMING_ALL,
|
||||||
GLOBLA_RULE,
|
GLOBLA_RULE,
|
||||||
DEFAULT_SUBRULES_LIST,
|
|
||||||
DEFAULT_OW_RULE,
|
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { loadOrFetchSubRules } from "./subRules";
|
import { loadOrFetchSubRules } from "./subRules";
|
||||||
import { getRulesWithDefault, setRules } from "./storage";
|
import { getRulesWithDefault, setRules } from "./storage";
|
||||||
import { trySyncRules } from "./sync";
|
import { trySyncRules } from "./sync";
|
||||||
|
import { FIXER_ALL } from "./webfix";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据href匹配规则
|
* 根据href匹配规则
|
||||||
@@ -22,11 +22,7 @@ import { trySyncRules } from "./sync";
|
|||||||
*/
|
*/
|
||||||
export const matchRule = async (
|
export const matchRule = async (
|
||||||
href,
|
href,
|
||||||
{
|
{ injectRules, subrulesList, owSubrule }
|
||||||
injectRules = true,
|
|
||||||
subrulesList = DEFAULT_SUBRULES_LIST,
|
|
||||||
owSubrule = DEFAULT_OW_RULE,
|
|
||||||
}
|
|
||||||
) => {
|
) => {
|
||||||
const rules = await getRulesWithDefault();
|
const rules = await getRulesWithDefault();
|
||||||
if (injectRules) {
|
if (injectRules) {
|
||||||
@@ -60,18 +56,49 @@ export const matchRule = async (
|
|||||||
const rule = rules.find((r) =>
|
const rule = rules.find((r) =>
|
||||||
r.pattern.split(",").some((p) => isMatch(href, p.trim()))
|
r.pattern.split(",").some((p) => isMatch(href, p.trim()))
|
||||||
);
|
);
|
||||||
const globalRule = rules.find((r) => r.pattern === GLOBAL_KEY) || GLOBLA_RULE;
|
const globalRule = {
|
||||||
|
...GLOBLA_RULE,
|
||||||
|
...(rules.find((r) => r.pattern === GLOBAL_KEY) || {}),
|
||||||
|
};
|
||||||
if (!rule) {
|
if (!rule) {
|
||||||
return globalRule;
|
return globalRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
rule.selector = rule.selector?.trim() || globalRule.selector;
|
[
|
||||||
rule.keepSelector = rule.keepSelector?.trim() || globalRule.keepSelector;
|
"selector",
|
||||||
rule.terms = rule.terms?.trim() || globalRule.terms;
|
"keepSelector",
|
||||||
rule.selectStyle = rule.selectStyle?.trim() || globalRule.selectStyle;
|
"terms",
|
||||||
rule.parentStyle = rule.parentStyle?.trim() || globalRule.parentStyle;
|
"selectStyle",
|
||||||
rule.injectJs = rule.injectJs?.trim() || globalRule.injectJs;
|
"parentStyle",
|
||||||
rule.injectCss = rule.injectCss?.trim() || globalRule.injectCss;
|
"injectJs",
|
||||||
|
"injectCss",
|
||||||
|
"fixerSelector",
|
||||||
|
].forEach((key) => {
|
||||||
|
if (!rule[key]?.trim()) {
|
||||||
|
rule[key] = globalRule[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
[
|
||||||
|
"translator",
|
||||||
|
"fromLang",
|
||||||
|
"toLang",
|
||||||
|
"transOpen",
|
||||||
|
"transOnly",
|
||||||
|
"transTiming",
|
||||||
|
"transTag",
|
||||||
|
"transTitle",
|
||||||
|
"detectRemote",
|
||||||
|
"fixerFunc",
|
||||||
|
].forEach((key) => {
|
||||||
|
if (rule[key] === undefined || rule[key] === GLOBAL_KEY) {
|
||||||
|
rule[key] = globalRule[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!rule.skipLangs || rule.skipLangs.length === 0) {
|
||||||
|
rule.skipLangs = globalRule.skipLangs;
|
||||||
|
}
|
||||||
if (rule.textStyle === GLOBAL_KEY) {
|
if (rule.textStyle === GLOBAL_KEY) {
|
||||||
rule.textStyle = globalRule.textStyle;
|
rule.textStyle = globalRule.textStyle;
|
||||||
rule.bgColor = globalRule.bgColor;
|
rule.bgColor = globalRule.bgColor;
|
||||||
@@ -80,11 +107,6 @@ export const matchRule = async (
|
|||||||
rule.bgColor = rule.bgColor?.trim() || globalRule.bgColor;
|
rule.bgColor = rule.bgColor?.trim() || globalRule.bgColor;
|
||||||
rule.textDiyStyle = rule.textDiyStyle?.trim() || globalRule.textDiyStyle;
|
rule.textDiyStyle = rule.textDiyStyle?.trim() || globalRule.textDiyStyle;
|
||||||
}
|
}
|
||||||
["translator", "fromLang", "toLang", "transOpen"].forEach((key) => {
|
|
||||||
if (rule[key] === GLOBAL_KEY) {
|
|
||||||
rule[key] = globalRule[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return rule;
|
return rule;
|
||||||
};
|
};
|
||||||
@@ -131,6 +153,14 @@ export const checkRules = (rules) => {
|
|||||||
transOpen,
|
transOpen,
|
||||||
bgColor,
|
bgColor,
|
||||||
textDiyStyle,
|
textDiyStyle,
|
||||||
|
transOnly,
|
||||||
|
transTiming,
|
||||||
|
transTag,
|
||||||
|
transTitle,
|
||||||
|
detectRemote,
|
||||||
|
skipLangs,
|
||||||
|
fixerSelector,
|
||||||
|
fixerFunc,
|
||||||
}) => ({
|
}) => ({
|
||||||
pattern: pattern.trim(),
|
pattern: pattern.trim(),
|
||||||
selector: type(selector) === "string" ? selector : "",
|
selector: type(selector) === "string" ? selector : "",
|
||||||
@@ -147,6 +177,14 @@ export const checkRules = (rules) => {
|
|||||||
toLang: matchValue([GLOBAL_KEY, ...toLangs], toLang),
|
toLang: matchValue([GLOBAL_KEY, ...toLangs], toLang),
|
||||||
textStyle: matchValue([GLOBAL_KEY, ...OPT_STYLE_ALL], textStyle),
|
textStyle: matchValue([GLOBAL_KEY, ...OPT_STYLE_ALL], textStyle),
|
||||||
transOpen: matchValue([GLOBAL_KEY, "true", "false"], transOpen),
|
transOpen: matchValue([GLOBAL_KEY, "true", "false"], transOpen),
|
||||||
|
transOnly: matchValue([GLOBAL_KEY, "true", "false"], transOnly),
|
||||||
|
transTiming: matchValue([GLOBAL_KEY, ...OPT_TIMING_ALL], transTiming),
|
||||||
|
transTag: matchValue([GLOBAL_KEY, "font", "span"], transTag),
|
||||||
|
transTitle: matchValue([GLOBAL_KEY, "true", "false"], transTitle),
|
||||||
|
detectRemote: matchValue([GLOBAL_KEY, "true", "false"], detectRemote),
|
||||||
|
skipLangs: type(skipLangs) === "array" ? skipLangs : [],
|
||||||
|
fixerSelector: type(fixerSelector) === "string" ? fixerSelector : "",
|
||||||
|
fixerFunc: matchValue([GLOBAL_KEY, ...FIXER_ALL], fixerFunc),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
STOKEY_SETTING,
|
STOKEY_SETTING,
|
||||||
STOKEY_RULES,
|
STOKEY_RULES,
|
||||||
STOKEY_WFRULES,
|
|
||||||
STOKEY_WORDS,
|
STOKEY_WORDS,
|
||||||
STOKEY_FAB,
|
STOKEY_FAB,
|
||||||
STOKEY_SYNC,
|
STOKEY_SYNC,
|
||||||
STOKEY_MSAUTH,
|
STOKEY_MSAUTH,
|
||||||
STOKEY_BDAUTH,
|
STOKEY_BDAUTH,
|
||||||
STOKEY_RULESCACHE_PREFIX,
|
STOKEY_RULESCACHE_PREFIX,
|
||||||
STOKEY_WEBFIXCACHE_PREFIX,
|
|
||||||
DEFAULT_SETTING,
|
DEFAULT_SETTING,
|
||||||
DEFAULT_RULES,
|
DEFAULT_RULES,
|
||||||
DEFAULT_SYNC,
|
DEFAULT_SYNC,
|
||||||
@@ -86,8 +84,10 @@ export const storage = {
|
|||||||
* 设置信息
|
* 设置信息
|
||||||
*/
|
*/
|
||||||
export const getSetting = () => getObj(STOKEY_SETTING);
|
export const getSetting = () => getObj(STOKEY_SETTING);
|
||||||
export const getSettingWithDefault = async () =>
|
export const getSettingWithDefault = async () => ({
|
||||||
(await getSetting()) || DEFAULT_SETTING;
|
...DEFAULT_SETTING,
|
||||||
|
...((await getSetting()) || {}),
|
||||||
|
});
|
||||||
export const setSetting = (val) => setObj(STOKEY_SETTING, val);
|
export const setSetting = (val) => setObj(STOKEY_SETTING, val);
|
||||||
export const updateSetting = (obj) => putObj(STOKEY_SETTING, obj);
|
export const updateSetting = (obj) => putObj(STOKEY_SETTING, obj);
|
||||||
|
|
||||||
@@ -99,14 +99,6 @@ export const getRulesWithDefault = async () =>
|
|||||||
(await getRules()) || DEFAULT_RULES;
|
(await getRules()) || DEFAULT_RULES;
|
||||||
export const setRules = (val) => setObj(STOKEY_RULES, val);
|
export const setRules = (val) => setObj(STOKEY_RULES, val);
|
||||||
|
|
||||||
/**
|
|
||||||
* 修复规则列表
|
|
||||||
*/
|
|
||||||
export const getWebfixRules = () => getObj(STOKEY_WFRULES);
|
|
||||||
export const getWebfixRulesWithDefault = async () =>
|
|
||||||
(await getWebfixRules()) || [];
|
|
||||||
export const setWebfixRules = (val) => setObj(STOKEY_WFRULES, val);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 词汇列表
|
* 词汇列表
|
||||||
*/
|
*/
|
||||||
@@ -123,14 +115,6 @@ export const delSubRules = (url) => del(STOKEY_RULESCACHE_PREFIX + url);
|
|||||||
export const setSubRules = (url, val) =>
|
export const setSubRules = (url, val) =>
|
||||||
setObj(STOKEY_RULESCACHE_PREFIX + url, val);
|
setObj(STOKEY_RULESCACHE_PREFIX + url, val);
|
||||||
|
|
||||||
/**
|
|
||||||
* 修复站点
|
|
||||||
*/
|
|
||||||
export const getWebfix = (url) => getObj(STOKEY_WEBFIXCACHE_PREFIX + url);
|
|
||||||
export const getWebfixWithDefault = async () => (await getWebfix()) || [];
|
|
||||||
export const setWebfix = (url, val) =>
|
|
||||||
setObj(STOKEY_WEBFIXCACHE_PREFIX + url, val);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fab位置
|
* fab位置
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
import { apiFetch } from "../apis";
|
import { apiFetch } from "../apis";
|
||||||
import { checkRules } from "./rules";
|
import { checkRules } from "./rules";
|
||||||
import { isAllchar } from "./utils";
|
import { isAllchar } from "./utils";
|
||||||
import { syncWebfix } from "./webfix";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新缓存同步时间
|
* 更新缓存同步时间
|
||||||
@@ -66,9 +65,6 @@ export const trySyncAllSubRules = async ({ subrulesList }) => {
|
|||||||
// 同步订阅规则
|
// 同步订阅规则
|
||||||
await syncAllSubRules(subrulesList);
|
await syncAllSubRules(subrulesList);
|
||||||
await updateSync({ subRulesSyncAt: now });
|
await updateSync({ subRulesSyncAt: now });
|
||||||
|
|
||||||
// 同步修复规则
|
|
||||||
await syncWebfix(process.env.REACT_APP_WEBFIXURL);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("[try sync all subrules]", err);
|
console.log("[try sync all subrules]", err);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import {
|
|||||||
APP_LCNAME,
|
APP_LCNAME,
|
||||||
KV_SETTING_KEY,
|
KV_SETTING_KEY,
|
||||||
KV_RULES_KEY,
|
KV_RULES_KEY,
|
||||||
KV_WFRULES_KEY,
|
|
||||||
KV_WORDS_KEY,
|
KV_WORDS_KEY,
|
||||||
KV_RULES_SHARE_KEY,
|
KV_RULES_SHARE_KEY,
|
||||||
KV_SALT_SHARE,
|
KV_SALT_SHARE,
|
||||||
@@ -14,10 +13,8 @@ import {
|
|||||||
getSettingWithDefault,
|
getSettingWithDefault,
|
||||||
getRulesWithDefault,
|
getRulesWithDefault,
|
||||||
getWordsWithDefault,
|
getWordsWithDefault,
|
||||||
getWebfixRulesWithDefault,
|
|
||||||
setSetting,
|
setSetting,
|
||||||
setRules,
|
setRules,
|
||||||
setWebfixRules,
|
|
||||||
setWords,
|
setWords,
|
||||||
} from "./storage";
|
} from "./storage";
|
||||||
import { apiSyncData } from "../apis";
|
import { apiSyncData } from "../apis";
|
||||||
@@ -141,25 +138,6 @@ export const trySyncRules = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步修复规则
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const syncWebfixRules = async () => {
|
|
||||||
const res = await syncData(KV_WFRULES_KEY, getWebfixRulesWithDefault);
|
|
||||||
if (res?.isNew) {
|
|
||||||
await setWebfixRules(res.value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const trySyncWebfixRules = async () => {
|
|
||||||
try {
|
|
||||||
await syncWebfixRules();
|
|
||||||
} catch (err) {
|
|
||||||
console.log("[sync user webfix rules]", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步词汇
|
* 同步词汇
|
||||||
* @returns
|
* @returns
|
||||||
@@ -207,13 +185,11 @@ export const syncShareRules = async ({ rules, syncUrl, syncKey }) => {
|
|||||||
export const syncSettingAndRules = async () => {
|
export const syncSettingAndRules = async () => {
|
||||||
await syncSetting();
|
await syncSetting();
|
||||||
await syncRules();
|
await syncRules();
|
||||||
await syncWebfixRules();
|
|
||||||
await syncWords();
|
await syncWords();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const trySyncSettingAndRules = async () => {
|
export const trySyncSettingAndRules = async () => {
|
||||||
await trySyncSetting();
|
await trySyncSetting();
|
||||||
await trySyncRules();
|
await trySyncRules();
|
||||||
await trySyncWebfixRules();
|
|
||||||
await trySyncWords();
|
await trySyncWords();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import {
|
|||||||
OPT_STYLE_DASHLINE,
|
OPT_STYLE_DASHLINE,
|
||||||
OPT_STYLE_FUZZY,
|
OPT_STYLE_FUZZY,
|
||||||
SHADOW_KEY,
|
SHADOW_KEY,
|
||||||
OPT_MOUSEKEY_DISABLE,
|
OPT_TIMING_PAGESCROLL,
|
||||||
OPT_MOUSEKEY_PAGEOPEN,
|
OPT_TIMING_PAGEOPEN,
|
||||||
OPT_MOUSEKEY_MOUSEOVER,
|
OPT_TIMING_MOUSEOVER,
|
||||||
DEFAULT_TRANS_APIS,
|
DEFAULT_TRANS_APIS,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import Content from "../views/Content";
|
import Content from "../views/Content";
|
||||||
@@ -29,7 +29,6 @@ import { injectInlineJs, injectInternalCss } from "./injector";
|
|||||||
export class Translator {
|
export class Translator {
|
||||||
_rule = {};
|
_rule = {};
|
||||||
_setting = {};
|
_setting = {};
|
||||||
_fixerSetting = null;
|
|
||||||
_rootNodes = new Set();
|
_rootNodes = new Set();
|
||||||
_tranNodes = new Map();
|
_tranNodes = new Map();
|
||||||
_skipNodeNames = [
|
_skipNodeNames = [
|
||||||
@@ -104,14 +103,13 @@ export class Translator {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(rule, setting, fixerSetting) {
|
constructor(rule, setting) {
|
||||||
const { fetchInterval, fetchLimit } = setting;
|
const { fetchInterval, fetchLimit } = setting;
|
||||||
updateFetchPool(fetchInterval, fetchLimit);
|
updateFetchPool(fetchInterval, fetchLimit);
|
||||||
this._overrideAttachShadow();
|
this._overrideAttachShadow();
|
||||||
|
|
||||||
this._setting = setting;
|
this._setting = setting;
|
||||||
this._rule = rule;
|
this._rule = rule;
|
||||||
this._fixerSetting = fixerSetting;
|
|
||||||
|
|
||||||
this._keepSelector = (rule.keepSelector || "")
|
this._keepSelector = (rule.keepSelector || "")
|
||||||
.split(SHADOW_KEY)
|
.split(SHADOW_KEY)
|
||||||
@@ -267,14 +265,15 @@ export class Translator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_register = () => {
|
_register = () => {
|
||||||
const { fromLang, toLang, injectJs, injectCss } = this._rule;
|
const { fromLang, toLang, injectJs, injectCss, fixerSelector, fixerFunc } =
|
||||||
|
this._rule;
|
||||||
if (fromLang === toLang) {
|
if (fromLang === toLang) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// webfix
|
// webfix
|
||||||
if (this._fixerSetting) {
|
if (fixerSelector && fixerFunc !== "-") {
|
||||||
runFixer(this._fixerSetting);
|
runFixer(fixerSelector, fixerFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 注入用户JS/CSS
|
// 注入用户JS/CSS
|
||||||
@@ -299,14 +298,14 @@ export class Translator {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this._setting.mouseKey ||
|
!this._rule.transTiming ||
|
||||||
this._setting.mouseKey === OPT_MOUSEKEY_DISABLE
|
this._rule.transTiming === OPT_TIMING_PAGESCROLL
|
||||||
) {
|
) {
|
||||||
// 监听节点显示
|
// 监听节点显示
|
||||||
this._tranNodes.forEach((_, node) => {
|
this._tranNodes.forEach((_, node) => {
|
||||||
this._interseObserver.observe(node);
|
this._interseObserver.observe(node);
|
||||||
});
|
});
|
||||||
} else if (this._setting.mouseKey === OPT_MOUSEKEY_PAGEOPEN) {
|
} else if (this._rule.transTiming === OPT_TIMING_PAGEOPEN) {
|
||||||
// 全文直接翻译
|
// 全文直接翻译
|
||||||
this._tranNodes.forEach((_, node) => {
|
this._tranNodes.forEach((_, node) => {
|
||||||
this._render(node);
|
this._render(node);
|
||||||
@@ -321,7 +320,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 翻译页面标题
|
// 翻译页面标题
|
||||||
if (this._setting.transTitle && !this._docTitle) {
|
if (this._rule.transTitle === "true" && !this._docTitle) {
|
||||||
const title = document.title;
|
const title = document.title;
|
||||||
this._docTitle = title;
|
this._docTitle = title;
|
||||||
this.translateText(title).then((trText) => {
|
this.translateText(title).then((trText) => {
|
||||||
@@ -336,8 +335,8 @@ export class Translator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = this._setting.mouseKey.slice(3);
|
const key = this._rule.transTiming.slice(3);
|
||||||
if (this._setting.mouseKey === OPT_MOUSEKEY_MOUSEOVER || e[key]) {
|
if (this._rule.transTiming === OPT_TIMING_MOUSEOVER || e[key]) {
|
||||||
e.target.removeEventListener("mouseenter", this._handleMouseover);
|
e.target.removeEventListener("mouseenter", this._handleMouseover);
|
||||||
e.target.removeEventListener("mouseleave", this._handleMouseout);
|
e.target.removeEventListener("mouseleave", this._handleMouseout);
|
||||||
this._render(e.target);
|
this._render(e.target);
|
||||||
@@ -357,7 +356,7 @@ export class Translator {
|
|||||||
|
|
||||||
_handleKeydown = (e) => {
|
_handleKeydown = (e) => {
|
||||||
// console.log("keydown", e);
|
// console.log("keydown", e);
|
||||||
const key = this._setting.mouseKey.slice(3);
|
const key = this._rule.transTiming.slice(3);
|
||||||
if (e[key] && this._mouseoverNode) {
|
if (e[key] && this._mouseoverNode) {
|
||||||
this._mouseoverNode.removeEventListener(
|
this._mouseoverNode.removeEventListener(
|
||||||
"mouseenter",
|
"mouseenter",
|
||||||
@@ -392,12 +391,12 @@ export class Translator {
|
|||||||
|
|
||||||
this._tranNodes.forEach((innerHTML, node) => {
|
this._tranNodes.forEach((innerHTML, node) => {
|
||||||
if (
|
if (
|
||||||
!this._setting.mouseKey ||
|
!this._rule.transTiming ||
|
||||||
this._setting.mouseKey === OPT_MOUSEKEY_DISABLE
|
this._rule.transTiming === OPT_TIMING_PAGESCROLL
|
||||||
) {
|
) {
|
||||||
// 解除节点显示监听
|
// 解除节点显示监听
|
||||||
this._interseObserver.unobserve(node);
|
this._interseObserver.unobserve(node);
|
||||||
} else if (this._setting.mouseKey !== OPT_MOUSEKEY_PAGEOPEN) {
|
} else if (this._rule.transTiming !== OPT_TIMING_PAGEOPEN) {
|
||||||
// 移除鼠标悬停监听
|
// 移除鼠标悬停监听
|
||||||
// node.style.pointerEvents = "none";
|
// node.style.pointerEvents = "none";
|
||||||
node.removeEventListener("mouseenter", this._handleMouseover);
|
node.removeEventListener("mouseenter", this._handleMouseover);
|
||||||
@@ -405,7 +404,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 移除/恢复元素
|
// 移除/恢复元素
|
||||||
if (innerHTML && this._setting.transOnly) {
|
if (innerHTML && this._rule.transOnly === "true") {
|
||||||
node.innerHTML = innerHTML;
|
node.innerHTML = innerHTML;
|
||||||
} else {
|
} else {
|
||||||
node.querySelector(APP_LCNAME)?.remove();
|
node.querySelector(APP_LCNAME)?.remove();
|
||||||
@@ -446,7 +445,7 @@ export class Translator {
|
|||||||
|
|
||||||
// 已翻译
|
// 已翻译
|
||||||
if (traEl) {
|
if (traEl) {
|
||||||
if (this._setting.transOnly) {
|
if (this._rule.transOnly === "true") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +464,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let q = el.innerText.trim();
|
let q = el.innerText.trim();
|
||||||
if (this._setting.transOnly) {
|
if (this._rule.transOnly === "true") {
|
||||||
this._tranNodes.set(el, el.innerHTML);
|
this._tranNodes.set(el, el.innerHTML);
|
||||||
} else {
|
} else {
|
||||||
this._tranNodes.set(el, q);
|
this._tranNodes.set(el, q);
|
||||||
@@ -522,7 +521,7 @@ export class Translator {
|
|||||||
|
|
||||||
traEl = document.createElement(APP_LCNAME);
|
traEl = document.createElement(APP_LCNAME);
|
||||||
traEl.style.visibility = "visible";
|
traEl.style.visibility = "visible";
|
||||||
// if (this._setting.transOnly) {
|
// if (this._rule.transOnly === "true") {
|
||||||
// el.innerHTML = "";
|
// el.innerHTML = "";
|
||||||
// }
|
// }
|
||||||
const { selectStyle, parentStyle } = this._rule;
|
const { selectStyle, parentStyle } = this._rule;
|
||||||
@@ -532,8 +531,6 @@ export class Translator {
|
|||||||
el.parentElement.style.cssText += parentStyle;
|
el.parentElement.style.cssText += parentStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log({ q, keeps });
|
|
||||||
|
|
||||||
const root = createRoot(traEl);
|
const root = createRoot(traEl);
|
||||||
root.render(<Content q={q} keeps={keeps} translator={this} $el={el} />);
|
root.render(<Content q={q} keeps={keeps} translator={this} $el={el} />);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,55 +1,18 @@
|
|||||||
import { isMatch } from "./utils";
|
|
||||||
import { getWebfix, setWebfix, getWebfixRulesWithDefault } from "./storage";
|
|
||||||
import { apiFetch } from "../apis";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修复程序类型
|
* 修复程序类型
|
||||||
*/
|
*/
|
||||||
|
const FIXER_NONE = "-";
|
||||||
const FIXER_BR = "br";
|
const FIXER_BR = "br";
|
||||||
const FIXER_BN = "bn";
|
const FIXER_BN = "bn";
|
||||||
const FIXER_BR_DIV = "brToDiv";
|
const FIXER_BR_DIV = "brToDiv";
|
||||||
const FIXER_BN_DIV = "bnToDiv";
|
const FIXER_BN_DIV = "bnToDiv";
|
||||||
const FIXER_FONTSIZE = "fontSize";
|
|
||||||
export const FIXER_ALL = [
|
export const FIXER_ALL = [
|
||||||
|
FIXER_NONE,
|
||||||
FIXER_BR,
|
FIXER_BR,
|
||||||
FIXER_BN,
|
FIXER_BN,
|
||||||
FIXER_BR_DIV,
|
FIXER_BR_DIV,
|
||||||
FIXER_BN_DIV,
|
FIXER_BN_DIV,
|
||||||
// FIXER_FONTSIZE,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 需要修复的站点列表
|
|
||||||
* - pattern 匹配网址
|
|
||||||
* - selector 需要修复的选择器
|
|
||||||
* - rootSelector 需要监听的选择器,可留空
|
|
||||||
* - fixer 修复函数,可针对不同网址,选用不同修复函数
|
|
||||||
*/
|
|
||||||
const DEFAULT_SITES = [
|
|
||||||
{
|
|
||||||
pattern: "www.phoronix.com",
|
|
||||||
selector: ".content",
|
|
||||||
rootSelector: "",
|
|
||||||
fixer: FIXER_BR,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "t.me/s/",
|
|
||||||
selector: ".tgme_widget_message_text",
|
|
||||||
rootSelector: ".tgme_channel_history",
|
|
||||||
fixer: FIXER_BR,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "baidu.com",
|
|
||||||
selector: "html",
|
|
||||||
rootSelector: "",
|
|
||||||
fixer: FIXER_FONTSIZE,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: "chat.openai.com",
|
|
||||||
selector: "div[data-testid^=conversation-turn] .items-start > div",
|
|
||||||
rootSelector: "",
|
|
||||||
fixer: FIXER_BN,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,14 +98,6 @@ function bnDivFixer(node) {
|
|||||||
return bnFixer(node, "div");
|
return bnFixer(node, "div");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 修复字体大小问题,如 baidu.com
|
|
||||||
* @param {*} node
|
|
||||||
*/
|
|
||||||
function fontSizeFixer(node) {
|
|
||||||
node.style.cssText += "font-size:1em;";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修复程序映射
|
* 修复程序映射
|
||||||
*/
|
*/
|
||||||
@@ -151,7 +106,6 @@ const fixerMap = {
|
|||||||
[FIXER_BN]: bnFixer,
|
[FIXER_BN]: bnFixer,
|
||||||
[FIXER_BR_DIV]: brDivFixer,
|
[FIXER_BR_DIV]: brDivFixer,
|
||||||
[FIXER_BN_DIV]: bnDivFixer,
|
[FIXER_BN_DIV]: bnDivFixer,
|
||||||
[FIXER_FONTSIZE]: fontSizeFixer,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,68 +143,16 @@ function run(selector, fixer, rootSelector) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步远程数据
|
|
||||||
* @param {*} url
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const syncWebfix = async (url) => {
|
|
||||||
const sites = await apiFetch(url);
|
|
||||||
await setWebfix(url, sites);
|
|
||||||
return sites;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从缓存或远程加载修复站点
|
|
||||||
* @param {*} url
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const loadOrFetchWebfix = async (url) => {
|
|
||||||
try {
|
|
||||||
let sites = await getWebfix(url);
|
|
||||||
if (sites?.length) {
|
|
||||||
return sites;
|
|
||||||
}
|
|
||||||
return syncWebfix(url);
|
|
||||||
} catch (err) {
|
|
||||||
console.log("[load webfix]", err.message);
|
|
||||||
return DEFAULT_SITES;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行fixer
|
* 执行fixer
|
||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
*/
|
*/
|
||||||
export async function runFixer({ selector, fixer, rootSelector }) {
|
export async function runFixer(selector, fixer = "-", rootSelector) {
|
||||||
try {
|
try {
|
||||||
run(selector, fixerMap[fixer], rootSelector);
|
if (Object.keys(fixerMap).includes(fixer)) {
|
||||||
|
run(selector, fixerMap[fixer], rootSelector);
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[kiss-webfix run]: ${err.message}`);
|
console.error(`[kiss-webfix run]: ${err.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 匹配fixer配置
|
|
||||||
*/
|
|
||||||
export async function matchFixer(href, { injectWebfix }) {
|
|
||||||
if (!injectWebfix) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const userSites = await getWebfixRulesWithDefault();
|
|
||||||
const subSites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL);
|
|
||||||
const sites = [...userSites, ...subSites];
|
|
||||||
for (let i = 0; i < sites.length; i++) {
|
|
||||||
const site = sites[i];
|
|
||||||
if (isMatch(href, site.pattern) && fixerMap[site.fixer]) {
|
|
||||||
return site;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`[kiss-webfix match]: ${err.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import {
|
|||||||
OPT_STYLE_DIY,
|
OPT_STYLE_DIY,
|
||||||
DEFAULT_COLOR,
|
DEFAULT_COLOR,
|
||||||
MSG_TRANS_CURRULE,
|
MSG_TRANS_CURRULE,
|
||||||
TRANS_NEWLINE_LENGTH,
|
|
||||||
DEFAULT_TRANS_TAG,
|
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { useTranslate } from "../../hooks/Translate";
|
import { useTranslate } from "../../hooks/Translate";
|
||||||
import { styled, css } from "@mui/material/styles";
|
import { styled, css } from "@mui/material/styles";
|
||||||
@@ -87,13 +85,10 @@ const StyledSpan = styled("span")`
|
|||||||
export default function Content({ q, keeps, translator, $el }) {
|
export default function Content({ q, keeps, translator, $el }) {
|
||||||
const [rule, setRule] = useState(translator.rule);
|
const [rule, setRule] = useState(translator.rule);
|
||||||
const { text, sameLang, loading } = useTranslate(q, rule, translator.setting);
|
const { text, sameLang, loading } = useTranslate(q, rule, translator.setting);
|
||||||
const { transOpen, textStyle, bgColor = "", textDiyStyle = "" } = rule;
|
const { transOpen, textStyle, bgColor, textDiyStyle, transOnly, transTag } =
|
||||||
|
rule;
|
||||||
|
|
||||||
const {
|
const { newlineLength } = translator.setting;
|
||||||
newlineLength = TRANS_NEWLINE_LENGTH,
|
|
||||||
transTag = DEFAULT_TRANS_TAG,
|
|
||||||
transOnly = false,
|
|
||||||
} = translator.setting;
|
|
||||||
|
|
||||||
const handleKissEvent = (e) => {
|
const handleKissEvent = (e) => {
|
||||||
const { action, args } = e.detail;
|
const { action, args } = e.detail;
|
||||||
@@ -113,7 +108,7 @@ export default function Content({ q, keeps, translator, $el }) {
|
|||||||
}, [translator.eventName]);
|
}, [translator.eventName]);
|
||||||
|
|
||||||
const gap = useMemo(() => {
|
const gap = useMemo(() => {
|
||||||
if (transOnly) {
|
if (transOnly === "true") {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return q.length >= newlineLength ? <br /> : " ";
|
return q.length >= newlineLength ? <br /> : " ";
|
||||||
@@ -142,7 +137,11 @@ export default function Content({ q, keeps, translator, $el }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transOnly && transOpen === "true" && $el.querySelector(APP_LCNAME)) {
|
if (
|
||||||
|
transOnly === "true" &&
|
||||||
|
transOpen === "true" &&
|
||||||
|
$el.querySelector(APP_LCNAME)
|
||||||
|
) {
|
||||||
Array.from($el.childNodes).forEach((el) => {
|
Array.from($el.childNodes).forEach((el) => {
|
||||||
if (el.localName !== APP_LCNAME) {
|
if (el.localName !== APP_LCNAME) {
|
||||||
el.remove();
|
el.remove();
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import DesignServicesIcon from "@mui/icons-material/DesignServices";
|
|||||||
import { useI18n } from "../../hooks/I18n";
|
import { useI18n } from "../../hooks/I18n";
|
||||||
import SyncIcon from "@mui/icons-material/Sync";
|
import SyncIcon from "@mui/icons-material/Sync";
|
||||||
import ApiIcon from "@mui/icons-material/Api";
|
import ApiIcon from "@mui/icons-material/Api";
|
||||||
import SendTimeExtensionIcon from "@mui/icons-material/SendTimeExtension";
|
|
||||||
import InputIcon from "@mui/icons-material/Input";
|
import InputIcon from "@mui/icons-material/Input";
|
||||||
import SelectAllIcon from "@mui/icons-material/SelectAll";
|
import SelectAllIcon from "@mui/icons-material/SelectAll";
|
||||||
import EventNoteIcon from "@mui/icons-material/EventNote";
|
import EventNoteIcon from "@mui/icons-material/EventNote";
|
||||||
@@ -65,12 +64,6 @@ export default function Navigator(props) {
|
|||||||
url: "/sync",
|
url: "/sync",
|
||||||
icon: <SyncIcon />,
|
icon: <SyncIcon />,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "webfix",
|
|
||||||
label: i18n("patch_setting"),
|
|
||||||
url: "/webfix",
|
|
||||||
icon: <SendTimeExtensionIcon />,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "words",
|
id: "words",
|
||||||
label: i18n("favorite_words"),
|
label: i18n("favorite_words"),
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import {
|
|||||||
OPT_STYLE_USE_COLOR,
|
OPT_STYLE_USE_COLOR,
|
||||||
URL_KISS_RULES_NEW_ISSUE,
|
URL_KISS_RULES_NEW_ISSUE,
|
||||||
OPT_SYNCTYPE_WORKER,
|
OPT_SYNCTYPE_WORKER,
|
||||||
|
OPT_TIMING_PAGESCROLL,
|
||||||
|
DEFAULT_TRANS_TAG,
|
||||||
|
OPT_TIMING_ALL,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { useState, useEffect, useMemo } from "react";
|
import { useState, useEffect, useMemo } from "react";
|
||||||
import { useI18n } from "../../hooks/I18n";
|
import { useI18n } from "../../hooks/I18n";
|
||||||
@@ -50,12 +53,10 @@ import HelpButton from "./HelpButton";
|
|||||||
import { useSyncCaches } from "../../hooks/Sync";
|
import { useSyncCaches } from "../../hooks/Sync";
|
||||||
import DownloadButton from "./DownloadButton";
|
import DownloadButton from "./DownloadButton";
|
||||||
import UploadButton from "./UploadButton";
|
import UploadButton from "./UploadButton";
|
||||||
|
import { FIXER_ALL } from "../../libs/webfix";
|
||||||
|
|
||||||
function RuleFields({ rule, rules, setShow, setKeyword }) {
|
function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||||
const initFormValues = rule || {
|
const initFormValues = { ...DEFAULT_RULE, ...(rule || {}) };
|
||||||
...DEFAULT_RULE,
|
|
||||||
transOpen: "true",
|
|
||||||
};
|
|
||||||
const editMode = !!rule;
|
const editMode = !!rule;
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
@@ -79,6 +80,14 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
transOpen,
|
transOpen,
|
||||||
bgColor,
|
bgColor,
|
||||||
textDiyStyle,
|
textDiyStyle,
|
||||||
|
transOnly = "false",
|
||||||
|
transTiming = OPT_TIMING_PAGESCROLL,
|
||||||
|
transTag = DEFAULT_TRANS_TAG,
|
||||||
|
transTitle = "false",
|
||||||
|
detectRemote = "false",
|
||||||
|
skipLangs = [],
|
||||||
|
fixerSelector = "",
|
||||||
|
fixerFunc = "-",
|
||||||
} = formValues;
|
} = formValues;
|
||||||
|
|
||||||
const hasSamePattern = (str) => {
|
const hasSamePattern = (str) => {
|
||||||
@@ -323,6 +332,141 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
|
|
||||||
{showMore && (
|
{showMore && (
|
||||||
<>
|
<>
|
||||||
|
<Box>
|
||||||
|
<Grid container spacing={2} columns={12}>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transOnly"
|
||||||
|
value={transOnly}
|
||||||
|
label={i18n("show_only_translations")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transTiming"
|
||||||
|
value={transTiming}
|
||||||
|
label={i18n("translate_timing")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
{OPT_TIMING_ALL.map((item) => (
|
||||||
|
<MenuItem key={item} value={item}>
|
||||||
|
{i18n(item)}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transTag"
|
||||||
|
value={transTag}
|
||||||
|
label={i18n("translation_element_tag")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"span"}>{`<span>`}</MenuItem>
|
||||||
|
<MenuItem value={"font"}>{`<font>`}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transTitle"
|
||||||
|
value={transTitle}
|
||||||
|
label={i18n("translate_page_title")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="detectRemote"
|
||||||
|
value={detectRemote}
|
||||||
|
label={i18n("detect_lang_remote")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
label={i18n("disable_langs")}
|
||||||
|
helperText={i18n("disable_langs_helper")}
|
||||||
|
name="skipLangs"
|
||||||
|
value={skipLangs}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
SelectProps={{
|
||||||
|
multiple: true,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{OPT_LANGS_TO.map(([langKey, langName]) => (
|
||||||
|
<MenuItem key={langKey} value={langKey}>
|
||||||
|
{langName}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={i18n("fixer_selector")}
|
||||||
|
name="fixerSelector"
|
||||||
|
value={fixerSelector}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
name="fixerFunc"
|
||||||
|
value={fixerFunc}
|
||||||
|
label={i18n("fixer_function")}
|
||||||
|
helperText={i18n("fixer_function_helper")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
{FIXER_ALL.map((item) => (
|
||||||
|
<MenuItem key={item} value={item}>
|
||||||
|
{item}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
label={i18n("terms")}
|
label={i18n("terms")}
|
||||||
|
|||||||
@@ -17,16 +17,12 @@ import {
|
|||||||
UI_LANGS,
|
UI_LANGS,
|
||||||
TRANS_NEWLINE_LENGTH,
|
TRANS_NEWLINE_LENGTH,
|
||||||
CACHE_NAME,
|
CACHE_NAME,
|
||||||
OPT_MOUSEKEY_ALL,
|
|
||||||
OPT_MOUSEKEY_DISABLE,
|
|
||||||
OPT_SHORTCUT_TRANSLATE,
|
OPT_SHORTCUT_TRANSLATE,
|
||||||
OPT_SHORTCUT_STYLE,
|
OPT_SHORTCUT_STYLE,
|
||||||
OPT_SHORTCUT_POPUP,
|
OPT_SHORTCUT_POPUP,
|
||||||
OPT_SHORTCUT_SETTING,
|
OPT_SHORTCUT_SETTING,
|
||||||
OPT_LANGS_TO,
|
|
||||||
DEFAULT_BLACKLIST,
|
DEFAULT_BLACKLIST,
|
||||||
MSG_CONTEXT_MENUS,
|
MSG_CONTEXT_MENUS,
|
||||||
DEFAULT_TRANS_TAG,
|
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { useShortcut } from "../../hooks/Shortcut";
|
import { useShortcut } from "../../hooks/Shortcut";
|
||||||
import ShortcutInput from "./ShortcutInput";
|
import ShortcutInput from "./ShortcutInput";
|
||||||
@@ -95,15 +91,9 @@ export default function Settings() {
|
|||||||
maxLength,
|
maxLength,
|
||||||
clearCache,
|
clearCache,
|
||||||
newlineLength = TRANS_NEWLINE_LENGTH,
|
newlineLength = TRANS_NEWLINE_LENGTH,
|
||||||
mouseKey = OPT_MOUSEKEY_DISABLE,
|
|
||||||
detectRemote = false,
|
|
||||||
contextMenuType = 1,
|
contextMenuType = 1,
|
||||||
transTag = DEFAULT_TRANS_TAG,
|
|
||||||
transOnly = false,
|
|
||||||
transTitle = false,
|
|
||||||
touchTranslate = 2,
|
touchTranslate = 2,
|
||||||
blacklist = DEFAULT_BLACKLIST.join(",\n"),
|
blacklist = DEFAULT_BLACKLIST.join(",\n"),
|
||||||
disableLangs = [],
|
|
||||||
} = setting;
|
} = setting;
|
||||||
const { isHide = false } = fab || {};
|
const { isHide = false } = fab || {};
|
||||||
|
|
||||||
@@ -171,62 +161,6 @@ export default function Settings() {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormControl size="small">
|
|
||||||
<InputLabel>{i18n("translate_timing")}</InputLabel>
|
|
||||||
<Select
|
|
||||||
name="mouseKey"
|
|
||||||
value={mouseKey}
|
|
||||||
label={i18n("translate_timing")}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{OPT_MOUSEKEY_ALL.map((item) => (
|
|
||||||
<MenuItem key={item} value={item}>
|
|
||||||
{i18n(item)}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormControl size="small">
|
|
||||||
<InputLabel>{i18n("translation_element_tag")}</InputLabel>
|
|
||||||
<Select
|
|
||||||
name="transTag"
|
|
||||||
value={transTag}
|
|
||||||
label={i18n("translation_element_tag")}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
<MenuItem value={"span"}>{`<span>`}</MenuItem>
|
|
||||||
<MenuItem value={"font"}>{`<font>`}</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormControl size="small">
|
|
||||||
<InputLabel>{i18n("show_only_translations")}</InputLabel>
|
|
||||||
<Select
|
|
||||||
name="transOnly"
|
|
||||||
value={transOnly}
|
|
||||||
label={i18n("show_only_translations")}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
<MenuItem value={false}>{i18n("disable")}</MenuItem>
|
|
||||||
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>{i18n("show_only_translations_help")}</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormControl size="small">
|
|
||||||
<InputLabel>{i18n("translate_page_title")}</InputLabel>
|
|
||||||
<Select
|
|
||||||
name="transTitle"
|
|
||||||
value={transTitle}
|
|
||||||
label={i18n("translate_page_title")}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
<MenuItem value={false}>{i18n("disable")}</MenuItem>
|
|
||||||
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormControl size="small">
|
<FormControl size="small">
|
||||||
<InputLabel>{i18n("touch_translate_shortcut")}</InputLabel>
|
<InputLabel>{i18n("touch_translate_shortcut")}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
@@ -272,38 +206,6 @@ export default function Settings() {
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl size="small">
|
|
||||||
<InputLabel>{i18n("detect_lang_remote")}</InputLabel>
|
|
||||||
<Select
|
|
||||||
name="detectRemote"
|
|
||||||
value={detectRemote}
|
|
||||||
label={i18n("detect_lang_remote")}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
<MenuItem value={false}>{i18n("disable")}</MenuItem>
|
|
||||||
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>{i18n("detect_lang_remote_help")}</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<FormControl size="small">
|
|
||||||
<InputLabel>{i18n("disable_langs")}</InputLabel>
|
|
||||||
<Select
|
|
||||||
multiple
|
|
||||||
name="disableLangs"
|
|
||||||
value={disableLangs}
|
|
||||||
label={i18n("disable_langs")}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{OPT_LANGS_TO.map(([langKey, langName]) => (
|
|
||||||
<MenuItem key={langKey} value={langKey}>
|
|
||||||
{langName}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
<FormHelperText>{i18n("disable_langs_helper")}</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
{isExt ? (
|
{isExt ? (
|
||||||
<>
|
<>
|
||||||
<FormControl size="small">
|
<FormControl size="small">
|
||||||
|
|||||||
@@ -1,358 +0,0 @@
|
|||||||
import Stack from "@mui/material/Stack";
|
|
||||||
import TextField from "@mui/material/TextField";
|
|
||||||
import { useCallback, useEffect, useState } from "react";
|
|
||||||
import { useI18n } from "../../hooks/I18n";
|
|
||||||
import Typography from "@mui/material/Typography";
|
|
||||||
import Accordion from "@mui/material/Accordion";
|
|
||||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
|
||||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
||||||
import Alert from "@mui/material/Alert";
|
|
||||||
import Box from "@mui/material/Box";
|
|
||||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
||||||
import Switch from "@mui/material/Switch";
|
|
||||||
import { useSetting } from "../../hooks/Setting";
|
|
||||||
import CircularProgress from "@mui/material/CircularProgress";
|
|
||||||
import { syncWebfix, loadOrFetchWebfix, FIXER_ALL } from "../../libs/webfix";
|
|
||||||
import Button from "@mui/material/Button";
|
|
||||||
import SyncIcon from "@mui/icons-material/Sync";
|
|
||||||
import { useAlert } from "../../hooks/Alert";
|
|
||||||
import HelpButton from "./HelpButton";
|
|
||||||
import { URL_KISS_RULES_NEW_ISSUE } from "../../config";
|
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
|
||||||
import { useWebfixRules } from "../../hooks/WebfixRules";
|
|
||||||
|
|
||||||
function WebfixFields({ rule, webfix, setShow }) {
|
|
||||||
const editMode = !!rule;
|
|
||||||
const initFormValues = rule || {
|
|
||||||
pattern: "",
|
|
||||||
selector: "",
|
|
||||||
rootSelector: "",
|
|
||||||
fixer: FIXER_ALL[0],
|
|
||||||
};
|
|
||||||
const i18n = useI18n();
|
|
||||||
const [disabled, setDisabled] = useState(editMode);
|
|
||||||
const [errors, setErrors] = useState({});
|
|
||||||
const [formValues, setFormValues] = useState(initFormValues);
|
|
||||||
|
|
||||||
const { pattern, selector, rootSelector, fixer } = formValues;
|
|
||||||
|
|
||||||
const hasSamePattern = (str) => {
|
|
||||||
for (const item of webfix.list || []) {
|
|
||||||
if (item.pattern === str && rule?.pattern !== str) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFocus = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const { name } = e.target;
|
|
||||||
setErrors((pre) => ({ ...pre, [name]: "" }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const { name, value } = e.target;
|
|
||||||
setFormValues((pre) => ({ ...pre, [name]: value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
if (editMode) {
|
|
||||||
setDisabled(true);
|
|
||||||
} else {
|
|
||||||
setShow(false);
|
|
||||||
}
|
|
||||||
setFormValues(initFormValues);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const errors = {};
|
|
||||||
if (!pattern.trim()) {
|
|
||||||
errors.pattern = i18n("error_cant_be_blank");
|
|
||||||
}
|
|
||||||
if (hasSamePattern(pattern)) {
|
|
||||||
errors.pattern = i18n("error_duplicate_values");
|
|
||||||
}
|
|
||||||
if (!selector.trim()) {
|
|
||||||
errors.selector = i18n("error_cant_be_blank");
|
|
||||||
}
|
|
||||||
if (Object.keys(errors).length > 0) {
|
|
||||||
setErrors(errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editMode) {
|
|
||||||
// 编辑
|
|
||||||
setDisabled(true);
|
|
||||||
webfix.put(rule.pattern, formValues);
|
|
||||||
} else {
|
|
||||||
// 添加
|
|
||||||
webfix.add(formValues);
|
|
||||||
setShow(false);
|
|
||||||
setFormValues(initFormValues);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<Stack spacing={3}>
|
|
||||||
<TextField
|
|
||||||
size="small"
|
|
||||||
label={i18n("pattern")}
|
|
||||||
error={!!errors.pattern}
|
|
||||||
helperText={errors.pattern}
|
|
||||||
name="pattern"
|
|
||||||
value={pattern}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
multiline
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
size="small"
|
|
||||||
label={i18n("root_selector")}
|
|
||||||
error={!!errors.rootSelector}
|
|
||||||
helperText={errors.rootSelector}
|
|
||||||
name="rootSelector"
|
|
||||||
value={rootSelector}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
multiline
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
size="small"
|
|
||||||
label={i18n("selector")}
|
|
||||||
error={!!errors.selector}
|
|
||||||
helperText={errors.selector}
|
|
||||||
name="selector"
|
|
||||||
value={selector}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
multiline
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
select
|
|
||||||
size="small"
|
|
||||||
name="fixer"
|
|
||||||
value={fixer}
|
|
||||||
label={i18n("fixer_function")}
|
|
||||||
helperText={i18n("fixer_function_helper")}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{FIXER_ALL.map((item) => (
|
|
||||||
<MenuItem key={item} value={item}>
|
|
||||||
{item}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</TextField>
|
|
||||||
|
|
||||||
{webfix &&
|
|
||||||
(editMode ? (
|
|
||||||
// 编辑
|
|
||||||
<Stack direction="row" spacing={2}>
|
|
||||||
{disabled ? (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="contained"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setDisabled(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n("edit")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
webfix.del(rule.pattern);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n("delete")}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Button size="small" variant="contained" type="submit">
|
|
||||||
{i18n("save")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
onClick={handleCancel}
|
|
||||||
>
|
|
||||||
{i18n("cancel")}
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
) : (
|
|
||||||
// 添加
|
|
||||||
<Stack direction="row" spacing={2}>
|
|
||||||
<Button size="small" variant="contained" type="submit">
|
|
||||||
{i18n("save")}
|
|
||||||
</Button>
|
|
||||||
<Button size="small" variant="outlined" onClick={handleCancel}>
|
|
||||||
{i18n("cancel")}
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function WebfixAccordion({ rule, webfix }) {
|
|
||||||
const [expanded, setExpanded] = useState(false);
|
|
||||||
|
|
||||||
const handleChange = (e) => {
|
|
||||||
setExpanded((pre) => !pre);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Accordion expanded={expanded} onChange={handleChange}>
|
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
opacity: webfix ? 1 : 0.5,
|
|
||||||
overflowWrap: "anywhere",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{rule.pattern}
|
|
||||||
</Typography>
|
|
||||||
</AccordionSummary>
|
|
||||||
<AccordionDetails>
|
|
||||||
{expanded && <WebfixFields rule={rule} webfix={webfix} />}
|
|
||||||
</AccordionDetails>
|
|
||||||
</Accordion>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Webfix() {
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [sites, setSites] = useState([]);
|
|
||||||
const i18n = useI18n();
|
|
||||||
const alert = useAlert();
|
|
||||||
const { setting, updateSetting } = useSetting();
|
|
||||||
const [showAdd, setShowAdd] = useState(false);
|
|
||||||
const webfix = useWebfixRules();
|
|
||||||
|
|
||||||
const loadSites = useCallback(async () => {
|
|
||||||
const sites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL);
|
|
||||||
setSites(sites);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleSyncTest = async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
await syncWebfix(process.env.REACT_APP_WEBFIXURL);
|
|
||||||
await loadSites();
|
|
||||||
alert.success(i18n("sync_success"));
|
|
||||||
} catch (err) {
|
|
||||||
console.log("[sync webfix]", err);
|
|
||||||
alert.error(i18n("sync_failed"));
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
await loadSites();
|
|
||||||
} catch (err) {
|
|
||||||
console.log("[load webfix]", err.message);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, [loadSites]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box>
|
|
||||||
<Stack spacing={3}>
|
|
||||||
<Alert severity="info">{i18n("patch_setting_help")}</Alert>
|
|
||||||
|
|
||||||
<Stack
|
|
||||||
direction="row"
|
|
||||||
alignItems="center"
|
|
||||||
spacing={2}
|
|
||||||
useFlexGap
|
|
||||||
flexWrap="wrap"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="contained"
|
|
||||||
disabled={showAdd}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setShowAdd(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n("add")}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
disabled={loading}
|
|
||||||
onClick={handleSyncTest}
|
|
||||||
startIcon={<SyncIcon />}
|
|
||||||
>
|
|
||||||
{i18n("sync_now")}
|
|
||||||
</Button>
|
|
||||||
<HelpButton url={URL_KISS_RULES_NEW_ISSUE} />
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch
|
|
||||||
size="small"
|
|
||||||
checked={!!setting.injectWebfix}
|
|
||||||
onChange={() => {
|
|
||||||
updateSetting({
|
|
||||||
injectWebfix: !setting.injectWebfix,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={i18n("inject_webfix")}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
{showAdd && <WebfixFields webfix={webfix} setShow={setShowAdd} />}
|
|
||||||
|
|
||||||
{webfix.list?.length > 0 && (
|
|
||||||
<Box>
|
|
||||||
{webfix.list.map((rule) => (
|
|
||||||
<WebfixAccordion key={rule.pattern} rule={rule} webfix={webfix} />
|
|
||||||
))}
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{setting.injectWebfix && (
|
|
||||||
<Box>
|
|
||||||
{loading ? (
|
|
||||||
<center>
|
|
||||||
<CircularProgress size={16} />
|
|
||||||
</center>
|
|
||||||
) : (
|
|
||||||
sites.map((rule) => (
|
|
||||||
<WebfixAccordion key={rule.pattern} rule={rule} />
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,6 @@ import Stack from "@mui/material/Stack";
|
|||||||
import { adaptScript } from "../../libs/gm";
|
import { adaptScript } from "../../libs/gm";
|
||||||
import Alert from "@mui/material/Alert";
|
import Alert from "@mui/material/Alert";
|
||||||
import Apis from "./Apis";
|
import Apis from "./Apis";
|
||||||
import Webfix from "./Webfix";
|
|
||||||
import InputSetting from "./InputSetting";
|
import InputSetting from "./InputSetting";
|
||||||
import Tranbox from "./Tranbox";
|
import Tranbox from "./Tranbox";
|
||||||
import FavWords from "./FavWords";
|
import FavWords from "./FavWords";
|
||||||
@@ -125,7 +124,6 @@ export default function Options() {
|
|||||||
<Route path="tranbox" element={<Tranbox />} />
|
<Route path="tranbox" element={<Tranbox />} />
|
||||||
<Route path="apis" element={<Apis />} />
|
<Route path="apis" element={<Apis />} />
|
||||||
<Route path="sync" element={<SyncSetting />} />
|
<Route path="sync" element={<SyncSetting />} />
|
||||||
<Route path="webfix" element={<Webfix />} />
|
|
||||||
<Route path="words" element={<FavWords />} />
|
<Route path="words" element={<FavWords />} />
|
||||||
<Route path="about" element={<About />} />
|
<Route path="about" element={<About />} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
Reference in New Issue
Block a user