webfix setting
This commit is contained in:
2
.env
2
.env
@@ -17,6 +17,8 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,18 @@ export const I18N = {
|
|||||||
zh: `同步设置`,
|
zh: `同步设置`,
|
||||||
en: `Sync Setting`,
|
en: `Sync Setting`,
|
||||||
},
|
},
|
||||||
|
patch_setting: {
|
||||||
|
zh: `补丁设置`,
|
||||||
|
en: `Patch Setting`,
|
||||||
|
},
|
||||||
|
patch_setting_help: {
|
||||||
|
zh: `针对一些特殊网站的修正脚本,以便翻译软件得到更好的展示效果。`,
|
||||||
|
en: `Corrected scripts for some special websites so that the translation software can get better display results.`,
|
||||||
|
},
|
||||||
|
inject_webfix: {
|
||||||
|
zh: `注入修复补丁`,
|
||||||
|
en: `Inject Webfix`,
|
||||||
|
},
|
||||||
about: {
|
about: {
|
||||||
zh: `关于`,
|
zh: `关于`,
|
||||||
en: `About`,
|
en: `About`,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export const STOKEY_RULES = `${APP_NAME}_rules`;
|
|||||||
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";
|
||||||
@@ -262,6 +263,7 @@ export const DEFAULT_SETTING = {
|
|||||||
newlineLength: TRANS_NEWLINE_LENGTH,
|
newlineLength: TRANS_NEWLINE_LENGTH,
|
||||||
clearCache: false, // 是否在浏览器下次启动时清除缓存
|
clearCache: false, // 是否在浏览器下次启动时清除缓存
|
||||||
injectRules: true, // 是否注入订阅规则
|
injectRules: true, // 是否注入订阅规则
|
||||||
|
injectWebfix: true, // 是否注入修复补丁
|
||||||
subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表
|
subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表
|
||||||
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
|
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
|
||||||
transApis: DEFAULT_TRANS_APIS, // 翻译接口
|
transApis: DEFAULT_TRANS_APIS, // 翻译接口
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { getSettingWithDefault, getRulesWithDefault } from "./libs/storage";
|
|||||||
import { Translator } from "./libs/translator";
|
import { Translator } from "./libs/translator";
|
||||||
import { isIframe } from "./libs/iframe";
|
import { isIframe } from "./libs/iframe";
|
||||||
import { matchRule } from "./libs/rules";
|
import { matchRule } from "./libs/rules";
|
||||||
|
import { webfix } from "./libs/webfix";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 入口函数
|
* 入口函数
|
||||||
@@ -19,6 +20,7 @@ const init = async () => {
|
|||||||
const rules = await getRulesWithDefault();
|
const rules = await getRulesWithDefault();
|
||||||
const rule = await matchRule(rules, href, setting);
|
const rule = await matchRule(rules, href, setting);
|
||||||
const translator = new Translator(rule, setting);
|
const translator = new Translator(rule, setting);
|
||||||
|
webfix(href, setting);
|
||||||
|
|
||||||
// 监听消息
|
// 监听消息
|
||||||
browser?.runtime.onMessage.addListener(async ({ action, args }) => {
|
browser?.runtime.onMessage.addListener(async ({ action, args }) => {
|
||||||
|
|||||||
130
src/libs/webfix.js
Normal file
130
src/libs/webfix.js
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import { isMatch } from "./utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要修复的站点列表
|
||||||
|
* - pattern 匹配网址
|
||||||
|
* - selector 需要修复的选择器
|
||||||
|
* - rootSlector 需要监听的选择器,可留空
|
||||||
|
* - fixer 修复函数,可针对不同网址,选用不同修复函数
|
||||||
|
*/
|
||||||
|
export const sites = [
|
||||||
|
{
|
||||||
|
pattern: "www.phoronix.com",
|
||||||
|
selector: ".content",
|
||||||
|
rootSlector: "",
|
||||||
|
fixer: brFixer,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "t.me/s/*",
|
||||||
|
selector: ".tgme_widget_message_text",
|
||||||
|
rootSlector: ".tgme_channel_history",
|
||||||
|
fixer: brFixer,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修复过的标记
|
||||||
|
*/
|
||||||
|
const fixedSign = "kissfixed";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 采用 `br` 换行网站的修复函数
|
||||||
|
* 目标是将 `br` 替换成 `p`
|
||||||
|
* @param {*} node
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function brFixer(node) {
|
||||||
|
if (node.hasAttribute(fixedSign)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node.setAttribute(fixedSign, "true");
|
||||||
|
|
||||||
|
var gapTags = ["BR", "WBR"];
|
||||||
|
var newlineTags = [
|
||||||
|
"DIV",
|
||||||
|
"UL",
|
||||||
|
"OL",
|
||||||
|
"LI",
|
||||||
|
"H1",
|
||||||
|
"H2",
|
||||||
|
"H3",
|
||||||
|
"H4",
|
||||||
|
"H5",
|
||||||
|
"H6",
|
||||||
|
"P",
|
||||||
|
"HR",
|
||||||
|
"PRE",
|
||||||
|
"TABLE",
|
||||||
|
];
|
||||||
|
|
||||||
|
var html = "";
|
||||||
|
node.childNodes.forEach(function (child, index) {
|
||||||
|
if (index === 0) {
|
||||||
|
html += "<p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gapTags.indexOf(child.nodeName) !== -1) {
|
||||||
|
html += "</p><p>";
|
||||||
|
} else if (newlineTags.indexOf(child.nodeName) !== -1) {
|
||||||
|
html += "</p>" + child.outerHTML + "<p>";
|
||||||
|
} else if (child.outerHTML) {
|
||||||
|
html += child.outerHTML;
|
||||||
|
} else if (child.nodeValue) {
|
||||||
|
html += child.nodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === node.childNodes.length - 1) {
|
||||||
|
html += "</p>";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
node.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找、监听节点,并执行修复函数
|
||||||
|
* @param {*} selector
|
||||||
|
* @param {*} fixer
|
||||||
|
* @param {*} rootSlector
|
||||||
|
*/
|
||||||
|
function run(selector, fixer, rootSlector) {
|
||||||
|
var mutaObserver = new MutationObserver(function (mutations) {
|
||||||
|
mutations.forEach(function (mutation) {
|
||||||
|
mutation.addedNodes.forEach(function (addNode) {
|
||||||
|
addNode.querySelectorAll(selector).forEach(fixer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var rootNodes = [document];
|
||||||
|
if (rootSlector) {
|
||||||
|
rootNodes = document.querySelectorAll(rootSlector);
|
||||||
|
}
|
||||||
|
|
||||||
|
rootNodes.forEach(function (rootNode) {
|
||||||
|
rootNode.querySelectorAll(selector).forEach(fixer);
|
||||||
|
mutaObserver.observe(rootNode, {
|
||||||
|
childList: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配站点
|
||||||
|
*/
|
||||||
|
export function webfix(href, { injectWebfix }) {
|
||||||
|
try {
|
||||||
|
if (!injectWebfix) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < sites.length; i++) {
|
||||||
|
var site = sites[i];
|
||||||
|
if (isMatch(href, site.pattern)) {
|
||||||
|
run(site.selector, site.fixer, site.rootSlector);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[kiss-webfix]: ${err.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import { isIframe } from "./libs/iframe";
|
|||||||
import { handlePing, injectScript } from "./libs/gm";
|
import { handlePing, injectScript } from "./libs/gm";
|
||||||
import { matchRule } from "./libs/rules";
|
import { matchRule } from "./libs/rules";
|
||||||
import { genEventName } from "./libs/utils";
|
import { genEventName } from "./libs/utils";
|
||||||
|
import { webfix } from "./libs/webfix";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 入口函数
|
* 入口函数
|
||||||
@@ -50,6 +51,7 @@ const init = async () => {
|
|||||||
const rules = await getRulesWithDefault();
|
const rules = await getRulesWithDefault();
|
||||||
const rule = await matchRule(rules, href, setting);
|
const rule = await matchRule(rules, href, setting);
|
||||||
const translator = new Translator(rule, setting);
|
const translator = new Translator(rule, setting);
|
||||||
|
webfix(href, setting);
|
||||||
|
|
||||||
if (isIframe) {
|
if (isIframe) {
|
||||||
// iframe
|
// iframe
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ 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";
|
||||||
|
|
||||||
function LinkItem({ label, url, icon }) {
|
function LinkItem({ label, url, icon }) {
|
||||||
const match = useMatch(url);
|
const match = useMatch(url);
|
||||||
@@ -49,6 +50,12 @@ export default function Navigator(props) {
|
|||||||
url: "/sync",
|
url: "/sync",
|
||||||
icon: <SyncIcon />,
|
icon: <SyncIcon />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "webfix",
|
||||||
|
label: i18n("patch_setting"),
|
||||||
|
url: "/webfix",
|
||||||
|
icon: <SendTimeExtensionIcon />,
|
||||||
|
},
|
||||||
{ id: "about", label: i18n("about"), url: "/about", icon: <InfoIcon /> },
|
{ id: "about", label: i18n("about"), url: "/about", icon: <InfoIcon /> },
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
|
|||||||
89
src/views/Options/Webfix.js
Normal file
89
src/views/Options/Webfix.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
import Stack from "@mui/material/Stack";
|
||||||
|
import TextField from "@mui/material/TextField";
|
||||||
|
import { 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 { sites as webfixSites } from "../../libs/webfix";
|
||||||
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||||
|
import Switch from "@mui/material/Switch";
|
||||||
|
import { useSetting } from "../../hooks/Setting";
|
||||||
|
|
||||||
|
function ApiFields({ site }) {
|
||||||
|
const { selector, rootSlector } = site;
|
||||||
|
return (
|
||||||
|
<Stack spacing={3}>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"rootSlector"}
|
||||||
|
name="rootSlector"
|
||||||
|
value={rootSlector || "document"}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"selector"}
|
||||||
|
name="selector"
|
||||||
|
value={selector}
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ApiAccordion({ site }) {
|
||||||
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
setExpanded((pre) => !pre);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Accordion expanded={expanded} onChange={handleChange}>
|
||||||
|
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||||
|
<Typography>{site.pattern}</Typography>
|
||||||
|
</AccordionSummary>
|
||||||
|
<AccordionDetails>
|
||||||
|
{expanded && <ApiFields site={site} />}
|
||||||
|
</AccordionDetails>
|
||||||
|
</Accordion>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Webfix() {
|
||||||
|
const i18n = useI18n();
|
||||||
|
const { setting, updateSetting } = useSetting();
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Stack spacing={3}>
|
||||||
|
<Alert severity="info">{i18n("patch_setting_help")}</Alert>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
size="small"
|
||||||
|
checked={!!setting.injectWebfix}
|
||||||
|
onChange={() => {
|
||||||
|
updateSetting({
|
||||||
|
injectWebfix: !setting.injectWebfix,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={i18n("inject_webfix")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
{webfixSites.map((site) => (
|
||||||
|
<ApiAccordion key={site.pattern} site={site} />
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ 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";
|
||||||
|
|
||||||
export default function Options() {
|
export default function Options() {
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
@@ -127,6 +128,7 @@ export default function Options() {
|
|||||||
<Route path="rules" element={<Rules />} />
|
<Route path="rules" element={<Rules />} />
|
||||||
<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="about" element={<About />} />
|
<Route path="about" element={<About />} />
|
||||||
</Route>
|
</Route>
|
||||||
</Routes>
|
</Routes>
|
||||||
|
|||||||
Reference in New Issue
Block a user