(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 = '
Non è stato possibile completare l’analisi.
' + escapeHtml(message || 'Riprova tra qualche istante.') + '
';
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
| Pagina | Punteggio | Problemi |
' + pageHtml + '
' : '';
var errorBlock = errors.length ? 'Nota sulla scansione: ' + errors.length + ' pagine o risorse non sono state analizzate correttamente.
' : '';
resultsPanel.innerHTML = '' +
'' +
'' + 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
' +
'
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();
}());