From 972b6c7f22f6812edaa7c6b0ce28f7dc1b8431ad Mon Sep 17 00:00:00 2001 From: typist Date: Wed, 29 Oct 2025 06:08:47 +0800 Subject: [PATCH] feat: enhance input handling for network tools - Added domain and URL normalization on blur for DNS, Ping, Speedtest, and TCPing components. - Improved user experience by ensuring valid input formats and extracting ports where applicable. --- src/components/tool/network/dns.tsx | 23 ++++++++++- src/components/tool/network/ping.tsx | 29 ++++++++++--- src/components/tool/network/speedtest.tsx | 29 ++++++++++--- src/components/tool/network/tcping.tsx | 50 ++++++++++++++++++++--- 4 files changed, 112 insertions(+), 19 deletions(-) diff --git a/src/components/tool/network/dns.tsx b/src/components/tool/network/dns.tsx index cae5ca1..229f6c2 100644 --- a/src/components/tool/network/dns.tsx +++ b/src/components/tool/network/dns.tsx @@ -41,6 +41,26 @@ const Tool: FC = () => { const [results, setResults] = useState([]); const [queryTime, setQueryTime] = useState(0); + const handleDomainBlur = () => { + if (!domain.trim()) return; + + let input = domain.trim(); + let cleanDomain = input; + + try { + // Try to parse as URL + const url = new URL(input.startsWith('http') ? input : `https://${input}`); + cleanDomain = url.hostname; + } catch { + // If parsing fails, fallback to manual cleanup + cleanDomain = input.replace(/^https?:\/\//, "").split("/")[0].split(":")[0]; + } + + if (cleanDomain !== input) { + setDomain(cleanDomain); + } + }; + const queryDNS = async () => { if (!domain.trim()) { toast.error("Please enter a domain name"); @@ -58,7 +78,7 @@ const Tool: FC = () => { const queries = DNS_RECORD_TYPES.map((recordType) => fetch( `https://cloudflare-dns.com/dns-query?name=${encodeURIComponent( - domain + domain.trim() )}&type=${recordType.value}`, { headers: { @@ -127,6 +147,7 @@ const Tool: FC = () => { placeholder="e.g. example.com" value={domain} onChange={(e) => setDomain(e.target.value)} + onBlur={handleDomainBlur} onKeyPress={handleKeyPress} disabled={loading} /> diff --git a/src/components/tool/network/ping.tsx b/src/components/tool/network/ping.tsx index 378226e..fc18af7 100644 --- a/src/components/tool/network/ping.tsx +++ b/src/components/tool/network/ping.tsx @@ -36,6 +36,27 @@ const Tool: FC = () => { const seqRef = useRef(0); const resultsContainerRef = useRef(null); + const handleUrlBlur = () => { + if (!url.trim()) return; + + let input = url.trim(); + + try { + // Try to parse as URL + const parsedUrl = new URL(input.startsWith('http') ? input : `https://${input}`); + const normalizedUrl = parsedUrl.toString(); + + if (normalizedUrl !== input) { + setUrl(normalizedUrl); + } + } catch { + // If parsing fails, add https:// prefix + if (!input.startsWith("http://") && !input.startsWith("https://")) { + setUrl(`https://${input}`); + } + } + }; + const ping = async () => { if (!url.trim()) { toast.error("Please enter a URL"); @@ -43,12 +64,7 @@ const Tool: FC = () => { } const seq = ++seqRef.current; - let targetUrl = url.trim(); - - // If no protocol prefix, default to https:// - if (!targetUrl.startsWith("http://") && !targetUrl.startsWith("https://")) { - targetUrl = `https://${targetUrl}`; - } + const targetUrl = url.trim(); const startTime = performance.now(); @@ -177,6 +193,7 @@ const Tool: FC = () => { placeholder="e.g. example.com or https://example.com" value={url} onChange={(e) => setUrl(e.target.value)} + onBlur={handleUrlBlur} disabled={running} /> diff --git a/src/components/tool/network/speedtest.tsx b/src/components/tool/network/speedtest.tsx index ea1d453..224af55 100644 --- a/src/components/tool/network/speedtest.tsx +++ b/src/components/tool/network/speedtest.tsx @@ -142,18 +142,34 @@ const Tool: FC = () => { } }; + const handleUrlBlur = () => { + if (!url.trim()) return; + + let input = url.trim(); + + try { + // Try to parse as URL + const parsedUrl = new URL(input.startsWith('http') ? input : `https://${input}`); + const normalizedUrl = parsedUrl.toString(); + + if (normalizedUrl !== input) { + setUrl(normalizedUrl); + } + } catch { + // If parsing fails, add https:// prefix + if (!input.startsWith("http://") && !input.startsWith("https://")) { + setUrl(`https://${input}`); + } + } + }; + const startTest = async () => { if (!url.trim()) { toast.error("Please enter a URL"); return; } - let targetUrl = url.trim(); - - // If no protocol prefix, default to https:// - if (!targetUrl.startsWith("http://") && !targetUrl.startsWith("https://")) { - targetUrl = `https://${targetUrl}`; - } + const targetUrl = url.trim(); setTesting(true); setResult(null); @@ -218,6 +234,7 @@ const Tool: FC = () => { placeholder="e.g. https://example.com" value={url} onChange={(e) => setUrl(e.target.value)} + onBlur={handleUrlBlur} onKeyPress={handleKeyPress} disabled={testing} /> diff --git a/src/components/tool/network/tcping.tsx b/src/components/tool/network/tcping.tsx index f94338b..7fbd7b5 100644 --- a/src/components/tool/network/tcping.tsx +++ b/src/components/tool/network/tcping.tsx @@ -37,6 +37,46 @@ const Tool: FC = () => { const seqRef = useRef(0); const resultsContainerRef = useRef(null); + const handleHostBlur = () => { + if (!host.trim()) return; + + let input = host.trim(); + let cleanHost = input; + let extractedPort: string | null = null; + + try { + // Try to parse as URL + const url = new URL(input.startsWith('http') ? input : `https://${input}`); + cleanHost = url.hostname; + + // Extract port if specified in URL + if (url.port) { + extractedPort = url.port; + } + } catch { + // If parsing fails, fallback to manual cleanup + const withoutProtocol = input.replace(/^https?:\/\//, ""); + const withoutPath = withoutProtocol.split("/")[0]; + + // Check for port in the format hostname:port + const portMatch = withoutPath.match(/^(.+):(\d+)$/); + if (portMatch) { + cleanHost = portMatch[1]; + extractedPort = portMatch[2]; + } else { + cleanHost = withoutPath; + } + } + + if (cleanHost !== input) { + setHost(cleanHost); + } + + if (extractedPort) { + setPort(extractedPort); + } + }; + const tcping = async () => { if (!host.trim()) { toast.error("Please enter a hostname or IP"); @@ -45,14 +85,11 @@ const Tool: FC = () => { const seq = ++seqRef.current; const portNum = parseInt(port) || 443; - let targetUrl = host.trim(); + const targetHost = host.trim(); - // 移除协议前缀 - targetUrl = targetUrl.replace(/^https?:\/\//, ""); - - // 构建测试 URL + // Build test URL const protocol = portNum === 443 ? "https" : "http"; - const url = `${protocol}://${targetUrl}:${portNum}`; + const url = `${protocol}://${targetHost}:${portNum}`; const startTime = performance.now(); @@ -182,6 +219,7 @@ const Tool: FC = () => { placeholder="e.g. example.com or 192.168.1.1" value={host} onChange={(e) => setHost(e.target.value)} + onBlur={handleHostBlur} disabled={running} />