mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 08:45:41 +08:00
* add a test rule * add translation support
This commit is contained in:
@@ -34,11 +34,6 @@ const StyledTextField = styled(TextField)(({ theme }) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 转义正则表达式特殊字符的函数
|
|
||||||
const escapeRegExp = (string: string) => {
|
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BaseSearchBox = (props: SearchProps) => {
|
export const BaseSearchBox = (props: SearchProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
@@ -60,9 +55,28 @@ export const BaseSearchBox = (props: SearchProps) => {
|
|||||||
inheritViewBox: true,
|
inheritViewBox: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 验证正则表达式的辅助函数
|
||||||
|
const validateRegex = (pattern: string) => {
|
||||||
|
if (!pattern) return true;
|
||||||
|
try {
|
||||||
|
new RegExp(pattern);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const createMatcher = useMemo(() => {
|
const createMatcher = useMemo(() => {
|
||||||
return (searchText: string) => {
|
return (searchText: string) => {
|
||||||
try {
|
try {
|
||||||
|
// 当启用正则表达式验证是否合规
|
||||||
|
if (useRegularExpression && searchText) {
|
||||||
|
const isValid = validateRegex(searchText);
|
||||||
|
if (!isValid) {
|
||||||
|
throw new Error(t("Invalid regular expression"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (content: string) => {
|
return (content: string) => {
|
||||||
if (!searchText) return true;
|
if (!searchText) return true;
|
||||||
|
|
||||||
@@ -70,29 +84,25 @@ export const BaseSearchBox = (props: SearchProps) => {
|
|||||||
let searchItem = !matchCase ? searchText.toLowerCase() : searchText;
|
let searchItem = !matchCase ? searchText.toLowerCase() : searchText;
|
||||||
|
|
||||||
if (useRegularExpression) {
|
if (useRegularExpression) {
|
||||||
const pattern = matchWholeWord
|
return new RegExp(searchItem).test(item);
|
||||||
? `\\b${escapeRegExp(searchItem)}\\b`
|
|
||||||
: escapeRegExp(searchItem);
|
|
||||||
return new RegExp(pattern).test(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchWholeWord) {
|
if (matchWholeWord) {
|
||||||
return new RegExp(`\\b${escapeRegExp(searchItem)}\\b`).test(item);
|
return new RegExp(`\\b${searchItem}\\b`).test(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.includes(searchItem);
|
return item.includes(searchItem);
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setErrorMessage(`${err}`);
|
setErrorMessage(err instanceof Error ? err.message : `${err}`);
|
||||||
return () => true;
|
return () => false; // 无效正则规则 不匹配值
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [matchCase, matchWholeWord, useRegularExpression]);
|
}, [matchCase, matchWholeWord, useRegularExpression, t]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!inputRef.current) return;
|
if (!inputRef.current) return;
|
||||||
const value = inputRef.current.value;
|
const value = inputRef.current.value;
|
||||||
setErrorMessage("");
|
|
||||||
props.onSearch(createMatcher(value), {
|
props.onSearch(createMatcher(value), {
|
||||||
text: value,
|
text: value,
|
||||||
matchCase,
|
matchCase,
|
||||||
@@ -104,6 +114,15 @@ export const BaseSearchBox = (props: SearchProps) => {
|
|||||||
const onChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
const onChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
const value = e.target?.value ?? "";
|
const value = e.target?.value ?? "";
|
||||||
setErrorMessage("");
|
setErrorMessage("");
|
||||||
|
|
||||||
|
// 验证正则表达式
|
||||||
|
if (useRegularExpression && value) {
|
||||||
|
const isValid = validateRegex(value);
|
||||||
|
if (!isValid) {
|
||||||
|
setErrorMessage(t("Invalid regular expression"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
props.onSearch(createMatcher(value), {
|
props.onSearch(createMatcher(value), {
|
||||||
text: value,
|
text: value,
|
||||||
matchCase,
|
matchCase,
|
||||||
@@ -113,7 +132,7 @@ export const BaseSearchBox = (props: SearchProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title={errorMessage} placement="bottom-start">
|
<Tooltip title={errorMessage || ""} placement="bottom-start">
|
||||||
<StyledTextField
|
<StyledTextField
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
inputRef={inputRef}
|
inputRef={inputRef}
|
||||||
@@ -125,6 +144,7 @@ export const BaseSearchBox = (props: SearchProps) => {
|
|||||||
placeholder={props.placeholder ?? t("Filter conditions")}
|
placeholder={props.placeholder ?? t("Filter conditions")}
|
||||||
sx={{ input: { py: 0.65, px: 1.25 } }}
|
sx={{ input: { py: 0.65, px: 1.25 } }}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
error={!!errorMessage}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
input: {
|
input: {
|
||||||
sx: { pr: 1 },
|
sx: { pr: 1 },
|
||||||
|
|||||||
@@ -647,5 +647,6 @@
|
|||||||
"Allowed Origins": "Allowed Origins",
|
"Allowed Origins": "Allowed Origins",
|
||||||
"Please enter a valid url": "Please enter a valid url",
|
"Please enter a valid url": "Please enter a valid url",
|
||||||
"Add": "Add",
|
"Add": "Add",
|
||||||
"Development mode: Automatically includes Tauri and localhost origins": "Development mode: Automatically includes Tauri and localhost origins"
|
"Development mode: Automatically includes Tauri and localhost origins": "Development mode: Automatically includes Tauri and localhost origins",
|
||||||
|
"Invalid regular expression": "Invalid regular expression"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -647,5 +647,6 @@
|
|||||||
"Allowed Origins": "允许的来源",
|
"Allowed Origins": "允许的来源",
|
||||||
"Please enter a valid url": "请输入有效的网址",
|
"Please enter a valid url": "请输入有效的网址",
|
||||||
"Add": "添加",
|
"Add": "添加",
|
||||||
"Development mode: Automatically includes Tauri and localhost origins": "开发模式:自动包含 Tauri 和 localhost 来源"
|
"Development mode: Automatically includes Tauri and localhost origins": "开发模式:自动包含 Tauri 和 localhost 来源",
|
||||||
|
"Invalid regular expression": "无效的正则表达式"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user