// ES6 Compliant Syntax
// Copilot name: GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-10-16
// File: showcase-demos/online-flipbook/index.js
// Setting the path to the Web Worker JS file relative to the html file of the viewer
Core.setWorkerPath('../../lib/core');
//Set license key, source, and viewer element
const licenseKey = 'YOUR_WEBVIEWER_LICENSE_KEY';
const source = 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/WebviewerDemoDoc.pdf';
const viewer = document.getElementById('viewer');
// Create flipbook container
const flipbook = document.createElement('div');
flipbook.id = 'flipbook';
// Loading message
const loadingMessage = document.createElement('div');
loadingMessage.id = 'loading-message';
loadingMessage.style.position = 'absolute';
loadingMessage.innerHTML = 'Preparing document...';
flipbook.appendChild(loadingMessage);
viewer.appendChild(flipbook);
// Create navigation buttons for previous and next page
const previousButton = document.createElement('button');
previousButton.className = 'btn-style';
previousButton.id = 'previous';
previousButton.innerHTML = 'Previous Page';
previousButton.onclick = () => $('#flipbook').turn('previous');
const nextButton = document.createElement('button');
nextButton.className = 'btn-style';
nextButton.id = 'next';
nextButton.innerHTML = 'Next Page';
nextButton.onclick = () => $('#flipbook').turn('next');
// Container for buttons (file picker will be added after DocumentViewer is created)
const controlsContainer = document.createElement('div');
controlsContainer.className = 'button-container';
controlsContainer.appendChild(previousButton);
controlsContainer.appendChild(nextButton);
viewer.insertBefore(controlsContainer, viewer.firstChild);
// Create an instance of the DocumentViewer
const documentViewer = new Core.DocumentViewer();
// Set the viewer and scrollview elements that DocumentViewer will append rendered pages to.
const viewerElement = document.createElement('div');
documentViewer.setViewerElement(viewerElement);
documentViewer.setScrollViewElement(viewerElement);
documentViewer.loadAsPDF = true;
// Load the document with explicit extension and error handling
try {
documentViewer.loadDocument(source, { extension: 'pdf' });
} catch (error) {
console.error('Error loading default document:', error);
loadingMessage.innerHTML = `Error loading default document: ${error.message || 'Network failure'}. Please use the file picker to load a local document.`;
loadingMessage.style.color = 'red';
}
// Add error event listener for network failures
documentViewer.addEventListener('documentLoadingProgress', (progress) => {
if (loadingMessage && flipbook.contains(loadingMessage)) {
loadingMessage.innerHTML = `Loading document... ${Math.round(progress * 100)}%`;
}
});
documentViewer.addEventListener('loaderror', (error) => {
console.error('Document load error:', error);
if (loadingMessage) {
loadingMessage.innerHTML = `Failed to load document: ${error.message || 'Network failure'}. Please check your connection and try again.`;
loadingMessage.style.color = 'red';
}
});
// Event listener for when the document is fully loaded
documentViewer.addEventListener('documentLoaded', () => {
// Complete reset of flipbook container to virgin state
const $flipbook = $('#flipbook');
// Remove all turn.js data attributes
$flipbook.removeData(); // Clears all jQuery data
// Remove all turn.js CSS classes
$flipbook.removeClass(); // Remove all classes
// Remove all turn.js HTML attributes
const turnAttributes = [
'data-turn', 'data-turn-page', 'data-turn-pages', 'data-turn-size',
'data-turn-orig-width', 'data-turn-orig-height', 'data-turn-page-number',
'data-turn-direction', 'data-turn-when', 'data-turn-corners'
];
turnAttributes.forEach(attr => $flipbook[0].removeAttribute(attr));
// Reset inline styles to original state
$flipbook[0].style.cssText = 'transition: margin-left 0.2s ease-in-out; margin: 0px auto; width: 90%; height: 90%;';
// Clear all existing content from flipbook container
while (flipbook.firstChild) {
flipbook.removeChild(flipbook.firstChild);
}
// Re-add loading message
loadingMessage.innerHTML = 'Preparing document...';
loadingMessage.style.color = '';
flipbook.appendChild(loadingMessage);
console.log('Added loading message');
const doc = documentViewer.getDocument();
const info = doc.getPageInfo(1);
const width = info.width;
const height = info.height;
const pageCount = doc.getPageCount();
const promises = [];
const canvases = [];
const boundingRect = flipbook.getBoundingClientRect();
// Calculate flipbook dimensions based on page aspect ratio
let flipbookHeight = boundingRect.height;
let flipbookWidth = boundingRect.width;
if (((flipbookHeight * width) / height) * 2 < flipbookWidth)
flipbookWidth = ((flipbookHeight * width) / height) * 2;
else
flipbookHeight = ((flipbookWidth / width) * height) / 2;
// Load each page's canvas
for (let i = 0; i < pageCount; i++) {
const pageNumber = i + 1;
promises.push(
doc.requirePage(pageNumber).then(() => {
return new Promise(resolve => {
doc.loadCanvas({
pageNumber,
drawComplete: (canvas, index) => {
canvases.push({ index, canvas });
loadingMessage.innerHTML = `Loading page canvas... (${canvases.length}/${pageCount})`;
resolve();
},
});
});
})
);
}
// Once all pages are loaded, initialize the flipbook
Promise.all(promises).then(() => {
// Safely remove loading message if it exists as a child
if (flipbook.contains(loadingMessage)) {
flipbook.removeChild(loadingMessage);
} else {
console.log('Loading message was already removed or not found in flipbook');
}
if (canvases.length === 1) {
// Handle single-page documents without turn.js to avoid range errors
console.log('Single page document - displaying without flipbook functionality');
const canvas = canvases[0].canvas;
flipbook.appendChild(canvas);
// Hide navigation buttons for single page
console.log('Hiding buttons for single page document');
if (previousButton) {
previousButton.style.display = 'none';
console.log('Previous button hidden');
}
if (nextButton) {
nextButton.style.display = 'none';
console.log('Next button hidden');
}
} else {
// Handle multi-page documents with turn.js flipbook
// Wrap each canvas in a div for proper turn.js page structure
canvases.sort((a, b) => a.index - b.index).forEach((o, index) => {
const pageDiv = document.createElement('div');
// Add page number indicator
const pageNumber = document.createElement('div');
pageNumber.className = 'page-number';
pageNumber.textContent = `${index + 1}`;
pageDiv.appendChild(pageNumber);
pageDiv.appendChild(o.canvas);
flipbook.appendChild(pageDiv);
});
// Initialize turn.js
$('#flipbook').turn({
width: flipbookWidth,
height: flipbookHeight,
autoCenter: true,
pages: canvases.length,
page: 1,
elevation: 50,
gradients: true,
acceleration: true,
duration: 400,
shadows: true,
shadowBlur: 6,
});
// Show navigation buttons for multi-page
console.log('Showing buttons for multi-page document');
if (previousButton) {
previousButton.style.display = 'inline-block';
console.log('Previous button shown');
}
if (nextButton) {
nextButton.style.display = 'inline-block';
console.log('Next button shown');
}
// Automatically advance to page 2 to demonstrate flipbook
setTimeout(() => {
try {
$('#flipbook').turn('next');
} catch (error) {
console.error('Error navigating to next page:', error);
}
}, 500);
}
}).catch(error => {
console.error('Error loading flipbook pages:', error);
// Provide specific error messages based on error type
let errorMessage = 'Error loading pages. ';
if (error.message && error.message.includes('Network failure')) {
errorMessage += 'Network connection issue. Please check your internet connection and try again.';
} else if (error.message && error.message.includes('CORS')) {
errorMessage += 'File access issue. Try using a local file instead.';
} else {
errorMessage += `${error.message || 'Unknown error'}. Please try again with a different file.`;
}
loadingMessage.innerHTML = errorMessage;
loadingMessage.style.color = 'red';
});
});
// UI Elements
// ui-elements.js
// Function to create and initialize UI elements
function createUIElements() {
return new Promise((resolve, reject) => {
// Dynamically load ui-elements.js if not already loaded
if (window.UIElements) {
console.log('UIElements already loaded');
resolve();
return;
}
const script = document.createElement('script');
script.src = '/showcase-demos/online-flipbook/ui-elements.js';
script.onload = () => {
console.log('✅ UIElements script loaded successfully');
UIElements.init();
resolve();
};
script.onerror = () => {
console.error('Failed to load UIElements script');
reject(new Error('Failed to load ui-elements.js'));
};
document.head.appendChild(script);
});
}
// Create file picker button using UIElements class (async)
createUIElements().then(() => {
console.log('UIElements loaded successfully');
const filePickerButton = UIElements.createFilePickerButton(documentViewer, loadingMessage);
controlsContainer.appendChild(filePickerButton); // Add Pick File button to the right of Next Page
}).catch(error => {
console.error('Failed to load UIElements:', error);
});