// ES6 Compliant Syntax
// GitHub Copilot - Model: GPT-4o
// Date: July 14, 2025
// File: index.js
import WebViewer from '@pdftron/webviewer';
const licenseKey = 'YOUR_WEBVIEWER_LICENSE_KEY'; // Demo requires a license key, get a demo license key from https://docs.apryse.com/core/guides/get-started/trial-key
// List of viewers with their configurations
// Each viewer can have its own document, alignment, size, instance, and merging features
let viewers = [
{
initialDoc: 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf',
style: {
alignment: 'Left',
width: '49%',
height: '100vh',
margin: '0 auto',
},
instance: null,
hasMerging: false, // The merging feature allows merging pages from one viewer to another
},
{
initialDoc: 'https://pdftron.s3.amazonaws.com/downloads/pl/report.docx',
style: {
alignment: 'Right',
width: '49%',
height: '100vh',
margin: '0 auto',
},
instance: null,
hasMerging: true,
},
];
// Customize the WebViewer UI
// Add custom buttons for merging (if merging feature is enabled) and downloading PDFs
function customizeUI(viewer) {
const { UI } = viewer.instance;
// Merge button
let mergeButton = null;
if (viewer.hasMerging) {
mergeButton = new UI.Components.CustomButton({
dataElement: 'mergeButton',
className: 'custom-button-class',
label: 'Merge Page',
title: 'Merge the left WebViewer\'s first page, to be inserted prior to the right WebViewer\'s first page.',
onClick: () => mergePage(), // Merge the pages
style: {
padding: '10px 20px',
backgroundColor: 'white',
color: 'blue',
border: '1px solid blue',
}
});
}
// Download Pdf button
let downloadButton = new UI.Components.CustomButton({
dataElement: 'downloadPdfButton',
className: 'custom-button-class',
label: 'Download as PDF',
onClick: () => downloadPdf(viewer.instance), // Download the PDF
style: {
padding: '10px 20px',
backgroundColor: 'blue',
color: 'white',
}
});
let defaultHeader = UI.getModularHeader('default-top-header');
// If the viewer has merging enabled, add the merge button and download button to the header
// Otherwise, just add the download button
if (viewer.hasMerging)
defaultHeader.setItems([...defaultHeader.items, mergeButton, downloadButton]);
else
defaultHeader.setItems([...defaultHeader.items, downloadButton]);
};
// Merge the first page from the left viewer to be located at position #1 of the right viewer
// This function will be called when the merge button is clicked
// This function retrieves the source document, exports annotations, and inserts page(s) into the destination document
const mergePage = async () => {
const srcDoc = await viewers[0].instance.Core.documentViewer.getDocument();
const dstDoc = await viewers[1].instance.Core.documentViewer.getDocument();
// get first page as a blob
const xfdfString = await viewers[0].instance.Core.annotationManager.exportAnnotations();
const data = await srcDoc.getFileData({
xfdfString,
});
const arr = new Uint8Array(data);
const blob = new Blob([arr], { type: 'application/pdf' });
const docToInsert = await viewers[1].instance.Core.createDocument(blob, { extension: 'pdf', l: licenseKey });
dstDoc.insertPages(docToInsert, [1], 1);
};
// Download the PDF
const downloadPdf = async (instance) => {
// Get the filename from the document
let filename = instance.Core.documentViewer.getDocument().getFilename();
// Ensure it ends with .pdf. If not, replace it with .pdf extension
if (!filename.endsWith('.pdf'))
filename = filename.replace(/\.[^/.]+$/, '') + '.pdf';
// Set the options for downloading the PDF
const options = {
filename: filename,
flags: instance.Core.SaveOptions.LINEARIZED,
downloadType: 'pdf'
};
instance.UI.downloadPdf(options);
};
// Create and initialize the WebViewer instances with their configurations,
// as many viewers are defined in the viewers list
function createWebViewer(viewer) {
const element = document.createElement('div');
element.id = `WebViewer${viewer.style.alignment}`;
element.style.width = viewer.style.width;
element.style.height = viewer.style.height;
element.style.margin = viewer.style.margin;
element.style.float = viewer.style.alignment;
//find 'viewer' element in the body and append the viewer element to it
const viewerElement = document.getElementById('viewer');
if (!viewerElement) {
console.error('Viewer element not found! Make sure the template execution area is ready.');
return;
}
viewerElement.appendChild(element);
WebViewer(
{
path: '/lib',
initialDoc: viewer.initialDoc,
loadAsPDF: true,
enableFilePicker: true, // Enable file picker to open files. In WebViewer -> menu icon -> Open File
licenseKey: licenseKey,
},
element
).then(instance => {
// Enable merging pages feature from another WebViewer
instance.UI.enableFeatures(instance.UI.Feature.MultipleViewerMerging);
instance.Core.documentViewer.addEventListener('documentLoaded', () => {
// Open the thumbnails panel
instance.UI.openElements(['thumbnailsPanel']);
// Select the first page in the thumbnails panel
setTimeout(() => {
instance.UI.ThumbnailsPanel.selectPages([1]);
}, 500);
console.log(`✅ ${element.id} loaded successfully.`);
// Store the instance reference in the viewer object
viewer.instance = instance;
// customize WebViewer UI
customizeUI(viewer);
});
}).catch((error) => {
console.error(`❌ Failed to initialize ${element.id}:`, error);
});
}
// Create the defined viewers in the viewers list
viewers.forEach(viewer => {
createWebViewer(viewer);
});