Compare commits

..

23 Commits

Author SHA1 Message Date
Gabe Yuan
c57a0a11fa v1.7.0 2023-09-11 23:21:15 +08:00
Gabe Yuan
fa244b2097 subrules sync time 2023-09-11 22:53:04 +08:00
Gabe Yuan
79612f8a1b subrules sync time 2023-09-11 17:56:31 +08:00
Gabe Yuan
2bf79dbc51 rootSlector -> rootSelector 2023-09-11 16:12:37 +08:00
Gabe Yuan
c2658d5dd0 v1.6.12 2023-09-11 14:35:52 +08:00
Gabe Yuan
13684884c7 i18n text 2023-09-11 13:45:26 +08:00
Gabe Yuan
f216a9254e update readme 2023-09-11 13:42:44 +08:00
Gabe Yuan
dbdbcbba2d update readme 2023-09-11 13:37:19 +08:00
Gabe Yuan
2ee4609192 fix sync bug 2023-09-11 11:33:28 +08:00
Gabe Yuan
0d93cf78f7 fix i18n text 2023-09-10 21:59:28 +08:00
Gabe Yuan
3398ca0dd7 fix i18n text 2023-09-10 21:56:06 +08:00
Gabe Yuan
c1778fbcbb v1.6.11 2023-09-10 15:23:50 +08:00
Gabe Yuan
1ef9974c05 fix sync webfix 2023-09-10 15:04:41 +08:00
Gabe Yuan
399c6b6fed add global rule text 2023-09-10 14:51:16 +08:00
Gabe Yuan
62a60eee44 update help text 2023-09-10 14:34:55 +08:00
Gabe Yuan
54339af885 update readme 2023-09-10 14:19:31 +08:00
Gabe Yuan
06cfd33e60 add open options shortcut for ext 2023-09-10 13:56:11 +08:00
Gabe Yuan
08c9d78d2a add save rule button 2023-09-10 13:44:34 +08:00
Gabe Yuan
e7a5e5dce1 add save rule button 2023-09-10 13:09:19 +08:00
Gabe Yuan
3a59a127d1 add save rule button 2023-09-10 12:35:03 +08:00
Gabe Yuan
26f213cad2 add fontsize fixer 2023-09-09 23:32:17 +08:00
Gabe Yuan
7b6148302d v1.6.10 2023-09-09 20:15:09 +08:00
Gabe Yuan
38c781b8f3 fix open setting shortcut 2023-09-09 20:13:36 +08:00
26 changed files with 322 additions and 149 deletions

2
.env
View File

@@ -2,7 +2,7 @@ GENERATE_SOURCEMAP=false
REACT_APP_NAME=KISS Translator
REACT_APP_NAME_CN=简约翻译
REACT_APP_VERSION=1.6.9
REACT_APP_VERSION=1.7.0
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator

View File

@@ -16,7 +16,34 @@ If you also like a little more simplicity, welcome to pick it up.
## Features
- Keep it simple, smart
- [x] Keep it simple, smart
- [x] Open source
- [x] Adapt to common browsers
- [x] Chrome/Edge/Firefox/Kiwi
- [ ] Safari
- [x] Supports multiple translation services
- [x] Google/Microsoft/DeepL/OpenAI
- [x] Custom translation interface
- [x] Data synchronization function
- [x] Custom rules + rule subscription
- [x] Custom style
- [x] Custom shortcut keys
- `Alt+Q` Toggle Translation
- `Alt+C` Toggle Styles
- `Alt+K` Open Popup
- `Alt+O` Open Options
## Download
- [x] Browser extension
- [x] Chrome [Installation address](https://chrome.google.com/webstore/detail/kiss-translator/bdiifdefkgmcblbcghdlonllpjhhjgof?hl=zh-CN)
- [x] Edge [Installation address](https://microsoftedge.microsoft.com/addons/detail/%E7%AE%80%E7%BA%A6%E7%BF%BB%E8%AF%91/jemckldkclkinpjighnoilpbldbdmmlh?hl=zh-CN)
- [x] Firefox [Installation address](https://addons.mozilla.org/zh-CN/firefox/addon/kiss-translator/)
- [ ] Safari
- [x] GreaseMonkey Script
- [x] Chrome/Edge/Firefox ([Tampermonkey](https://www.tampermonkey.net/)/[Violentmonkey](https://violentmonkey.github.io/)) [Installation link 1](https://fishjar.github.io/kiss-translator/kiss-translator.user.js)、 [Installation link 2](https://kiss-translator.rayjar.com/kiss-translator.user.js)
- Greasy Fork [Installation address](https://greasyfork.org/zh-CN/scripts/472840-kiss-translator)
- [x] iOS Safari ([Userscripts Safari](https://github.com/quoid/userscripts)) [Installation link 1](https://fishjar.github.io/kiss-translator/kiss-translator-ios-safari.user.js)、 [Installation link 2](https://kiss-translator.rayjar.com/kiss-translator.user-ios-safari.js)
## Associated ProjectS
@@ -38,42 +65,7 @@ If you also like a little more simplicity, welcome to pick it up.
- Supports query of English words, sentences and Chinese characters.
- Supports history records and word collections.
## Description
### Support shortcut keys
- `Alt+Q` Toggle Translation
- `Alt+C` Toggle Styles
- `Alt+K` Open Menu
## Schedule
- [x] Provide trial installation package
- [x] Adapt browser
- [x] Chrome
- [x] Edge
- [x] Firefox
- [ ] Safari
- [x] Kiwi
- [x] Support translation services
- [x] Google
- [x] Microsoft
- [x] DeepL
- [x] OpenAI
- [x] Upload to app Store
- [x] Chrome [Install Link](https://chrome.google.com/webstore/detail/kiss-translator/bdiifdefkgmcblbcghdlonllpjhhjgof)
- [x] Edge [Install Link](https://microsoftedge.microsoft.com/addons/detail/kiss-translator/jemckldkclkinpjighnoilpbldbdmmlh)
- [x] Firefox [Install Link](https://addons.mozilla.org/en-US/firefox/addon/kiss-translator/)
- [ ] Safari
- [x] Greasy Fork [Install Link](https://greasyfork.org/en/scripts/472840-kiss-translator)
- [x] Open source
- [x] Data Synchronization Function
- [x] Greasemonkey Script ([Setting Page 1](https://fishjar.github.io/kiss-translator/options.html)、[Setting Page 2](https://kiss-translator.rayjar.com/options))
- [x] [Tampermonkey](https://www.tampermonkey.net/) (Chrome/Edge/Firefox) [Install Link 1](https://fishjar.github.io/kiss-translator/kiss-translator.user.js)、[Install Link 2](https://kiss-translator.rayjar.com/kiss-translator.user.js)
- [x] [Violentmonkey](https://violentmonkey.github.io/) (Chrome/Edge/Firefox) [Install Link 1](https://fishjar.github.io/kiss-translator/kiss-translator.user.js)、[Install Link 2](https://kiss-translator.rayjar.com/kiss-translator.user.js)
- [x] [Userscripts Safari](https://github.com/quoid/userscripts) (iOS Safari) [Install Link 1](https://fishjar.github.io/kiss-translator/kiss-translator-ios-safari.user.js)、[Install Link 2](https://kiss-translator.rayjar.com/kiss-translator.user-ios-safari.js)
## Guide
## Development Guidelines
```sh
git clone https://github.com/fishjar/kiss-translator.git

View File

@@ -16,7 +16,34 @@
## 特点
- 保持简约
- [x] 保持简约
- [x] 开放源代码
- [x] 适配常见浏览器
- [x] Chrome/Edge/Firefox/Kiwi
- [ ] Safari
- [x] 支持多种翻译服务
- [x] Google/Microsoft/DeepL/OpenAI
- [x] 自定义翻译接口
- [x] 数据同步功能
- [x] 自定义规则 + 规则订阅
- [x] 自定义样式
- [x] 自定义快捷键
- `Alt+Q` 开启翻译
- `Alt+C` 切换样式
- `Alt+K` 打开弹窗
- `Alt+O` 打开设置
## 下载
- [x] 浏览器扩展
- [x] Chrome [安装地址](https://chrome.google.com/webstore/detail/kiss-translator/bdiifdefkgmcblbcghdlonllpjhhjgof?hl=zh-CN)
- [x] Edge [安装地址](https://microsoftedge.microsoft.com/addons/detail/%E7%AE%80%E7%BA%A6%E7%BF%BB%E8%AF%91/jemckldkclkinpjighnoilpbldbdmmlh?hl=zh-CN)
- [x] Firefox [安装地址](https://addons.mozilla.org/zh-CN/firefox/addon/kiss-translator/)
- [ ] Safari
- [x] 油猴脚本
- [x] Chrome/Edge/Firefox ([Tampermonkey](https://www.tampermonkey.net/)/[Violentmonkey](https://violentmonkey.github.io/)) [安装链接 1](https://fishjar.github.io/kiss-translator/kiss-translator.user.js)、 [安装链接 2](https://kiss-translator.rayjar.com/kiss-translator.user.js)
- Greasy Fork [安装地址](https://greasyfork.org/zh-CN/scripts/472840-kiss-translator)
- [x] iOS Safari ([Userscripts Safari](https://github.com/quoid/userscripts)) [安装链接 1](https://fishjar.github.io/kiss-translator/kiss-translator-ios-safari.user.js)、 [安装链接 2](https://kiss-translator.rayjar.com/kiss-translator.user-ios-safari.js)
## 关联项目
@@ -38,42 +65,7 @@
- 支持英文单词、句子、汉字的查询。
- 支持历史记录、单词收藏。
## 简要说明
### 支持快捷键
- `Alt+Q` 开启翻译
- `Alt+C` 切换样式
- `Alt+K` 打开菜单
## 进度
- [x] 提供试用安装包
- [x] 适配浏览器
- [x] Chrome
- [x] Edge
- [x] Firefox
- [ ] Safari
- [x] Kiwi
- [x] 支持翻译服务
- [x] Google
- [x] Microsoft
- [x] DeepL
- [x] OpenAI
- [x] 上架应用市场
- [x] Chrome [安装地址](https://chrome.google.com/webstore/detail/kiss-translator/bdiifdefkgmcblbcghdlonllpjhhjgof?hl=zh-CN)
- [x] Edge [安装地址](https://microsoftedge.microsoft.com/addons/detail/%E7%AE%80%E7%BA%A6%E7%BF%BB%E8%AF%91/jemckldkclkinpjighnoilpbldbdmmlh?hl=zh-CN)
- [x] Firefox [安装地址](https://addons.mozilla.org/zh-CN/firefox/addon/kiss-translator/)
- [ ] Safari
- [x] Greasy Fork [安装地址](https://greasyfork.org/zh-CN/scripts/472840-kiss-translator)
- [x] 开放源代码
- [x] 数据同步功能
- [x] 油猴脚本 ([设置页面 1](https://fishjar.github.io/kiss-translator/options.html)、[设置页面 2](https://kiss-translator.rayjar.com/options))
- [x] [Tampermonkey](https://www.tampermonkey.net/) (Chrome/Edge/Firefox) [安装链接 1](https://fishjar.github.io/kiss-translator/kiss-translator.user.js)、[安装链接 2](https://kiss-translator.rayjar.com/kiss-translator.user.js)
- [x] [Violentmonkey](https://violentmonkey.github.io/) (Chrome/Edge/Firefox) [安装链接 1](https://fishjar.github.io/kiss-translator/kiss-translator.user.js)、[安装链接 2](https://kiss-translator.rayjar.com/kiss-translator.user.js)
- [x] [Userscripts Safari](https://github.com/quoid/userscripts) (iOS Safari) [安装链接 1](https://fishjar.github.io/kiss-translator/kiss-translator-ios-safari.user.js)、[安装链接 2](https://kiss-translator.rayjar.com/kiss-translator.user-ios-safari.js)
## 指引
## 开发指引
```sh
git clone https://github.com/fishjar/kiss-translator.git

View File

@@ -1,7 +1,7 @@
{
"name": "kiss-translator",
"description": "A minimalist bilingual translation Extension & Greasemonkey Script",
"version": "1.6.9",
"version": "1.7.0",
"author": "Gabe<yugang2002@gmail.com>",
"private": true,
"dependencies": {

View File

@@ -10,5 +10,8 @@
},
"toggle_style": {
"message": "Toggle Style"
},
"open_options": {
"message": "Open Options"
}
}

View File

@@ -6,9 +6,12 @@
"message": "一个简约的双语网页翻译扩展 & 油猴脚本"
},
"toggle_translate": {
"message": "切换翻译"
"message": "开启翻译"
},
"toggle_style": {
"message": "切换样式"
},
"open_options": {
"message": "打开设置"
}
}

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_app_name__",
"description": "__MSG_app_description__",
"version": "1.6.9",
"version": "1.7.0",
"default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator",
@@ -33,6 +33,12 @@
"default": "Alt+C"
},
"description": "__MSG_toggle_style__"
},
"openOptions": {
"suggested_key": {
"default": "Alt+O"
},
"description": "__MSG_open_options__"
}
},
"permissions": ["<all_urls>", "storage"],

View File

@@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "__MSG_app_name__",
"description": "__MSG_app_description__",
"version": "1.6.9",
"version": "1.7.0",
"default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator",
@@ -34,6 +34,12 @@
"default": "Alt+C"
},
"description": "__MSG_toggle_style__"
},
"openOptions": {
"suggested_key": {
"default": "Alt+O"
},
"description": "__MSG_open_options__"
}
},
"permissions": ["storage"],

View File

@@ -7,6 +7,7 @@ import {
MSG_TRANS_TOGGLE_STYLE,
CMD_TOGGLE_TRANSLATE,
CMD_TOGGLE_STYLE,
CMD_OPEN_OPTIONS,
} from "./config";
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
import { trySyncSettingAndRules } from "./libs/sync";
@@ -85,6 +86,9 @@ browser.commands.onCommand.addListener((command) => {
case CMD_TOGGLE_STYLE:
sendTabMsg(MSG_TRANS_TOGGLE_STYLE);
break;
case CMD_OPEN_OPTIONS:
browser.runtime.openOptionsPage();
break;
default:
}
});

View File

@@ -43,6 +43,7 @@ const customApiLangs = `["en", "English - English"],
`;
const customApiHelpZH = `/// 自定义翻译源接口说明
// 请求Request数据将按下面规范发送
{
url: {{YOUR_URL}},
@@ -70,6 +71,7 @@ ${customApiLangs}
`;
const customApiHelpEN = `/// Custom translation source interface description
// Request data will be sent according to the following specifications
{
url: {{YOUR_URL}},
@@ -342,8 +344,8 @@ export const I18N = {
en: `Follow the syntax of "CSS"`,
},
setting: {
zh: `设置`,
en: `Setting`,
zh: `设置 (Alt+O)`,
en: `Setting (Alt+O)`,
},
pattern: {
zh: `匹配网址`,
@@ -527,14 +529,22 @@ export const I18N = {
},
hide_fab_button: {
zh: `隐藏悬浮按钮`,
en: `"Hide Fab Button`,
en: `Hide Fab Button`,
},
show: {
zh: `显示`,
en: `"Show`,
en: `Show`,
},
hide: {
zh: `隐藏`,
en: `"Hide`,
en: `Hide`,
},
save_rule: {
zh: `保存规则`,
en: `Save Rule`,
},
global_rule: {
zh: `全局规则`,
en: `Global Rule`,
},
};

View File

@@ -29,6 +29,7 @@ export const STOKEY_WEBFIXCACHE_PREFIX = `${APP_NAME}_webfixcache_`;
export const CMD_TOGGLE_TRANSLATE = "toggleTranslate";
export const CMD_TOGGLE_STYLE = "toggleStyle";
export const CMD_OPEN_OPTIONS = "openOptions";
export const CLIENT_WEB = "web";
export const CLIENT_CHROME = "chrome";
@@ -284,4 +285,5 @@ export const DEFAULT_SYNC = {
rulesUpdateAt: 0,
rulesSyncAt: 0,
subRulesSyncAt: 0, // 订阅规则同步时间
dataCaches: {}, // 缓存同步时间
};

View File

@@ -14,7 +14,7 @@ export function useRules() {
const updateRules = useCallback(
async (rules) => {
await save(rules);
trySyncRules();
trySyncRules(false, true);
},
[save]
);

View File

@@ -19,7 +19,7 @@ export function SettingProvider({ children }) {
const syncSetting = useMemo(
() =>
debounce(() => {
trySyncSetting();
trySyncSetting(false, true);
}, [2000]),
[]
);

View File

@@ -31,6 +31,7 @@ export function useStorage(key, defaultVal = null) {
if (val) {
setData(val);
} else if (defaultVal) {
setData(defaultVal);
await storage.setObj(key, defaultVal);
}
}, [key, defaultVal]);

View File

@@ -48,7 +48,7 @@ export function useSubRules() {
const addSub = useCallback(
async (url) => {
const subrulesList = [...list];
subrulesList.push({ url, selected: false, syncAt: Date.now() });
subrulesList.push({ url, selected: false });
await updateSetting({ subrulesList });
},
[list, updateSetting]

View File

@@ -1,3 +1,4 @@
import { useCallback } from "react";
import { STOKEY_SYNC, DEFAULT_SYNC } from "../config";
import { useStorage } from "./Storage";
@@ -6,6 +7,40 @@ import { useStorage } from "./Storage";
* @returns
*/
export function useSync() {
const { data, update } = useStorage(STOKEY_SYNC, DEFAULT_SYNC);
return { sync: data, updateSync: update };
const { data, update, reload } = useStorage(STOKEY_SYNC, DEFAULT_SYNC);
return { sync: data, updateSync: update, reloadSync: reload };
}
/**
* caches sync hook
* @param {*} url
* @returns
*/
export function useSyncCaches() {
const { sync, updateSync, reloadSync } = useSync();
const updateDataCache = useCallback(
async (url) => {
const dataCaches = sync.dataCaches || {};
dataCaches[url] = Date.now();
await updateSync({ dataCaches });
},
[sync, updateSync]
);
const deleteDataCache = useCallback(
async (url) => {
const dataCaches = sync.dataCaches || {};
delete dataCaches[url];
await updateSync({ dataCaches });
},
[sync, updateSync]
);
return {
dataCaches: sync.dataCaches || {},
updateDataCache,
deleteDataCache,
reloadSync,
};
}

View File

@@ -19,3 +19,12 @@ export const sendTabMsg = async (action, args) => {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
return browser.tabs.sendMessage(tabs[0].id, { action, args });
};
/**
* 获取当前tab信息
* @returns
*/
export const getTabInfo = async () => {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
return tabs[0];
};

View File

@@ -11,6 +11,8 @@ import {
DEFAULT_OW_RULE,
} from "../config";
import { loadOrFetchSubRules } from "./subRules";
import { getRulesWithDefault, setRules } from "./storage";
import { trySyncRules } from "./sync";
/**
* 根据href匹配规则
@@ -47,9 +49,8 @@ export const matchRule = async (
mixRule[key] = val;
});
const subRules = (await loadOrFetchSubRules(selectedSub.url)).map(
(item) => ({ ...item, ...mixRule })
);
let subRules = await loadOrFetchSubRules(selectedSub.url);
subRules = subRules.map((item) => ({ ...item, ...mixRule }));
rules.splice(-1, 0, ...subRules);
}
} catch (err) {
@@ -134,3 +135,19 @@ export const checkRules = (rules) => {
return rules;
};
/**
* 保存或更新rule
* @param {*} newRule
*/
export const saveRule = async (newRule) => {
const rules = await getRulesWithDefault();
const rule = rules.find((item) => isMatch(newRule.pattern, item.pattern));
if (rule && rule.pattern !== GLOBAL_KEY) {
Object.assign(rule, { ...newRule, pattern: rule.pattern });
} else {
rules.unshift(newRule);
}
await setRules(rules);
trySyncRules(false, true);
};

View File

@@ -10,6 +10,16 @@ import { apiFetch } from "../apis";
import { checkRules } from "./rules";
import { isAllchar } from "./utils";
/**
* 更新缓存同步时间
* @param {*} url
*/
const updateSyncDataCache = async (url) => {
const { dataCaches = {} } = await getSyncWithDefault();
dataCaches[url] = Date.now();
await updateSync({ dataCaches });
};
/**
* 同步订阅规则
* @param {*} url
@@ -35,6 +45,7 @@ export const syncAllSubRules = async (subrulesList, isBg = false) => {
for (let subrules of subrulesList) {
try {
await syncSubRules(subrules.url, isBg);
await updateSyncDataCache(subrules.url);
} catch (err) {
console.log(`[sync subrule error]: ${subrules.url}`, err);
}
@@ -70,9 +81,10 @@ export const trySyncAllSubRules = async ({ subrulesList }, isBg = false) => {
* @returns
*/
export const loadOrFetchSubRules = async (url) => {
const rules = await getSubRules(url);
if (rules?.length) {
return rules;
let rules = await getSubRules(url);
if (!rules || rules.length === 0) {
rules = await syncSubRules(url);
await updateSyncDataCache(url);
}
return syncSubRules(url);
return rules || [];
};

View File

@@ -19,12 +19,21 @@ import { sha256 } from "./utils";
* 同步设置
* @returns
*/
const syncSetting = async (isBg = false) => {
const { syncUrl, syncKey, settingUpdateAt = 0 } = await getSyncWithDefault();
const syncSetting = async (isBg = false, isForce = false) => {
let {
syncUrl,
syncKey,
settingUpdateAt = 0,
settingSyncAt = 0,
} = await getSyncWithDefault();
if (!syncUrl || !syncKey) {
return;
}
if (isForce) {
settingUpdateAt = Date.now();
}
const setting = await getSettingWithDefault();
const res = await apiSyncData(
syncUrl,
@@ -32,7 +41,7 @@ const syncSetting = async (isBg = false) => {
{
key: KV_SETTING_KEY,
value: setting,
updateAt: settingUpdateAt,
updateAt: settingSyncAt === 0 ? 0 : settingUpdateAt,
},
isBg
);
@@ -48,9 +57,9 @@ const syncSetting = async (isBg = false) => {
return res.value;
};
export const trySyncSetting = async (isBg = false) => {
export const trySyncSetting = async (isBg = false, isForce = false) => {
try {
return await syncSetting(isBg);
return await syncSetting(isBg, isForce);
} catch (err) {
console.log("[sync setting]", err);
}
@@ -60,12 +69,21 @@ export const trySyncSetting = async (isBg = false) => {
* 同步规则
* @returns
*/
const syncRules = async (isBg = false) => {
const { syncUrl, syncKey, rulesUpdateAt } = await getSyncWithDefault();
const syncRules = async (isBg = false, isForce = false) => {
let {
syncUrl,
syncKey,
rulesUpdateAt = 0,
rulesSyncAt = 0,
} = await getSyncWithDefault();
if (!syncUrl || !syncKey) {
return;
}
if (isForce) {
rulesUpdateAt = Date.now();
}
const rules = await getRulesWithDefault();
const res = await apiSyncData(
syncUrl,
@@ -73,7 +91,7 @@ const syncRules = async (isBg = false) => {
{
key: KV_RULES_KEY,
value: rules,
updateAt: rulesUpdateAt,
updateAt: rulesSyncAt === 0 ? 0 : rulesUpdateAt,
},
isBg
);
@@ -89,9 +107,9 @@ const syncRules = async (isBg = false) => {
return res.value;
};
export const trySyncRules = async (isBg = false) => {
export const trySyncRules = async (isBg = false, isForce = false) => {
try {
return await syncRules(isBg);
return await syncRules(isBg, isForce);
} catch (err) {
console.log("[sync user rules]", err);
}

View File

@@ -5,27 +5,34 @@ import { apiFetch } from "../apis";
/**
* 修复程序类型
*/
const WEBFIX_BR = "br";
const FIXER_BR = "br";
const FIXER_FONTSIZE = "fontSize";
/**
* 需要修复的站点列表
* - pattern 匹配网址
* - selector 需要修复的选择器
* - rootSlector 需要监听的选择器,可留空
* - rootSelector 需要监听的选择器,可留空
* - fixer 修复函数,可针对不同网址,选用不同修复函数
*/
const DEFAULT_SITES = [
{
pattern: "www.phoronix.com",
selector: ".content",
rootSlector: "",
fixer: WEBFIX_BR,
rootSelector: "",
fixer: FIXER_BR,
},
{
pattern: "t.me/s/*",
pattern: "t.me/s/",
selector: ".tgme_widget_message_text",
rootSlector: ".tgme_channel_history",
fixer: WEBFIX_BR,
rootSelector: ".tgme_channel_history",
fixer: FIXER_BR,
},
{
pattern: "baidu.com",
selector: "html",
rootSelector: "",
fixer: FIXER_FONTSIZE,
},
];
@@ -87,20 +94,29 @@ function brFixer(node) {
node.innerHTML = html;
}
/**
* 修复字体大小问题,如 baidu.com
* @param {*} node
*/
function fontSizeFixer(node) {
node.style.cssText += "font-size:1em;";
}
/**
* 修复程序映射
*/
const fixerMap = {
[WEBFIX_BR]: brFixer,
[FIXER_BR]: brFixer,
[FIXER_FONTSIZE]: fontSizeFixer,
};
/**
* 查找、监听节点,并执行修复函数
* @param {*} selector
* @param {*} fixer
* @param {*} rootSlector
* @param {*} rootSelector
*/
function run(selector, fixer, rootSlector) {
function run(selector, fixer, rootSelector) {
var mutaObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (addNode) {
@@ -110,8 +126,8 @@ function run(selector, fixer, rootSlector) {
});
var rootNodes = [document];
if (rootSlector) {
rootNodes = document.querySelectorAll(rootSlector);
if (rootSelector) {
rootNodes = document.querySelectorAll(rootSelector);
}
rootNodes.forEach(function (rootNode) {
@@ -165,7 +181,7 @@ export async function webfix(href, { injectWebfix }) {
var site = sites[i];
if (isMatch(href, site.pattern)) {
if (fixerMap[site.fixer]) {
run(site.selector, fixerMap[site.fixer], site.rootSlector);
run(site.selector, fixerMap[site.fixer], site.rootSelector);
}
break;
}

View File

@@ -109,7 +109,7 @@ export default function Action({ translator, fab }) {
GM.registerMenuCommand(
"Open Setting (Alt+o)",
(event) => {
setShowPopup((pre) => !pre);
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
},
"O"
)

View File

@@ -48,6 +48,7 @@ import { delSubRules, getSyncWithDefault } from "../../libs/storage";
import OwSubRule from "./OwSubRule";
import ClearAllIcon from "@mui/icons-material/ClearAll";
import HelpButton from "./HelpButton";
import { useSyncCaches } from "../../hooks/Sync";
function RuleFields({ rule, rules, setShow, setKeyword }) {
const initFormValues = rule || {
@@ -362,6 +363,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
}
function RuleAccordion({ rule, rules }) {
const i18n = useI18n();
const [expanded, setExpanded] = useState(false);
const handleChange = (e) => {
@@ -376,7 +378,9 @@ function RuleAccordion({ rule, rules }) {
opacity: rules ? 1 : 0.5,
}}
>
{rule.pattern}
{rule.pattern === GLOBAL_KEY
? `[${i18n("global_rule")}] ${rule.pattern}`
: rule.pattern}
</Typography>
</AccordionSummary>
<AccordionDetails>
@@ -621,8 +625,9 @@ function SubRulesItem({
syncAt,
selectedUrl,
delSub,
updateSub,
setSelectedRules,
updateDataCache,
deleteDataCache,
}) {
const [loading, setLoading] = useState(false);
@@ -630,6 +635,7 @@ function SubRulesItem({
try {
await delSub(url);
await delSubRules(url);
await deleteDataCache(url);
} catch (err) {
console.log("[del subrules]", err);
}
@@ -642,7 +648,7 @@ function SubRulesItem({
if (rules.length > 0 && url === selectedUrl) {
setSelectedRules(rules);
}
await updateSub(url, { syncAt: Date.now() });
await updateDataCache(url);
} catch (err) {
console.log("[sync sub rules]", err);
} finally {
@@ -677,7 +683,7 @@ function SubRulesItem({
);
}
function SubRulesEdit({ subList, addSub }) {
function SubRulesEdit({ subList, addSub, updateDataCache }) {
const i18n = useI18n();
const [inputText, setInputText] = useState("");
const [inputError, setInputError] = useState("");
@@ -712,6 +718,7 @@ function SubRulesEdit({ subList, addSub }) {
throw new Error("empty rules");
}
await addSub(url);
await updateDataCache(url);
setShowInput(false);
setInputText("");
} catch (err) {
@@ -784,7 +791,6 @@ function SubRules({ subRules }) {
const {
subList,
selectSub,
updateSub,
addSub,
delSub,
selectedUrl,
@@ -792,27 +798,38 @@ function SubRules({ subRules }) {
setSelectedRules,
loading,
} = subRules;
const { dataCaches, updateDataCache, deleteDataCache, reloadSync } =
useSyncCaches();
const handleSelect = (e) => {
const url = e.target.value;
selectSub(url);
};
useEffect(() => {
reloadSync();
}, [selectedRules, reloadSync]);
return (
<Stack spacing={3}>
<SubRulesEdit subList={subList} addSub={addSub} />
<SubRulesEdit
subList={subList}
addSub={addSub}
updateDataCache={updateDataCache}
/>
<RadioGroup value={selectedUrl} onChange={handleSelect}>
{subList.map((item, index) => (
<SubRulesItem
key={item.url}
url={item.url}
syncAt={item.syncAt}
syncAt={dataCaches[item.url]}
index={index}
selectedUrl={selectedUrl}
delSub={delSub}
updateSub={updateSub}
setSelectedRules={setSelectedRules}
updateDataCache={updateDataCache}
deleteDataCache={deleteDataCache}
/>
))}
</RadioGroup>

View File

@@ -1,6 +1,6 @@
import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useI18n } from "../../hooks/I18n";
import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion";
@@ -21,14 +21,14 @@ import HelpButton from "./HelpButton";
import { URL_KISS_RULES_NEW_ISSUE } from "../../config";
function ApiFields({ site }) {
const { selector, rootSlector, fixer } = site;
const { selector, rootSelector, fixer } = site;
return (
<Stack spacing={3}>
<TextField
size="small"
label={"rootSlector"}
name="rootSlector"
value={rootSlector || "document"}
label={"rootSelector"}
name="rootSelector"
value={rootSelector || "document"}
disabled
/>
<TextField
@@ -75,11 +75,17 @@ export default function Webfix() {
const alert = useAlert();
const { setting, updateSetting } = useSetting();
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);
@@ -93,15 +99,14 @@ export default function Webfix() {
(async () => {
try {
setLoading(true);
const sites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL);
setSites(sites);
await loadSites();
} catch (err) {
console.log("[load webfix]", err.message);
} finally {
setLoading(false);
}
})();
}, []);
}, [loadSites]);
return (
<Box>

View File

@@ -36,7 +36,7 @@ export default function Options() {
// 检查版本是否一致
if (version !== process.env.REACT_APP_VERSION) {
setError(
`The version of the script(v${version}) and this page(v${process.env.REACT_APP_VERSION}) are inconsistent.`
`The version is inconsistent, please check whether the script(v${version}) is the latest version(v${process.env.REACT_APP_VERSION}). (版本不一致,请检查脚本(v${version})是否为最新版(v${process.env.REACT_APP_VERSION}))`
);
break;
}
@@ -53,7 +53,7 @@ export default function Options() {
}
if (++i > 8) {
setError("Time out.");
setError("Time out. (连接超时)");
break;
}
@@ -78,26 +78,26 @@ export default function Options() {
</Divider>
<h2>
Please confirm whether to install or enable KISS Translator
GreaseMonkey script?
GreaseMonkey script? (请检查是否安装或启用简约翻译油猴脚本)
</h2>
<Stack spacing={2}>
<Link href={process.env.REACT_APP_USERSCRIPT_DOWNLOADURL}>
Install Userscript 1
Install Userscript for Tampermonkey/Violentmonkey 1 (油猴脚本 安装地址 1)
</Link>
<Link href={process.env.REACT_APP_USERSCRIPT_DOWNLOADURL2}>
Install Userscript 2
Install Userscript for Tampermonkey/Violentmonkey 2 (油猴脚本 安装地址 2)
</Link>
<Link href={process.env.REACT_APP_USERSCRIPT_IOS_DOWNLOADURL}>
Install Userscript Safari 1
Install Userscript for iOS Safari 1 (油猴脚本 iOS Safari专用 安装地址 1)
</Link>
<Link href={process.env.REACT_APP_USERSCRIPT_IOS_DOWNLOADURL2}>
Install Userscript Safari 2
Install Userscript for iOS Safari 2 (油猴脚本 iOS Safari专用 安装地址 2)
</Link>
<Link href={process.env.REACT_APP_OPTIONSPAGE}>
Open Options Page 1
Open Options Page 1 (打开设置页面 1)
</Link>
<Link href={process.env.REACT_APP_OPTIONSPAGE2}>
Open Options Page 2
Open Options Page 2 (打开设置页面 2)
</Link>
</Stack>
</center>

View File

@@ -5,7 +5,7 @@ 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 { sendTabMsg } from "../../libs/msg";
import { sendTabMsg, getTabInfo } from "../../libs/msg";
import { browser } from "../../libs/browser";
import { isExt } from "../../libs/client";
import { useI18n } from "../../hooks/I18n";
@@ -24,6 +24,7 @@ import {
CACHE_NAME,
} from "../../config";
import { sendIframeMsg } from "../../libs/iframe";
import { saveRule } from "../../libs/rules";
export default function Popup({ setShowPopup, translator: tran }) {
const i18n = useI18n();
@@ -77,6 +78,20 @@ export default function Popup({ setShowPopup, translator: tran }) {
}
};
const handleSaveRule = async () => {
try {
let host = window.location.host;
if (isExt) {
const tab = await getTabInfo();
const url = new URL(tab.url);
host = url.host;
}
saveRule({ ...rule, pattern: host });
} catch (err) {
console.log("[save rule]", err);
}
};
useEffect(() => {
if (!isExt) {
return;
@@ -218,9 +233,19 @@ export default function Popup({ setShowPopup, translator: tran }) {
/>
)}
<Button variant="text" onClick={handleOpenSetting}>
{i18n("setting")}
</Button>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
spacing={2}
>
<Button variant="text" onClick={handleSaveRule}>
{i18n("save_rule")}
</Button>
<Button variant="text" onClick={handleOpenSetting}>
{i18n("setting")}
</Button>
</Stack>
</Stack>
</Box>
);