pdf-accessibility/index.html
Vadym Samoilenko 62094f4dfa Move document history to separate history.html page
- history.html: standalone page with My Documents table + auth
- js/history.js: renderHistory, loadHistory, deleteHistoryJob logic
- js/app-history.js: MSAL auth init for history.html
- index.html: remove history section, add 'My Documents' link in header
- js/app.js: show historyLink after auth, open job from ?job_id= URL param
- deploy.sh: include history.html in deploy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 15:21:19 +00:00

266 lines
16 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Enterprise PDF Accessibility Checker</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- MSAL config (values injected from env or kept as data attributes) -->
<div id="msalConfig" hidden
data-tenant-id="e519c2e6-bc6d-4fdf-8d9c-923c2f002385"
data-client-id="9079054c-9620-4757-a256-23413042f1ef"
data-redirect-uri="https://ai-sandbox.oliver.solutions/pdf-accessibility"></div>
<!-- Auth Overlay (Azure AD / MSAL) -->
<div class="auth-overlay" id="authOverlay" role="dialog" aria-label="Sign in required" aria-modal="true" aria-describedby="authCardDesc">
<div class="auth-card">
<h2>PDF Accessibility Checker</h2>
<p id="authCardDesc">Sign in with your organization account to continue.</p>
<button class="btn-microsoft" onclick="loginWithMicrosoft()" aria-label="Sign in with Microsoft">
<svg width="20" height="20" viewBox="0 0 21 21" aria-hidden="true"><rect x="1" y="1" width="9" height="9" fill="#f25022"/><rect x="11" y="1" width="9" height="9" fill="#7fba00"/><rect x="1" y="11" width="9" height="9" fill="#00a4ef"/><rect x="11" y="11" width="9" height="9" fill="#ffb900"/></svg>
Sign in with Microsoft
</button>
</div>
</div>
<header>
<div class="container">
<div class="header-inner">
<div>
<h1>Enterprise PDF Accessibility Checker</h1>
<p class="subtitle">Comprehensive WCAG 2.1 compliance validation with AI-powered analysis</p>
</div>
<div class="header-actions">
<a href="history.html" id="historyLink" style="display:none;text-decoration:none;" class="btn btn-secondary" style="padding:8px 16px;font-size:13px;">&#x1F4C2; My Documents</a>
<span class="user-info" id="userInfo"></span>
<button id="logoutBtn" onclick="logout()" style="display:none;">Sign Out</button>
<button id="themeToggle" onclick="toggleDarkMode()" aria-label="Toggle dark mode">Dark</button>
</div>
</div>
</div>
</header>
<main id="main-content">
<div class="container">
<!-- Upload Section -->
<div class="card" id="uploadSection">
<h2>Upload PDF Document</h2>
<div class="upload-mode-tabs" role="tablist" aria-label="Upload mode">
<button class="upload-tab active" id="tabSingle" role="tab" aria-selected="true" aria-controls="singleUploadArea" onclick="switchUploadMode('single')">Single File</button>
<button class="upload-tab" id="tabBatch" role="tab" aria-selected="false" aria-controls="batchUploadArea" onclick="switchUploadMode('batch')">Batch Upload</button>
</div>
<div id="singleUploadArea" role="tabpanel" aria-labelledby="tabSingle" tabindex="0">
<div class="upload-area" id="uploadArea" role="button" tabindex="0" aria-label="Drop PDF here or click to browse">
<div class="upload-icon">&#x1F4C4;</div>
<div class="upload-text">Drop your PDF here or click to browse</div>
<div class="upload-hint">Maximum file size: 50MB</div>
<input type="file" id="fileInput" accept=".pdf" aria-hidden="true">
</div>
<div class="upload-ready" id="uploadReadyState" aria-live="polite">
<div class="ready-filename" id="readyFilename"></div>
<div class="ready-filesize" id="readyFilesize"></div>
<button class="btn-start" onclick="beginCheck()" aria-label="Start accessibility check">
&#x25B6; Start Accessibility Check
</button>
<button class="btn-remove" onclick="removeFile()" aria-label="Remove file">Remove</button>
</div>
</div>
<div id="batchUploadArea" style="display:none;" role="tabpanel" aria-labelledby="tabBatch" tabindex="-1">
<div class="upload-area" id="batchDropArea" role="button" tabindex="0" aria-label="Drop multiple PDFs here or click to browse">
<div class="upload-icon">&#x1F4DA;</div>
<div class="upload-text">Drop multiple PDFs here or click to browse</div>
<div class="upload-hint">Maximum 10 files, 50MB each</div>
<input type="file" id="batchFileInput" accept=".pdf" multiple aria-hidden="true">
</div>
<div id="batchFileList" style="display:none;margin-top:15px;"></div>
<div id="batchActions" style="display:none;margin-top:15px;gap:10px;">
<button class="btn btn-primary" onclick="startBatchUpload()" id="batchUploadBtn">Upload &amp; Check All</button>
<button class="btn btn-secondary" onclick="clearBatchFiles()">Clear</button>
</div>
<div id="batchProgress" style="display:none;margin-top:20px;"></div>
</div>
<div class="api-config">
<h3 style="margin-bottom:15px;">Check Options</h3>
<div class="form-group" style="display:flex;align-items:center;gap:10px;margin-bottom:10px;">
<input type="checkbox" id="quickMode" style="width:auto;height:18px;cursor:pointer;">
<label for="quickMode" style="cursor:pointer;margin:0;font-weight:600;">
Quick Mode (Skip AI analysis, OCR, and color contrast)
</label>
</div>
<div class="help-text">
Quick mode runs basic checks only — great for initial scans. Completes in ~10 seconds vs ~2 minutes.
</div>
</div>
<div class="progress-container" id="progressContainer" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" aria-label="Analysis progress">
<div class="progress-header">
<div class="progress-text" id="progressText">Uploading...</div>
<div class="progress-percent" id="progressPercent">0%</div>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill" style="width:0%"></div>
</div>
<div class="progress-log" id="progressLog">
<div class="log-header">Processing Details</div>
<div class="log-content" id="logContent" aria-live="polite">
<div class="log-entry" role="status">Initializing...</div>
</div>
</div>
</div>
</div>
<!-- Results Section -->
<div class="results" id="resultsSection">
<div class="card">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;">
<h2>Accessibility Report</h2>
<div style="display:flex;gap:10px;">
<button class="btn btn-secondary" onclick="exportReport('html')" id="exportHtmlBtn" title="Download HTML report">Export Report</button>
<button class="btn btn-secondary" onclick="exportReport('json')" id="exportJsonBtn" title="Download JSON data">Export JSON</button>
<button class="btn btn-secondary" onclick="exportReport('pdf')" id="exportPdfBtn" title="Download PDF report (PAC-style)">&#x1F4C4; PDF Report</button>
<button class="btn btn-secondary" onclick="resetCheck()">Check Another PDF</button>
</div>
</div>
<div class="score-display">
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
<output class="score-number" id="scoreNumber" aria-label="Accessibility score">--</output>
<span class="score-adjusted-label" id="adjustedLabel" style="display:none;">(Adjusted)</span>
</div>
<div>
<div class="score-label">Accessibility Score</div>
<button id="recheckBtn" class="btn-recheck" onclick="recalculateScore()"
style="display:none;"
title="Recalculate score applying dismissed issues and manual overrides">
Recalculate Score
</button>
</div>
</div>
<div class="stats-grid" id="statsGrid" role="group" aria-label="Issue severity counts"></div>
<div id="wcagCompliance" style="display:none;" aria-label="WCAG conformance level status"></div>
<div id="scoreBreakdown"></div>
</div>
<!-- Auto-Fix Card -->
<div class="card" id="remediationCard" style="display:none;">
<h2>Auto-Fix Available</h2>
<p style="color:var(--text-light);margin-bottom:15px;">
<span id="fixableCount">0</span> issues can be automatically fixed.
</p>
<div id="fixesList" style="margin-bottom:15px;"></div>
<button class="btn btn-primary" onclick="applyFixes()" id="applyFixesBtn" style="display:inline-flex;align-items:center;gap:8px;">
<span>Apply Automatic Fixes</span>
</button>
<div id="fixResult" style="margin-top:15px;display:none;" role="alert"></div>
</div>
<!-- Next Steps Card -->
<div class="card" id="nextStepsCard" style="display:none;">
<h2>Recommended Next Steps</h2>
<p style="color:var(--text-muted);font-size:13px;margin-bottom:16px;">Prioritised actions to improve accessibility — fix in this order for maximum impact.</p>
<ol id="nextStepsList" style="list-style:none;padding:0;margin:0;"></ol>
</div>
<!-- Matterhorn Protocol Card -->
<div class="card" id="matterhornCard" style="display:none;">
<h2>Matterhorn Protocol — PDF/UA-1</h2>
<div id="matterhornBanner"></div>
<table id="matterhornTable" aria-label="Matterhorn Protocol checkpoints">
<thead>
<tr>
<th>Checkpoint</th>
<th>How</th>
<th>Status</th>
</tr>
</thead>
<tbody id="matterhornBody"></tbody>
</table>
</div>
<!-- Visual Page Viewer -->
<div class="card" id="pageViewerCard" style="display:none;">
<h2>Visual Page Inspector</h2>
<p style="color:var(--text-light);margin-bottom:20px;">Click on issues to see their exact location on the page</p>
<div class="page-viewer-layout" style="display:flex;gap:20px;align-items:flex-start;">
<div class="page-selector-wrap" style="flex-shrink:0;">
<div style="background:var(--surface);padding:15px;border-radius:8px;min-width:150px;">
<h3 style="font-size:14px;margin-bottom:10px;">Select Page</h3>
<div id="pageSelector" style="display:flex;flex-direction:column;gap:5px;" role="tablist"></div>
</div>
</div>
<div style="flex:1;background:var(--surface-alt);border-radius:8px;padding:20px;position:relative;min-height:600px;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:15px;">
<h3 id="currentPageTitle" style="font-size:16px;margin:0;">Page 1</h3>
<div style="display:flex;gap:10px;">
<button onclick="zoomOut()" style="padding:8px 12px;border:1px solid var(--border);background:var(--surface);border-radius:6px;cursor:pointer;color:var(--text);" aria-label="Zoom out">-</button>
<span id="zoomLevel" style="padding:8px 12px;background:var(--surface);border-radius:6px;min-width:60px;text-align:center;">100%</span>
<button onclick="zoomIn()" style="padding:8px 12px;border:1px solid var(--border);background:var(--surface);border-radius:6px;cursor:pointer;color:var(--text);" aria-label="Zoom in">+</button>
<button onclick="resetZoom()" style="padding:8px 12px;border:1px solid var(--border);background:var(--surface);border-radius:6px;cursor:pointer;color:var(--text);" aria-label="Reset zoom to 100%">Reset</button>
</div>
</div>
<div id="pageImageContainer" style="overflow:auto;max-height:800px;background:white;border-radius:8px;position:relative;">
<div id="zoomContainer" style="position:relative;display:inline-block;transform-origin:top left;">
<img id="pageImage" src="" alt="PDF Page" style="display:block;max-width:100%;">
<svg id="markerOverlay" style="position:absolute;top:0;left:0;pointer-events:none;width:100%;height:100%;"></svg>
</div>
</div>
<div id="markerLegend" style="margin-top:15px;padding:15px;background:var(--surface);border-radius:8px;" role="region" aria-label="Issue location legend">
<strong>Legend:</strong>
<span style="margin-left:10px;padding:4px 8px;background:#dc2626;color:white;border-radius:4px;font-size:12px;">Critical</span>
<span style="margin-left:10px;padding:4px 8px;background:#ef4444;color:white;border-radius:4px;font-size:12px;">Error</span>
<span style="margin-left:10px;padding:4px 8px;background:#f59e0b;color:white;border-radius:4px;font-size:12px;">Warning</span>
<span style="margin-left:10px;padding:4px 8px;background:#3b82f6;color:white;border-radius:4px;font-size:12px;">Info</span>
</div>
</div>
</div>
</div>
<div class="card">
<h2>Issues &amp; Recommendations</h2>
<div class="filters" role="toolbar" aria-label="Filter issues by severity">
<button class="filter-btn active" onclick="filterIssues('all')" aria-pressed="true">All</button>
<button class="filter-btn" onclick="filterIssues('CRITICAL')" aria-pressed="false">Critical</button>
<button class="filter-btn" onclick="filterIssues('ERROR')" aria-pressed="false">Errors</button>
<button class="filter-btn" onclick="filterIssues('WARNING')" aria-pressed="false">Warnings</button>
<button class="filter-btn" onclick="filterIssues('INFO')" aria-pressed="false">Info</button>
</div>
<div id="issuesList" role="list"></div>
<div style="margin-top:28px;padding-top:20px;border-top:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;">
<span style="font-size:13px;color:var(--text-muted);">Review complete — check another document or export your report.</span>
<button class="btn btn-primary" onclick="resetCheck()" style="padding:12px 28px;font-size:15px;">&#x2B06; Check Another PDF</button>
</div>
</div>
</div>
</div>
</main>
<!-- JS Modules -->
<script src="js/utils.js"></script>
<script src="js/api.js"></script>
<script src="js/upload.js"></script>
<script src="js/batch.js"></script>
<script src="js/results.js"></script>
<script src="js/page-viewer.js"></script>
<script src="js/app.js"></script>
</body>
</html>