V1.1 Gut!

This commit is contained in:
2026-01-15 21:19:13 +01:00
parent 37cadcc8db
commit 01dad3025c
3 changed files with 491 additions and 53 deletions

View File

@@ -114,6 +114,27 @@ document.getElementById('pdfInput').addEventListener('change', async (e) => {
document.getElementById('uploadSection').style.display = 'none';
document.getElementById('statusSection').style.display = 'block';
// Show signature placeholder
document.getElementById('signaturePlaceholder').style.display = 'block';
// If signature already exists, make sure overlay will be visible
if (signatureDataUrl) {
const overlay = document.getElementById('signatureOverlay');
if (overlay) {
// Ensure overlay is ready to be shown
overlay.style.display = 'none'; // Reset first
overlay.classList.remove('show'); // Reset class
// Reset position to default when loading new PDF
signaturePos.x = 0.5;
signaturePos.y = 0.1;
console.log('Overlay zurückgesetzt für neues PDF-Laden, Position auf Standard zurückgesetzt');
}
} else {
// Reset position to default if no signature
signaturePos.x = 0.5;
signaturePos.y = 0.1;
}
// Render PDF preview using the copy
await renderPdfPreview(renderCopy);
@@ -174,6 +195,111 @@ async function renderPdfPreview(pdfBytes, pageNum = 1) {
// Update page navigation
updatePageNavigation();
// If signature was already received, show it again after PDF loads
setTimeout(() => {
const overlay = document.getElementById('signatureOverlay');
const placeholder = document.getElementById('signaturePlaceholder');
if (signatureDataUrl && overlay) {
// Signature was already received, restore it
console.log('=== Unterschrift war bereits vorhanden, zeige sie wieder an ===');
const img = document.getElementById('signatureImage');
const placeholderImg = document.getElementById('placeholderSignatureImage');
const placeholderContent = document.getElementById('placeholderContent');
// Show in placeholder
placeholder.style.display = 'block';
placeholderImg.src = signatureDataUrl;
placeholderImg.style.display = 'block';
placeholderContent.style.display = 'none';
// Show in overlay - IMPORTANT: Set image src FIRST, then show overlay
img.src = signatureDataUrl;
// Ensure overlay is visible
overlay.classList.add('show');
overlay.style.display = 'block'; // Force display
console.log('Overlay show-Klasse hinzugefügt:', overlay.classList.contains('show'));
// Position overlay (only if single page view, not all pages)
const pdfPreview = document.getElementById('pdfPreview');
if (!pdfPreview.classList.contains('scrollable')) {
// Single page view - position overlay
const canvas = document.getElementById('pdfCanvas');
if (canvas && canvas.clientWidth > 0 && canvas.clientHeight > 0) {
const overlayWidth = 250;
// Calculate position and ensure it's within bounds
let leftPos = canvas.clientWidth * signaturePos.x - overlayWidth / 2;
let topPos = canvas.clientHeight * signaturePos.y;
// Clamp position to visible area
leftPos = Math.max(0, Math.min(leftPos, canvas.clientWidth - overlayWidth));
topPos = Math.max(0, Math.min(topPos, canvas.clientHeight - 100)); // 100px min height for overlay
overlay.style.left = leftPos + 'px';
overlay.style.top = topPos + 'px';
overlay.style.position = 'absolute';
overlay.style.zIndex = '10';
// Update signaturePos with clamped values
signaturePos.x = (leftPos + overlayWidth / 2) / canvas.clientWidth;
signaturePos.y = topPos / canvas.clientHeight;
console.log('Overlay positioniert nach PDF-Laden:', overlay.style.left, overlay.style.top);
console.log('Canvas Größe:', canvas.clientWidth, 'x', canvas.clientHeight);
console.log('Overlay sichtbar:', overlay.classList.contains('show'), 'display:', overlay.style.display);
} else {
// Retry positioning - canvas might not be ready yet
console.log('Canvas noch nicht bereit, versuche erneut...');
setTimeout(() => {
const canvas = document.getElementById('pdfCanvas');
if (canvas && canvas.clientWidth > 0) {
const overlayWidth = 250;
// Calculate position and ensure it's within bounds
let leftPos = canvas.clientWidth * signaturePos.x - overlayWidth / 2;
let topPos = canvas.clientHeight * signaturePos.y;
// Clamp position to visible area
leftPos = Math.max(0, Math.min(leftPos, canvas.clientWidth - overlayWidth));
topPos = Math.max(0, Math.min(topPos, canvas.clientHeight - 100));
overlay.style.left = leftPos + 'px';
overlay.style.top = topPos + 'px';
overlay.style.position = 'absolute';
overlay.style.zIndex = '10';
overlay.classList.add('show');
overlay.style.display = 'block';
// Update signaturePos with clamped values
signaturePos.x = (leftPos + overlayWidth / 2) / canvas.clientWidth;
signaturePos.y = topPos / canvas.clientHeight;
console.log('Overlay positioniert (2. Versuch nach PDF-Laden):', overlay.style.left, overlay.style.top);
console.log('Overlay sichtbar:', overlay.classList.contains('show'));
} else {
console.error('Canvas auch nach Retry nicht gefunden!');
}
}, 500);
}
} else {
// All pages view - hide overlay
overlay.classList.remove('show');
overlay.style.display = 'none';
}
// Show controls
document.getElementById('signatureControls').classList.add('show');
} else {
// No signature yet, show placeholder
if (!overlay.classList.contains('show')) {
placeholder.style.display = 'block';
} else {
placeholder.style.display = 'none';
}
}
}, 300); // Increased delay to ensure canvas is ready
console.log('PDF Seite', pageNum, 'erfolgreich gerendert');
} catch (error) {
console.error('Fehler beim Rendern des PDFs:', error);
@@ -207,6 +333,14 @@ async function renderAllPages(pdfBytes) {
const pdfPreview = document.getElementById('pdfPreview');
pdfPreview.classList.add('scrollable');
// Hide signature overlay when showing all pages
const overlay = document.getElementById('signatureOverlay');
if (overlay) {
overlay.classList.remove('show');
overlay.style.display = 'none';
console.log('Overlay ausgeblendet beim Rendern aller Seiten');
}
// Render all pages
for (let pageNum = 1; pageNum <= numPages; pageNum++) {
@@ -253,6 +387,7 @@ function updatePageNavigation() {
const pageInfo = document.getElementById('pageInfo');
const prevBtn = document.getElementById('prevPageBtn');
const nextBtn = document.getElementById('nextPageBtn');
const jumpInput = document.getElementById('jumpToPageInput');
const pageSelector = document.getElementById('pageSelector');
const currentPageNumSpan = document.getElementById('currentPageNum');
@@ -262,6 +397,12 @@ function updatePageNavigation() {
prevBtn.disabled = currentPageNum <= 1;
nextBtn.disabled = currentPageNum >= totalPages;
// Update jump input max value and placeholder
if (jumpInput) {
jumpInput.max = totalPages;
jumpInput.placeholder = `1-${totalPages}`;
}
// Show page selector if signature is visible
if (document.getElementById('signatureOverlay').classList.contains('show')) {
pageSelector.style.display = 'block';
@@ -273,12 +414,98 @@ function updatePageNavigation() {
}
}
async function jumpToPage() {
const jumpInput = document.getElementById('jumpToPageInput');
const pageNum = parseInt(jumpInput.value);
if (isNaN(pageNum) || pageNum < 1 || pageNum > totalPages) {
alert(`Bitte geben Sie eine gültige Seitennummer zwischen 1 und ${totalPages} ein.`);
jumpInput.value = '';
return;
}
if (pageNum === currentPageNum) {
jumpInput.value = '';
return; // Already on this page
}
await renderPdfPreview(originalPdfBytes, pageNum);
// Reposition overlay if signature is visible
setTimeout(() => {
const overlay = document.getElementById('signatureOverlay');
if (overlay && overlay.classList.contains('show')) {
const canvas = document.getElementById('pdfCanvas');
if (canvas && canvas.clientWidth > 0 && canvas.clientHeight > 0) {
const overlayWidth = 250;
// Calculate position and ensure it's within bounds
let leftPos = canvas.clientWidth * signaturePos.x - overlayWidth / 2;
let topPos = canvas.clientHeight * signaturePos.y;
// Clamp position to visible area
leftPos = Math.max(0, Math.min(leftPos, canvas.clientWidth - overlayWidth));
topPos = Math.max(0, Math.min(topPos, canvas.clientHeight - 100));
overlay.style.left = leftPos + 'px';
overlay.style.top = topPos + 'px';
overlay.style.position = 'absolute';
// Update signaturePos with clamped values
signaturePos.x = (leftPos + overlayWidth / 2) / canvas.clientWidth;
signaturePos.y = topPos / canvas.clientHeight;
console.log('Overlay nach Seitenwechsel positioniert:', overlay.style.left, overlay.style.top);
}
}
}, 100);
// Send page change to signature station
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'page_change',
pageNum: pageNum,
totalPages: totalPages
}));
}
// Clear input
jumpInput.value = '';
}
async function changePage(direction) {
const newPage = currentPageNum + direction;
if (newPage < 1 || newPage > totalPages) return;
await renderPdfPreview(originalPdfBytes, newPage);
// Reposition overlay if signature is visible
setTimeout(() => {
const overlay = document.getElementById('signatureOverlay');
if (overlay && overlay.classList.contains('show')) {
const canvas = document.getElementById('pdfCanvas');
if (canvas && canvas.clientWidth > 0 && canvas.clientHeight > 0) {
const overlayWidth = 250;
// Calculate position and ensure it's within bounds
let leftPos = canvas.clientWidth * signaturePos.x - overlayWidth / 2;
let topPos = canvas.clientHeight * signaturePos.y;
// Clamp position to visible area
leftPos = Math.max(0, Math.min(leftPos, canvas.clientWidth - overlayWidth));
topPos = Math.max(0, Math.min(topPos, canvas.clientHeight - 100));
overlay.style.left = leftPos + 'px';
overlay.style.top = topPos + 'px';
overlay.style.position = 'absolute';
// Update signaturePos with clamped values
signaturePos.x = (leftPos + overlayWidth / 2) / canvas.clientWidth;
signaturePos.y = topPos / canvas.clientHeight;
console.log('Overlay nach Seitenwechsel positioniert:', overlay.style.left, overlay.style.top);
}
}
}, 100);
// Send page change to signature station
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
@@ -308,12 +535,37 @@ function updatePageSelection() {
}
}
// Placeholder handling is now simpler - just show/hide
async function showSignatureOverlay(signatureDataUrl) {
console.log('=== showSignatureOverlay aufgerufen ===');
console.log('signatureDataUrl Länge:', signatureDataUrl ? signatureDataUrl.length : 'NULL');
const overlay = document.getElementById('signatureOverlay');
const img = document.getElementById('signatureImage');
const placeholder = document.getElementById('signaturePlaceholder');
const placeholderImg = document.getElementById('placeholderSignatureImage');
const placeholderContent = document.getElementById('placeholderContent');
if (!overlay || !img || !placeholder) {
console.error('FEHLER: Overlay, img oder placeholder nicht gefunden!');
return;
}
// Show signature in placeholder first (always visible)
placeholder.style.display = 'block';
placeholderImg.src = signatureDataUrl;
placeholderImg.style.display = 'block';
placeholderContent.style.display = 'none';
console.log('Unterschrift im Platzhalter angezeigt');
// Also show in overlay for dragging on PDF
img.src = signatureDataUrl;
overlay.classList.add('show');
overlay.style.display = 'block'; // Force display
overlay.style.position = 'absolute'; // Ensure positioning works
overlay.style.zIndex = '10'; // Ensure it's on top
document.getElementById('signatureControls').classList.add('show');
@@ -324,90 +576,159 @@ async function showSignatureOverlay(signatureDataUrl) {
}
document.getElementById('statusMessage').className = 'status signed';
document.getElementById('statusMessage').textContent = '✅ Unterschrift erhalten! Wähle die Seite(n) und positioniere sie.';
document.getElementById('statusMessage').textContent = '✅ Unterschrift erhalten! Unterschrift oben sichtbar. Ziehe sie auf das PDF.';
document.getElementById('downloadButton').disabled = true;
document.getElementById('downloadHint').style.display = 'none';
// Position signature initially (use clientWidth for displayed size)
const canvas = document.getElementById('pdfCanvas');
overlay.style.left = (canvas.clientWidth * signaturePos.x) + 'px';
overlay.style.top = (canvas.clientHeight * signaturePos.y) + 'px';
// Initialize drag and resize handlers (only once)
initializeDragAndResize();
// Make signature draggable
makeDraggable(overlay);
makeResizable(overlay);
// Wait for canvas to be ready, then position signature overlay
setTimeout(() => {
const canvas = document.getElementById('pdfCanvas');
if (canvas && canvas.clientWidth > 0 && canvas.clientHeight > 0) {
// Position signature overlay on PDF (centered horizontally, top area)
const overlayWidth = 250; // Initial width
// Calculate position and ensure it's within bounds
let leftPos = canvas.clientWidth * signaturePos.x - overlayWidth / 2;
let topPos = canvas.clientHeight * signaturePos.y;
// Clamp position to visible area
leftPos = Math.max(0, Math.min(leftPos, canvas.clientWidth - overlayWidth));
topPos = Math.max(0, Math.min(topPos, canvas.clientHeight - 100)); // 100px min height for overlay
overlay.style.left = leftPos + 'px';
overlay.style.top = topPos + 'px';
overlay.style.position = 'absolute';
// Update signaturePos with clamped values
signaturePos.x = (leftPos + overlayWidth / 2) / canvas.clientWidth;
signaturePos.y = topPos / canvas.clientHeight;
console.log('Overlay positioniert bei:', overlay.style.left, overlay.style.top);
console.log('Canvas Größe:', canvas.clientWidth, 'x', canvas.clientHeight);
console.log('Overlay sichtbar:', overlay.classList.contains('show'));
} else {
console.error('Canvas nicht gefunden oder noch nicht geladen');
// Retry after a bit longer delay
setTimeout(() => {
const canvas = document.getElementById('pdfCanvas');
if (canvas && canvas.clientWidth > 0) {
const overlayWidth = 250;
// Calculate position and ensure it's within bounds
let leftPos = canvas.clientWidth * signaturePos.x - overlayWidth / 2;
let topPos = canvas.clientHeight * signaturePos.y;
// Clamp position to visible area
leftPos = Math.max(0, Math.min(leftPos, canvas.clientWidth - overlayWidth));
topPos = Math.max(0, Math.min(topPos, canvas.clientHeight - 100));
overlay.style.left = leftPos + 'px';
overlay.style.top = topPos + 'px';
overlay.style.position = 'absolute';
// Update signaturePos with clamped values
signaturePos.x = (leftPos + overlayWidth / 2) / canvas.clientWidth;
signaturePos.y = topPos / canvas.clientHeight;
console.log('Overlay positioniert (2. Versuch) bei:', overlay.style.left, overlay.style.top);
}
}, 500);
}
}, 200);
}
function makeDraggable(element) {
let isDragging = false;
let startX, startY, initialX, initialY;
// Dragging state (shared across calls)
let isDragging = false;
let isResizing = false;
let dragStartX, dragStartY, dragInitialX, dragInitialY;
let resizeStartX, resizeStartWidth;
element.addEventListener('mousedown', (e) => {
// Initialize dragging/resizing once
let dragInitialized = false;
function initializeDragAndResize() {
if (dragInitialized) return; // Only initialize once
const overlay = document.getElementById('signatureOverlay');
const resizeHandle = document.getElementById('resizeHandle');
if (!overlay || !resizeHandle) return;
// Make draggable
overlay.addEventListener('mousedown', (e) => {
if (e.target.classList.contains('resize-handle') || e.target.classList.contains('handle')) {
return;
}
isDragging = true;
startX = e.clientX;
startY = e.clientY;
initialX = element.offsetLeft;
initialY = element.offsetTop;
element.style.cursor = 'grabbing';
dragStartX = e.clientX;
dragStartY = e.clientY;
dragInitialX = overlay.offsetLeft;
dragInitialY = overlay.offsetTop;
overlay.style.cursor = 'grabbing';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
if (isDragging && overlay.classList.contains('show')) {
const dx = e.clientX - dragStartX;
const dy = e.clientY - dragStartY;
overlay.style.left = (dragInitialX + dx) + 'px';
overlay.style.top = (dragInitialY + dy) + 'px';
}
const dx = e.clientX - startX;
const dy = e.clientY - startY;
element.style.left = (initialX + dx) + 'px';
element.style.top = (initialY + dy) + 'px';
if (isResizing && overlay.classList.contains('show')) {
const dx = e.clientX - resizeStartX;
const newWidth = Math.max(100, resizeStartWidth + dx);
overlay.querySelector('img').style.maxWidth = newWidth + 'px';
}
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
element.style.cursor = 'move';
overlay.style.cursor = 'move';
updateSignaturePosition();
}
});
}
function makeResizable(element) {
const resizeHandle = document.getElementById('resizeHandle');
let isResizing = false;
let startX, startWidth;
resizeHandle.addEventListener('mousedown', (e) => {
e.stopPropagation();
isResizing = true;
startX = e.clientX;
startWidth = element.querySelector('img').width;
});
document.addEventListener('mousemove', (e) => {
if (!isResizing) return;
const dx = e.clientX - startX;
const newWidth = Math.max(100, startWidth + dx);
element.querySelector('img').style.maxWidth = newWidth + 'px';
});
document.addEventListener('mouseup', () => {
if (isResizing) {
isResizing = false;
updateSignatureScale();
}
});
// Make resizable
resizeHandle.addEventListener('mousedown', (e) => {
e.stopPropagation();
isResizing = true;
resizeStartX = e.clientX;
resizeStartWidth = overlay.querySelector('img').width;
});
dragInitialized = true;
}
function makeDraggable(element) {
// Function kept for compatibility, but actual initialization is in initializeDragAndResize
}
function makeResizable(element) {
// Function kept for compatibility, but actual initialization is in initializeDragAndResize
}
function updateSignaturePosition() {
const overlay = document.getElementById('signatureOverlay');
const canvas = document.getElementById('pdfCanvas');
signaturePos.x = overlay.offsetLeft / canvas.width;
signaturePos.y = overlay.offsetTop / canvas.height;
console.log('Neue Position:', signaturePos);
// Use clientWidth/clientHeight instead of width/height (display size vs internal size)
const canvasDisplayWidth = canvas.clientWidth || canvas.width;
const canvasDisplayHeight = canvas.clientHeight || canvas.height;
if (canvasDisplayWidth > 0 && canvasDisplayHeight > 0) {
signaturePos.x = overlay.offsetLeft / canvasDisplayWidth;
signaturePos.y = overlay.offsetTop / canvasDisplayHeight;
console.log('Neue Position:', signaturePos, 'Canvas Display:', canvasDisplayWidth, 'x', canvasDisplayHeight);
} else {
console.error('Canvas Display Größe ist 0!');
}
}
function updateSignatureScale() {
@@ -527,16 +848,39 @@ async function addSignatureToPdf() {
function removeSignatureOverlay() {
// Only remove the overlay, keep signedPdfBytes intact
document.getElementById('signatureOverlay').classList.remove('show');
const overlay = document.getElementById('signatureOverlay');
overlay.classList.remove('show');
overlay.style.display = 'none'; // Explicitly hide overlay
document.getElementById('signatureControls').classList.remove('show');
// Reset placeholder to default state
const placeholder = document.getElementById('signaturePlaceholder');
const placeholderImg = document.getElementById('placeholderSignatureImage');
const placeholderContent = document.getElementById('placeholderContent');
placeholderImg.style.display = 'none';
placeholderContent.style.display = 'flex';
placeholder.style.display = 'block';
signatureDataUrl = null;
console.log('removeSignatureOverlay() aufgerufen - signedPdfBytes:', signedPdfBytes ? signedPdfBytes.length + ' bytes' : 'NULL');
}
function removeSignature() {
// Complete reset including signedPdfBytes
document.getElementById('signatureOverlay').classList.remove('show');
const overlay = document.getElementById('signatureOverlay');
overlay.classList.remove('show');
overlay.style.display = 'none'; // Explicitly hide overlay
document.getElementById('signatureControls').classList.remove('show');
// Reset placeholder to default state
const placeholder = document.getElementById('signaturePlaceholder');
const placeholderImg = document.getElementById('placeholderSignatureImage');
const placeholderContent = document.getElementById('placeholderContent');
placeholder.style.display = 'block';
placeholderImg.style.display = 'none';
placeholderImg.src = '';
placeholderContent.style.display = 'flex';
document.getElementById('statusMessage').className = 'status waiting';
document.getElementById('statusMessage').textContent = 'Warte auf Unterschrift von der Signatur-Station...';
document.getElementById('downloadButton').disabled = true;
@@ -753,5 +1097,20 @@ document.getElementById('discardButton').addEventListener('click', () => {
}
});
// Initialize drag and resize on load
initializeDragAndResize();
// Add Enter key handler for jump to page input
document.addEventListener('DOMContentLoaded', () => {
const jumpInput = document.getElementById('jumpToPageInput');
if (jumpInput) {
jumpInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
jumpToPage();
}
});
}
});
// Connect WebSocket on load
connectWebSocket();