{"version":3,"sources":["jsdelivr-header.js","/wp/plugins/maxtdesign-pdf-viewer/trunk/assets/js/mdpv-viewer.js"],"names":[],"mappings":"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","file":"/wp/plugins/maxtdesign-pdf-viewer/trunk/assets/js/mdpv-viewer.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.48.0.\n * Original file: /wp/plugins/maxtdesign-pdf-viewer/trunk/assets/js/mdpv-viewer.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/**\r\n * MaxtDesign PDF Viewer - Full Viewer Module\r\n *\r\n * Handles PDF.js initialization, document loading, and page rendering.\r\n * Dynamically imported by mdpv-loader.js when viewer is activated.\r\n *\r\n * @package MaxtDesign\\PDFViewer\r\n * @since 1.0.0\r\n */\r\n\r\n/**\r\n * CSS class names\r\n * @type {Object}\r\n */\r\nconst CLASSES = {\r\n\tviewer: 'mdpv-viewer',\r\n\tactive: 'mdpv-active',\r\n\tloading: 'mdpv-loading',\r\n\tloadingActive: 'mdpv-loading-active',\r\n\tpreview: 'mdpv-preview',\r\n\tactivate: 'mdpv-activate',\r\n\tcanvasContainer: 'mdpv-canvas-container',\r\n\tcanvas: 'mdpv-canvas',\r\n\ttoolbar: 'mdpv-toolbar',\r\n\ttoolbarGroup: 'mdpv-toolbar-group',\r\n\ttoolbarBtn: 'mdpv-toolbar-btn',\r\n\ttoolbarPageInfo: 'mdpv-toolbar-page-info',\r\n\ttoolbarPageInput: 'mdpv-toolbar-page-input',\r\n\ttoolbarZoom: 'mdpv-toolbar-zoom',\r\n\ttoolbarZoomLabel: 'mdpv-toolbar-zoom-label',\r\n\tfullscreen: 'mdpv-fullscreen',\r\n\terrorContainer: 'mdpv-error-container',\r\n\terrorMessage: 'mdpv-error-message',\r\n};\r\n\r\n/**\r\n * Default zoom levels\r\n * @type {number[]}\r\n */\r\nconst ZOOM_LEVELS = [ 0.5, 0.75, 1, 1.25, 1.5, 2, 3 ];\r\n\r\n/**\r\n * Default configuration\r\n * @type {Object}\r\n */\r\nconst DEFAULT_CONFIG = {\r\n\tpdfUrl: '',\r\n\tpdfId: 0,\r\n\tpageCount: 1,\r\n\tshowToolbar: true,\r\n\tshowDownload: true,\r\n\tshowPrint: true,\r\n\tshowFullscreen: true,\r\n\tworkerUrl: '',\r\n\ti18n: {},\r\n};\r\n\r\n/**\r\n * PDF.js library reference (loaded dynamically)\r\n * @type {Object|null}\r\n */\r\nlet pdfjsLib = null;\r\n\r\n/**\r\n * MDPVViewer Class\r\n *\r\n * Main viewer class that handles PDF rendering and interaction.\r\n */\r\nexport class MDPVViewer {\r\n\t/**\r\n\t * Create viewer instance\r\n\t *\r\n\t * @param {HTMLElement} container - Viewer container element\r\n\t * @param {Object} config - Viewer configuration\r\n\t */\r\n\tconstructor( container, config = {} ) {\r\n\t\t/** @type {HTMLElement} */\r\n\t\tthis.container = container;\r\n\r\n\t\t/** @type {Object} */\r\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\r\n\r\n\t\t/** @type {Object|null} PDF.js document instance */\r\n\t\tthis.pdfDoc = null;\r\n\r\n\t\t/** @type {number} Current page number (1-indexed) */\r\n\t\tthis.currentPage = 1;\r\n\r\n\t\t/** @type {number} Total page count */\r\n\t\tthis.totalPages = this.config.pageCount || 1;\r\n\r\n\t\t/** @type {number} Current zoom level */\r\n\t\tthis.scale = 1;\r\n\r\n\t\t/** @type {number} Current zoom level index */\r\n\t\tthis.zoomIndex = Math.max( 0, ZOOM_LEVELS.indexOf( 1 ) );\r\n\r\n\t\t/** @type {boolean} Is currently rendering */\r\n\t\tthis.isRendering = false;\r\n\r\n\t\t/** @type {Object|null} Current render task */\r\n\t\tthis.renderTask = null;\r\n\r\n\t\t/** @type {HTMLCanvasElement|null} */\r\n\t\tthis.canvas = null;\r\n\r\n\t\t/** @type {CanvasRenderingContext2D|null} */\r\n\t\tthis.ctx = null;\r\n\r\n\t\t/** @type {HTMLElement|null} */\r\n\t\tthis.canvasContainer = null;\r\n\r\n\t\t/** @type {HTMLElement|null} */\r\n\t\tthis.toolbar = null;\r\n\r\n\t\t/** @type {boolean} Is in fullscreen mode */\r\n\t\tthis.isFullscreen = false;\r\n\r\n\t\t/** @type {AbortController|null} For cleanup */\r\n\t\tthis.abortController = new AbortController();\r\n\r\n\t\t// Initialize\r\n\t\tthis.init();\r\n\t}\r\n\r\n\t/**\r\n\t * Initialize the viewer\r\n\t */\r\n\tasync init() {\r\n\t\ttry {\r\n\t\t\t// Load PDF.js library\r\n\t\t\tawait this.loadPdfJs();\r\n\r\n\t\t\t// Set up the viewer UI\r\n\t\t\tthis.setupUI();\r\n\r\n\t\t\t// Load the PDF document\r\n\t\t\tawait this.loadDocument();\r\n\r\n\t\t\t// Render first page\r\n\t\t\tawait this.renderPage( this.currentPage );\r\n\r\n\t\t\t// Mark as active\r\n\t\t\tthis.container.classList.add( CLASSES.active );\r\n\t\t\tthis.container.classList.remove( CLASSES.loadingActive );\r\n\r\n\t\t\t// Hide loading indicator\r\n\t\t\tthis.hideLoading();\r\n\r\n\t\t\t// Set up event listeners\r\n\t\t\tthis.setupEventListeners();\r\n\r\n\t\t\t// Focus for keyboard navigation\r\n\t\t\tthis.container.setAttribute( 'tabindex', '0' );\r\n\t\t\tthis.container.setAttribute( 'role', 'application' );\r\n\t\t\tthis.container.setAttribute( 'aria-label', this.config.i18n.viewerLabel || 'PDF Viewer - Use arrow keys to navigate pages' );\r\n\t\t\t\r\n\t\t\t// Focus the container\r\n\t\t\tthis.container.focus({ preventScroll: true });\r\n\r\n\t\t\t// Re-focus on click anywhere in viewer\r\n\t\t\tthis.container.addEventListener( 'click', () => {\r\n\t\t\t\tif ( document.activeElement !== this.container && \r\n\t\t\t\t\t ! this.container.contains( document.activeElement ) ) {\r\n\t\t\t\t\tthis.container.focus({ preventScroll: true });\r\n\t\t\t\t}\r\n\t\t\t}, { signal: this.abortController.signal } );\r\n\t\t} catch ( error ) {\r\n\t\t\tconsole.error( '[MDPV Viewer] Initialization failed:', error );\r\n\t\t\tthis.showError( error.message || this.config.i18n.error || 'Failed to load document' );\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Load PDF.js library dynamically\r\n\t */\r\n\tasync loadPdfJs() {\r\n\t\tif ( pdfjsLib ) {\r\n\t\t\treturn; // Already loaded\r\n\t\t}\r\n\r\n\t\t// Try to get PDF.js URL from config, or construct from plugin URL\r\n\t\tlet pdfJsUrl = this.config.pdfjsUrl;\r\n\t\tif ( ! pdfJsUrl ) {\r\n\t\t\tconst pluginUrl = this.config.pluginUrl || window.mdpvConfig?.pluginUrl || '';\r\n\t\t\tpdfJsUrl = pluginUrl + 'vendor/pdfjs/pdf.min.mjs';\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst module = await import( pdfJsUrl );\r\n\t\t\tpdfjsLib = module;\r\n\r\n\t\t\t// Set worker path\r\n\t\t\tlet workerUrl = this.config.workerUrl;\r\n\t\t\tif ( ! workerUrl ) {\r\n\t\t\t\t// Try to construct from pdfjsUrl or pluginUrl\r\n\t\t\t\tif ( this.config.pdfjsUrl ) {\r\n\t\t\t\t\tworkerUrl = this.config.pdfjsUrl.replace( 'pdf.min.mjs', 'pdf.worker.min.mjs' );\r\n\t\t\t\t} else {\r\n\t\t\t\t\tconst pluginUrl = this.config.pluginUrl || window.mdpvConfig?.pluginUrl || '';\r\n\t\t\t\t\tworkerUrl = pluginUrl + 'vendor/pdfjs/pdf.worker.min.mjs';\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tpdfjsLib.GlobalWorkerOptions.workerSrc = workerUrl;\r\n\t\t} catch ( error ) {\r\n\t\t\tconsole.error( '[MDPV Viewer] Failed to load PDF.js:', error );\r\n\t\t\tthrow new Error( this.config.i18n.loadError || 'Failed to load PDF viewer library' );\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Load the PDF document\r\n\t */\r\n\tasync loadDocument() {\r\n\t\tif ( ! this.config.pdfUrl ) {\r\n\t\t\tthrow new Error( 'No PDF URL provided' );\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst documentOptions = {\r\n\t\t\t\turl: this.config.pdfUrl,\r\n\t\t\t\tcMapPacked: true,\r\n\t\t\t};\r\n\r\n\t\t\t// Use local cmaps URL if available, otherwise PDF.js will handle it\r\n\t\t\tif ( this.config.cmapsUrl ) {\r\n\t\t\t\tdocumentOptions.cMapUrl = this.config.cmapsUrl;\r\n\t\t\t}\r\n\r\n\t\t\tconst loadingTask = pdfjsLib.getDocument( documentOptions );\r\n\r\n\t\t\tthis.pdfDoc = await loadingTask.promise;\r\n\t\t\tthis.totalPages = this.pdfDoc.numPages;\r\n\r\n\t\t\t// Update toolbar if already created\r\n\t\t\tthis.updateToolbarPageInfo();\r\n\t\t} catch ( error ) {\r\n\t\t\tconsole.error( '[MDPV Viewer] Failed to load document:', error );\r\n\r\n\t\t\tif ( error.name === 'PasswordException' ) {\r\n\t\t\t\tthrow new Error( this.config.i18n.passwordRequired || 'This PDF requires a password' );\r\n\t\t\t}\r\n\r\n\t\t\tthrow new Error( this.config.i18n.error || 'Failed to load document' );\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Set up viewer UI elements\r\n\t */\r\n\tsetupUI() {\r\n\t\t// Create canvas container\r\n\t\tthis.canvasContainer = document.createElement( 'div' );\r\n\t\tthis.canvasContainer.className = CLASSES.canvasContainer;\r\n\r\n\t\t// Create canvas\r\n\t\tthis.canvas = document.createElement( 'canvas' );\r\n\t\tthis.canvas.className = CLASSES.canvas;\r\n\t\tthis.ctx = this.canvas.getContext( '2d' );\r\n\r\n\t\tthis.canvasContainer.appendChild( this.canvas );\r\n\t\tthis.container.appendChild( this.canvasContainer );\r\n\r\n\t\t// Create toolbar if enabled\r\n\t\tif ( this.config.showToolbar ) {\r\n\t\t\tthis.createToolbar();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Create toolbar element\r\n\t */\r\n\tcreateToolbar() {\r\n\t\tthis.toolbar = document.createElement( 'div' );\r\n\t\tthis.toolbar.className = CLASSES.toolbar;\r\n\t\tthis.toolbar.setAttribute( 'role', 'toolbar' );\r\n\t\tthis.toolbar.setAttribute( 'aria-label', this.config.i18n.toolbar || 'PDF Controls' );\r\n\r\n\t\t// Left group: Navigation\r\n\t\tconst navGroup = this.createToolbarGroup();\r\n\t\t\r\n\t\t// Previous page button\r\n\t\tnavGroup.appendChild( this.createToolbarButton(\r\n\t\t\t'prev',\r\n\t\t\tthis.config.i18n.prevPage || 'Previous page',\r\n\t\t\tthis.getIcon( 'chevronLeft' ),\r\n\t\t\t() => this.prevPage()\r\n\t\t) );\r\n\r\n\t\t// Page info\r\n\t\tnavGroup.appendChild( this.createPageInfo() );\r\n\r\n\t\t// Next page button\r\n\t\tnavGroup.appendChild( this.createToolbarButton(\r\n\t\t\t'next',\r\n\t\t\tthis.config.i18n.nextPage || 'Next page',\r\n\t\t\tthis.getIcon( 'chevronRight' ),\r\n\t\t\t() => this.nextPage()\r\n\t\t) );\r\n\r\n\t\tthis.toolbar.appendChild( navGroup );\r\n\r\n\t\t// Center group: Zoom\r\n\t\tconst zoomGroup = this.createToolbarGroup();\r\n\t\tzoomGroup.classList.add( CLASSES.toolbarZoom );\r\n\r\n\t\t// Zoom out button\r\n\t\tzoomGroup.appendChild( this.createToolbarButton(\r\n\t\t\t'zoomOut',\r\n\t\t\tthis.config.i18n.zoomOut || 'Zoom out',\r\n\t\t\tthis.getIcon( 'minus' ),\r\n\t\t\t() => this.zoomOut()\r\n\t\t) );\r\n\r\n\t\t// Zoom label\r\n\t\tconst zoomLabel = document.createElement( 'span' );\r\n\t\tzoomLabel.className = CLASSES.toolbarZoomLabel;\r\n\t\tzoomLabel.id = 'mdpv-zoom-label-' + this.config.pdfId;\r\n\t\tzoomLabel.textContent = Math.round( this.scale * 100 ) + '%';\r\n\t\tzoomGroup.appendChild( zoomLabel );\r\n\t\tthis.zoomLabel = zoomLabel;\r\n\r\n\t\t// Zoom in button\r\n\t\tzoomGroup.appendChild( this.createToolbarButton(\r\n\t\t\t'zoomIn',\r\n\t\t\tthis.config.i18n.zoomIn || 'Zoom in',\r\n\t\t\tthis.getIcon( 'plus' ),\r\n\t\t\t() => this.zoomIn()\r\n\t\t) );\r\n\r\n\t\tthis.toolbar.appendChild( zoomGroup );\r\n\r\n\t\t// Right group: Actions\r\n\t\tconst actionsGroup = this.createToolbarGroup();\r\n\r\n\t\t// Download button\r\n\t\tif ( this.config.showDownload ) {\r\n\t\t\tactionsGroup.appendChild( this.createToolbarButton(\r\n\t\t\t\t'download',\r\n\t\t\t\tthis.config.i18n.download || 'Download',\r\n\t\t\t\tthis.getIcon( 'download' ),\r\n\t\t\t\t() => this.download()\r\n\t\t\t) );\r\n\t\t}\r\n\r\n\t\t// Print button\r\n\t\tif ( this.config.showPrint ) {\r\n\t\t\tactionsGroup.appendChild( this.createToolbarButton(\r\n\t\t\t\t'print',\r\n\t\t\t\tthis.config.i18n.print || 'Print',\r\n\t\t\t\tthis.getIcon( 'print' ),\r\n\t\t\t\t() => this.print()\r\n\t\t\t) );\r\n\t\t}\r\n\r\n\t\t// Fullscreen button\r\n\t\tif ( this.config.showFullscreen ) {\r\n\t\t\tconst fsBtn = this.createToolbarButton(\r\n\t\t\t\t'fullscreen',\r\n\t\t\t\tthis.config.i18n.fullscreen || 'Fullscreen',\r\n\t\t\t\tthis.getIcon( 'fullscreen' ),\r\n\t\t\t\t() => this.toggleFullscreen()\r\n\t\t\t);\r\n\t\t\tthis.fullscreenBtn = fsBtn;\r\n\t\t\tactionsGroup.appendChild( fsBtn );\r\n\t\t}\r\n\r\n\t\tthis.toolbar.appendChild( actionsGroup );\r\n\r\n\t\t// Add to container\r\n\t\tthis.container.appendChild( this.toolbar );\r\n\r\n\t\t// Initialize button states\r\n\t\tthis.updateNavigationButtons();\r\n\t\tthis.updateZoomLabel();\r\n\t}\r\n\r\n\t/**\r\n\t * Create toolbar button group\r\n\t *\r\n\t * @returns {HTMLElement} Group element\r\n\t */\r\n\tcreateToolbarGroup() {\r\n\t\tconst group = document.createElement( 'div' );\r\n\t\tgroup.className = CLASSES.toolbarGroup;\r\n\t\tgroup.setAttribute( 'role', 'group' );\r\n\t\treturn group;\r\n\t}\r\n\r\n\t/**\r\n\t * Create toolbar button\r\n\t *\r\n\t * @param {string} name - Button name for identification\r\n\t * @param {string} label - Accessible label\r\n\t * @param {string} iconSvg - SVG icon HTML\r\n\t * @param {Function} onClick - Click handler\r\n\t * @returns {HTMLButtonElement} Button element\r\n\t */\r\n\tcreateToolbarButton( name, label, iconSvg, onClick ) {\r\n\t\tconst button = document.createElement( 'button' );\r\n\t\tbutton.type = 'button';\r\n\t\tbutton.className = CLASSES.toolbarBtn;\r\n\t\tbutton.setAttribute( 'aria-label', label );\r\n\t\tbutton.setAttribute( 'title', label );\r\n\t\tbutton.dataset.action = name;\r\n\t\tbutton.innerHTML = iconSvg;\r\n\r\n\t\tbutton.addEventListener( 'click', onClick, { \r\n\t\t\tsignal: this.abortController.signal \r\n\t\t} );\r\n\r\n\t\treturn button;\r\n\t}\r\n\r\n\t/**\r\n\t * Create page info element\r\n\t *\r\n\t * @returns {HTMLElement} Page info element\r\n\t */\r\n\tcreatePageInfo() {\r\n\t\tconst pageInfo = document.createElement( 'div' );\r\n\t\tpageInfo.className = CLASSES.toolbarPageInfo;\r\n\r\n\t\t// Page input\r\n\t\tconst pageInput = document.createElement( 'input' );\r\n\t\tpageInput.type = 'number';\r\n\t\tpageInput.className = CLASSES.toolbarPageInput;\r\n\t\tpageInput.min = '1';\r\n\t\tpageInput.max = String( this.totalPages );\r\n\t\tpageInput.value = String( this.currentPage );\r\n\t\tpageInput.setAttribute( 'aria-label', this.config.i18n.page || 'Page number' );\r\n\t\t\r\n\t\tpageInput.addEventListener( 'change', ( e ) => {\r\n\t\t\tthis.goToPage( e.target.value );\r\n\t\t}, { signal: this.abortController.signal } );\r\n\r\n\t\tpageInput.addEventListener( 'keydown', ( e ) => {\r\n\t\t\tif ( e.key === 'Enter' ) {\r\n\t\t\t\tthis.goToPage( e.target.value );\r\n\t\t\t\te.target.blur();\r\n\t\t\t}\r\n\t\t}, { signal: this.abortController.signal } );\r\n\r\n\t\tthis.pageInput = pageInput;\r\n\r\n\t\t// \"of X\" text\r\n\t\tconst ofText = document.createElement( 'span' );\r\n\t\tofText.textContent = ` ${this.config.i18n.of || 'of'} `;\r\n\r\n\t\tconst totalSpan = document.createElement( 'span' );\r\n\t\ttotalSpan.textContent = String( this.totalPages );\r\n\t\tthis.totalPagesSpan = totalSpan;\r\n\r\n\t\tpageInfo.appendChild( pageInput );\r\n\t\tpageInfo.appendChild( ofText );\r\n\t\tpageInfo.appendChild( totalSpan );\r\n\r\n\t\treturn pageInfo;\r\n\t}\r\n\r\n\t/**\r\n\t * Render a specific page\r\n\t *\r\n\t * @param {number} pageNum - Page number (1-indexed)\r\n\t */\r\n\tasync renderPage( pageNum ) {\r\n\t\tif ( ! this.pdfDoc || this.isRendering ) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Validate page number\r\n\t\tpageNum = Math.max( 1, Math.min( pageNum, this.totalPages ) );\r\n\t\tthis.currentPage = pageNum;\r\n\r\n\t\tthis.isRendering = true;\r\n\r\n\t\ttry {\r\n\t\t\t// Cancel any existing render\r\n\t\t\tif ( this.renderTask ) {\r\n\t\t\t\tthis.renderTask.cancel();\r\n\t\t\t\tthis.renderTask = null;\r\n\t\t\t}\r\n\r\n\t\t\t// Get the page\r\n\t\t\tconst page = await this.pdfDoc.getPage( pageNum );\r\n\r\n\t\t\t// Calculate scale based on container width\r\n\t\t\tconst containerWidth = this.canvasContainer.clientWidth;\r\n\t\t\tconst viewport = page.getViewport( { scale: 1 } );\r\n\r\n\t\t\t// Calculate scale to fit width, then apply zoom\r\n\t\t\tconst baseScale = containerWidth / viewport.width;\r\n\t\t\tconst scaledViewport = page.getViewport( { scale: baseScale * this.scale } );\r\n\r\n\t\t\t// Set canvas dimensions\r\n\t\t\tthis.canvas.width = scaledViewport.width;\r\n\t\t\tthis.canvas.height = scaledViewport.height;\r\n\r\n\t\t\t// Render the page\r\n\t\t\tconst renderContext = {\r\n\t\t\t\tcanvasContext: this.ctx,\r\n\t\t\t\tviewport: scaledViewport,\r\n\t\t\t};\r\n\r\n\t\t\tthis.renderTask = page.render( renderContext );\r\n\t\t\tawait this.renderTask.promise;\r\n\r\n\t\t\tthis.renderTask = null;\r\n\r\n\t\t\t// Update toolbar\r\n\t\t\tthis.updateToolbarPageInfo();\r\n\t\t} catch ( error ) {\r\n\t\t\tif ( error.name !== 'RenderingCancelledException' ) {\r\n\t\t\t\tconsole.error( '[MDPV Viewer] Render failed:', error );\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tthis.isRendering = false;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Go to previous page\r\n\t */\r\n\tprevPage() {\r\n\t\tif ( this.currentPage > 1 ) {\r\n\t\t\tthis.renderPage( this.currentPage - 1 );\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Go to next page\r\n\t */\r\n\tnextPage() {\r\n\t\tif ( this.currentPage < this.totalPages ) {\r\n\t\t\tthis.renderPage( this.currentPage + 1 );\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Go to specific page\r\n\t *\r\n\t * @param {number} pageNum - Page number\r\n\t */\r\n\tgoToPage( pageNum ) {\r\n\t\tconst num = parseInt( pageNum, 10 );\r\n\t\tif ( ! isNaN( num ) && num >= 1 && num <= this.totalPages ) {\r\n\t\t\tthis.renderPage( num );\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Zoom in\r\n\t */\r\n\tzoomIn() {\r\n\t\tif ( this.zoomIndex < ZOOM_LEVELS.length - 1 ) {\r\n\t\t\tthis.zoomIndex++;\r\n\t\t\tthis.scale = ZOOM_LEVELS[ this.zoomIndex ];\r\n\t\t\tthis.renderPage( this.currentPage );\r\n\t\t\tthis.updateZoomLabel();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Zoom out\r\n\t */\r\n\tzoomOut() {\r\n\t\tif ( this.zoomIndex > 0 ) {\r\n\t\t\tthis.zoomIndex--;\r\n\t\t\tthis.scale = ZOOM_LEVELS[ this.zoomIndex ];\r\n\t\t\tthis.renderPage( this.currentPage );\r\n\t\t\tthis.updateZoomLabel();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Set specific zoom level\r\n\t *\r\n\t * @param {number} scale - Zoom scale (0.5 to 3)\r\n\t */\r\n\tsetZoom( scale ) {\r\n\t\tthis.scale = Math.max( 0.5, Math.min( 3, scale ) );\r\n\t\t// Find closest zoom level index\r\n\t\tconst foundIndex = ZOOM_LEVELS.findIndex( z => z >= this.scale );\r\n\t\tthis.zoomIndex = foundIndex >= 0 ? foundIndex : ZOOM_LEVELS.length - 1;\r\n\t\tthis.renderPage( this.currentPage );\r\n\t\tthis.updateZoomLabel();\r\n\t}\r\n\r\n\t/**\r\n\t * Download the PDF\r\n\t */\r\n\tdownload() {\r\n\t\tconst link = document.createElement( 'a' );\r\n\t\tlink.href = this.config.pdfUrl;\r\n\t\tlink.download = this.getFilename();\r\n\t\tlink.click();\r\n\t}\r\n\r\n\t/**\r\n\t * Print the PDF\r\n\t */\r\n\tprint() {\r\n\t\t// Open PDF in new window for printing\r\n\t\tconst printWindow = window.open( this.config.pdfUrl, '_blank' );\r\n\t\tif ( printWindow ) {\r\n\t\t\tprintWindow.addEventListener( 'load', () => {\r\n\t\t\t\tprintWindow.print();\r\n\t\t\t} );\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Get SVG icon by name\r\n\t *\r\n\t * @param {string} name - Icon name\r\n\t * @returns {string} SVG HTML\r\n\t */\r\n\tgetIcon( name ) {\r\n\t\tconst icons = {\r\n\t\t\tchevronLeft: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"15 18 9 12 15 6\"></polyline></svg>`,\r\n\r\n\t\t\tchevronRight: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"9 18 15 12 9 6\"></polyline></svg>`,\r\n\r\n\t\t\tminus: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line></svg>`,\r\n\r\n\t\t\tplus: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line></svg>`,\r\n\r\n\t\t\tdownload: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"></path><polyline points=\"7 10 12 15 17 10\"></polyline><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"></line></svg>`,\r\n\r\n\t\t\tprint: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"6 9 6 2 18 2 18 9\"></polyline><path d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2\"></path><rect x=\"6\" y=\"14\" width=\"12\" height=\"8\"></rect></svg>`,\r\n\r\n\t\t\tfullscreen: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"15 3 21 3 21 9\"></polyline><polyline points=\"9 21 3 21 3 15\"></polyline><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"></line><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"></line></svg>`,\r\n\r\n\t\t\texitFullscreen: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><polyline points=\"4 14 10 14 10 20\"></polyline><polyline points=\"20 10 14 10 14 4\"></polyline><line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\"></line><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"></line></svg>`,\r\n\r\n\t\t};\r\n\r\n\t\treturn icons[ name ] || '';\r\n\t}\r\n\r\n\t/**\r\n\t * Toggle fullscreen mode\r\n\t */\r\n\ttoggleFullscreen() {\r\n\t\tif ( this.isFullscreen ) {\r\n\t\t\tthis.exitFullscreen();\r\n\t\t} else {\r\n\t\t\tthis.enterFullscreen();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Enter fullscreen mode\r\n\t */\r\n\tenterFullscreen() {\r\n\t\t// Check if already in fullscreen\r\n\t\tif ( this.isFullscreen ) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// Check if fullscreen is available\r\n\t\tif ( ! document.fullscreenEnabled && \r\n\t\t\t ! document.webkitFullscreenEnabled && \r\n\t\t\t ! document.msFullscreenEnabled ) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet promise = null;\r\n\r\n\t\ttry {\r\n\t\t\tif ( this.container.requestFullscreen ) {\r\n\t\t\t\tpromise = this.container.requestFullscreen();\r\n\t\t\t} else if ( this.container.webkitRequestFullscreen ) {\r\n\t\t\t\tpromise = this.container.webkitRequestFullscreen();\r\n\t\t\t} else if ( this.container.msRequestFullscreen ) {\r\n\t\t\t\tpromise = this.container.msRequestFullscreen();\r\n\t\t\t}\r\n\r\n\t\t\t// Handle promise rejection silently (browser may reject if not user-initiated)\r\n\t\t\tif ( promise && typeof promise.catch === 'function' ) {\r\n\t\t\t\tpromise.catch( ( error ) => {\r\n\t\t\t\t\t// Silently handle rejection - fullscreen may not be available\r\n\t\t\t\t\t// or may require a direct user interaction in some contexts\r\n\t\t\t\t\t// Don't log to console to avoid cluttering\r\n\t\t\t\t} );\r\n\t\t\t}\r\n\t\t} catch ( error ) {\r\n\t\t\t// Silently handle synchronous errors (e.g., \"API can only be initiated by a user gesture\")\r\n\t\t\t// The fullscreenchange event will still fire if fullscreen succeeds via other means\r\n\t\t\t// Suppress console output by not re-throwing or logging\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Exit fullscreen mode\r\n\t */\r\n\texitFullscreen() {\r\n\t\t// Check if not in fullscreen\r\n\t\tif ( ! this.isFullscreen ) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tlet promise = null;\r\n\r\n\t\ttry {\r\n\t\t\tif ( document.exitFullscreen ) {\r\n\t\t\t\tpromise = document.exitFullscreen();\r\n\t\t\t} else if ( document.webkitExitFullscreen ) {\r\n\t\t\t\tpromise = document.webkitExitFullscreen();\r\n\t\t\t} else if ( document.msExitFullscreen ) {\r\n\t\t\t\tpromise = document.msExitFullscreen();\r\n\t\t\t}\r\n\r\n\t\t\t// Handle promise rejection silently\r\n\t\t\tif ( promise && typeof promise.catch === 'function' ) {\r\n\t\t\t\tpromise.catch( () => {\r\n\t\t\t\t\t// Silently handle rejection\r\n\t\t\t\t} );\r\n\t\t\t}\r\n\t\t} catch ( error ) {\r\n\t\t\t// Silently handle synchronous errors\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Handle fullscreen change\r\n\t */\r\n\thandleFullscreenChange() {\r\n\t\tthis.isFullscreen = !! (\r\n\t\t\tdocument.fullscreenElement ||\r\n\t\t\tdocument.webkitFullscreenElement ||\r\n\t\t\tdocument.msFullscreenElement\r\n\t\t);\r\n\r\n\t\tthis.container.classList.toggle( CLASSES.fullscreen, this.isFullscreen );\r\n\r\n\t\t// Update fullscreen button icon\r\n\t\tthis.updateFullscreenButton();\r\n\r\n\t\t// Re-render at new size\r\n\t\tsetTimeout( () => {\r\n\t\t\tthis.renderPage( this.currentPage );\r\n\t\t}, 100 );\r\n\t}\r\n\r\n\t/**\r\n\t * Update fullscreen button icon\r\n\t */\r\n\tupdateFullscreenButton() {\r\n\t\tif ( ! this.fullscreenBtn ) return;\r\n\r\n\t\tconst icon = this.isFullscreen \r\n\t\t\t? this.getIcon( 'exitFullscreen' )\r\n\t\t\t: this.getIcon( 'fullscreen' );\r\n\t\t\r\n\t\tconst label = this.isFullscreen\r\n\t\t\t? ( this.config.i18n.exitFullscreen || 'Exit fullscreen' )\r\n\t\t\t: ( this.config.i18n.fullscreen || 'Fullscreen' );\r\n\r\n\t\tthis.fullscreenBtn.innerHTML = icon;\r\n\t\tthis.fullscreenBtn.setAttribute( 'aria-label', label );\r\n\t\tthis.fullscreenBtn.setAttribute( 'title', label );\r\n\t}\r\n\r\n\t/**\r\n\t * Set up event listeners\r\n\t */\r\n\tsetupEventListeners() {\r\n\t\tconst signal = this.abortController.signal;\r\n\r\n\t\t// Keyboard navigation - use capture phase to intercept before browser\r\n\t\tthis.container.addEventListener( \r\n\t\t\t'keydown', \r\n\t\t\t( e ) => this.handleKeydown( e ), \r\n\t\t\t{ signal, capture: true } \r\n\t\t);\r\n\r\n\t\t// Also listen on document for when viewer is \"active\" but not focused\r\n\t\tdocument.addEventListener(\r\n\t\t\t'keydown',\r\n\t\t\t( e ) => {\r\n\t\t\t\t// Only handle if this viewer is active and visible\r\n\t\t\t\tif ( this.container.classList.contains( CLASSES.active ) && this.isViewerVisible() ) {\r\n\t\t\t\t\tthis.handleKeydown( e );\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t{ signal }\r\n\t\t);\r\n\r\n\t\t// Fullscreen change events\r\n\t\tdocument.addEventListener( 'fullscreenchange', () => this.handleFullscreenChange(), { signal } );\r\n\t\tdocument.addEventListener( 'webkitfullscreenchange', () => this.handleFullscreenChange(), { signal } );\r\n\t\tdocument.addEventListener( 'msfullscreenchange', () => this.handleFullscreenChange(), { signal } );\r\n\r\n\t\t// Window resize - re-render at new size\r\n\t\twindow.addEventListener( 'resize', () => this.handleResize(), { signal } );\r\n\r\n\t\t// Mouse wheel zoom\r\n\t\tthis.container.addEventListener( 'wheel', ( e ) => this.handleWheel( e ), { signal, passive: false } );\r\n\r\n\t\t// Touch events for mobile\r\n\t\tthis.setupTouchEvents();\r\n\t}\r\n\r\n\t/**\r\n\t * Handle keyboard events\r\n\t *\r\n\t * @param {KeyboardEvent} e - Keyboard event\r\n\t */\r\n\thandleKeydown( e ) {\r\n\t\t// Don't handle if focus is in input field\r\n\t\tif ( e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' ) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst key = e.key;\r\n\t\tconst code = e.code;\r\n\t\tconst ctrlOrCmd = e.ctrlKey || e.metaKey;\r\n\r\n\t\t// Handle Ctrl/Cmd combinations first (must preventDefault immediately)\r\n\t\tif ( ctrlOrCmd ) {\r\n\t\t\tswitch ( code ) {\r\n\t\t\t\tcase 'Equal':      // Plus key (=/+)\r\n\t\t\t\tcase 'NumpadAdd':  // Numpad +\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\tthis.zoomIn();\r\n\t\t\t\t\treturn;\r\n\r\n\t\t\t\tcase 'Minus':       // Minus key (-/_)\r\n\t\t\t\tcase 'NumpadSubtract': // Numpad -\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\tthis.zoomOut();\r\n\t\t\t\t\treturn;\r\n\r\n\t\t\t\tcase 'Digit0':     // Zero key\r\n\t\t\t\tcase 'Numpad0':    // Numpad 0\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\tthis.setZoom( 1 ); // Reset to 100%\r\n\t\t\t\t\treturn;\r\n\r\n\t\t\t\tcase 'KeyS':       // S key\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\tthis.download();\r\n\t\t\t\t\treturn;\r\n\r\n\t\t\t\tcase 'KeyP':       // P key\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\tthis.print();\r\n\t\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Handle non-modifier keys\r\n\t\tswitch ( key ) {\r\n\t\t\tcase 'ArrowLeft':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.prevPage();\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'ArrowRight':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.nextPage();\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'ArrowUp':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.prevPage();\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'ArrowDown':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.nextPage();\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'PageUp':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.prevPage();\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'PageDown':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.nextPage();\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase ' ': // Space bar\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.nextPage();\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'Home':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.goToPage( 1 );\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'End':\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tthis.goToPage( this.totalPages );\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'f':\r\n\t\t\tcase 'F':\r\n\t\t\t\t// Only if not combined with Ctrl/Cmd (Ctrl+F is browser find)\r\n\t\t\t\tif ( ! ctrlOrCmd ) {\r\n\t\t\t\t\te.preventDefault();\r\n\t\t\t\t\te.stopPropagation();\r\n\t\t\t\t\t// Call fullscreen directly within the user gesture event handler\r\n\t\t\t\t\t// to ensure it's recognized as a user-initiated action\r\n\t\t\t\t\tthis.toggleFullscreen();\r\n\t\t\t\t}\r\n\t\t\t\tbreak;\r\n\r\n\t\t\tcase 'Escape':\r\n\t\t\t\t// Let browser handle Escape for exiting fullscreen\r\n\t\t\t\t// We just track the state change via fullscreenchange event\r\n\t\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Check if viewer is visible in viewport\r\n\t *\r\n\t * @returns {boolean} True if viewer is visible\r\n\t */\r\n\tisViewerVisible() {\r\n\t\tconst rect = this.container.getBoundingClientRect();\r\n\t\tconst windowHeight = window.innerHeight || document.documentElement.clientHeight;\r\n\t\tconst windowWidth = window.innerWidth || document.documentElement.clientWidth;\r\n\r\n\t\t// Check if at least 50% of the viewer is visible\r\n\t\tconst verticalVisible = rect.top < windowHeight && rect.bottom > 0;\r\n\t\tconst horizontalVisible = rect.left < windowWidth && rect.right > 0;\r\n\r\n\t\treturn verticalVisible && horizontalVisible;\r\n\t}\r\n\r\n\t/**\r\n\t * Handle window resize\r\n\t */\r\n\thandleResize() {\r\n\t\tconst debouncedResize = this.debounce( () => {\r\n\t\t\tif ( ! this.isRendering ) {\r\n\t\t\t\tthis.renderPage( this.currentPage );\r\n\t\t\t}\r\n\t\t}, 250 );\r\n\r\n\t\tdebouncedResize();\r\n\t}\r\n\r\n\t/**\r\n\t * Handle mouse wheel for zoom\r\n\t *\r\n\t * @param {WheelEvent} e - Wheel event\r\n\t */\r\n\thandleWheel( e ) {\r\n\t\t// Only zoom if Ctrl/Cmd key is held\r\n\t\tif ( ! ( e.ctrlKey || e.metaKey ) ) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\te.preventDefault();\r\n\r\n\t\tif ( e.deltaY < 0 ) {\r\n\t\t\tthis.zoomIn();\r\n\t\t} else if ( e.deltaY > 0 ) {\r\n\t\t\tthis.zoomOut();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Set up touch events for mobile navigation and zoom\r\n\t */\r\n\tsetupTouchEvents() {\r\n\t\tconst signal = this.abortController.signal;\r\n\r\n\t\tlet touchStartDistance = 0;\r\n\t\tlet touchStartScale = this.scale;\r\n\t\tlet lastTouchTime = 0;\r\n\t\tlet touchStartX = 0;\r\n\t\tlet touchStartY = 0;\r\n\r\n\t\t// Handle touch start\r\n\t\tthis.container.addEventListener( 'touchstart', ( e ) => {\r\n\t\t\tif ( e.touches.length === 2 ) {\r\n\t\t\t\t// Pinch zoom\r\n\t\t\t\tconst touch1 = e.touches[ 0 ];\r\n\t\t\t\tconst touch2 = e.touches[ 1 ];\r\n\t\t\t\ttouchStartDistance = Math.hypot(\r\n\t\t\t\t\ttouch2.clientX - touch1.clientX,\r\n\t\t\t\t\ttouch2.clientY - touch1.clientY\r\n\t\t\t\t);\r\n\t\t\t\ttouchStartScale = this.scale;\r\n\t\t\t} else if ( e.touches.length === 1 ) {\r\n\t\t\t\t// Single touch for swipe\r\n\t\t\t\ttouchStartX = e.touches[ 0 ].clientX;\r\n\t\t\t\ttouchStartY = e.touches[ 0 ].clientY;\r\n\t\t\t\tlastTouchTime = Date.now();\r\n\t\t\t}\r\n\t\t}, { signal, passive: true } );\r\n\r\n\t\t// Handle touch move\r\n\t\tthis.container.addEventListener( 'touchmove', ( e ) => {\r\n\t\t\tif ( e.touches.length === 2 ) {\r\n\t\t\t\t// Pinch zoom\r\n\t\t\t\te.preventDefault();\r\n\t\t\t\tconst touch1 = e.touches[ 0 ];\r\n\t\t\t\tconst touch2 = e.touches[ 1 ];\r\n\t\t\t\tconst currentDistance = Math.hypot(\r\n\t\t\t\t\ttouch2.clientX - touch1.clientX,\r\n\t\t\t\t\ttouch2.clientY - touch1.clientY\r\n\t\t\t\t);\r\n\r\n\t\t\t\tconst scaleChange = currentDistance / touchStartDistance;\r\n\t\t\t\tconst newScale = touchStartScale * scaleChange;\r\n\t\t\t\tthis.setZoom( newScale );\r\n\t\t\t}\r\n\t\t}, { signal, passive: false } );\r\n\r\n\t\t// Handle touch end\r\n\t\tthis.container.addEventListener( 'touchend', ( e ) => {\r\n\t\t\tif ( e.changedTouches.length === 1 && e.touches.length === 0 ) {\r\n\t\t\t\t// Single touch ended - check for swipe\r\n\t\t\t\tconst touch = e.changedTouches[ 0 ];\r\n\t\t\t\tconst deltaX = touch.clientX - touchStartX;\r\n\t\t\t\tconst deltaY = touch.clientY - touchStartY;\r\n\t\t\t\tconst deltaTime = Date.now() - lastTouchTime;\r\n\r\n\t\t\t\t// Swipe detection: horizontal movement > 50px and < 300ms\r\n\t\t\t\tif ( Math.abs( deltaX ) > 50 && Math.abs( deltaY ) < 50 && deltaTime < 300 ) {\r\n\t\t\t\t\tif ( deltaX > 0 ) {\r\n\t\t\t\t\t\tthis.prevPage();\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tthis.nextPage();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}, { signal, passive: true } );\r\n\t}\r\n\r\n\t/**\r\n\t * Update toolbar page info\r\n\t */\r\n\tupdateToolbarPageInfo() {\r\n\t\tif ( this.pageInput ) {\r\n\t\t\tthis.pageInput.value = String( this.currentPage );\r\n\t\t\tthis.pageInput.max = String( this.totalPages );\r\n\t\t}\r\n\r\n\t\tif ( this.totalPagesSpan ) {\r\n\t\t\tthis.totalPagesSpan.textContent = String( this.totalPages );\r\n\t\t}\r\n\r\n\t\t// Update button states\r\n\t\tthis.updateNavigationButtons();\r\n\t}\r\n\r\n\t/**\r\n\t * Update navigation button states\r\n\t */\r\n\tupdateNavigationButtons() {\r\n\t\tconst prevBtn = this.toolbar?.querySelector( '[data-action=\"prev\"]' );\r\n\t\tconst nextBtn = this.toolbar?.querySelector( '[data-action=\"next\"]' );\r\n\r\n\t\tif ( prevBtn ) {\r\n\t\t\tprevBtn.disabled = this.currentPage <= 1;\r\n\t\t}\r\n\r\n\t\tif ( nextBtn ) {\r\n\t\t\tnextBtn.disabled = this.currentPage >= this.totalPages;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Update zoom label\r\n\t */\r\n\tupdateZoomLabel() {\r\n\t\tif ( this.zoomLabel ) {\r\n\t\t\tthis.zoomLabel.textContent = Math.round( this.scale * 100 ) + '%';\r\n\t\t}\r\n\r\n\t\t// Update button states\r\n\t\tconst zoomOutBtn = this.toolbar?.querySelector( '[data-action=\"zoomOut\"]' );\r\n\t\tconst zoomInBtn = this.toolbar?.querySelector( '[data-action=\"zoomIn\"]' );\r\n\r\n\t\tif ( zoomOutBtn ) {\r\n\t\t\tzoomOutBtn.disabled = this.zoomIndex <= 0;\r\n\t\t}\r\n\r\n\t\tif ( zoomInBtn ) {\r\n\t\t\tzoomInBtn.disabled = this.zoomIndex >= ZOOM_LEVELS.length - 1;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Get filename from URL\r\n\t *\r\n\t * @returns {string} Filename\r\n\t */\r\n\tgetFilename() {\r\n\t\ttry {\r\n\t\t\tconst url = new URL( this.config.pdfUrl );\r\n\t\t\tconst pathname = url.pathname;\r\n\t\t\treturn pathname.substring( pathname.lastIndexOf( '/' ) + 1 ) || 'document.pdf';\r\n\t\t} catch {\r\n\t\t\treturn 'document.pdf';\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Hide loading indicator\r\n\t */\r\n\thideLoading() {\r\n\t\tconst loadingEl = this.container.querySelector( '.' + CLASSES.loading );\r\n\t\tif ( loadingEl ) {\r\n\t\t\tloadingEl.hidden = true;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Show error message\r\n\t *\r\n\t * @param {string} message - Error message\r\n\t */\r\n\tshowError( message ) {\r\n\t\tthis.container.classList.remove( CLASSES.loadingActive );\r\n\t\tthis.hideLoading();\r\n\r\n\t\tlet errorContainer = this.container.querySelector( '.' + CLASSES.errorContainer );\r\n\t\tif ( errorContainer ) {\r\n\t\t\terrorContainer.innerHTML = `<div class=\"${CLASSES.errorMessage}\">${this.escapeHtml( message )}</div>`;\r\n\t\t\terrorContainer.hidden = false;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Escape HTML\r\n\t *\r\n\t * @param {string} text - Text to escape\r\n\t * @returns {string} Escaped text\r\n\t */\r\n\tescapeHtml( text ) {\r\n\t\tconst div = document.createElement( 'div' );\r\n\t\tdiv.textContent = text;\r\n\t\treturn div.innerHTML;\r\n\t}\r\n\r\n\t/**\r\n\t * Debounce function calls\r\n\t *\r\n\t * @param {Function} func - Function to debounce\r\n\t * @param {number} wait - Wait time in milliseconds\r\n\t * @returns {Function} Debounced function\r\n\t */\r\n\tdebounce( func, wait ) {\r\n\t\tlet timeout;\r\n\t\treturn function executedFunction( ...args ) {\r\n\t\t\tconst later = () => {\r\n\t\t\t\tclearTimeout( timeout );\r\n\t\t\t\tfunc.apply( this, args );\r\n\t\t\t};\r\n\t\t\tclearTimeout( timeout );\r\n\t\t\ttimeout = setTimeout( later, wait );\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * Announce message to screen readers\r\n\t *\r\n\t * @param {string} message - Message to announce\r\n\t */\r\n\tannounce( message ) {\r\n\t\tconst announcement = document.createElement( 'div' );\r\n\t\tannouncement.setAttribute( 'role', 'status' );\r\n\t\tannouncement.setAttribute( 'aria-live', 'polite' );\r\n\t\tannouncement.setAttribute( 'aria-atomic', 'true' );\r\n\t\tannouncement.className = 'mdpv-sr-only';\r\n\t\tannouncement.textContent = message;\r\n\r\n\t\tdocument.body.appendChild( announcement );\r\n\r\n\t\tsetTimeout( () => {\r\n\t\t\tif ( announcement.parentNode ) {\r\n\t\t\t\tannouncement.parentNode.removeChild( announcement );\r\n\t\t\t}\r\n\t\t}, 1000 );\r\n\t}\r\n\r\n\t/**\r\n\t * Clean up all resources\r\n\t *\r\n\t * Call this before removing the viewer from DOM\r\n\t */\r\n\tdestroy() {\r\n\t\t// Abort all event listeners\r\n\t\tif ( this.abortController ) {\r\n\t\t\tthis.abortController.abort();\r\n\t\t\tthis.abortController = null;\r\n\t\t}\r\n\r\n\t\t// Cancel any active render\r\n\t\tif ( this.renderTask ) {\r\n\t\t\tthis.renderTask.cancel();\r\n\t\t\tthis.renderTask = null;\r\n\t\t}\r\n\r\n\t\t// Destroy PDF document\r\n\t\tif ( this.pdfDoc ) {\r\n\t\t\tthis.pdfDoc.destroy();\r\n\t\t\tthis.pdfDoc = null;\r\n\t\t}\r\n\r\n\t\t// Clear canvas\r\n\t\tif ( this.ctx && this.canvas ) {\r\n\t\t\tthis.ctx.clearRect( 0, 0, this.canvas.width, this.canvas.height );\r\n\t\t}\r\n\r\n\t\t// Remove added elements\r\n\t\tif ( this.canvasContainer && this.canvasContainer.parentNode ) {\r\n\t\t\tthis.canvasContainer.parentNode.removeChild( this.canvasContainer );\r\n\t\t}\r\n\r\n\t\tif ( this.toolbar && this.toolbar.parentNode ) {\r\n\t\t\tthis.toolbar.parentNode.removeChild( this.toolbar );\r\n\t\t}\r\n\r\n\t\t// Remove classes\r\n\t\tthis.container.classList.remove( CLASSES.active, CLASSES.loadingActive, CLASSES.fullscreen );\r\n\r\n\t\t// Clear references\r\n\t\tthis.canvas = null;\r\n\t\tthis.ctx = null;\r\n\t\tthis.canvasContainer = null;\r\n\t\tthis.toolbar = null;\r\n\t\tthis.pageInput = null;\r\n\t\tthis.totalPagesSpan = null;\r\n\t\tthis.zoomLabel = null;\r\n\t\tthis.fullscreenBtn = null;\r\n\r\n\t\t// Remove tabindex\r\n\t\tthis.container.removeAttribute( 'tabindex' );\r\n\r\n\t\tconsole.log( '[MDPV Viewer] Destroyed' );\r\n\t}\r\n\r\n\t/**\r\n\t * Static method to test viewer with a PDF URL\r\n\t * For development/debugging only\r\n\t *\r\n\t * @param {string} pdfUrl - URL to PDF file\r\n\t * @param {HTMLElement|string} container - Container element or selector\r\n\t * @returns {MDPVViewer} Viewer instance\r\n\t */\r\n\tstatic test( pdfUrl, container = null ) {\r\n\t\t// Create container if not provided\r\n\t\tif ( ! container ) {\r\n\t\t\tcontainer = document.createElement( 'div' );\r\n\t\t\tcontainer.style.cssText = 'width:100%;max-width:800px;margin:20px auto;aspect-ratio:612/792;';\r\n\t\t\tcontainer.className = CLASSES.viewer;\r\n\t\t\tdocument.body.appendChild( container );\r\n\t\t} else if ( typeof container === 'string' ) {\r\n\t\t\tcontainer = document.querySelector( container );\r\n\t\t}\r\n\r\n\t\tif ( ! container ) {\r\n\t\t\tconsole.error( '[MDPV] Test: Container not found' );\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t// Add required elements\r\n\t\tcontainer.innerHTML = `\r\n\t\t\t<div class=\"${CLASSES.loading}\">\r\n\t\t\t\t<div class=\"mdpv-spinner\"></div>\r\n\t\t\t\t<span>Loading...</span>\r\n\t\t\t</div>\r\n\t\t\t<div class=\"${CLASSES.errorContainer}\" hidden></div>\r\n\t\t`;\r\n\r\n\t\t// Create viewer\r\n\t\tconst viewer = new MDPVViewer( container, {\r\n\t\t\tpdfUrl: pdfUrl,\r\n\t\t\tpdfId: 0,\r\n\t\t\tpageCount: 1,\r\n\t\t\tshowToolbar: true,\r\n\t\t\tshowDownload: true,\r\n\t\t\tshowPrint: true,\r\n\t\t\tshowFullscreen: true,\r\n\t\t\tpluginUrl: '', // Will need to be set for PDF.js\r\n\t\t\tworkerUrl: '',\r\n\t\t\ti18n: {\r\n\t\t\t\tloading: 'Loading...',\r\n\t\t\t\terror: 'Failed to load',\r\n\t\t\t\tpage: 'Page',\r\n\t\t\t\tof: 'of',\r\n\t\t\t\tprevPage: 'Previous',\r\n\t\t\t\tnextPage: 'Next',\r\n\t\t\t\tzoomIn: 'Zoom in',\r\n\t\t\t\tzoomOut: 'Zoom out',\r\n\t\t\t\tdownload: 'Download',\r\n\t\t\t\tprint: 'Print',\r\n\t\t\t\tfullscreen: 'Fullscreen',\r\n\t\t\t\texitFullscreen: 'Exit fullscreen',\r\n\t\t\t},\r\n\t\t} );\r\n\r\n\t\tconsole.log( '[MDPV] Test viewer created:', viewer );\r\n\t\treturn viewer;\r\n\t}\r\n}\r\n\r\n// Default export for compatibility\r\nexport default MDPVViewer;\r\n\r\n// Expose globally for debugging (development only)\r\nif ( typeof window !== 'undefined' ) {\r\n\twindow.MDPVViewer = MDPVViewer;\r\n}\r\n"]}