(function () { 'use strict'; var form = document.getElementById('freeReportForm'); if (!form || !window.fetch || !window.FormData) return; var submit = document.getElementById('scanSubmit'); var analysis = document.getElementById('analysis'); var progressPanel = document.getElementById('progressPanel'); var resultsPanel = document.getElementById('resultsPanel'); var progressMessage = document.getElementById('progressMessage'); var progressPercent = document.getElementById('progressPercent'); var progressBar = document.getElementById('progressBar'); var progressTrack = progressBar.parentNode; var pagesCount = document.getElementById('pagesCount'); var visitedCount = document.getElementById('visitedCount'); var queuedCount = document.getElementById('queuedCount'); var currentUrl = document.getElementById('currentUrl'); var pdfLoader = document.getElementById('pdfLoader'); var captchaQuestion = document.getElementById('captchaQuestion'); var captchaAnswer = document.getElementById('captchaAnswer'); var captchaTokenInput = document.getElementById('captchaId'); var captchaRefresh = document.getElementById('captchaRefresh'); var captchaMessage = document.getElementById('captchaMessage'); var running = false; var jobId = null; function escapeHtml(value) { return String(value === null || value === undefined ? '' : value) .replace(/&/g, '&').replace(//g, '>') .replace(/"/g, '"').replace(/'/g, '''); } function labelSeverity(value) { var labels = { critical: 'Bloccante', serious: 'Seria', moderate: 'Moderata', minor: 'Minore' }; return labels[value] || value; } function post(action, values) { var data = new FormData(); data.append('action', action); if (jobId) data.append('job_id', jobId); Object.keys(values || {}).forEach(function (key) { data.append(key, values[key]); }); return fetch('/freereport/api/crawl.php', { method: 'POST', body: data, credentials: 'same-origin' }) .then(function (response) { return response.json().catch(function () { throw new Error('Il server non ha restituito una risposta valida.'); }); }); } function setRunning(value) { running = value; submit.disabled = value || !captchaTokenInput.value; submit.innerHTML = value ? 'Analisi in corso…' : 'Analizza ora '; analysis.setAttribute('aria-busy', value ? 'true' : 'false'); } function showCaptchaMessage(message) { captchaMessage.textContent = message || ''; captchaMessage.hidden = !message; } function loadCaptcha() { captchaTokenInput.value = ''; captchaAnswer.value = ''; captchaQuestion.textContent = 'Preparazione della domanda…'; showCaptchaMessage(''); if (!running) submit.disabled = true; captchaRefresh.disabled = true; return post('challenge').then(function (payload) { if (!payload.success || !payload.challenge_id || !payload.question) { throw new Error(payload.message || 'Domanda di sicurezza non disponibile.'); } captchaTokenInput.value = payload.challenge_id; captchaQuestion.textContent = payload.question; if (!running) submit.disabled = false; }).catch(function (error) { captchaQuestion.textContent = 'Domanda non disponibile'; showCaptchaMessage(error.message || 'Riprova tra qualche istante.'); }).then(function () { captchaRefresh.disabled = false; }); } function beginProgress() { analysis.hidden = false; progressPanel.hidden = false; resultsPanel.innerHTML = ''; jobId = null; updateProgress({ metrics: { progress: 0, pages: 0, visited: 0, queued: 0 }, message: 'Preparazione della scansione…', last: {} }); var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; analysis.scrollIntoView({ behavior: reduceMotion ? 'auto' : 'smooth', block: 'start' }); } function updateProgress(payload) { var metrics = payload.metrics || {}; var last = payload.last || {}; var value = Math.max(0, Math.min(100, Number(metrics.progress || 0))); progressMessage.textContent = payload.message || 'Analisi in corso…'; progressPercent.textContent = value + '%'; progressBar.style.width = value + '%'; progressTrack.setAttribute('aria-valuenow', value); pagesCount.textContent = metrics.pages || 0; visitedCount.textContent = metrics.visited || 0; queuedCount.textContent = metrics.queued || 0; currentUrl.textContent = last.url || '—'; } function fail(message) { setRunning(false); progressPanel.hidden = true; resultsPanel.innerHTML = ''; loadCaptcha(); } function renderResults(payload) { var report = payload.accessibility || {}; var counts = report.counts || {}; var issues = report.top_issues || []; var pages = report.worst_pages || []; var manual = report.manual_checks || []; var errors = payload.errors || []; var site = payload.site_url || document.getElementById('siteUrl').value; var issueHtml = ''; var pageHtml = ''; var manualHtml = ''; issues.slice(0, 8).forEach(function (issue) { issueHtml += '
' + '' + escapeHtml(labelSeverity(issue.severity)) + '' + '

' + escapeHtml(issue.title) + '

' + escapeHtml(issue.description) + '

' + 'WCAG ' + escapeHtml(issue.wcag) + ' · ' + escapeHtml(issue.occurrences) + ' occ.
'; }); pages.slice(0, 10).forEach(function (page) { var pageCounts = page.counts || {}; var total = Number(pageCounts.critical || 0) + Number(pageCounts.serious || 0) + Number(pageCounts.moderate || 0) + Number(pageCounts.minor || 0); pageHtml += '' + escapeHtml(page.title || 'Pagina senza titolo') + '' + escapeHtml(page.url) + '' + escapeHtml(page.score) + '/100' + total + ''; }); manual.forEach(function (check) { manualHtml += '
  • WCAG ' + escapeHtml(check.wcag) + ' · ' + escapeHtml(check.title) + '
    ' + escapeHtml(check.description) + '
  • '; }); var issuesBlock = issueHtml ? '
    ' + issueHtml + '
    ' : '
    Nessuna criticità rilevabile automaticamente nelle pagine analizzate. Sono comunque necessari i controlli manuali.
    '; var pagesBlock = pageHtml ? '

    Pagine da trattare per prime

    Prime 10 per punteggio

    ' + pageHtml + '
    PaginaPunteggioProblemi
    ' : ''; var errorBlock = errors.length ? '
    Nota sulla scansione: ' + errors.length + ' pagine o risorse non sono state analizzate correttamente.
    ' : ''; resultsPanel.innerHTML = '
    ' + '
    ' + escapeHtml(report.score === null || report.score === undefined ? '—' : report.score) + '/100
    ' + '
    ANALISI COMPLETATA

    Il report per ' + escapeHtml(site) + '

    ' + escapeHtml(report.pages_analyzed || 0) + ' pagine analizzate secondo criteri WCAG 2.2 A/AA.

    ' + '
    ' + '
    ' + escapeHtml(report.pages_analyzed || 0) + 'Pagine analizzate
    ' + escapeHtml(counts.critical || 0) + 'Criticità bloccanti
    ' + escapeHtml(counts.serious || 0) + 'Problemi seri
    ' + escapeHtml(report.total_issues || 0) + 'Segnalazioni totali
    ' + '

    Problemi prioritari

    Prime 8 categorie per gravità

    ' + issuesBlock + '
    ' + pagesBlock + '
    Verifiche manuali ancora necessarie
      ' + manualHtml + '
    ' + '

    Il punteggio è indicativo: l’analisi automatica non costituisce certificazione di conformità. Il PDF include il dettaglio completo delle segnalazioni rilevate.

    ' + errorBlock + '
    '; loadCaptcha(); } function step() { if (!running) return; post('step').then(function (payload) { if (!payload.success) throw new Error(payload.message || 'Errore durante la scansione.'); updateProgress(payload); if (payload.finished) { if (!payload.accessibility || !payload.accessibility.pages_analyzed) { fail(payload.message || 'Non abbiamo trovato pagine HTML analizzabili su questo sito.'); return; } setRunning(false); progressPanel.hidden = true; renderResults(payload); return; } window.setTimeout(step, 180); }).catch(function (error) { fail(error.message); }); } form.addEventListener('submit', function (event) { event.preventDefault(); if (running) return; var url = document.getElementById('siteUrl').value.trim(); if (!url) { document.getElementById('siteUrl').focus(); return; } if (!captchaTokenInput.value || captchaAnswer.value.trim() === '') { showCaptchaMessage('Rispondi alla domanda di sicurezza.'); captchaAnswer.focus(); return; } beginProgress(); setRunning(true); post('start', { url: url, captcha_id: captchaTokenInput.value, captcha_answer: captchaAnswer.value }).then(function (payload) { if (!payload.success || !payload.job_id) throw new Error(payload.message || 'Impossibile avviare la scansione.'); captchaTokenInput.value = ''; jobId = payload.job_id; updateProgress(payload); step(); }).catch(function (error) { fail(error.message); }); }); captchaRefresh.addEventListener('click', function () { if (!running) loadCaptcha(); }); document.addEventListener('click', function (event) { var link = event.target.closest ? event.target.closest('.pdf-button') : null; if (!link || link.getAttribute('aria-busy') === 'true') return; event.preventDefault(); pdfLoader.hidden = false; link.setAttribute('aria-busy', 'true'); fetch(link.href, { credentials: 'same-origin' }).then(function (response) { var type = response.headers.get('Content-Type') || ''; if (!response.ok || type.indexOf('application/pdf') === -1) { return response.text().then(function (message) { throw new Error(message || 'Impossibile generare il PDF.'); }); } return response.blob().then(function (blob) { return { blob: blob, disposition: response.headers.get('Content-Disposition') || '' }; }); }).then(function (download) { var match = download.disposition.match(/filename="?([^";]+)"?/i); var objectUrl = URL.createObjectURL(download.blob); var anchor = document.createElement('a'); anchor.href = objectUrl; anchor.download = match ? match[1] : 'report-accessibilita.pdf'; document.body.appendChild(anchor); anchor.click(); anchor.remove(); window.setTimeout(function () { URL.revokeObjectURL(objectUrl); }, 1000); }).catch(function (error) { window.alert(error.message || 'Impossibile generare il PDF.'); }).then(function () { pdfLoader.hidden = true; link.removeAttribute('aria-busy'); }); }); if (document.modelContext && typeof document.modelContext.registerTool === 'function') { var toolLifecycle = new AbortController(); var registration = document.modelContext.registerTool({ name: 'start_accessibility_scan', title: 'Avvia analisi di accessibilità', description: 'Avvia il report gratuito VisiblyWeb per un sito pubblico e aggiorna questa pagina con avanzamento e risultati.', inputSchema: { type: 'object', properties: { url: { type: 'string', minLength: 4, description: 'URL o dominio pubblico da analizzare.' }, captchaAnswer: { type: 'string', minLength: 1, description: 'Risposta alla domanda aritmetica visibile nella pagina.' } }, required: ['url', 'captchaAnswer'], additionalProperties: false }, annotations: { readOnlyHint: false, untrustedContentHint: false }, execute: function (input) { if (!input || typeof input.url !== 'string' || input.url.trim().length < 4 || typeof input.captchaAnswer !== 'string' || !input.captchaAnswer.trim()) { return Promise.reject(new Error('Inserisci un URL valido e la risposta alla domanda di sicurezza.')); } if (running) { return Promise.reject(new Error('È già in corso un’analisi.')); } document.getElementById('siteUrl').value = input.url.trim(); captchaAnswer.value = input.captchaAnswer.trim(); form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); return Promise.resolve({ status: 'started', url: input.url.trim() }); } }, { signal: toolLifecycle.signal }); Promise.resolve(registration).catch(function () {}); window.addEventListener('pagehide', function () { toolLifecycle.abort(); }, { once: true }); } loadCaptcha(); }());