266 lines
16 KiB
HTML
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;">📂 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">📄</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">
|
|
▶ 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">📚</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 & 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)">📄 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 & 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;">⬆ 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>
|