Preview uploaded documents in an in-page modal instead of a new tab
Chrome blocks top-level navigation to data: URLs (anti-phishing), so the earlier target="_blank" preview links silently opened a blank tab for every uploaded document — real bug, caught by live testing. Replaces that with a same-tab modal: clicking a document name opens it in an overlay (<iframe> for PDFs, <img> for images — data: URLs work fine for embedding, just not top-level navigation), with its own download button and a close control. The small ⬇ icon next to each chip still downloads directly, unaffected since the `download` attribute uses a different code path than navigation.
This commit is contained in:
parent
92101e3077
commit
dd24d7217a
@ -360,6 +360,41 @@
|
||||
.contract-template-form .field-checkbox input { width: auto; }
|
||||
.signature-pad-wrap { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
|
||||
.signature-pad-canvas { border: 1px solid var(--border); border-radius: 8px; background: #fff; touch-action: none; cursor: crosshair; }
|
||||
|
||||
/* --- Dokument-Vorschau (Modal) --- */
|
||||
.doc-preview-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 200;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
}
|
||||
.doc-preview-box {
|
||||
background: var(--card-bg);
|
||||
border-radius: 14px;
|
||||
box-shadow: var(--shadow);
|
||||
width: 100%;
|
||||
max-width: 720px;
|
||||
max-height: 90vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.doc-preview-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 18px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
gap: 12px;
|
||||
}
|
||||
.doc-preview-header strong { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.doc-preview-body { flex: 1; overflow: auto; background: var(--bg); display: flex; align-items: center; justify-content: center; min-height: 300px; }
|
||||
.doc-preview-body img { max-width: 100%; display: block; }
|
||||
.doc-preview-body iframe { width: 100%; height: 75vh; border: none; }
|
||||
#trashCalendarEl { font-size: 13px; }
|
||||
#trashCalendarEl .fc { font-family: inherit; }
|
||||
#trashCalendarEl .fc-toolbar-title { font-size: 16px; font-weight: 700; color: var(--text); }
|
||||
@ -1032,6 +1067,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================= DOKUMENT-VORSCHAU (Modal) ================= -->
|
||||
<div id="docPreviewOverlay" class="doc-preview-overlay" style="display:none" onclick="if (event.target === this) closeDocumentPreview()">
|
||||
<div class="doc-preview-box">
|
||||
<div class="doc-preview-header">
|
||||
<strong id="docPreviewTitle"></strong>
|
||||
<div style="display:flex; gap:10px; align-items:center;">
|
||||
<a id="docPreviewDownload" class="btn-secondary" download>Herunterladen</a>
|
||||
<button type="button" class="btn-secondary" onclick="closeDocumentPreview()">Schließen ✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="doc-preview-body" id="docPreviewBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_BASE_URL = window.WG_API_BASE_URL ||
|
||||
(location.protocol === 'file:' ? 'http://localhost:3000/v1' : '/v1');
|
||||
@ -2854,25 +2903,30 @@
|
||||
return `Dokument ${index + 1}.${ext}`;
|
||||
}
|
||||
|
||||
// Klick auf den Namen öffnet eine Vorschau im neuen Tab (Browser können
|
||||
// PDFs/Bilder nativ anzeigen); der Pfeil daneben lädt bei Bedarf separat
|
||||
// herunter. Für alle hochgeladenen Dokumente (Verträge, Ausweis, Schufa) einheitlich.
|
||||
function docFileExt(url) {
|
||||
return url.includes('application/pdf') ? 'pdf' : (/^data:image\/(\w+)/.exec(url)?.[1] || 'jpg');
|
||||
}
|
||||
|
||||
// Klick auf den Namen öffnet eine kleine Vorschau im selben Tab (Modal) —
|
||||
// ein Link mit target="_blank" auf eine data:-URL würde Chrome als
|
||||
// Top-Level-Navigation blockieren (Phishing-Schutz), als eingebettetes
|
||||
// <img>/<iframe> im Modal ist das kein Problem. Der Pfeil daneben lädt bei
|
||||
// Bedarf separat herunter. Für alle hochgeladenen Dokumente (Verträge,
|
||||
// Ausweis, Schufa) einheitlich.
|
||||
function buildDocumentChip(label, url) {
|
||||
const chip = el('span', 'invite-status-chip');
|
||||
chip.style.cssText = 'background:var(--bg); color:var(--text); text-transform:none; display:inline-flex; align-items:center; gap:7px;';
|
||||
|
||||
const previewLink = document.createElement('a');
|
||||
previewLink.href = url;
|
||||
previewLink.target = '_blank';
|
||||
previewLink.rel = 'noopener';
|
||||
previewLink.textContent = label;
|
||||
previewLink.style.color = 'var(--text)';
|
||||
chip.appendChild(previewLink);
|
||||
const previewBtn = document.createElement('button');
|
||||
previewBtn.type = 'button';
|
||||
previewBtn.textContent = label;
|
||||
previewBtn.style.cssText = 'background:none; border:none; padding:0; margin:0; font:inherit; color:var(--text); text-decoration:underline; cursor:pointer;';
|
||||
previewBtn.onclick = () => openDocumentPreview(label, url);
|
||||
chip.appendChild(previewBtn);
|
||||
|
||||
const ext = url.includes('application/pdf') ? 'pdf' : (/^data:image\/(\w+)/.exec(url)?.[1] || 'jpg');
|
||||
const downloadLink = document.createElement('a');
|
||||
downloadLink.href = url;
|
||||
downloadLink.download = `${label.replace(/[^\w.-]+/g, '_')}.${ext}`;
|
||||
downloadLink.download = `${label.replace(/[^\w.-]+/g, '_')}.${docFileExt(url)}`;
|
||||
downloadLink.title = 'Herunterladen';
|
||||
downloadLink.textContent = '⬇';
|
||||
downloadLink.style.cssText = 'color:var(--text-muted); text-decoration:none; font-size:12px;';
|
||||
@ -2881,6 +2935,31 @@
|
||||
return chip;
|
||||
}
|
||||
|
||||
function openDocumentPreview(label, url) {
|
||||
document.getElementById('docPreviewTitle').textContent = label;
|
||||
const body = document.getElementById('docPreviewBody');
|
||||
body.innerHTML = '';
|
||||
if (url.startsWith('data:application/pdf')) {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = url;
|
||||
body.appendChild(iframe);
|
||||
} else {
|
||||
const img = document.createElement('img');
|
||||
img.src = url;
|
||||
img.alt = label;
|
||||
body.appendChild(img);
|
||||
}
|
||||
const downloadLink = document.getElementById('docPreviewDownload');
|
||||
downloadLink.href = url;
|
||||
downloadLink.download = `${label.replace(/[^\w.-]+/g, '_')}.${docFileExt(url)}`;
|
||||
document.getElementById('docPreviewOverlay').style.display = 'flex';
|
||||
}
|
||||
|
||||
function closeDocumentPreview() {
|
||||
document.getElementById('docPreviewOverlay').style.display = 'none';
|
||||
document.getElementById('docPreviewBody').innerHTML = '';
|
||||
}
|
||||
|
||||
function buildProfileCompletenessBadge(user) {
|
||||
const missing = [];
|
||||
if (!user.phoneNumber) missing.push('Telefonnummer');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user