Add localization for loading page count in various PDF processing pages

This commit is contained in:
Sebastian Espei
2026-03-10 20:13:13 +01:00
parent 571ce07af6
commit 2ede256de2
20 changed files with 944 additions and 806 deletions

View File

@@ -251,6 +251,7 @@
"add": "Hinzufügen", "add": "Hinzufügen",
"remove": "Entfernen", "remove": "Entfernen",
"loading": "Laden...", "loading": "Laden...",
"loadingPageCount": "Seitenanzahl wird geladen...",
"error": "Fehler", "error": "Fehler",
"success": "Erfolg", "success": "Erfolg",
"file": "Datei", "file": "Datei",

View File

@@ -260,6 +260,7 @@
"add": "Add", "add": "Add",
"remove": "Remove", "remove": "Remove",
"loading": "Loading...", "loading": "Loading...",
"loadingPageCount": "Loading pages...",
"error": "Error", "error": "Error",
"success": "Success", "success": "Success",
"file": "File", "file": "File",

View File

@@ -124,7 +124,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { import {
downloadFile, downloadFile,
readFileAsArrayBuffer, readFileAsArrayBuffer,
@@ -66,7 +67,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { import {
downloadFile, downloadFile,
readFileAsArrayBuffer, readFileAsArrayBuffer,
@@ -60,7 +61,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(currentFile.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(currentFile.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -45,7 +45,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; // Initial state metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`; // Initial state
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { import {
downloadFile, downloadFile,
readFileAsArrayBuffer, readFileAsArrayBuffer,
@@ -50,7 +51,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -45,7 +45,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; // Initial state metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`; // Initial state
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -45,7 +45,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; // Initial state metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`; // Initial state
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { import {
downloadFile, downloadFile,
readFileAsArrayBuffer, readFileAsArrayBuffer,
@@ -53,7 +54,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { import {
downloadFile, downloadFile,
readFileAsArrayBuffer, readFileAsArrayBuffer,
@@ -53,7 +54,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -45,7 +45,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; // Initial state metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`; // Initial state
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -46,7 +46,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; // Initial state metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`; // Initial state
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -45,7 +45,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; // Initial state metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`; // Initial state
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { import {
downloadFile, downloadFile,
readFileAsArrayBuffer, readFileAsArrayBuffer,
@@ -50,7 +51,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { import {
downloadFile, downloadFile,
readFileAsArrayBuffer, readFileAsArrayBuffer,
@@ -50,7 +51,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -130,7 +130,7 @@ const updateUI = () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);

View File

@@ -1,312 +1,354 @@
import { createIcons, icons } from 'lucide'; import { createIcons, icons } from 'lucide';
import { showAlert, showLoader, hideLoader } from '../ui.js'; import { showAlert, showLoader, hideLoader } from '../ui.js';
import { readFileAsArrayBuffer, formatBytes, downloadFile, getPDFDocument } from '../utils/helpers.js'; import {
readFileAsArrayBuffer,
formatBytes,
downloadFile,
getPDFDocument,
} from '../utils/helpers.js';
import { PDFDocument } from 'pdf-lib'; import { PDFDocument } from 'pdf-lib';
import { t } from '../i18n/i18n';
interface SignState { interface SignState {
file: File | null; file: File | null;
pdfDoc: any; pdfDoc: any;
viewerIframe: HTMLIFrameElement | null; viewerIframe: HTMLIFrameElement | null;
viewerReady: boolean; viewerReady: boolean;
blobUrl: string | null; blobUrl: string | null;
} }
const signState: SignState = { const signState: SignState = {
file: null, file: null,
pdfDoc: null, pdfDoc: null,
viewerIframe: null, viewerIframe: null,
viewerReady: false, viewerReady: false,
blobUrl: null, blobUrl: null,
}; };
if (document.readyState === 'loading') { if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializePage); document.addEventListener('DOMContentLoaded', initializePage);
} else { } else {
initializePage(); initializePage();
} }
function initializePage() { function initializePage() {
createIcons({ icons }); createIcons({ icons });
const fileInput = document.getElementById('file-input') as HTMLInputElement; const fileInput = document.getElementById('file-input') as HTMLInputElement;
const dropZone = document.getElementById('drop-zone'); const dropZone = document.getElementById('drop-zone');
const processBtn = document.getElementById('process-btn'); const processBtn = document.getElementById('process-btn');
if (fileInput) { if (fileInput) {
fileInput.addEventListener('change', handleFileUpload); fileInput.addEventListener('change', handleFileUpload);
} }
if (dropZone) { if (dropZone) {
dropZone.addEventListener('dragover', (e) => { dropZone.addEventListener('dragover', (e) => {
e.preventDefault(); e.preventDefault();
dropZone.classList.add('bg-gray-700'); dropZone.classList.add('bg-gray-700');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('bg-gray-700');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('bg-gray-700');
const droppedFiles = e.dataTransfer?.files;
if (droppedFiles && droppedFiles.length > 0) {
handleFile(droppedFiles[0]);
}
});
// Clear value on click to allow re-selecting the same file
fileInput?.addEventListener('click', () => {
if (fileInput) fileInput.value = '';
});
}
if (processBtn) {
processBtn.addEventListener('click', applyAndSaveSignatures);
}
document.getElementById('back-to-tools')?.addEventListener('click', () => {
cleanup();
window.location.href = import.meta.env.BASE_URL;
}); });
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('bg-gray-700');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('bg-gray-700');
const droppedFiles = e.dataTransfer?.files;
if (droppedFiles && droppedFiles.length > 0) {
handleFile(droppedFiles[0]);
}
});
// Clear value on click to allow re-selecting the same file
fileInput?.addEventListener('click', () => {
if (fileInput) fileInput.value = '';
});
}
if (processBtn) {
processBtn.addEventListener('click', applyAndSaveSignatures);
}
document.getElementById('back-to-tools')?.addEventListener('click', () => {
cleanup();
window.location.href = import.meta.env.BASE_URL;
});
} }
function handleFileUpload(e: Event) { function handleFileUpload(e: Event) {
const input = e.target as HTMLInputElement; const input = e.target as HTMLInputElement;
if (input.files && input.files.length > 0) { if (input.files && input.files.length > 0) {
handleFile(input.files[0]); handleFile(input.files[0]);
} }
} }
function handleFile(file: File) { function handleFile(file: File) {
if (file.type !== 'application/pdf' && !file.name.toLowerCase().endsWith('.pdf')) { if (
showAlert('Invalid File', 'Please select a PDF file.'); file.type !== 'application/pdf' &&
return; !file.name.toLowerCase().endsWith('.pdf')
} ) {
showAlert('Invalid File', 'Please select a PDF file.');
return;
}
signState.file = file; signState.file = file;
updateFileDisplay(); updateFileDisplay();
setupSignTool(); setupSignTool();
} }
async function updateFileDisplay() { async function updateFileDisplay() {
const fileDisplayArea = document.getElementById('file-display-area'); const fileDisplayArea = document.getElementById('file-display-area');
if (!fileDisplayArea || !signState.file) return; if (!fileDisplayArea || !signState.file) return;
fileDisplayArea.innerHTML = '';
const fileDiv = document.createElement('div');
fileDiv.className =
'flex items-center justify-between bg-gray-700 p-3 rounded-lg';
const infoContainer = document.createElement('div');
infoContainer.className = 'flex flex-col flex-1 min-w-0';
const nameSpan = document.createElement('div');
nameSpan.className = 'truncate font-medium text-gray-200 text-sm mb-1';
nameSpan.textContent = signState.file.name;
const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(signState.file.size)}${t('common.loadingPageCount')}`;
infoContainer.append(nameSpan, metaSpan);
const removeBtn = document.createElement('button');
removeBtn.className = 'ml-4 text-red-400 hover:text-red-300 flex-shrink-0';
removeBtn.innerHTML = '<i data-lucide=\"trash-2\" class=\"w-4 h-4\"></i>';
removeBtn.onclick = () => {
signState.file = null;
signState.pdfDoc = null;
fileDisplayArea.innerHTML = ''; fileDisplayArea.innerHTML = '';
document.getElementById('signature-editor')?.classList.add('hidden');
};
const fileDiv = document.createElement('div'); fileDiv.append(infoContainer, removeBtn);
fileDiv.className = 'flex items-center justify-between bg-gray-700 p-3 rounded-lg'; fileDisplayArea.appendChild(fileDiv);
createIcons({ icons });
const infoContainer = document.createElement('div'); // Load page count
infoContainer.className = 'flex flex-col flex-1 min-w-0'; try {
const arrayBuffer = await readFileAsArrayBuffer(signState.file);
const nameSpan = document.createElement('div'); const pdfDoc = await getPDFDocument({ data: arrayBuffer }).promise;
nameSpan.className = 'truncate font-medium text-gray-200 text-sm mb-1'; metaSpan.textContent = `${formatBytes(signState.file.size)}${pdfDoc.numPages} pages`;
nameSpan.textContent = signState.file.name; } catch (error) {
console.error('Error loading PDF:', error);
const metaSpan = document.createElement('div'); }
metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(signState.file.size)} • Loading pages...`;
infoContainer.append(nameSpan, metaSpan);
const removeBtn = document.createElement('button');
removeBtn.className = 'ml-4 text-red-400 hover:text-red-300 flex-shrink-0';
removeBtn.innerHTML = '<i data-lucide=\"trash-2\" class=\"w-4 h-4\"></i>';
removeBtn.onclick = () => {
signState.file = null;
signState.pdfDoc = null;
fileDisplayArea.innerHTML = '';
document.getElementById('signature-editor')?.classList.add('hidden');
};
fileDiv.append(infoContainer, removeBtn);
fileDisplayArea.appendChild(fileDiv);
createIcons({ icons });
// Load page count
try {
const arrayBuffer = await readFileAsArrayBuffer(signState.file);
const pdfDoc = await getPDFDocument({ data: arrayBuffer }).promise;
metaSpan.textContent = `${formatBytes(signState.file.size)}${pdfDoc.numPages} pages`;
} catch (error) {
console.error('Error loading PDF:', error);
}
} }
async function setupSignTool() { async function setupSignTool() {
const signatureEditor = document.getElementById('signature-editor'); const signatureEditor = document.getElementById('signature-editor');
if (signatureEditor) { if (signatureEditor) {
signatureEditor.classList.remove('hidden'); signatureEditor.classList.remove('hidden');
} }
showLoader('Loading PDF viewer...'); showLoader('Loading PDF viewer...');
const container = document.getElementById('canvas-container-sign'); const container = document.getElementById('canvas-container-sign');
if (!container) { if (!container) {
console.error('Sign tool canvas container not found'); console.error('Sign tool canvas container not found');
hideLoader(); hideLoader();
return; return;
} }
if (!signState.file) { if (!signState.file) {
console.error('No file loaded for signing'); console.error('No file loaded for signing');
hideLoader(); hideLoader();
return; return;
} }
container.textContent = ''; container.textContent = '';
const iframe = document.createElement('iframe'); const iframe = document.createElement('iframe');
iframe.style.width = '100%'; iframe.style.width = '100%';
iframe.style.height = '100%'; iframe.style.height = '100%';
iframe.style.border = 'none'; iframe.style.border = 'none';
container.appendChild(iframe); container.appendChild(iframe);
signState.viewerIframe = iframe; signState.viewerIframe = iframe;
const pdfBytes = await readFileAsArrayBuffer(signState.file); const pdfBytes = await readFileAsArrayBuffer(signState.file);
const blob = new Blob([pdfBytes as BlobPart], { type: 'application/pdf' }); const blob = new Blob([pdfBytes as BlobPart], { type: 'application/pdf' });
signState.blobUrl = URL.createObjectURL(blob); signState.blobUrl = URL.createObjectURL(blob);
try { try {
const existingPrefsRaw = localStorage.getItem('pdfjs.preferences'); const existingPrefsRaw = localStorage.getItem('pdfjs.preferences');
const existingPrefs = existingPrefsRaw ? JSON.parse(existingPrefsRaw) : {}; const existingPrefs = existingPrefsRaw ? JSON.parse(existingPrefsRaw) : {};
delete (existingPrefs as any).annotationEditorMode; delete (existingPrefs as any).annotationEditorMode;
const newPrefs = { const newPrefs = {
...existingPrefs, ...existingPrefs,
enableSignatureEditor: true, enableSignatureEditor: true,
enablePermissions: false, enablePermissions: false,
};
localStorage.setItem('pdfjs.preferences', JSON.stringify(newPrefs));
} catch { }
const viewerUrl = new URL(`${import.meta.env.BASE_URL}pdfjs-viewer/viewer.html`, window.location.origin);
const query = new URLSearchParams({ file: signState.blobUrl });
iframe.src = `${viewerUrl.toString()}?${query.toString()}`;
iframe.onload = () => {
hideLoader();
signState.viewerReady = true;
try {
const viewerWindow: any = iframe.contentWindow;
if (viewerWindow && viewerWindow.PDFViewerApplication) {
const app = viewerWindow.PDFViewerApplication;
const doc = viewerWindow.document;
const eventBus = app.eventBus;
eventBus?._on('annotationeditoruimanager', () => {
const editorModeButtons = doc.getElementById('editorModeButtons');
editorModeButtons?.classList.remove('hidden');
const editorSignature = doc.getElementById('editorSignature');
editorSignature?.removeAttribute('hidden');
const editorSignatureButton = doc.getElementById('editorSignatureButton') as HTMLButtonElement | null;
if (editorSignatureButton) {
editorSignatureButton.disabled = false;
}
const editorStamp = doc.getElementById('editorStamp');
editorStamp?.removeAttribute('hidden');
const editorStampButton = doc.getElementById('editorStampButton') as HTMLButtonElement | null;
if (editorStampButton) {
editorStampButton.disabled = false;
}
try {
const highlightBtn = doc.getElementById('editorHighlightButton') as HTMLButtonElement | null;
highlightBtn?.click();
} catch { }
});
}
} catch (e) {
console.error('Could not initialize PDF.js viewer for signing:', e);
}
const saveBtn = document.getElementById('process-btn') as HTMLButtonElement | null;
if (saveBtn) {
saveBtn.style.display = '';
}
}; };
localStorage.setItem('pdfjs.preferences', JSON.stringify(newPrefs));
} catch {}
const viewerUrl = new URL(
`${import.meta.env.BASE_URL}pdfjs-viewer/viewer.html`,
window.location.origin
);
const query = new URLSearchParams({ file: signState.blobUrl });
iframe.src = `${viewerUrl.toString()}?${query.toString()}`;
iframe.onload = () => {
hideLoader();
signState.viewerReady = true;
try {
const viewerWindow: any = iframe.contentWindow;
if (viewerWindow && viewerWindow.PDFViewerApplication) {
const app = viewerWindow.PDFViewerApplication;
const doc = viewerWindow.document;
const eventBus = app.eventBus;
eventBus?._on('annotationeditoruimanager', () => {
const editorModeButtons = doc.getElementById('editorModeButtons');
editorModeButtons?.classList.remove('hidden');
const editorSignature = doc.getElementById('editorSignature');
editorSignature?.removeAttribute('hidden');
const editorSignatureButton = doc.getElementById(
'editorSignatureButton'
) as HTMLButtonElement | null;
if (editorSignatureButton) {
editorSignatureButton.disabled = false;
}
const editorStamp = doc.getElementById('editorStamp');
editorStamp?.removeAttribute('hidden');
const editorStampButton = doc.getElementById(
'editorStampButton'
) as HTMLButtonElement | null;
if (editorStampButton) {
editorStampButton.disabled = false;
}
try {
const highlightBtn = doc.getElementById(
'editorHighlightButton'
) as HTMLButtonElement | null;
highlightBtn?.click();
} catch {}
});
}
} catch (e) {
console.error('Could not initialize PDF.js viewer for signing:', e);
}
const saveBtn = document.getElementById(
'process-btn'
) as HTMLButtonElement | null;
if (saveBtn) {
saveBtn.style.display = '';
}
};
} }
async function applyAndSaveSignatures() { async function applyAndSaveSignatures() {
if (!signState.viewerReady || !signState.viewerIframe) { if (!signState.viewerReady || !signState.viewerIframe) {
showAlert('Viewer not ready', 'Please wait for the PDF viewer to load.'); showAlert('Viewer not ready', 'Please wait for the PDF viewer to load.');
return; return;
}
try {
const viewerWindow: any = signState.viewerIframe.contentWindow;
if (!viewerWindow || !viewerWindow.PDFViewerApplication) {
showAlert('Viewer not ready', 'The PDF viewer is still initializing.');
return;
} }
try { const app = viewerWindow.PDFViewerApplication;
const viewerWindow: any = signState.viewerIframe.contentWindow; const flattenCheckbox = document.getElementById(
if (!viewerWindow || !viewerWindow.PDFViewerApplication) { 'flatten-signature-toggle'
showAlert('Viewer not ready', 'The PDF viewer is still initializing.'); ) as HTMLInputElement | null;
return; const shouldFlatten = flattenCheckbox?.checked;
if (shouldFlatten) {
showLoader('Flattening and saving PDF...');
const rawPdfBytes = await app.pdfDocument.saveDocument(
app.pdfDocument.annotationStorage
);
const pdfBytes = new Uint8Array(rawPdfBytes);
const pdfDoc = await PDFDocument.load(pdfBytes);
pdfDoc.getForm().flatten();
const flattenedPdfBytes = await pdfDoc.save();
const blob = new Blob([flattenedPdfBytes as BlobPart], {
type: 'application/pdf',
});
downloadFile(
blob,
`signed_flattened_${signState.file?.name || 'document.pdf'}`
);
hideLoader();
showAlert('Success', 'Signed PDF saved successfully!', 'success', () => {
resetState();
});
} else {
app.eventBus?.dispatch('download', { source: app });
showAlert(
'Success',
'Signed PDF downloaded successfully!',
'success',
() => {
resetState();
} }
);
const app = viewerWindow.PDFViewerApplication;
const flattenCheckbox = document.getElementById('flatten-signature-toggle') as HTMLInputElement | null;
const shouldFlatten = flattenCheckbox?.checked;
if (shouldFlatten) {
showLoader('Flattening and saving PDF...');
const rawPdfBytes = await app.pdfDocument.saveDocument(app.pdfDocument.annotationStorage);
const pdfBytes = new Uint8Array(rawPdfBytes);
const pdfDoc = await PDFDocument.load(pdfBytes);
pdfDoc.getForm().flatten();
const flattenedPdfBytes = await pdfDoc.save();
const blob = new Blob([flattenedPdfBytes as BlobPart], { type: 'application/pdf' });
downloadFile(blob, `signed_flattened_${signState.file?.name || 'document.pdf'}`);
hideLoader();
showAlert('Success', 'Signed PDF saved successfully!', 'success', () => {
resetState();
});
} else {
app.eventBus?.dispatch('download', { source: app });
showAlert('Success', 'Signed PDF downloaded successfully!', 'success', () => {
resetState();
});
}
} catch (error) {
console.error('Failed to export the signed PDF:', error);
hideLoader();
showAlert('Export failed', 'Could not export the signed PDF. Please try again.');
} }
} catch (error) {
console.error('Failed to export the signed PDF:', error);
hideLoader();
showAlert(
'Export failed',
'Could not export the signed PDF. Please try again.'
);
}
} }
function resetState() { function resetState() {
cleanup(); cleanup();
signState.file = null; signState.file = null;
signState.viewerIframe = null; signState.viewerIframe = null;
signState.viewerReady = false; signState.viewerReady = false;
const signatureEditor = document.getElementById('signature-editor'); const signatureEditor = document.getElementById('signature-editor');
if (signatureEditor) { if (signatureEditor) {
signatureEditor.classList.add('hidden'); signatureEditor.classList.add('hidden');
} }
const container = document.getElementById('canvas-container-sign'); const container = document.getElementById('canvas-container-sign');
if (container) { if (container) {
container.textContent = ''; container.textContent = '';
} }
const fileDisplayArea = document.getElementById('file-display-area'); const fileDisplayArea = document.getElementById('file-display-area');
if (fileDisplayArea) { if (fileDisplayArea) {
fileDisplayArea.innerHTML = ''; fileDisplayArea.innerHTML = '';
} }
const processBtn = document.getElementById('process-btn') as HTMLButtonElement | null; const processBtn = document.getElementById(
if (processBtn) { 'process-btn'
processBtn.style.display = 'none'; ) as HTMLButtonElement | null;
} if (processBtn) {
processBtn.style.display = 'none';
}
const flattenCheckbox = document.getElementById('flatten-signature-toggle') as HTMLInputElement | null; const flattenCheckbox = document.getElementById(
if (flattenCheckbox) { 'flatten-signature-toggle'
flattenCheckbox.checked = false; ) as HTMLInputElement | null;
} if (flattenCheckbox) {
flattenCheckbox.checked = false;
}
} }
function cleanup() { function cleanup() {
if (signState.blobUrl) { if (signState.blobUrl) {
URL.revokeObjectURL(signState.blobUrl); URL.revokeObjectURL(signState.blobUrl);
signState.blobUrl = null; signState.blobUrl = null;
} }
} }

View File

@@ -1,4 +1,5 @@
import { showLoader, hideLoader, showAlert } from '../ui.js'; import { showLoader, hideLoader, showAlert } from '../ui.js';
import { t } from '../i18n/i18n';
import { createIcons, icons } from 'lucide'; import { createIcons, icons } from 'lucide';
import * as pdfjsLib from 'pdfjs-dist'; import * as pdfjsLib from 'pdfjs-dist';
import { import {
@@ -71,7 +72,7 @@ document.addEventListener('DOMContentLoaded', () => {
const metaSpan = document.createElement('div'); const metaSpan = document.createElement('div');
metaSpan.className = 'text-xs text-gray-400'; metaSpan.className = 'text-xs text-gray-400';
metaSpan.textContent = `${formatBytes(file.size)}Loading pages...`; // Placeholder metaSpan.textContent = `${formatBytes(file.size)}${t('common.loadingPageCount')}`; // Placeholder
infoContainer.append(nameSpan, metaSpan); infoContainer.append(nameSpan, metaSpan);