mirror of
https://github.com/mengxi-ream/read-frog.git
synced 2026-04-30 01:56:46 +00:00
Compare commits
1 commit
main
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5850c27c39 |
6 changed files with 62 additions and 14 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { i18n } from "#imports"
|
||||
import { useAtom } from "jotai"
|
||||
import { configFieldsAtomMap } from "@/utils/atoms/config"
|
||||
import { normalizeDomainPattern } from "@/utils/url"
|
||||
import { ConfigCard } from "../../components/config-card"
|
||||
import { PatternsTable } from "../../components/patterns-table"
|
||||
|
||||
|
|
@ -9,13 +10,13 @@ export function FloatingButtonDisabledSites() {
|
|||
const { disabledFloatingButtonPatterns = [] } = floatingButtonConfig
|
||||
|
||||
const addPattern = (pattern: string) => {
|
||||
const cleanedPattern = pattern.trim()
|
||||
if (!cleanedPattern || disabledFloatingButtonPatterns.includes(cleanedPattern))
|
||||
const normalizedPattern = normalizeDomainPattern(pattern)
|
||||
if (!normalizedPattern || disabledFloatingButtonPatterns.includes(normalizedPattern))
|
||||
return
|
||||
|
||||
void setFloatingButtonConfig({
|
||||
...floatingButtonConfig,
|
||||
disabledFloatingButtonPatterns: [...disabledFloatingButtonPatterns, cleanedPattern],
|
||||
disabledFloatingButtonPatterns: [...disabledFloatingButtonPatterns, normalizedPattern],
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useAtom } from "jotai"
|
|||
import { Label } from "@/components/ui/base-ui/label"
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/base-ui/radio-group"
|
||||
import { configFieldsAtomMap } from "@/utils/atoms/config"
|
||||
import { normalizeDomainPattern } from "@/utils/url"
|
||||
import { ConfigCard } from "../../components/config-card"
|
||||
import { PatternsTable } from "../../components/patterns-table"
|
||||
|
||||
|
|
@ -15,13 +16,13 @@ export default function SiteControlMode() {
|
|||
const patterns = siteControl[patternsKey] ?? []
|
||||
|
||||
const addPattern = async (pattern: string) => {
|
||||
const cleanedPattern = pattern.trim()
|
||||
if (!cleanedPattern || patterns.includes(cleanedPattern))
|
||||
const normalizedPattern = normalizeDomainPattern(pattern)
|
||||
if (!normalizedPattern || patterns.includes(normalizedPattern))
|
||||
return
|
||||
|
||||
await setSiteControl({
|
||||
...siteControl,
|
||||
[patternsKey]: [...patterns, cleanedPattern],
|
||||
[patternsKey]: [...patterns, normalizedPattern],
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { i18n } from "#imports"
|
||||
import { useAtom } from "jotai"
|
||||
import { configFieldsAtomMap } from "@/utils/atoms/config"
|
||||
import { normalizeDomainPattern } from "@/utils/url"
|
||||
import { ConfigCard } from "../../components/config-card"
|
||||
import { PatternsTable } from "../../components/patterns-table"
|
||||
|
||||
|
|
@ -9,13 +10,13 @@ export function SelectionToolbarDisabledSites() {
|
|||
const { disabledSelectionToolbarPatterns = [] } = selectionToolbarConfig
|
||||
|
||||
const addPattern = (pattern: string) => {
|
||||
const cleanedPattern = pattern.trim()
|
||||
if (!cleanedPattern || disabledSelectionToolbarPatterns.includes(cleanedPattern))
|
||||
const normalizedPattern = normalizeDomainPattern(pattern)
|
||||
if (!normalizedPattern || disabledSelectionToolbarPatterns.includes(normalizedPattern))
|
||||
return
|
||||
|
||||
void setSelectionToolbarConfig({
|
||||
...selectionToolbarConfig,
|
||||
disabledSelectionToolbarPatterns: [...disabledSelectionToolbarPatterns, cleanedPattern],
|
||||
disabledSelectionToolbarPatterns: [...disabledSelectionToolbarPatterns, normalizedPattern],
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { i18n } from "#imports"
|
||||
import { useAtom } from "jotai"
|
||||
import { configFieldsAtomMap } from "@/utils/atoms/config"
|
||||
import { normalizeDomainPattern } from "@/utils/url"
|
||||
import { ConfigCard } from "../../components/config-card"
|
||||
import { PatternsTable } from "../../components/patterns-table"
|
||||
|
||||
|
|
@ -9,14 +10,14 @@ export function AutoTranslateWebsitePatterns() {
|
|||
const { autoTranslatePatterns } = translateConfig.page
|
||||
|
||||
const addPattern = (pattern: string) => {
|
||||
const cleanedPattern = pattern.trim()
|
||||
if (!cleanedPattern || autoTranslatePatterns.includes(cleanedPattern))
|
||||
const normalizedPattern = normalizeDomainPattern(pattern)
|
||||
if (!normalizedPattern || autoTranslatePatterns.includes(normalizedPattern))
|
||||
return
|
||||
|
||||
void setTranslateConfig({
|
||||
page: {
|
||||
...translateConfig.page,
|
||||
autoTranslatePatterns: [...autoTranslatePatterns, cleanedPattern],
|
||||
autoTranslatePatterns: [...autoTranslatePatterns, normalizedPattern],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,23 @@
|
|||
import { describe, expect, it } from "vitest"
|
||||
import { matchDomainPattern } from "../url"
|
||||
import { matchDomainPattern, normalizeDomainPattern } from "../url"
|
||||
|
||||
describe("normalizeDomainPattern", () => {
|
||||
it("extracts the hostname from a full URL", () => {
|
||||
expect(normalizeDomainPattern("https://news.ycombinator.com/")).toBe("news.ycombinator.com")
|
||||
})
|
||||
|
||||
it("extracts the hostname from a bare hostname with a path", () => {
|
||||
expect(normalizeDomainPattern("news.ycombinator.com/item?id=1")).toBe("news.ycombinator.com")
|
||||
})
|
||||
|
||||
it("preserves a plain domain pattern", () => {
|
||||
expect(normalizeDomainPattern(" Example.com ")).toBe("example.com")
|
||||
})
|
||||
|
||||
it("returns invalid non-url input as a trimmed lowercase pattern", () => {
|
||||
expect(normalizeDomainPattern(" not a valid url pattern ")).toBe("not a valid url pattern")
|
||||
})
|
||||
})
|
||||
|
||||
describe("matchDomainPattern", () => {
|
||||
describe("exact domain match", () => {
|
||||
|
|
@ -37,6 +55,11 @@ describe("matchDomainPattern", () => {
|
|||
const result = matchDomainPattern("https://x.com", " x.com ")
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it("should match when the pattern is a full URL", () => {
|
||||
const result = matchDomainPattern("https://news.ycombinator.com/item?id=1", "https://news.ycombinator.com/")
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("subdomain matching", () => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,26 @@
|
|||
import { z } from "zod"
|
||||
|
||||
export function normalizeDomainPattern(pattern: string): string {
|
||||
const cleanedPattern = pattern.trim()
|
||||
if (!cleanedPattern) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const candidates = cleanedPattern.includes("://")
|
||||
? [cleanedPattern]
|
||||
: [cleanedPattern, `https://${cleanedPattern}`]
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (!z.url().safeParse(candidate).success) {
|
||||
continue
|
||||
}
|
||||
|
||||
return new URL(candidate).hostname.toLowerCase()
|
||||
}
|
||||
|
||||
return cleanedPattern.toLowerCase()
|
||||
}
|
||||
|
||||
export function matchDomainPattern(url: string, pattern: string): boolean {
|
||||
if (!z.url().safeParse(url).success) {
|
||||
return false
|
||||
|
|
@ -7,7 +28,7 @@ export function matchDomainPattern(url: string, pattern: string): boolean {
|
|||
|
||||
const urlObj = new URL(url)
|
||||
const hostname = urlObj.hostname.toLowerCase()
|
||||
const patternLower = pattern.toLowerCase().trim()
|
||||
const patternLower = normalizeDomainPattern(pattern)
|
||||
|
||||
if (hostname === patternLower) {
|
||||
return true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue