diff --git a/index.html b/index.html index 8631eb4..e166ab7 100644 --- a/index.html +++ b/index.html @@ -11,12 +11,12 @@ -
+ -
+
- +
+ + `; + + } +} + +function refreshGeneralTip() { + const { tip } = getRandomTip(TIPS.general, lastGeneralTipIndex); + const tipEl = document.querySelector('.tips-general-tip'); + if (tipEl) { + tipEl.style.opacity = '0'; + setTimeout(() => { + tipEl.textContent = tip; + tipEl.style.opacity = '1'; + }, 200); + } +} + +function showTips(threatTypes) { + const resultEl = document.getElementById('result'); + if (!resultEl) return; + + // Remove any existing tips card + const existing = resultEl.querySelector('.tips-card'); + if (existing) existing.remove(); + + const tipsHtml = buildTipsHtml(threatTypes); + resultEl.insertAdjacentHTML('beforeend', tipsHtml); +} + // ───────────────────────────── // SCANNER // ───────────────────────────── @@ -107,25 +278,7 @@ let dangerCount = 0; function isValidUrl(urlString) { try { - const urlObj = new URL(urlString); - const hostname = urlObj.hostname; - - // To allow local testing - if (hostname === 'localhost' || hostname === '127.0.0.1') { - return true; - } - - const parts = hostname.split('.'); - if (parts.length < 2) { - return false; - } - - const tld = parts[parts.length - 1]; - // TLD must be at least 2 chars & consist of only letters - if (tld.length < 2 || !/^[a-zA-Z]+$/.test(tld)) { - return false; - } - + new URL(urlString); return true; } catch (e) { return false; @@ -158,15 +311,6 @@ function formatAndValidateUrl(input) { url = 'https://' + url; } - // Validate URL length - if (url.length > 2048) { - return { - valid: false, - error: 'URL exceeds maximum length of 2048 characters.', - url: null - }; - } - if (!isValidUrl(url)) { return { @@ -213,8 +357,12 @@ function formatAndValidateUrl(input) { function fillExample(url) { - document.getElementById('urlInput').value = url; - document.getElementById('urlInput').focus(); + const input = document.getElementById('urlInput'); + input.value = url; + input.focus(); + + // Update aria-label to reflect filled value for screen readers + input.setAttribute('aria-label', `URL input, filled with ${url}. Press Enter or click Scan URL to scan.`); } @@ -288,7 +436,7 @@ function calculateRiskScore(url, isThreat) { score += 10; breakdown.push({ text: 'Excessive subdomains used', type: 'warning' }); } else { - breakdown.push({ text: 'Domain structure appears normal', type: 'safe' }); + breakdown.push({ text: 'Domain structure appears normal', type: 'safe' }); } } catch (e) { score += 20; @@ -312,6 +460,14 @@ function showResult(type, title, desc, url, threats) { error: '!' }; + // Map result type to human-readable label for screen readers + const ariaLabels = { + safe: 'Safe', + danger: 'Danger', + error: 'Error', + loading: 'Loading' + }; + const isThreat = type === 'danger'; let riskSectionHtml = ''; let riskData = null; @@ -325,31 +481,39 @@ function showResult(type, title, desc, url, threats) { let breakdownHtml = riskData.breakdown.map(item => { let icon = ''; - if (item.type === 'safe') icon = ``; - else if (item.type === 'warning') icon = ``; - else if (item.type === 'danger') icon = ``; + let iconLabel = ''; + if (item.type === 'safe') { + icon = ``; + iconLabel = 'Safe'; + } else if (item.type === 'warning') { + icon = ``; + iconLabel = 'Warning'; + } else if (item.type === 'danger') { + icon = ``; + iconLabel = 'Danger'; + } - return `
${icon} ${item.text}
`; + return `
${iconLabel}:${icon} ${item.text}
`; }).join(''); riskSectionHtml = ` -
+
-
0/100
+
0
Risk Score
-
0%
+
0%
Confidence
- -
+ +
-
+
${breakdownHtml}
@@ -358,36 +522,45 @@ function showResult(type, title, desc, url, threats) { document.getElementById('result').innerHTML = ` -
+
-
+
${title}
${desc}
- ${url ? `
${url}
` : ''} + ${url ? `
${url}
` : ''} ${threats && threats.length - ? `
${threats.map(t => - `${t}`).join('')}
` - : ''} + ? `
${threats.map(t => + `${t}`).join('')}
` + : ''} ${(type === 'safe' || type === 'danger') ? `
- - + +
` : ''}
`; + // Move focus to result div so screen readers announce the outcome + const resultEl = document.getElementById('result'); + resultEl.setAttribute('tabindex', '-1'); + resultEl.focus(); + if (riskSectionHtml) { + // Append risk section inside result div, after the result card + resultEl.insertAdjacentHTML('beforeend', riskSectionHtml); + setTimeout(() => { const bar = document.querySelector('.risk-meter-bar'); if (bar) { @@ -464,27 +637,29 @@ async function checkSecurity() { document.getElementById('scanBtn'); btn.disabled = true; + btn.setAttribute('aria-busy', 'true'); + btn.setAttribute('aria-label', 'Scanning URL, please wait...'); // Loading State — enhanced scan animation document.getElementById('result').innerHTML = ` -
+
-
+
Scanning URL...
-
${url}
+
${url}
-
+