Dokumente am Auftrag öffnen denselben PDF-Betrachter mit Zoom (Zwei-Finger, Knöpfe, Doppeltipp) [deploy]
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 14s
All checks were successful
Deploy baustelle-pwa / deploy (push) Successful in 14s
Der alte Dokumenten-Betrachter (eine Seite, nur Vor/Zurück) hatte keinen Zoom — deshalb ging Finger-auseinanderziehen dort nicht. Jetzt ein Betrachter für alles; Download bleibt die Originaldatei vom Server. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
55b9a4f2d0
commit
a6cdc7b861
1 changed files with 21 additions and 78 deletions
95
app.js
95
app.js
|
|
@ -2403,7 +2403,16 @@ async function openPageActionsModal(berichtId, pageId, relpath, note, title) {
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
* PDF-VORSCHAU MODAL
|
* PDF-VORSCHAU MODAL
|
||||||
* ============================================================ */
|
* ============================================================ */
|
||||||
function openPdfModal(blobUrl, filename) {
|
/**
|
||||||
|
* Der EINE PDF-Betrachter der App — Berichtsvorschau, Lieferschein und Dokumente am Auftrag.
|
||||||
|
* Bis 15.10.2026 gab es zwei: die Dokumente öffneten einen älteren ohne Zoom (eine Seite,
|
||||||
|
* nur Vor/Zurück), deshalb ging „Finger auseinanderziehen" dort nicht.
|
||||||
|
*
|
||||||
|
* @param {string} blobUrl
|
||||||
|
* @param {string} filename
|
||||||
|
* @param {Function} [beiDownload] eigener Download-Weg (z. B. Originaldatei vom Server)
|
||||||
|
*/
|
||||||
|
function openPdfModal(blobUrl, filename, beiDownload) {
|
||||||
const fname = filename || 'bericht.pdf';
|
const fname = filename || 'bericht.pdf';
|
||||||
const modal = document.createElement('div');
|
const modal = document.createElement('div');
|
||||||
modal.className = 'fullscreen-modal pdfv-modal';
|
modal.className = 'fullscreen-modal pdfv-modal';
|
||||||
|
|
@ -2432,6 +2441,9 @@ function openPdfModal(blobUrl, filename) {
|
||||||
await shareFile(blob, fname, 'application/pdf', fname);
|
await shareFile(blob, fname, 'application/pdf', fname);
|
||||||
} catch (e) { showToast('Teilen fehlgeschlagen: ' + e.message, 'error'); }
|
} catch (e) { showToast('Teilen fehlgeschlagen: ' + e.message, 'error'); }
|
||||||
};
|
};
|
||||||
|
if (typeof beiDownload === 'function') {
|
||||||
|
modal.querySelector('#pdf-download').onclick = (e) => { e.preventDefault(); beiDownload(); };
|
||||||
|
}
|
||||||
|
|
||||||
const scroller = modal.querySelector('#pdfv-scroll');
|
const scroller = modal.querySelector('#pdfv-scroll');
|
||||||
const stack = modal.querySelector('#pdfv-stack');
|
const stack = modal.querySelector('#pdfv-stack');
|
||||||
|
|
@ -3268,86 +3280,17 @@ function openFileViewer({ url, blob, mime }, filename, relpath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openPdfViewer(blob, filename, relpath) {
|
async function openPdfViewer(blob, filename, relpath) {
|
||||||
console.log('[PDF] Opening:', filename, 'size:', blob.size, 'type:', blob.type);
|
if (!blob || blob.size === 0) {
|
||||||
|
|
||||||
if (blob.size === 0) {
|
|
||||||
showToast('❌ PDF-Datei ist leer oder nicht gefunden', 'error');
|
showToast('❌ PDF-Datei ist leer oder nicht gefunden', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Derselbe Betrachter wie überall (Zoom per Knopf, Zwei-Finger, Doppeltipp, Strg+Rad).
|
||||||
const modal = document.createElement('div');
|
// Download wie bisher als Originaldatei vom Server, nicht aus dem Zwischenspeicher.
|
||||||
modal.className = 'fullscreen-modal pdf-viewer-modal';
|
const url = URL.createObjectURL(blob);
|
||||||
modal.innerHTML = `
|
openPdfModal(url, filename || 'dokument.pdf', relpath ? () => {
|
||||||
<div class="fs-header">
|
|
||||||
<button class="icon-btn" id="pdf-prev" title="← Seite zurück">‹</button>
|
|
||||||
<div class="pdf-page-info" id="pdf-page-info">⏳</div>
|
|
||||||
<button class="icon-btn" id="pdf-next" title="Seite vor →">›</button>
|
|
||||||
<div class="fs-title">${escapeHtml(filename || '')}</div>
|
|
||||||
<button class="icon-btn" id="pdf-close">✕</button>
|
|
||||||
<button class="icon-btn" id="pdf-share" title="Teilen">📤</button>
|
|
||||||
<button class="icon-btn" id="pdf-download" title="Download">⬇</button>
|
|
||||||
</div>
|
|
||||||
<div class="pdf-body" id="pdf-body">
|
|
||||||
<canvas id="pdf-canvas"></canvas>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
document.body.appendChild(modal);
|
|
||||||
pushModal(modal);
|
|
||||||
|
|
||||||
const canvas = modal.querySelector('#pdf-canvas');
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
const pageInfo = modal.querySelector('#pdf-page-info');
|
|
||||||
let pdf, currentPage = 1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const arrayBuffer = await blob.arrayBuffer();
|
|
||||||
console.log('[PDF] ArrayBuffer size:', arrayBuffer.byteLength);
|
|
||||||
|
|
||||||
if (arrayBuffer.byteLength === 0) {
|
|
||||||
throw new Error('PDF-Datei ist leer');
|
|
||||||
}
|
|
||||||
|
|
||||||
pdf = await pdfjs.getDocument(new Uint8Array(arrayBuffer)).promise;
|
|
||||||
console.log('[PDF] Loaded:', pdf.numPages, 'pages');
|
|
||||||
pageInfo.textContent = `1 / ${pdf.numPages}`;
|
|
||||||
|
|
||||||
async function renderPage(num) {
|
|
||||||
if (num < 1 || num > pdf.numPages) return;
|
|
||||||
currentPage = num;
|
|
||||||
try {
|
|
||||||
const page = await pdf.getPage(num);
|
|
||||||
const viewport = page.getViewport({ scale: window.devicePixelRatio });
|
|
||||||
canvas.width = viewport.width;
|
|
||||||
canvas.height = viewport.height;
|
|
||||||
await page.render({ canvasContext: ctx, viewport }).promise;
|
|
||||||
pageInfo.textContent = `${num} / ${pdf.numPages}`;
|
|
||||||
} catch (e) {
|
|
||||||
console.error('[PDF] Render error on page', num, e);
|
|
||||||
pageInfo.textContent = `❌ Seite ${num} Fehler`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await renderPage(1);
|
|
||||||
modal.querySelector('#pdf-prev').onclick = () => renderPage(currentPage - 1);
|
|
||||||
modal.querySelector('#pdf-next').onclick = () => renderPage(currentPage + 1);
|
|
||||||
modal.querySelector('#pdf-download').onclick = async () => {
|
|
||||||
const params = new URLSearchParams({ relpath, download: 1 });
|
const params = new URLSearchParams({ relpath, download: 1 });
|
||||||
window.location.href = window.location.origin + '/custom/bericht/api/photo.php?' + params.toString();
|
window.location.href = window.location.origin + '/custom/bericht/api/photo.php?' + params.toString();
|
||||||
};
|
} : null);
|
||||||
modal.querySelector('#pdf-share').onclick = () => {
|
|
||||||
shareFile(blob, filename || 'dokument.pdf', 'application/pdf', filename);
|
|
||||||
};
|
|
||||||
modal.querySelector('#pdf-prev').disabled = false;
|
|
||||||
modal.querySelector('#pdf-next').disabled = pdf.numPages === 1;
|
|
||||||
} catch (err) {
|
|
||||||
pageInfo.textContent = '❌ ' + (err.message || 'PDF-Fehler');
|
|
||||||
console.error('[PDF] Load error:', err);
|
|
||||||
showToast('PDF-Fehler: ' + err.message, 'error');
|
|
||||||
}
|
|
||||||
|
|
||||||
modal.querySelector('#pdf-close').onclick = () => {
|
|
||||||
closeModal(modal);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue