web-mojo 2.1.758 → 2.1.761

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.es.js +10 -10
  3. package/dist/auth.cjs.js +1 -1
  4. package/dist/auth.cjs.js.map +1 -1
  5. package/dist/auth.es.js +10 -9
  6. package/dist/auth.es.js.map +1 -1
  7. package/dist/charts.cjs.js +1 -1
  8. package/dist/charts.es.js +2 -2
  9. package/dist/chunks/{ChatView-CoCylKpB.js → ChatView-BaKGKYIW.js} +6 -6
  10. package/dist/chunks/{ChatView-CoCylKpB.js.map → ChatView-BaKGKYIW.js.map} +1 -1
  11. package/dist/chunks/{ChatView-S4pMSPhI.js → ChatView-CQLSGsuA.js} +2 -2
  12. package/dist/chunks/{ChatView-S4pMSPhI.js.map → ChatView-CQLSGsuA.js.map} +1 -1
  13. package/dist/chunks/{ContextMenu-C5RTltSd.js → ContextMenu-Ccy78itn.js} +2 -2
  14. package/dist/chunks/{ContextMenu-C5RTltSd.js.map → ContextMenu-Ccy78itn.js.map} +1 -1
  15. package/dist/chunks/{ContextMenu-BKUnE3JT.js → ContextMenu-EtrS3sqW.js} +2 -2
  16. package/dist/chunks/{ContextMenu-BKUnE3JT.js.map → ContextMenu-EtrS3sqW.js.map} +1 -1
  17. package/dist/chunks/{DataView-D7CYJ31b.js → DataView-B-NO26Rf.js} +2 -2
  18. package/dist/chunks/{DataView-D7CYJ31b.js.map → DataView-B-NO26Rf.js.map} +1 -1
  19. package/dist/chunks/{DataView-idgJVB89.js → DataView-DNnk7fTT.js} +2 -2
  20. package/dist/chunks/{DataView-idgJVB89.js.map → DataView-DNnk7fTT.js.map} +1 -1
  21. package/dist/chunks/{Dialog-BPhwGiQx.js → Dialog-CBChqVIZ.js} +5 -5
  22. package/dist/chunks/{Dialog-BPhwGiQx.js.map → Dialog-CBChqVIZ.js.map} +1 -1
  23. package/dist/chunks/{Dialog-4ra2w2tV.js → Dialog-v6xXatPb.js} +2 -2
  24. package/dist/chunks/{Dialog-4ra2w2tV.js.map → Dialog-v6xXatPb.js.map} +1 -1
  25. package/dist/chunks/{FormView-a7Rl2bmm.js → FormView-B95jjgZr.js} +2 -2
  26. package/dist/chunks/{FormView-a7Rl2bmm.js.map → FormView-B95jjgZr.js.map} +1 -1
  27. package/dist/chunks/{FormView-C1ljUoea.js → FormView-BzhM9nar.js} +2 -2
  28. package/dist/chunks/{FormView-C1ljUoea.js.map → FormView-BzhM9nar.js.map} +1 -1
  29. package/dist/chunks/{MetricsMiniChartWidget-hdDNDf7M.js → MetricsMiniChartWidget-BLO12yFH.js} +3 -3
  30. package/dist/chunks/{MetricsMiniChartWidget-hdDNDf7M.js.map → MetricsMiniChartWidget-BLO12yFH.js.map} +1 -1
  31. package/dist/chunks/{MetricsMiniChartWidget-m_U_ucCF.js → MetricsMiniChartWidget-D5P4K2VW.js} +2 -2
  32. package/dist/chunks/{MetricsMiniChartWidget-m_U_ucCF.js.map → MetricsMiniChartWidget-D5P4K2VW.js.map} +1 -1
  33. package/dist/chunks/{PDFViewer-OvkZ_4H3.js → PDFViewer-DHetE0mX.js} +2 -2
  34. package/dist/chunks/{PDFViewer-OvkZ_4H3.js.map → PDFViewer-DHetE0mX.js.map} +1 -1
  35. package/dist/chunks/{PDFViewer-DwJDeXQH.js → PDFViewer-DO4ec_8P.js} +3 -3
  36. package/dist/chunks/{PDFViewer-DwJDeXQH.js.map → PDFViewer-DO4ec_8P.js.map} +1 -1
  37. package/dist/chunks/{Page-CbWUdARI.js → Page-BQ7bila2.js} +2 -2
  38. package/dist/chunks/{Page-CbWUdARI.js.map → Page-BQ7bila2.js.map} +1 -1
  39. package/dist/chunks/{Page-D7lbK30W.js → Page-Dn1oAANw.js} +2 -2
  40. package/dist/chunks/{Page-D7lbK30W.js.map → Page-Dn1oAANw.js.map} +1 -1
  41. package/dist/chunks/TokenManager-BXQKyhDc.js +2 -0
  42. package/dist/chunks/TokenManager-BXQKyhDc.js.map +1 -0
  43. package/dist/chunks/{TokenManager-Fjt083wv.js → TokenManager-CAZNcCMs.js} +3 -3
  44. package/dist/chunks/TokenManager-CAZNcCMs.js.map +1 -0
  45. package/dist/chunks/{TopNav-CKfu-goV.js → TopNav-Dxw-w4PV.js} +2 -2
  46. package/dist/chunks/{TopNav-CKfu-goV.js.map → TopNav-Dxw-w4PV.js.map} +1 -1
  47. package/dist/chunks/{TopNav-B7o7jhkD.js → TopNav-OcY6ViTW.js} +5 -5
  48. package/dist/chunks/{TopNav-B7o7jhkD.js.map → TopNav-OcY6ViTW.js.map} +1 -1
  49. package/dist/chunks/{WebApp-CYCNA3GB.js → WebApp-D0KJTN0p.js} +13 -13
  50. package/dist/chunks/{WebApp-CYCNA3GB.js.map → WebApp-D0KJTN0p.js.map} +1 -1
  51. package/dist/chunks/{WebApp-Cnkm2125.js → WebApp-DlfbVd3B.js} +2 -2
  52. package/dist/chunks/{WebApp-Cnkm2125.js.map → WebApp-DlfbVd3B.js.map} +1 -1
  53. package/dist/docit.cjs.js +1 -1
  54. package/dist/docit.es.js +6 -6
  55. package/dist/index.cjs.js +1 -1
  56. package/dist/index.es.js +12 -12
  57. package/dist/lightbox.cjs.js +1 -1
  58. package/dist/lightbox.es.js +4 -4
  59. package/package.json +1 -1
  60. package/dist/chunks/TokenManager-Bv9T1Pxb.js +0 -2
  61. package/dist/chunks/TokenManager-Bv9T1Pxb.js.map +0 -1
  62. package/dist/chunks/TokenManager-Fjt083wv.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PDFViewer-DwJDeXQH.js","sources":["../../src/extensions/lightbox/LightboxGallery.js","../../src/extensions/lightbox/PDFViewer.js"],"sourcesContent":["/**\n * LightboxGallery - Simple fullscreen image gallery\n * Clean, minimal lightbox for viewing single images or galleries\n */\n\nimport View from '@core/View.js';\n\nexport default class LightboxGallery extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `lightbox-gallery ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Handle single image or array of images and normalize to objects\n const rawImages = Array.isArray(options.images) ? options.images : [options.images || options.src].filter(Boolean);\n this.images = rawImages.map(img => {\n if (typeof img === 'string') {\n return { src: img, alt: '' };\n }\n return { src: img.src, alt: img.alt || '' };\n });\n this.currentIndex = options.startIndex || 0;\n this.showNavigation = options.showNavigation !== false && this.images.length > 1;\n this.showCounter = options.showCounter !== false && this.images.length > 1;\n this.allowKeyboard = options.allowKeyboard !== false;\n this.closeOnBackdrop = options.closeOnBackdrop !== false;\n this.fitToScreen = options.fitToScreen !== false; // Start in fit-to-screen mode\n\n // Bind keyboard handler for cleanup\n this._keyboardHandler = this.handleKeyboard.bind(this);\n\n // Set template properties directly on view instance\n this.updateTemplateProperties();\n }\n\n updateTemplateProperties() {\n this.currentImage = this.images[this.currentIndex] || { src: '', alt: '' };\n this.currentNumber = this.currentIndex + 1;\n this.total = this.images.length;\n this.isFirst = this.currentIndex === 0;\n this.isLast = this.currentIndex === this.images.length - 1;\n this.imageStyle = this.fitToScreen\n ? 'width: 90vw; max-height: 100%; object-fit: contain; user-select: none; cursor: zoom-in;'\n : 'max-width: none; max-height: none; user-select: none; cursor: zoom-out;';\n this.containerStyle = this.fitToScreen\n ? ''\n : 'overflow: auto;';\n this.modeIndicator = this.fitToScreen ? 'Fit to Screen' : 'Original Size';\n }\n\n async getTemplate() {\n const currentImage = this.images[this.currentIndex];\n const hasMultiple = this.images.length > 1;\n\n return `\n <div class=\"lightbox-overlay position-fixed top-0 start-0 w-100 h-100 d-flex align-items-center justify-content-center\"\n style=\"background: rgba(0,0,0,0.9); z-index: 9999;\"\n data-action=\"backdrop-click\">\n\n <!-- Close button -->\n <button type=\"button\" class=\"btn-close btn-close-white position-absolute top-0 end-0 m-4\"\n data-action=\"close\"\n style=\"z-index: 10001;\"\n title=\"Close\"></button>\n\n <!-- Counter -->\n {{#showCounter}}\n <div class=\"lightbox-counter position-absolute top-0 start-50 translate-middle-x mt-4 text-white\"\n style=\"z-index: 10001; font-size: 1.1rem;\">\n {{currentNumber}} of {{total}}\n </div>\n {{/showCounter}}\n\n <!-- Mode Indicator -->\n <div class=\"lightbox-mode-indicator position-absolute bottom-0 start-50 translate-middle-x mb-4 text-white bg-dark bg-opacity-75 px-3 py-2 rounded\"\n style=\"z-index: 10001; font-size: 0.9rem;\">\n {{modeIndicator}} • Click image to toggle\n </div>\n\n <!-- Navigation -->\n {{#showNavigation}}\n <button type=\"button\" class=\"btn btn-light btn-lg position-absolute start-0 top-50 translate-middle-y ms-4\"\n data-action=\"prev\"\n style=\"z-index: 10001;\"\n title=\"Previous\"\n {{#isFirst}}disabled{{/isFirst}}>\n <i class=\"bi bi-chevron-left\"></i>\n </button>\n\n <button type=\"button\" class=\"btn btn-light btn-lg position-absolute end-0 top-50 translate-middle-y me-4\"\n data-action=\"next\"\n style=\"z-index: 10001;\"\n title=\"Next\"\n {{#isLast}}disabled{{/isLast}}>\n <i class=\"bi bi-chevron-right\"></i>\n </button>\n {{/showNavigation}}\n\n <!-- Image container -->\n <div class=\"lightbox-image-container w-100 h-100 d-flex align-items-center justify-content-center p-5\"\n style=\"{{containerStyle}}\">\n {{#currentImage}}\n <img src=\"{{src}}\"\n alt=\"{{alt}}\"\n class=\"lightbox-image img-fluid\"\n style=\"{{imageStyle}}\"\n data-action=\"image-click\">\n {{/currentImage}}\n </div>\n\n <!-- Loading spinner -->\n <div class=\"lightbox-loading position-absolute top-50 start-50 translate-middle text-white\"\n style=\"display: none;\">\n <div class=\"spinner-border\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n `;\n }\n\n\n\n async onAfterRender() {\n // Add to body for fullscreen\n document.body.appendChild(this.element);\n document.body.style.overflow = 'hidden';\n\n // Set up keyboard navigation\n if (this.allowKeyboard) {\n document.addEventListener('keydown', this._keyboardHandler);\n }\n\n // Preload next/previous images\n this.preloadAdjacentImages();\n }\n\n // Action handlers\n async handleActionClose() {\n this.close();\n }\n\n async handleActionBackdropClick(e) {\n // Only close if clicked on backdrop, not image\n if (this.closeOnBackdrop && e.target === e.currentTarget) {\n this.close();\n }\n }\n\n async handleActionPrev() {\n this.showPrevious();\n }\n\n async handleActionNext() {\n this.showNext();\n }\n\n async handleActionImageClick() {\n this.toggleImageMode();\n }\n\n // Navigation methods\n showPrevious() {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n this.updateImage();\n this.preloadAdjacentImages();\n }\n }\n\n showNext() {\n if (this.currentIndex < this.images.length - 1) {\n this.currentIndex++;\n this.updateImage();\n this.preloadAdjacentImages();\n }\n }\n\n goToImage(index) {\n if (index >= 0 && index < this.images.length && index !== this.currentIndex) {\n this.currentIndex = index;\n this.updateImage();\n this.preloadAdjacentImages();\n }\n }\n\n // Update image without full re-render\n async updateImage() {\n const currentImage = this.images[this.currentIndex];\n const imgElement = this.element.querySelector('.lightbox-image');\n const counterElement = this.element.querySelector('.lightbox-counter');\n const prevBtn = this.element.querySelector('[data-action=\"prev\"]');\n const nextBtn = this.element.querySelector('[data-action=\"next\"]');\n\n if (imgElement) {\n // Show loading\n this.showLoading();\n\n // Update image\n imgElement.src = currentImage.src;\n imgElement.alt = currentImage.alt;\n\n // Wait for image to load\n await this.waitForImageLoad(imgElement);\n\n // Hide loading\n this.hideLoading();\n }\n\n // Update counter\n if (counterElement) {\n counterElement.textContent = `${this.currentIndex + 1} of ${this.images.length}`;\n }\n\n // Update navigation buttons\n if (prevBtn) {\n prevBtn.disabled = this.currentIndex === 0;\n }\n if (nextBtn) {\n nextBtn.disabled = this.currentIndex === this.images.length - 1;\n }\n\n // Update template properties\n this.updateTemplateProperties();\n\n // Update image display mode\n this.updateImageDisplay();\n\n // Emit event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('lightbox:image-changed', {\n gallery: this,\n index: this.currentIndex,\n image: currentImage\n });\n }\n }\n\n showLoading() {\n const loading = this.element.querySelector('.lightbox-loading');\n if (loading) {\n loading.style.display = 'block';\n }\n }\n\n hideLoading() {\n const loading = this.element.querySelector('.lightbox-loading');\n if (loading) {\n loading.style.display = 'none';\n }\n }\n\n waitForImageLoad(imgElement) {\n return new Promise((resolve) => {\n if (imgElement.complete) {\n resolve();\n } else {\n imgElement.onload = resolve;\n imgElement.onerror = resolve; // Still resolve on error\n }\n });\n }\n\n // Preload adjacent images for smooth navigation\n preloadAdjacentImages() {\n const preloadIndexes = [];\n\n // Previous image\n if (this.currentIndex > 0) {\n preloadIndexes.push(this.currentIndex - 1);\n }\n\n // Next image\n if (this.currentIndex < this.images.length - 1) {\n preloadIndexes.push(this.currentIndex + 1);\n }\n\n preloadIndexes.forEach(index => {\n const image = this.images[index];\n\n // Create image element to trigger browser caching\n const preloadImg = new Image();\n preloadImg.src = image.src;\n });\n }\n\n // Keyboard navigation\n handleKeyboard(e) {\n switch (e.key) {\n case 'Escape':\n e.preventDefault();\n this.close();\n break;\n case 'ArrowLeft':\n e.preventDefault();\n this.showPrevious();\n break;\n case 'ArrowRight':\n e.preventDefault();\n this.showNext();\n break;\n case 'Home':\n e.preventDefault();\n this.goToImage(0);\n break;\n case 'End':\n e.preventDefault();\n this.goToImage(this.images.length - 1);\n break;\n }\n }\n\n // Toggle between fit-to-screen and original size\n toggleImageMode() {\n this.fitToScreen = !this.fitToScreen;\n this.updateTemplateProperties();\n this.updateImageDisplay();\n\n // Emit mode change event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('lightbox:mode-changed', {\n gallery: this,\n fitToScreen: this.fitToScreen\n });\n }\n }\n\n // Update image display without full re-render\n updateImageDisplay() {\n const imgElement = this.element.querySelector('.lightbox-image');\n const containerElement = this.element.querySelector('.lightbox-image-container');\n const indicatorElement = this.element.querySelector('.lightbox-mode-indicator');\n\n if (imgElement) {\n if (this.fitToScreen) {\n imgElement.style.maxWidth = '100%';\n imgElement.style.maxHeight = '100%';\n imgElement.style.objectFit = 'contain';\n imgElement.style.cursor = 'zoom-in';\n } else {\n imgElement.style.maxWidth = 'none';\n imgElement.style.maxHeight = 'none';\n imgElement.style.objectFit = 'none';\n imgElement.style.cursor = 'zoom-out';\n }\n imgElement.style.userSelect = 'none';\n }\n\n if (containerElement) {\n containerElement.style.overflow = this.fitToScreen ? '' : 'auto';\n }\n\n if (indicatorElement) {\n indicatorElement.textContent = `${this.modeIndicator} • Click image to toggle`;\n }\n }\n\n // Close lightbox\n close() {\n // Emit close event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('lightbox:closed', { gallery: this });\n }\n\n this.destroy();\n }\n\n async onBeforeDestroy() {\n // Restore body overflow\n document.body.style.overflow = '';\n\n // Remove keyboard listener\n if (this.allowKeyboard) {\n document.removeEventListener('keydown', this._keyboardHandler);\n }\n\n // Remove from body\n if (this.element.parentNode === document.body) {\n document.body.removeChild(this.element);\n }\n }\n\n // Static method to show lightbox\n static show(images, options = {}) {\n const lightbox = new LightboxGallery({\n images,\n ...options\n });\n\n lightbox.render().then(() => {\n lightbox.mount();\n });\n\n return lightbox;\n }\n}\n\nwindow.LightboxGallery = LightboxGallery;\n","/**\n * PDFViewer - PDF document viewer component with zoom and navigation\n * Built for the MOJO framework with PDF.js integration\n */\n\nimport View from '@core/View.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class PDFViewer extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `pdf-viewer ${options.className || ''}`,\n tagName: 'div'\n });\n\n // PDF properties\n this.pdfUrl = options.pdfUrl || options.src || '';\n this.title = options.title || 'PDF Document';\n\n // PDF.js objects\n this.pdfDoc = null;\n this.currentPage = 1;\n this.totalPages = 0;\n this.pageRendering = false;\n this.pageNumPending = null;\n\n // Zoom and display state\n this.scale = 1.0;\n this.minScale = 0.25;\n this.maxScale = 5.0;\n this.scaleStep = 0.25;\n this.fitMode = 'page'; // 'page', 'width', 'auto'\n\n // Canvas and context\n this.canvas = null;\n this.ctx = null;\n\n // Options\n this.showControls = options.showControls !== false;\n this.allowZoom = options.allowZoom !== false;\n this.allowNavigation = options.allowNavigation !== false;\n this.showPageNumbers = options.showPageNumbers !== false;\n\n // Loading state\n this.isLoaded = false;\n this.isLoading = false;\n\n // PDF.js worker path - can be customized\n this.pdfjsWorkerPath = options.pdfjsWorkerPath || 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.0.379/pdf.worker.min.js';\n this.pdfjsCMapUrl = options.pdfjsCMapUrl || 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.0.379/cmaps/';\n\n // Elements\n this.canvasContainer = null;\n this.controlsElement = null;\n this.statusElement = null;\n this.pageInput = null;\n }\n\n async getTemplate() {\n return `\n <div class=\"pdf-viewer-container\">\n {{#showControls}}\n <div class=\"pdf-viewer-toolbar\" data-container=\"toolbar\">\n <div class=\"btn-toolbar\" role=\"toolbar\">\n <!-- Navigation Controls -->\n {{#allowNavigation}}\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Navigation\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"first-page\" title=\"First Page\">\n <i class=\"bi bi-chevron-double-left\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"prev-page\" title=\"Previous Page\">\n <i class=\"bi bi-chevron-left\"></i>\n </button>\n \n {{#showPageNumbers}}\n <div class=\"input-group input-group-sm\" style=\"width: 120px;\">\n <input type=\"number\" class=\"form-control text-center page-input\" min=\"1\" value=\"1\" data-change-action=\"page-input\">\n <span class=\"input-group-text page-total\">/ 0</span>\n </div>\n {{/showPageNumbers}}\n \n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"next-page\" title=\"Next Page\">\n <i class=\"bi bi-chevron-right\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"last-page\" title=\"Last Page\">\n <i class=\"bi bi-chevron-double-right\"></i>\n </button>\n </div>\n {{/allowNavigation}}\n\n <!-- Zoom Controls -->\n {{#allowZoom}}\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Zoom\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"zoom-out\" title=\"Zoom Out\">\n <i class=\"bi bi-zoom-out\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"zoom-in\" title=\"Zoom In\">\n <i class=\"bi bi-zoom-in\"></i>\n </button>\n \n <div class=\"btn-group\" role=\"group\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm dropdown-toggle\" data-bs-toggle=\"dropdown\" title=\"Fit\">\n <i class=\"bi bi-arrows-fullscreen\"></i>\n </button>\n <ul class=\"dropdown-menu\">\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"fit-page\">Fit Page</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"fit-width\">Fit Width</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"actual-size\">Actual Size</a></li>\n </ul>\n </div>\n </div>\n {{/allowZoom}}\n\n <!-- Utility Controls -->\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Utilities\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"download\" title=\"Download\">\n <i class=\"bi bi-download\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"print\" title=\"Print\">\n <i class=\"bi bi-printer\"></i>\n </button>\n </div>\n </div>\n </div>\n {{/showControls}}\n\n <!-- PDF Content Area -->\n <div class=\"pdf-viewer-content\" data-container=\"content\">\n <div class=\"pdf-canvas-container\" data-container=\"canvasContainer\">\n <canvas class=\"pdf-canvas\" data-container=\"canvas\"></canvas>\n </div>\n\n <div class=\"pdf-viewer-overlay\">\n <div class=\"pdf-viewer-loading\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading PDF...</span>\n </div>\n <div class=\"mt-2\">Loading PDF...</div>\n </div>\n </div>\n\n <div class=\"pdf-viewer-error\" style=\"display: none;\">\n <div class=\"alert alert-danger\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle\"></i>\n <strong>Error:</strong> <span class=\"error-message\">Failed to load PDF</span>\n </div>\n </div>\n </div>\n\n <!-- Status Bar -->\n <div class=\"pdf-viewer-status\" data-container=\"status\">\n <small class=\"text-muted\">\n <span class=\"current-page\">0</span> of <span class=\"total-pages\">0</span> pages |\n <span class=\"zoom-level\">100%</span> |\n <span class=\"document-title\">{{title}}</span>\n </small>\n </div>\n </div>\n `;\n }\n\n get() {\n return {\n pdfUrl: this.pdfUrl,\n title: this.title,\n showControls: this.showControls,\n allowZoom: this.allowZoom,\n allowNavigation: this.allowNavigation,\n showPageNumbers: this.showPageNumbers\n };\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.canvas = this.element.querySelector('.pdf-canvas');\n this.canvasContainer = this.element.querySelector('.pdf-canvas-container');\n this.controlsElement = this.element.querySelector('.pdf-viewer-toolbar');\n this.statusElement = this.element.querySelector('.pdf-viewer-status');\n this.pageInput = this.element.querySelector('.page-input');\n this.overlayElement = this.element.querySelector('.pdf-viewer-overlay');\n this.errorElement = this.element.querySelector('.pdf-viewer-error');\n\n if (this.canvas) {\n this.ctx = this.canvas.getContext('2d');\n }\n// Set up essential event listeners (keyboard, resize)\nthis.setupEssentialEventListeners();\n\n// Initialize PDF.js and load PDF\nawait this.initializePDFJS();\nif (this.pdfUrl) {\n await this.loadPDF();\n}\n}\n\n\n\n setupEssentialEventListeners() {\n // Essential events that can't be handled by EventDelegate\n const keydownHandler = (e) => this.handleKeyDown(e);\n document.addEventListener('keydown', keydownHandler);\n\n // Canvas resize observer for fit mode\n let resizeObserver = null;\n if (this.canvasContainer) {\n resizeObserver = new ResizeObserver(() => {\n if (this.fitMode !== 'auto') {\n this.applyFitMode();\n }\n });\n resizeObserver.observe(this.canvasContainer);\n }\n\n // Store listeners for cleanup\n this._essentialListeners = [\n { el: document, type: 'keydown', fn: keydownHandler }\n ];\n this._resizeObserver = resizeObserver;\n }\n\n async initializePDFJS() {\n try {\n // Load PDF.js if not already loaded\n if (typeof window.pdfjsLib === 'undefined') {\n await this.loadPDFJSLibrary();\n }\n\n // Configure PDF.js\n window.pdfjsLib.GlobalWorkerOptions.workerSrc = this.pdfjsWorkerPath;\n \n return true;\n } catch (error) {\n console.error('Failed to initialize PDF.js:', error);\n this.showError('Failed to initialize PDF viewer');\n return false;\n }\n }\n\n async loadPDFJSLibrary() {\n return new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.0.379/pdf.min.js';\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n }\n\n // Action Handlers\n async handleActionFirstPage() {\n await this.goToPage(1);\n }\n\n async handleActionPrevPage() {\n await this.goToPage(this.currentPage - 1);\n }\n\n async handleActionNextPage() {\n await this.goToPage(this.currentPage + 1);\n }\n\n async handleActionLastPage() {\n await this.goToPage(this.totalPages);\n }\n\n async onChangePageInput(event, element) {\n const pageNumber = parseInt(element.value, 10);\n if (pageNumber >= 1 && pageNumber <= this.totalPages) {\n await this.goToPage(pageNumber);\n } else {\n element.value = this.currentPage;\n }\n }\n\n async handleActionZoomIn() {\n this.setScale(this.scale + this.scaleStep);\n }\n\n async handleActionZoomOut() {\n this.setScale(this.scale - this.scaleStep);\n }\n\n async handleActionFitPage() {\n this.setFitMode('page');\n }\n\n async handleActionFitWidth() {\n this.setFitMode('width');\n }\n\n async handleActionActualSize() {\n this.setScale(1.0);\n this.fitMode = 'auto';\n }\n\n async handleActionDownload() {\n this.downloadPDF();\n }\n\n async handleActionPrint() {\n window.print();\n }\n\n // PDF Loading\n async loadPDF() {\n if (!this.pdfUrl || !window.pdfjsLib) {\n this.showError('PDF URL or PDF.js library not available');\n return false;\n }\n\n this.isLoading = true;\n this.showLoading();\n\n try {\n const loadingTask = window.pdfjsLib.getDocument({\n url: this.pdfUrl,\n cMapUrl: this.pdfjsCMapUrl,\n cMapPacked: true\n });\n\n this.pdfDoc = await loadingTask.promise;\n this.totalPages = this.pdfDoc.numPages;\n this.currentPage = 1;\n\n // Update UI\n this.updatePageControls();\n this.updateStatus();\n\n // Render first page\n await this.renderPage(1);\n\n this.isLoaded = true;\n this.isLoading = false;\n this.element.classList.add('loaded');\n this.hideLoading();\n\n // Apply initial fit mode\n this.applyFitMode();\n\n // Emit loaded event via EventBus\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:loaded', { \n viewer: this, \n pdfUrl: this.pdfUrl,\n totalPages: this.totalPages\n });\n }\n\n return true;\n\n } catch (error) {\n console.error('Error loading PDF:', error);\n this.isLoading = false;\n this.showError('Failed to load PDF document');\n \n // Emit error event via EventBus\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:error', { \n viewer: this, \n pdfUrl: this.pdfUrl,\n error: error.message\n });\n }\n \n return false;\n }\n }\n\n async renderPage(pageNumber) {\n if (this.pageRendering) {\n this.pageNumPending = pageNumber;\n return;\n }\n\n if (!this.pdfDoc || !this.canvas || !this.ctx) {\n return;\n }\n\n this.pageRendering = true;\n this.currentPage = pageNumber;\n\n try {\n const page = await this.pdfDoc.getPage(pageNumber);\n const viewport = page.getViewport({ scale: this.scale });\n\n // Set canvas dimensions\n this.canvas.height = viewport.height;\n this.canvas.width = viewport.width;\n\n // Clear canvas\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\n // Render page\n const renderContext = {\n canvasContext: this.ctx,\n viewport: viewport\n };\n\n const renderTask = page.render(renderContext);\n await renderTask.promise;\n\n this.pageRendering = false;\n\n // If there was a pending page render request\n if (this.pageNumPending !== null) {\n const pendingPage = this.pageNumPending;\n this.pageNumPending = null;\n await this.renderPage(pendingPage);\n }\n\n this.updatePageControls();\n this.updateStatus();\n\n // Emit page changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:page-changed', { \n viewer: this, \n currentPage: this.currentPage,\n totalPages: this.totalPages\n });\n }\n\n } catch (error) {\n console.error('Error rendering page:', error);\n this.pageRendering = false;\n this.showError('Failed to render PDF page');\n }\n }\n\n // Navigation\n async goToPage(pageNumber) {\n if (!this.pdfDoc || pageNumber < 1 || pageNumber > this.totalPages) {\n return;\n }\n\n await this.renderPage(pageNumber);\n }\n\n // Zoom and Fit\n setScale(scale) {\n const oldScale = this.scale;\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, scale));\n this.fitMode = 'auto';\n \n if (this.isLoaded) {\n this.renderPage(this.currentPage);\n }\n\n // Emit scale change event\n const eventBus = this.getApp()?.events;\n if (eventBus && oldScale !== this.scale) {\n eventBus.emit('pdfviewer:scale-changed', { \n viewer: this, \n oldScale, \n newScale: this.scale \n });\n }\n }\n\n setFitMode(mode) {\n const oldMode = this.fitMode;\n this.fitMode = mode;\n this.applyFitMode();\n\n // Emit fit mode change event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:fit-mode-changed', { \n viewer: this, \n oldMode, \n newMode: mode \n });\n }\n }\n\n applyFitMode() {\n if (!this.isLoaded || !this.pdfDoc || !this.canvasContainer) {\n return;\n }\n\n this.pdfDoc.getPage(this.currentPage).then(page => {\n const containerRect = this.canvasContainer.getBoundingClientRect();\n const viewport = page.getViewport({ scale: 1 });\n\n let newScale;\n if (this.fitMode === 'page') {\n const scaleX = (containerRect.width - 40) / viewport.width;\n const scaleY = (containerRect.height - 40) / viewport.height;\n newScale = Math.min(scaleX, scaleY);\n } else if (this.fitMode === 'width') {\n newScale = (containerRect.width - 40) / viewport.width;\n } else {\n return; // auto mode, don't change scale\n }\n\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, newScale));\n this.renderPage(this.currentPage);\n });\n }\n\n // Event Handlers\n handleKeyDown(e) {\n // Only handle if PDF viewer is focused or no input is focused\n if (e.target.tagName === 'INPUT' && e.target !== this.pageInput) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n case 'PageUp':\n e.preventDefault();\n this.goToPage(this.currentPage - 1);\n break;\n case 'ArrowRight':\n case 'PageDown':\n e.preventDefault();\n this.goToPage(this.currentPage + 1);\n break;\n case 'Home':\n e.preventDefault();\n this.goToPage(1);\n break;\n case 'End':\n e.preventDefault();\n this.goToPage(this.totalPages);\n break;\n case '+':\n case '=':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.setScale(this.scale + this.scaleStep);\n }\n break;\n case '-':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.setScale(this.scale - this.scaleStep);\n }\n break;\n case '0':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.setFitMode('page');\n }\n break;\n }\n }\n\n // UI Updates\n updatePageControls() {\n // Update page input\n if (this.pageInput) {\n this.pageInput.value = this.currentPage;\n }\n\n // Update page total display\n const pageTotalElement = this.element.querySelector('.page-total');\n if (pageTotalElement) {\n pageTotalElement.textContent = `/ ${this.totalPages}`;\n }\n\n // Update navigation buttons\n const firstBtn = this.element.querySelector('[data-action=\"first-page\"]');\n const prevBtn = this.element.querySelector('[data-action=\"prev-page\"]');\n const nextBtn = this.element.querySelector('[data-action=\"next-page\"]');\n const lastBtn = this.element.querySelector('[data-action=\"last-page\"]');\n\n if (firstBtn) firstBtn.disabled = this.currentPage <= 1;\n if (prevBtn) prevBtn.disabled = this.currentPage <= 1;\n if (nextBtn) nextBtn.disabled = this.currentPage >= this.totalPages;\n if (lastBtn) lastBtn.disabled = this.currentPage >= this.totalPages;\n\n // Update zoom buttons\n const zoomInBtn = this.element.querySelector('[data-action=\"zoom-in\"]');\n const zoomOutBtn = this.element.querySelector('[data-action=\"zoom-out\"]');\n\n if (zoomInBtn) zoomInBtn.disabled = this.scale >= this.maxScale;\n if (zoomOutBtn) zoomOutBtn.disabled = this.scale <= this.minScale;\n }\n\n updateStatus() {\n if (!this.statusElement) return;\n\n const currentPageElement = this.statusElement.querySelector('.current-page');\n const totalPagesElement = this.statusElement.querySelector('.total-pages');\n const zoomLevelElement = this.statusElement.querySelector('.zoom-level');\n\n if (currentPageElement) {\n currentPageElement.textContent = this.currentPage;\n }\n if (totalPagesElement) {\n totalPagesElement.textContent = this.totalPages;\n }\n if (zoomLevelElement) {\n zoomLevelElement.textContent = `${Math.round(this.scale * 100)}%`;\n }\n }\n\n // Utility Methods\n showLoading() {\n if (this.overlayElement) {\n this.overlayElement.style.display = 'flex';\n }\n }\n\n hideLoading() {\n if (this.overlayElement) {\n this.overlayElement.style.display = 'none';\n }\n }\n\n showError(message) {\n this.hideLoading();\n \n if (this.errorElement) {\n const errorMessageElement = this.errorElement.querySelector('.error-message');\n if (errorMessageElement) {\n errorMessageElement.textContent = message;\n }\n this.errorElement.style.display = 'block';\n }\n\n console.error('PDF Viewer Error:', message);\n }\n\n downloadPDF() {\n if (!this.pdfUrl) return;\n\n const link = document.createElement('a');\n link.href = this.pdfUrl;\n link.download = this.title + '.pdf';\n link.target = '_blank';\n link.click();\n }\n\n // Public API\n setPDF(pdfUrl, title = '') {\n const oldPdfUrl = this.pdfUrl;\n this.pdfUrl = pdfUrl;\n this.title = title || 'PDF Document';\n this.isLoaded = false;\n this.element.classList.remove('loaded');\n \n if (this.pdfDoc) {\n this.pdfDoc.destroy();\n this.pdfDoc = null;\n }\n \n this.currentPage = 1;\n this.totalPages = 0;\n this.scale = 1.0;\n \n if (pdfUrl) {\n this.loadPDF();\n }\n\n // Emit PDF changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:pdf-changed', { \n viewer: this, \n oldPdfUrl, \n newPdfUrl: pdfUrl \n });\n }\n }\n\n getCurrentPage() {\n return this.currentPage;\n }\n\n getTotalPages() {\n return this.totalPages;\n }\n\n getCurrentScale() {\n return this.scale;\n }\n\n async onBeforeDestroy() {\n // Clean up PDF.js resources\n if (this.pdfDoc) {\n this.pdfDoc.destroy();\n this.pdfDoc = null;\n }\n\n this.pageRendering = false;\n this.pageNumPending = null;\n\n // Clean up essential event listeners\n if (this._essentialListeners) {\n this._essentialListeners.forEach(({ el, type, fn }) => {\n if (el) el.removeEventListener(type, fn);\n });\n this._essentialListeners = null;\n }\n\n // Clean up resize observer\n if (this._resizeObserver) {\n this._resizeObserver.disconnect();\n this._resizeObserver = null;\n }\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:destroyed', { viewer: this });\n }\n }\n\n // Static method to show PDF in a fullscreen dialog\n static async showDialog(pdfUrl, options = {}) {\n const {\n title = 'PDF Viewer',\n size = 'fullscreen',\n showControls = true,\n allowZoom = true,\n allowNavigation = true,\n showPageNumbers = true,\n ...dialogOptions\n } = options;\n\n const viewer = new PDFViewer({\n pdfUrl,\n title,\n showControls,\n allowZoom,\n allowNavigation,\n showPageNumbers\n });\n\n const dialog = new Dialog({\n title,\n body: viewer,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n buttons: [\n { \n text: 'Download', \n action: 'download', \n class: 'btn btn-outline-primary' \n },\n { \n text: 'Close', \n action: 'close', \n class: 'btn btn-secondary',\n dismiss: true\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render();\n document.body.appendChild(dialog.element);\n await dialog.mount();\n\n // Show the dialog\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve(viewer);\n });\n\n dialog.on('action:download', () => {\n viewer.downloadPDF();\n });\n\n dialog.on('action:close', () => {\n dialog.hide();\n });\n });\n }\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PDFViewer-DO4ec_8P.js","sources":["../../src/extensions/lightbox/LightboxGallery.js","../../src/extensions/lightbox/PDFViewer.js"],"sourcesContent":["/**\n * LightboxGallery - Simple fullscreen image gallery\n * Clean, minimal lightbox for viewing single images or galleries\n */\n\nimport View from '@core/View.js';\n\nexport default class LightboxGallery extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `lightbox-gallery ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Handle single image or array of images and normalize to objects\n const rawImages = Array.isArray(options.images) ? options.images : [options.images || options.src].filter(Boolean);\n this.images = rawImages.map(img => {\n if (typeof img === 'string') {\n return { src: img, alt: '' };\n }\n return { src: img.src, alt: img.alt || '' };\n });\n this.currentIndex = options.startIndex || 0;\n this.showNavigation = options.showNavigation !== false && this.images.length > 1;\n this.showCounter = options.showCounter !== false && this.images.length > 1;\n this.allowKeyboard = options.allowKeyboard !== false;\n this.closeOnBackdrop = options.closeOnBackdrop !== false;\n this.fitToScreen = options.fitToScreen !== false; // Start in fit-to-screen mode\n\n // Bind keyboard handler for cleanup\n this._keyboardHandler = this.handleKeyboard.bind(this);\n\n // Set template properties directly on view instance\n this.updateTemplateProperties();\n }\n\n updateTemplateProperties() {\n this.currentImage = this.images[this.currentIndex] || { src: '', alt: '' };\n this.currentNumber = this.currentIndex + 1;\n this.total = this.images.length;\n this.isFirst = this.currentIndex === 0;\n this.isLast = this.currentIndex === this.images.length - 1;\n this.imageStyle = this.fitToScreen\n ? 'width: 90vw; max-height: 100%; object-fit: contain; user-select: none; cursor: zoom-in;'\n : 'max-width: none; max-height: none; user-select: none; cursor: zoom-out;';\n this.containerStyle = this.fitToScreen\n ? ''\n : 'overflow: auto;';\n this.modeIndicator = this.fitToScreen ? 'Fit to Screen' : 'Original Size';\n }\n\n async getTemplate() {\n const currentImage = this.images[this.currentIndex];\n const hasMultiple = this.images.length > 1;\n\n return `\n <div class=\"lightbox-overlay position-fixed top-0 start-0 w-100 h-100 d-flex align-items-center justify-content-center\"\n style=\"background: rgba(0,0,0,0.9); z-index: 9999;\"\n data-action=\"backdrop-click\">\n\n <!-- Close button -->\n <button type=\"button\" class=\"btn-close btn-close-white position-absolute top-0 end-0 m-4\"\n data-action=\"close\"\n style=\"z-index: 10001;\"\n title=\"Close\"></button>\n\n <!-- Counter -->\n {{#showCounter}}\n <div class=\"lightbox-counter position-absolute top-0 start-50 translate-middle-x mt-4 text-white\"\n style=\"z-index: 10001; font-size: 1.1rem;\">\n {{currentNumber}} of {{total}}\n </div>\n {{/showCounter}}\n\n <!-- Mode Indicator -->\n <div class=\"lightbox-mode-indicator position-absolute bottom-0 start-50 translate-middle-x mb-4 text-white bg-dark bg-opacity-75 px-3 py-2 rounded\"\n style=\"z-index: 10001; font-size: 0.9rem;\">\n {{modeIndicator}} • Click image to toggle\n </div>\n\n <!-- Navigation -->\n {{#showNavigation}}\n <button type=\"button\" class=\"btn btn-light btn-lg position-absolute start-0 top-50 translate-middle-y ms-4\"\n data-action=\"prev\"\n style=\"z-index: 10001;\"\n title=\"Previous\"\n {{#isFirst}}disabled{{/isFirst}}>\n <i class=\"bi bi-chevron-left\"></i>\n </button>\n\n <button type=\"button\" class=\"btn btn-light btn-lg position-absolute end-0 top-50 translate-middle-y me-4\"\n data-action=\"next\"\n style=\"z-index: 10001;\"\n title=\"Next\"\n {{#isLast}}disabled{{/isLast}}>\n <i class=\"bi bi-chevron-right\"></i>\n </button>\n {{/showNavigation}}\n\n <!-- Image container -->\n <div class=\"lightbox-image-container w-100 h-100 d-flex align-items-center justify-content-center p-5\"\n style=\"{{containerStyle}}\">\n {{#currentImage}}\n <img src=\"{{src}}\"\n alt=\"{{alt}}\"\n class=\"lightbox-image img-fluid\"\n style=\"{{imageStyle}}\"\n data-action=\"image-click\">\n {{/currentImage}}\n </div>\n\n <!-- Loading spinner -->\n <div class=\"lightbox-loading position-absolute top-50 start-50 translate-middle text-white\"\n style=\"display: none;\">\n <div class=\"spinner-border\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n `;\n }\n\n\n\n async onAfterRender() {\n // Add to body for fullscreen\n document.body.appendChild(this.element);\n document.body.style.overflow = 'hidden';\n\n // Set up keyboard navigation\n if (this.allowKeyboard) {\n document.addEventListener('keydown', this._keyboardHandler);\n }\n\n // Preload next/previous images\n this.preloadAdjacentImages();\n }\n\n // Action handlers\n async handleActionClose() {\n this.close();\n }\n\n async handleActionBackdropClick(e) {\n // Only close if clicked on backdrop, not image\n if (this.closeOnBackdrop && e.target === e.currentTarget) {\n this.close();\n }\n }\n\n async handleActionPrev() {\n this.showPrevious();\n }\n\n async handleActionNext() {\n this.showNext();\n }\n\n async handleActionImageClick() {\n this.toggleImageMode();\n }\n\n // Navigation methods\n showPrevious() {\n if (this.currentIndex > 0) {\n this.currentIndex--;\n this.updateImage();\n this.preloadAdjacentImages();\n }\n }\n\n showNext() {\n if (this.currentIndex < this.images.length - 1) {\n this.currentIndex++;\n this.updateImage();\n this.preloadAdjacentImages();\n }\n }\n\n goToImage(index) {\n if (index >= 0 && index < this.images.length && index !== this.currentIndex) {\n this.currentIndex = index;\n this.updateImage();\n this.preloadAdjacentImages();\n }\n }\n\n // Update image without full re-render\n async updateImage() {\n const currentImage = this.images[this.currentIndex];\n const imgElement = this.element.querySelector('.lightbox-image');\n const counterElement = this.element.querySelector('.lightbox-counter');\n const prevBtn = this.element.querySelector('[data-action=\"prev\"]');\n const nextBtn = this.element.querySelector('[data-action=\"next\"]');\n\n if (imgElement) {\n // Show loading\n this.showLoading();\n\n // Update image\n imgElement.src = currentImage.src;\n imgElement.alt = currentImage.alt;\n\n // Wait for image to load\n await this.waitForImageLoad(imgElement);\n\n // Hide loading\n this.hideLoading();\n }\n\n // Update counter\n if (counterElement) {\n counterElement.textContent = `${this.currentIndex + 1} of ${this.images.length}`;\n }\n\n // Update navigation buttons\n if (prevBtn) {\n prevBtn.disabled = this.currentIndex === 0;\n }\n if (nextBtn) {\n nextBtn.disabled = this.currentIndex === this.images.length - 1;\n }\n\n // Update template properties\n this.updateTemplateProperties();\n\n // Update image display mode\n this.updateImageDisplay();\n\n // Emit event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('lightbox:image-changed', {\n gallery: this,\n index: this.currentIndex,\n image: currentImage\n });\n }\n }\n\n showLoading() {\n const loading = this.element.querySelector('.lightbox-loading');\n if (loading) {\n loading.style.display = 'block';\n }\n }\n\n hideLoading() {\n const loading = this.element.querySelector('.lightbox-loading');\n if (loading) {\n loading.style.display = 'none';\n }\n }\n\n waitForImageLoad(imgElement) {\n return new Promise((resolve) => {\n if (imgElement.complete) {\n resolve();\n } else {\n imgElement.onload = resolve;\n imgElement.onerror = resolve; // Still resolve on error\n }\n });\n }\n\n // Preload adjacent images for smooth navigation\n preloadAdjacentImages() {\n const preloadIndexes = [];\n\n // Previous image\n if (this.currentIndex > 0) {\n preloadIndexes.push(this.currentIndex - 1);\n }\n\n // Next image\n if (this.currentIndex < this.images.length - 1) {\n preloadIndexes.push(this.currentIndex + 1);\n }\n\n preloadIndexes.forEach(index => {\n const image = this.images[index];\n\n // Create image element to trigger browser caching\n const preloadImg = new Image();\n preloadImg.src = image.src;\n });\n }\n\n // Keyboard navigation\n handleKeyboard(e) {\n switch (e.key) {\n case 'Escape':\n e.preventDefault();\n this.close();\n break;\n case 'ArrowLeft':\n e.preventDefault();\n this.showPrevious();\n break;\n case 'ArrowRight':\n e.preventDefault();\n this.showNext();\n break;\n case 'Home':\n e.preventDefault();\n this.goToImage(0);\n break;\n case 'End':\n e.preventDefault();\n this.goToImage(this.images.length - 1);\n break;\n }\n }\n\n // Toggle between fit-to-screen and original size\n toggleImageMode() {\n this.fitToScreen = !this.fitToScreen;\n this.updateTemplateProperties();\n this.updateImageDisplay();\n\n // Emit mode change event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('lightbox:mode-changed', {\n gallery: this,\n fitToScreen: this.fitToScreen\n });\n }\n }\n\n // Update image display without full re-render\n updateImageDisplay() {\n const imgElement = this.element.querySelector('.lightbox-image');\n const containerElement = this.element.querySelector('.lightbox-image-container');\n const indicatorElement = this.element.querySelector('.lightbox-mode-indicator');\n\n if (imgElement) {\n if (this.fitToScreen) {\n imgElement.style.maxWidth = '100%';\n imgElement.style.maxHeight = '100%';\n imgElement.style.objectFit = 'contain';\n imgElement.style.cursor = 'zoom-in';\n } else {\n imgElement.style.maxWidth = 'none';\n imgElement.style.maxHeight = 'none';\n imgElement.style.objectFit = 'none';\n imgElement.style.cursor = 'zoom-out';\n }\n imgElement.style.userSelect = 'none';\n }\n\n if (containerElement) {\n containerElement.style.overflow = this.fitToScreen ? '' : 'auto';\n }\n\n if (indicatorElement) {\n indicatorElement.textContent = `${this.modeIndicator} • Click image to toggle`;\n }\n }\n\n // Close lightbox\n close() {\n // Emit close event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('lightbox:closed', { gallery: this });\n }\n\n this.destroy();\n }\n\n async onBeforeDestroy() {\n // Restore body overflow\n document.body.style.overflow = '';\n\n // Remove keyboard listener\n if (this.allowKeyboard) {\n document.removeEventListener('keydown', this._keyboardHandler);\n }\n\n // Remove from body\n if (this.element.parentNode === document.body) {\n document.body.removeChild(this.element);\n }\n }\n\n // Static method to show lightbox\n static show(images, options = {}) {\n const lightbox = new LightboxGallery({\n images,\n ...options\n });\n\n lightbox.render().then(() => {\n lightbox.mount();\n });\n\n return lightbox;\n }\n}\n\nwindow.LightboxGallery = LightboxGallery;\n","/**\n * PDFViewer - PDF document viewer component with zoom and navigation\n * Built for the MOJO framework with PDF.js integration\n */\n\nimport View from '@core/View.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class PDFViewer extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `pdf-viewer ${options.className || ''}`,\n tagName: 'div'\n });\n\n // PDF properties\n this.pdfUrl = options.pdfUrl || options.src || '';\n this.title = options.title || 'PDF Document';\n\n // PDF.js objects\n this.pdfDoc = null;\n this.currentPage = 1;\n this.totalPages = 0;\n this.pageRendering = false;\n this.pageNumPending = null;\n\n // Zoom and display state\n this.scale = 1.0;\n this.minScale = 0.25;\n this.maxScale = 5.0;\n this.scaleStep = 0.25;\n this.fitMode = 'page'; // 'page', 'width', 'auto'\n\n // Canvas and context\n this.canvas = null;\n this.ctx = null;\n\n // Options\n this.showControls = options.showControls !== false;\n this.allowZoom = options.allowZoom !== false;\n this.allowNavigation = options.allowNavigation !== false;\n this.showPageNumbers = options.showPageNumbers !== false;\n\n // Loading state\n this.isLoaded = false;\n this.isLoading = false;\n\n // PDF.js worker path - can be customized\n this.pdfjsWorkerPath = options.pdfjsWorkerPath || 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.0.379/pdf.worker.min.js';\n this.pdfjsCMapUrl = options.pdfjsCMapUrl || 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.0.379/cmaps/';\n\n // Elements\n this.canvasContainer = null;\n this.controlsElement = null;\n this.statusElement = null;\n this.pageInput = null;\n }\n\n async getTemplate() {\n return `\n <div class=\"pdf-viewer-container\">\n {{#showControls}}\n <div class=\"pdf-viewer-toolbar\" data-container=\"toolbar\">\n <div class=\"btn-toolbar\" role=\"toolbar\">\n <!-- Navigation Controls -->\n {{#allowNavigation}}\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Navigation\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"first-page\" title=\"First Page\">\n <i class=\"bi bi-chevron-double-left\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"prev-page\" title=\"Previous Page\">\n <i class=\"bi bi-chevron-left\"></i>\n </button>\n \n {{#showPageNumbers}}\n <div class=\"input-group input-group-sm\" style=\"width: 120px;\">\n <input type=\"number\" class=\"form-control text-center page-input\" min=\"1\" value=\"1\" data-change-action=\"page-input\">\n <span class=\"input-group-text page-total\">/ 0</span>\n </div>\n {{/showPageNumbers}}\n \n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"next-page\" title=\"Next Page\">\n <i class=\"bi bi-chevron-right\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"last-page\" title=\"Last Page\">\n <i class=\"bi bi-chevron-double-right\"></i>\n </button>\n </div>\n {{/allowNavigation}}\n\n <!-- Zoom Controls -->\n {{#allowZoom}}\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Zoom\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"zoom-out\" title=\"Zoom Out\">\n <i class=\"bi bi-zoom-out\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"zoom-in\" title=\"Zoom In\">\n <i class=\"bi bi-zoom-in\"></i>\n </button>\n \n <div class=\"btn-group\" role=\"group\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm dropdown-toggle\" data-bs-toggle=\"dropdown\" title=\"Fit\">\n <i class=\"bi bi-arrows-fullscreen\"></i>\n </button>\n <ul class=\"dropdown-menu\">\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"fit-page\">Fit Page</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"fit-width\">Fit Width</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"actual-size\">Actual Size</a></li>\n </ul>\n </div>\n </div>\n {{/allowZoom}}\n\n <!-- Utility Controls -->\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Utilities\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"download\" title=\"Download\">\n <i class=\"bi bi-download\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"print\" title=\"Print\">\n <i class=\"bi bi-printer\"></i>\n </button>\n </div>\n </div>\n </div>\n {{/showControls}}\n\n <!-- PDF Content Area -->\n <div class=\"pdf-viewer-content\" data-container=\"content\">\n <div class=\"pdf-canvas-container\" data-container=\"canvasContainer\">\n <canvas class=\"pdf-canvas\" data-container=\"canvas\"></canvas>\n </div>\n\n <div class=\"pdf-viewer-overlay\">\n <div class=\"pdf-viewer-loading\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading PDF...</span>\n </div>\n <div class=\"mt-2\">Loading PDF...</div>\n </div>\n </div>\n\n <div class=\"pdf-viewer-error\" style=\"display: none;\">\n <div class=\"alert alert-danger\" role=\"alert\">\n <i class=\"bi bi-exclamation-triangle\"></i>\n <strong>Error:</strong> <span class=\"error-message\">Failed to load PDF</span>\n </div>\n </div>\n </div>\n\n <!-- Status Bar -->\n <div class=\"pdf-viewer-status\" data-container=\"status\">\n <small class=\"text-muted\">\n <span class=\"current-page\">0</span> of <span class=\"total-pages\">0</span> pages |\n <span class=\"zoom-level\">100%</span> |\n <span class=\"document-title\">{{title}}</span>\n </small>\n </div>\n </div>\n `;\n }\n\n get() {\n return {\n pdfUrl: this.pdfUrl,\n title: this.title,\n showControls: this.showControls,\n allowZoom: this.allowZoom,\n allowNavigation: this.allowNavigation,\n showPageNumbers: this.showPageNumbers\n };\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.canvas = this.element.querySelector('.pdf-canvas');\n this.canvasContainer = this.element.querySelector('.pdf-canvas-container');\n this.controlsElement = this.element.querySelector('.pdf-viewer-toolbar');\n this.statusElement = this.element.querySelector('.pdf-viewer-status');\n this.pageInput = this.element.querySelector('.page-input');\n this.overlayElement = this.element.querySelector('.pdf-viewer-overlay');\n this.errorElement = this.element.querySelector('.pdf-viewer-error');\n\n if (this.canvas) {\n this.ctx = this.canvas.getContext('2d');\n }\n// Set up essential event listeners (keyboard, resize)\nthis.setupEssentialEventListeners();\n\n// Initialize PDF.js and load PDF\nawait this.initializePDFJS();\nif (this.pdfUrl) {\n await this.loadPDF();\n}\n}\n\n\n\n setupEssentialEventListeners() {\n // Essential events that can't be handled by EventDelegate\n const keydownHandler = (e) => this.handleKeyDown(e);\n document.addEventListener('keydown', keydownHandler);\n\n // Canvas resize observer for fit mode\n let resizeObserver = null;\n if (this.canvasContainer) {\n resizeObserver = new ResizeObserver(() => {\n if (this.fitMode !== 'auto') {\n this.applyFitMode();\n }\n });\n resizeObserver.observe(this.canvasContainer);\n }\n\n // Store listeners for cleanup\n this._essentialListeners = [\n { el: document, type: 'keydown', fn: keydownHandler }\n ];\n this._resizeObserver = resizeObserver;\n }\n\n async initializePDFJS() {\n try {\n // Load PDF.js if not already loaded\n if (typeof window.pdfjsLib === 'undefined') {\n await this.loadPDFJSLibrary();\n }\n\n // Configure PDF.js\n window.pdfjsLib.GlobalWorkerOptions.workerSrc = this.pdfjsWorkerPath;\n \n return true;\n } catch (error) {\n console.error('Failed to initialize PDF.js:', error);\n this.showError('Failed to initialize PDF viewer');\n return false;\n }\n }\n\n async loadPDFJSLibrary() {\n return new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.0.379/pdf.min.js';\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n }\n\n // Action Handlers\n async handleActionFirstPage() {\n await this.goToPage(1);\n }\n\n async handleActionPrevPage() {\n await this.goToPage(this.currentPage - 1);\n }\n\n async handleActionNextPage() {\n await this.goToPage(this.currentPage + 1);\n }\n\n async handleActionLastPage() {\n await this.goToPage(this.totalPages);\n }\n\n async onChangePageInput(event, element) {\n const pageNumber = parseInt(element.value, 10);\n if (pageNumber >= 1 && pageNumber <= this.totalPages) {\n await this.goToPage(pageNumber);\n } else {\n element.value = this.currentPage;\n }\n }\n\n async handleActionZoomIn() {\n this.setScale(this.scale + this.scaleStep);\n }\n\n async handleActionZoomOut() {\n this.setScale(this.scale - this.scaleStep);\n }\n\n async handleActionFitPage() {\n this.setFitMode('page');\n }\n\n async handleActionFitWidth() {\n this.setFitMode('width');\n }\n\n async handleActionActualSize() {\n this.setScale(1.0);\n this.fitMode = 'auto';\n }\n\n async handleActionDownload() {\n this.downloadPDF();\n }\n\n async handleActionPrint() {\n window.print();\n }\n\n // PDF Loading\n async loadPDF() {\n if (!this.pdfUrl || !window.pdfjsLib) {\n this.showError('PDF URL or PDF.js library not available');\n return false;\n }\n\n this.isLoading = true;\n this.showLoading();\n\n try {\n const loadingTask = window.pdfjsLib.getDocument({\n url: this.pdfUrl,\n cMapUrl: this.pdfjsCMapUrl,\n cMapPacked: true\n });\n\n this.pdfDoc = await loadingTask.promise;\n this.totalPages = this.pdfDoc.numPages;\n this.currentPage = 1;\n\n // Update UI\n this.updatePageControls();\n this.updateStatus();\n\n // Render first page\n await this.renderPage(1);\n\n this.isLoaded = true;\n this.isLoading = false;\n this.element.classList.add('loaded');\n this.hideLoading();\n\n // Apply initial fit mode\n this.applyFitMode();\n\n // Emit loaded event via EventBus\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:loaded', { \n viewer: this, \n pdfUrl: this.pdfUrl,\n totalPages: this.totalPages\n });\n }\n\n return true;\n\n } catch (error) {\n console.error('Error loading PDF:', error);\n this.isLoading = false;\n this.showError('Failed to load PDF document');\n \n // Emit error event via EventBus\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:error', { \n viewer: this, \n pdfUrl: this.pdfUrl,\n error: error.message\n });\n }\n \n return false;\n }\n }\n\n async renderPage(pageNumber) {\n if (this.pageRendering) {\n this.pageNumPending = pageNumber;\n return;\n }\n\n if (!this.pdfDoc || !this.canvas || !this.ctx) {\n return;\n }\n\n this.pageRendering = true;\n this.currentPage = pageNumber;\n\n try {\n const page = await this.pdfDoc.getPage(pageNumber);\n const viewport = page.getViewport({ scale: this.scale });\n\n // Set canvas dimensions\n this.canvas.height = viewport.height;\n this.canvas.width = viewport.width;\n\n // Clear canvas\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\n // Render page\n const renderContext = {\n canvasContext: this.ctx,\n viewport: viewport\n };\n\n const renderTask = page.render(renderContext);\n await renderTask.promise;\n\n this.pageRendering = false;\n\n // If there was a pending page render request\n if (this.pageNumPending !== null) {\n const pendingPage = this.pageNumPending;\n this.pageNumPending = null;\n await this.renderPage(pendingPage);\n }\n\n this.updatePageControls();\n this.updateStatus();\n\n // Emit page changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:page-changed', { \n viewer: this, \n currentPage: this.currentPage,\n totalPages: this.totalPages\n });\n }\n\n } catch (error) {\n console.error('Error rendering page:', error);\n this.pageRendering = false;\n this.showError('Failed to render PDF page');\n }\n }\n\n // Navigation\n async goToPage(pageNumber) {\n if (!this.pdfDoc || pageNumber < 1 || pageNumber > this.totalPages) {\n return;\n }\n\n await this.renderPage(pageNumber);\n }\n\n // Zoom and Fit\n setScale(scale) {\n const oldScale = this.scale;\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, scale));\n this.fitMode = 'auto';\n \n if (this.isLoaded) {\n this.renderPage(this.currentPage);\n }\n\n // Emit scale change event\n const eventBus = this.getApp()?.events;\n if (eventBus && oldScale !== this.scale) {\n eventBus.emit('pdfviewer:scale-changed', { \n viewer: this, \n oldScale, \n newScale: this.scale \n });\n }\n }\n\n setFitMode(mode) {\n const oldMode = this.fitMode;\n this.fitMode = mode;\n this.applyFitMode();\n\n // Emit fit mode change event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:fit-mode-changed', { \n viewer: this, \n oldMode, \n newMode: mode \n });\n }\n }\n\n applyFitMode() {\n if (!this.isLoaded || !this.pdfDoc || !this.canvasContainer) {\n return;\n }\n\n this.pdfDoc.getPage(this.currentPage).then(page => {\n const containerRect = this.canvasContainer.getBoundingClientRect();\n const viewport = page.getViewport({ scale: 1 });\n\n let newScale;\n if (this.fitMode === 'page') {\n const scaleX = (containerRect.width - 40) / viewport.width;\n const scaleY = (containerRect.height - 40) / viewport.height;\n newScale = Math.min(scaleX, scaleY);\n } else if (this.fitMode === 'width') {\n newScale = (containerRect.width - 40) / viewport.width;\n } else {\n return; // auto mode, don't change scale\n }\n\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, newScale));\n this.renderPage(this.currentPage);\n });\n }\n\n // Event Handlers\n handleKeyDown(e) {\n // Only handle if PDF viewer is focused or no input is focused\n if (e.target.tagName === 'INPUT' && e.target !== this.pageInput) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowLeft':\n case 'PageUp':\n e.preventDefault();\n this.goToPage(this.currentPage - 1);\n break;\n case 'ArrowRight':\n case 'PageDown':\n e.preventDefault();\n this.goToPage(this.currentPage + 1);\n break;\n case 'Home':\n e.preventDefault();\n this.goToPage(1);\n break;\n case 'End':\n e.preventDefault();\n this.goToPage(this.totalPages);\n break;\n case '+':\n case '=':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.setScale(this.scale + this.scaleStep);\n }\n break;\n case '-':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.setScale(this.scale - this.scaleStep);\n }\n break;\n case '0':\n if (e.ctrlKey || e.metaKey) {\n e.preventDefault();\n this.setFitMode('page');\n }\n break;\n }\n }\n\n // UI Updates\n updatePageControls() {\n // Update page input\n if (this.pageInput) {\n this.pageInput.value = this.currentPage;\n }\n\n // Update page total display\n const pageTotalElement = this.element.querySelector('.page-total');\n if (pageTotalElement) {\n pageTotalElement.textContent = `/ ${this.totalPages}`;\n }\n\n // Update navigation buttons\n const firstBtn = this.element.querySelector('[data-action=\"first-page\"]');\n const prevBtn = this.element.querySelector('[data-action=\"prev-page\"]');\n const nextBtn = this.element.querySelector('[data-action=\"next-page\"]');\n const lastBtn = this.element.querySelector('[data-action=\"last-page\"]');\n\n if (firstBtn) firstBtn.disabled = this.currentPage <= 1;\n if (prevBtn) prevBtn.disabled = this.currentPage <= 1;\n if (nextBtn) nextBtn.disabled = this.currentPage >= this.totalPages;\n if (lastBtn) lastBtn.disabled = this.currentPage >= this.totalPages;\n\n // Update zoom buttons\n const zoomInBtn = this.element.querySelector('[data-action=\"zoom-in\"]');\n const zoomOutBtn = this.element.querySelector('[data-action=\"zoom-out\"]');\n\n if (zoomInBtn) zoomInBtn.disabled = this.scale >= this.maxScale;\n if (zoomOutBtn) zoomOutBtn.disabled = this.scale <= this.minScale;\n }\n\n updateStatus() {\n if (!this.statusElement) return;\n\n const currentPageElement = this.statusElement.querySelector('.current-page');\n const totalPagesElement = this.statusElement.querySelector('.total-pages');\n const zoomLevelElement = this.statusElement.querySelector('.zoom-level');\n\n if (currentPageElement) {\n currentPageElement.textContent = this.currentPage;\n }\n if (totalPagesElement) {\n totalPagesElement.textContent = this.totalPages;\n }\n if (zoomLevelElement) {\n zoomLevelElement.textContent = `${Math.round(this.scale * 100)}%`;\n }\n }\n\n // Utility Methods\n showLoading() {\n if (this.overlayElement) {\n this.overlayElement.style.display = 'flex';\n }\n }\n\n hideLoading() {\n if (this.overlayElement) {\n this.overlayElement.style.display = 'none';\n }\n }\n\n showError(message) {\n this.hideLoading();\n \n if (this.errorElement) {\n const errorMessageElement = this.errorElement.querySelector('.error-message');\n if (errorMessageElement) {\n errorMessageElement.textContent = message;\n }\n this.errorElement.style.display = 'block';\n }\n\n console.error('PDF Viewer Error:', message);\n }\n\n downloadPDF() {\n if (!this.pdfUrl) return;\n\n const link = document.createElement('a');\n link.href = this.pdfUrl;\n link.download = this.title + '.pdf';\n link.target = '_blank';\n link.click();\n }\n\n // Public API\n setPDF(pdfUrl, title = '') {\n const oldPdfUrl = this.pdfUrl;\n this.pdfUrl = pdfUrl;\n this.title = title || 'PDF Document';\n this.isLoaded = false;\n this.element.classList.remove('loaded');\n \n if (this.pdfDoc) {\n this.pdfDoc.destroy();\n this.pdfDoc = null;\n }\n \n this.currentPage = 1;\n this.totalPages = 0;\n this.scale = 1.0;\n \n if (pdfUrl) {\n this.loadPDF();\n }\n\n // Emit PDF changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:pdf-changed', { \n viewer: this, \n oldPdfUrl, \n newPdfUrl: pdfUrl \n });\n }\n }\n\n getCurrentPage() {\n return this.currentPage;\n }\n\n getTotalPages() {\n return this.totalPages;\n }\n\n getCurrentScale() {\n return this.scale;\n }\n\n async onBeforeDestroy() {\n // Clean up PDF.js resources\n if (this.pdfDoc) {\n this.pdfDoc.destroy();\n this.pdfDoc = null;\n }\n\n this.pageRendering = false;\n this.pageNumPending = null;\n\n // Clean up essential event listeners\n if (this._essentialListeners) {\n this._essentialListeners.forEach(({ el, type, fn }) => {\n if (el) el.removeEventListener(type, fn);\n });\n this._essentialListeners = null;\n }\n\n // Clean up resize observer\n if (this._resizeObserver) {\n this._resizeObserver.disconnect();\n this._resizeObserver = null;\n }\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('pdfviewer:destroyed', { viewer: this });\n }\n }\n\n // Static method to show PDF in a fullscreen dialog\n static async showDialog(pdfUrl, options = {}) {\n const {\n title = 'PDF Viewer',\n size = 'fullscreen',\n showControls = true,\n allowZoom = true,\n allowNavigation = true,\n showPageNumbers = true,\n ...dialogOptions\n } = options;\n\n const viewer = new PDFViewer({\n pdfUrl,\n title,\n showControls,\n allowZoom,\n allowNavigation,\n showPageNumbers\n });\n\n const dialog = new Dialog({\n title,\n body: viewer,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n buttons: [\n { \n text: 'Download', \n action: 'download', \n class: 'btn btn-outline-primary' \n },\n { \n text: 'Close', \n action: 'close', \n class: 'btn btn-secondary',\n dismiss: true\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render();\n document.body.appendChild(dialog.element);\n await dialog.mount();\n\n // Show the dialog\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve(viewer);\n });\n\n dialog.on('action:download', () => {\n viewer.downloadPDF();\n });\n\n dialog.on('action:close', () => {\n dialog.hide();\n });\n });\n }\n}"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";const e=require("./WebApp-Cnkm2125.js");class Page extends e.View{constructor(e={}){e.tagName=e.tagName||"main",e.className=e.className||"mojo-page";const t=e.pageName||"";t&&!e.id&&(e.id="page_"+t.toLowerCase().replace(/\s+/g,"_")),super(e),this.pageName=e.pageName||this.constructor.pageName||"",this.route=e.route||this.constructor.route||"",this.title=e.title||this.pageName||"",this.id||!this.constructor.pageName||e.pageName||(this.id="page_"+this.constructor.pageName.toLowerCase().replace(/\s+/g,"_")),this.pageIcon=e.icon||e.pageIcon||this.constructor.pageIcon||"bi bi-file-text",this.displayName=e.displayName||this.constructor.displayName||this.pageName||"",this.pageDescription=e.pageDescription||this.constructor.pageDescription||"",this.params={},this.query={},this.matched=!1,this.isActive=!1,this.pageOptions={title:e.title||this.pageName||"Untitled Page",description:e.description||"",requiresAuth:e.requiresAuth||!1,...e.pageOptions},this.savedState=null,console.log(`Page ${this.pageName} constructed with route: ${this.route}`)}async onParams(e={},t={}){this.params=e,this.query=t}canEnter(){if(this.options.permissions){const e=this.getApp().activeUser;if(!e||!e.hasPermission(this.options.permissions))return!1}return!(this.options.requiresGroup&&!this.getApp().activeGroup)}async onEnter(){this.isActive=!0,await this.onInitView(),this.savedState&&(this.restoreState(this.savedState),this.savedState=null),this.pageOptions&&this.pageOptions.title&&"undefined"!=typeof document&&(document.title=this.pageOptions.title),this.emit("activated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} entered`)}async onExit(){this.savedState=this.captureState(),this.isActive=!1,this.emit("deactivated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} exiting`)}getMetadata(){return{name:this.pageName,displayName:this.displayName||this.pageName,icon:this.pageIcon,description:this.pageDescription,route:this.route,isActive:this.isActive}}async onActionDefault(e){console.log(`Default action '${e}' triggered on page: ${this.pageName}`)}async makeActive(){this.getApp().showPage(this)}async onActionNavigate(e,t){e.preventDefault();const s=t.dataset.page;this.getApp().showPage(s)}captureState(){return this.element?{scrollTop:this.element.scrollTop,formData:this.captureFormData(),custom:this.captureCustomState()}:null}restoreState(e){e&&this.element&&(this.element.scrollTop=e.scrollTop||0,this.restoreFormData(e.formData),e.custom&&this.restoreCustomState(e.custom))}captureFormData(){const e={};return this.element?(this.element.querySelectorAll("input, select, textarea").forEach(t=>{t.name&&("checkbox"===t.type?e[t.name]=t.checked:"radio"===t.type?t.checked&&(e[t.name]=t.value):e[t.name]=t.value)}),e):e}restoreFormData(e){e&&this.element&&Object.entries(e).forEach(([e,t])=>{const s=this.element.querySelector(`[name="${e}"]`);if(s)if("checkbox"===s.type)s.checked=t;else if("radio"===s.type){const s=this.element.querySelector(`[name="${e}"][value="${t}"]`);s&&(s.checked=!0)}else s.value=t})}captureCustomState(){return{}}restoreCustomState(e){}setMeta(e={}){if("undefined"!=typeof document){if(e.title&&(document.title=e.title,this.pageOptions.title=e.title),e.description){let t=document.querySelector('meta[name="description"]');t||(t=document.createElement("meta"),t.name="description",document.head.appendChild(t)),t.content=e.description,this.pageOptions.description=e.description}Object.entries(e).forEach(([e,t])=>{if("title"!==e&&"description"!==e){let s=document.querySelector(`meta[name="${e}"]`);s||(s=document.createElement("meta"),s.name=e,document.head.appendChild(s)),s.content=t}})}}showError(e){if(super.showError(e),this.element){const t=document.createElement("div");t.className="alert alert-danger alert-dismissible fade show",t.innerHTML=`\n ${e}\n <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>\n `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},5e3)}}showSuccess(e){if(super.showSuccess(e),this.element){const t=document.createElement("div");t.className="alert alert-success alert-dismissible fade show",t.innerHTML=`\n ${e}\n <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>\n `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},3e3)}}async onBeforeRender(){await super.onBeforeRender(),this.setMeta({title:this.pageOptions.title,description:this.pageOptions.description})}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof document&&this.pageName&&document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}async onBeforeDestroy(){await super.onBeforeDestroy(),"undefined"!=typeof document&&this.pageName&&document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}navigate(e,t={},s={}){return this.app&&this.app.router?this.app.router.navigate(e,s):"undefined"!=typeof window&&window.MOJO?.router?window.MOJO.router.navigate(e,s):void console.error("No router available for navigation")}getRoute(){if(this.route){let e=this.route;return"string"==typeof e&&e.startsWith("/")&&(e=e.substring(1)),e}return this.pageName}syncUrl(e=!0){this.updateBrowserUrl(this.query,!1,!1)}updateBrowserUrl(e=null,t=!1,s=!1){this.getApp(),this.app.router.updateBrowserUrl(this.getRoute(),e,t,s)}static define(e){class DefinedPage extends Page{constructor(t={}){super({...e,...t})}}return DefinedPage.template=e.template,DefinedPage.pageName=e.pageName,DefinedPage.route=e.route,DefinedPage}}exports.Page=Page;
2
- //# sourceMappingURL=Page-CbWUdARI.js.map
1
+ "use strict";const e=require("./WebApp-DlfbVd3B.js");class Page extends e.View{constructor(e={}){e.tagName=e.tagName||"main",e.className=e.className||"mojo-page";const t=e.pageName||"";t&&!e.id&&(e.id="page_"+t.toLowerCase().replace(/\s+/g,"_")),super(e),this.pageName=e.pageName||this.constructor.pageName||"",this.route=e.route||this.constructor.route||"",this.title=e.title||this.pageName||"",this.id||!this.constructor.pageName||e.pageName||(this.id="page_"+this.constructor.pageName.toLowerCase().replace(/\s+/g,"_")),this.pageIcon=e.icon||e.pageIcon||this.constructor.pageIcon||"bi bi-file-text",this.displayName=e.displayName||this.constructor.displayName||this.pageName||"",this.pageDescription=e.pageDescription||this.constructor.pageDescription||"",this.params={},this.query={},this.matched=!1,this.isActive=!1,this.pageOptions={title:e.title||this.pageName||"Untitled Page",description:e.description||"",requiresAuth:e.requiresAuth||!1,...e.pageOptions},this.savedState=null,console.log(`Page ${this.pageName} constructed with route: ${this.route}`)}async onParams(e={},t={}){this.params=e,this.query=t}canEnter(){if(this.options.permissions){const e=this.getApp().activeUser;if(!e||!e.hasPermission(this.options.permissions))return!1}return!(this.options.requiresGroup&&!this.getApp().activeGroup)}async onEnter(){this.isActive=!0,await this.onInitView(),this.savedState&&(this.restoreState(this.savedState),this.savedState=null),this.pageOptions&&this.pageOptions.title&&"undefined"!=typeof document&&(document.title=this.pageOptions.title),this.emit("activated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} entered`)}async onExit(){this.savedState=this.captureState(),this.isActive=!1,this.emit("deactivated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} exiting`)}getMetadata(){return{name:this.pageName,displayName:this.displayName||this.pageName,icon:this.pageIcon,description:this.pageDescription,route:this.route,isActive:this.isActive}}async onActionDefault(e){console.log(`Default action '${e}' triggered on page: ${this.pageName}`)}async makeActive(){this.getApp().showPage(this)}async onActionNavigate(e,t){e.preventDefault();const s=t.dataset.page;this.getApp().showPage(s)}captureState(){return this.element?{scrollTop:this.element.scrollTop,formData:this.captureFormData(),custom:this.captureCustomState()}:null}restoreState(e){e&&this.element&&(this.element.scrollTop=e.scrollTop||0,this.restoreFormData(e.formData),e.custom&&this.restoreCustomState(e.custom))}captureFormData(){const e={};return this.element?(this.element.querySelectorAll("input, select, textarea").forEach(t=>{t.name&&("checkbox"===t.type?e[t.name]=t.checked:"radio"===t.type?t.checked&&(e[t.name]=t.value):e[t.name]=t.value)}),e):e}restoreFormData(e){e&&this.element&&Object.entries(e).forEach(([e,t])=>{const s=this.element.querySelector(`[name="${e}"]`);if(s)if("checkbox"===s.type)s.checked=t;else if("radio"===s.type){const s=this.element.querySelector(`[name="${e}"][value="${t}"]`);s&&(s.checked=!0)}else s.value=t})}captureCustomState(){return{}}restoreCustomState(e){}setMeta(e={}){if("undefined"!=typeof document){if(e.title&&(document.title=e.title,this.pageOptions.title=e.title),e.description){let t=document.querySelector('meta[name="description"]');t||(t=document.createElement("meta"),t.name="description",document.head.appendChild(t)),t.content=e.description,this.pageOptions.description=e.description}Object.entries(e).forEach(([e,t])=>{if("title"!==e&&"description"!==e){let s=document.querySelector(`meta[name="${e}"]`);s||(s=document.createElement("meta"),s.name=e,document.head.appendChild(s)),s.content=t}})}}showError(e){if(super.showError(e),this.element){const t=document.createElement("div");t.className="alert alert-danger alert-dismissible fade show",t.innerHTML=`\n ${e}\n <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>\n `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},5e3)}}showSuccess(e){if(super.showSuccess(e),this.element){const t=document.createElement("div");t.className="alert alert-success alert-dismissible fade show",t.innerHTML=`\n ${e}\n <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>\n `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},3e3)}}async onBeforeRender(){await super.onBeforeRender(),this.setMeta({title:this.pageOptions.title,description:this.pageOptions.description})}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof document&&this.pageName&&document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}async onBeforeDestroy(){await super.onBeforeDestroy(),"undefined"!=typeof document&&this.pageName&&document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}navigate(e,t={},s={}){return this.app&&this.app.router?this.app.router.navigate(e,s):"undefined"!=typeof window&&window.MOJO?.router?window.MOJO.router.navigate(e,s):void console.error("No router available for navigation")}getRoute(){if(this.route){let e=this.route;return"string"==typeof e&&e.startsWith("/")&&(e=e.substring(1)),e}return this.pageName}syncUrl(e=!0){this.updateBrowserUrl(this.query,!1,!1)}updateBrowserUrl(e=null,t=!1,s=!1){this.getApp(),this.app.router.updateBrowserUrl(this.getRoute(),e,t,s)}static define(e){class DefinedPage extends Page{constructor(t={}){super({...e,...t})}}return DefinedPage.template=e.template,DefinedPage.pageName=e.pageName,DefinedPage.route=e.route,DefinedPage}}exports.Page=Page;
2
+ //# sourceMappingURL=Page-BQ7bila2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Page-CbWUdARI.js","sources":["../../src/core/Page.js"],"sourcesContent":["/**\n * Page - Extends View with routing capabilities for MOJO framework\n * Handles URL routing, parameters, and page-specific actions\n *\n * Event Emitter notes:\n * - Uses EventEmitter via View base class.\n * - Use .emit/.on/.off/.once for all custom events.\n */\n\nimport View from '@core/View.js';\n\nclass Page extends View {\n constructor(options = {}) {\n // Set default tag name for pages\n options.tagName = options.tagName || 'main';\n options.className = options.className || 'mojo-page';\n\n // Set page ID based on page name\n const pageName = options.pageName || '';\n if (pageName && !options.id) {\n options.id = 'page_' + pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n super(options);\n\n // Core page properties from design doc\n this.pageName = options.pageName || this.constructor.pageName || '';\n this.route = options.route || this.constructor.route || '';\n this.title = options.title || this.pageName || '';\n\n // Set page ID if not already set and we have a page_name from constructor\n if (!this.id && this.constructor.pageName && !options.pageName) {\n this.id = 'page_' + this.constructor.pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n // Page metadata for event system\n this.pageIcon = options.icon || options.pageIcon || this.constructor.pageIcon || 'bi bi-file-text';\n this.displayName = options.displayName || this.constructor.displayName || this.pageName || '';\n this.pageDescription = options.pageDescription || this.constructor.pageDescription || '';\n\n // Routing state\n this.params = {};\n this.query = {};\n this.matched = false;\n this.isActive = false;\n\n // Page-specific options\n this.pageOptions = {\n title: options.title || this.pageName || 'Untitled Page',\n description: options.description || '',\n requiresAuth: options.requiresAuth || false,\n ...options.pageOptions\n };\n\n // State preservation\n this.savedState = null;\n\n console.log(`Page ${this.pageName} constructed with route: ${this.route}`);\n }\n\n /**\n * Handle route parameters - from design doc\n * @param {object} params - Route parameters\n * @param {object} query - Query string parameters\n */\n async onParams(params = {}, query = {}) {\n // const paramsChanged = JSON.stringify(params) !== JSON.stringify(this.params);\n // const queryChanged = JSON.stringify(query) !== JSON.stringify(this.query);\n\n this.params = params;\n this.query = query;\n\n // Only re-render if params actually changed and page is active\n // if (this.isActive && (paramsChanged || queryChanged)) {\n // console.log(`Page ${this.pageName} params changed, re-rendering`);\n // await this.render();\n // }\n }\n\n canEnter() {\n if (this.options.permissions) {\n const user = this.getApp().activeUser;\n if (!user || !user.hasPermission(this.options.permissions)) {\n return false;\n }\n }\n if (this.options.requiresGroup && !this.getApp().activeGroup) {\n return false;\n }\n return true;\n }\n\n /**\n * Called when entering this page (before render)\n * Override this method for initialization logic\n */\n async onEnter() {\n this.isActive = true;\n await this.onInitView();\n\n // Restore saved state if exists\n if (this.savedState) {\n this.restoreState(this.savedState);\n this.savedState = null;\n }\n\n // Set page title if provided\n if (this.pageOptions && this.pageOptions.title && typeof document !== 'undefined') {\n document.title = this.pageOptions.title;\n }\n\n // Emit activation event\n this.emit('activated', {\n page: this.getMetadata()\n });\n\n console.log(`Page ${this.pageName} entered`);\n }\n\n /**\n * Called when leaving this page (before cleanup)\n * Override this method for cleanup logic like removing listeners, clearing timers, etc.\n */\n async onExit() {\n // Save state before exit\n this.savedState = this.captureState();\n this.isActive = false;\n\n // Emit deactivation event\n this.emit('deactivated', {\n page: this.getMetadata()\n });\n console.log(`Page ${this.pageName} exiting`);\n }\n\n /**\n * Get page metadata for display and events\n * @returns {object} Page metadata\n */\n getMetadata() {\n return {\n name: this.pageName,\n displayName: this.displayName || this.pageName,\n icon: this.pageIcon,\n description: this.pageDescription,\n route: this.route,\n isActive: this.isActive\n };\n }\n\n /**\n * Handle default action - fallback from design doc\n */\n async onActionDefault(action) {\n console.log(`Default action '${action}' triggered on page: ${this.pageName}`);\n }\n\n async makeActive() {\n this.getApp().showPage(this);\n }\n\n async onActionNavigate(event, element) {\n event.preventDefault();\n const page = element.dataset.page;\n this.getApp().showPage(page);\n }\n\n /**\n * Capture current page state for preservation\n * @returns {object|null} Captured state\n */\n captureState() {\n if (!this.element) return null;\n\n return {\n scrollTop: this.element.scrollTop,\n formData: this.captureFormData(),\n custom: this.captureCustomState()\n };\n }\n\n /**\n * Restore saved state\n * @param {object} state - State to restore\n */\n restoreState(state) {\n if (!state || !this.element) return;\n\n this.element.scrollTop = state.scrollTop || 0;\n this.restoreFormData(state.formData);\n if (state.custom) {\n this.restoreCustomState(state.custom);\n }\n }\n\n /**\n * Capture form data from page\n * @returns {object} Form data\n */\n captureFormData() {\n const data = {};\n if (!this.element) return data;\n\n this.element.querySelectorAll('input, select, textarea').forEach(field => {\n if (field.name) {\n if (field.type === 'checkbox') {\n data[field.name] = field.checked;\n } else if (field.type === 'radio') {\n if (field.checked) {\n data[field.name] = field.value;\n }\n } else {\n data[field.name] = field.value;\n }\n }\n });\n\n return data;\n }\n\n /**\n * Restore form data to page\n * @param {object} formData - Form data to restore\n */\n restoreFormData(formData) {\n if (!formData || !this.element) return;\n\n Object.entries(formData).forEach(([name, value]) => {\n const field = this.element.querySelector(`[name=\"${name}\"]`);\n if (field) {\n if (field.type === 'checkbox') {\n field.checked = value;\n } else if (field.type === 'radio') {\n const radio = this.element.querySelector(`[name=\"${name}\"][value=\"${value}\"]`);\n if (radio) radio.checked = true;\n } else {\n field.value = value;\n }\n }\n });\n }\n\n /**\n * Capture custom state - override in subclasses\n * @returns {object} Custom state\n */\n captureCustomState() {\n return {};\n }\n\n /**\n * Restore custom state - override in subclasses\n * @param {object} state - Custom state to restore\n */\n restoreCustomState(state) {\n // Override in subclasses\n }\n\n\n\n /**\n * Set page metadata\n * @param {object} meta - Metadata object\n */\n setMeta(meta = {}) {\n if (typeof document === 'undefined') {\n return;\n }\n\n // Set title\n if (meta.title) {\n document.title = meta.title;\n this.pageOptions.title = meta.title;\n }\n\n // Set description\n if (meta.description) {\n let descMeta = document.querySelector('meta[name=\"description\"]');\n if (!descMeta) {\n descMeta = document.createElement('meta');\n descMeta.name = 'description';\n document.head.appendChild(descMeta);\n }\n descMeta.content = meta.description;\n this.pageOptions.description = meta.description;\n }\n\n // Set other meta tags\n Object.entries(meta).forEach(([key, value]) => {\n if (key !== 'title' && key !== 'description') {\n let metaEl = document.querySelector(`meta[name=\"${key}\"]`);\n if (!metaEl) {\n metaEl = document.createElement('meta');\n metaEl.name = key;\n document.head.appendChild(metaEl);\n }\n metaEl.content = value;\n }\n });\n }\n\n\n /**\n * Show error message with page context\n * @param {string} message - Error message\n */\n showError(message) {\n super.showError(message);\n\n // Page-specific error display can be implemented here\n if (this.element) {\n // Example: Add error to page\n const errorDiv = document.createElement('div');\n errorDiv.className = 'alert alert-danger alert-dismissible fade show';\n errorDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(errorDiv, this.element.firstChild);\n\n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (errorDiv.parentNode) {\n errorDiv.parentNode.removeChild(errorDiv);\n }\n }, 5000);\n }\n }\n\n /**\n * Show success message with page context\n * @param {string} message - Success message\n */\n showSuccess(message) {\n super.showSuccess(message);\n\n // Page-specific success display\n if (this.element) {\n const successDiv = document.createElement('div');\n successDiv.className = 'alert alert-success alert-dismissible fade show';\n successDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(successDiv, this.element.firstChild);\n\n // Auto-remove after 3 seconds\n setTimeout(() => {\n if (successDiv.parentNode) {\n successDiv.parentNode.removeChild(successDiv);\n }\n }, 3000);\n }\n }\n\n /**\n * Page-specific before render hook\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n // Set page metadata before rendering\n this.setMeta({\n title: this.pageOptions.title,\n description: this.pageOptions.description\n });\n }\n\n /**\n * Page-specific after mount hook\n */\n async onAfterMount() {\n await super.onAfterMount();\n\n // Add page-specific class to body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Page-specific before destroy hook\n */\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove page-specific class from body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Navigate to another page using the app's router\n * @param {string} route - Route to navigate to\n * @param {object} params - Route parameters\n * @param {object} options - Navigation options\n */\n navigate(route, params = {}, options = {}) {\n // Delegate to app's router\n if (this.app && this.app.router) {\n return this.app.router.navigate(route, options);\n }\n\n // Fallback to MOJO global router\n if (typeof window !== 'undefined' && window.MOJO?.router) {\n return window.MOJO.router.navigate(route, options);\n }\n\n console.error('No router available for navigation');\n }\n\n getRoute() {\n if (this.route) {\n let route = this.route;\n if (typeof route === 'string' && route.startsWith('/')) {\n route = route.substring(1);\n }\n return route;\n }\n return this.pageName;\n }\n\n syncUrl(force = true) {\n this.updateBrowserUrl(this.query, false, false);\n }\n\n updateBrowserUrl(query = null, replace = false, trigger = false) {\n this.getApp();\n // we need to do this to normalize the URL\n // const targetPath = this.app.buildPagePath(this, this.params, query);\n // const { pageName, queryParams } = this.app.router.parseInput(targetPath);\n this.app.router.updateBrowserUrl(this.getRoute(), query, replace, trigger);\n }\n\n /**\n * Static method to define a page class with metadata\n * @param {object} definition - Page class definition\n * @returns {class} Page class\n */\n static define(definition) {\n class DefinedPage extends Page {\n constructor(options = {}) {\n super({\n ...definition,\n ...options\n });\n }\n }\n\n // Copy static properties\n DefinedPage.template = definition.template;\n DefinedPage.pageName = definition.pageName;\n DefinedPage.route = definition.route;\n\n return DefinedPage;\n }\n}\n\nexport default Page;\n"],"names":["Page","View","constructor","options","tagName","className","pageName","id","toLowerCase","replace","super","this","route","title","pageIcon","icon","displayName","pageDescription","params","query","matched","isActive","pageOptions","description","requiresAuth","savedState","console","log","onParams","canEnter","permissions","user","getApp","activeUser","hasPermission","requiresGroup","activeGroup","onEnter","onInitView","restoreState","document","emit","page","getMetadata","onExit","captureState","name","onActionDefault","action","makeActive","showPage","onActionNavigate","event","element","preventDefault","dataset","scrollTop","formData","captureFormData","custom","captureCustomState","state","restoreFormData","restoreCustomState","data","querySelectorAll","forEach","field","type","checked","value","Object","entries","querySelector","radio","setMeta","meta","descMeta","createElement","head","appendChild","content","key","metaEl","showError","message","errorDiv","innerHTML","insertBefore","firstChild","setTimeout","parentNode","removeChild","showSuccess","successDiv","onBeforeRender","onAfterMount","body","classList","add","onBeforeDestroy","remove","navigate","app","router","window","MOJO","error","getRoute","startsWith","substring","syncUrl","force","updateBrowserUrl","trigger","define","definition","DefinedPage","template"],"mappings":"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"}
1
+ {"version":3,"file":"Page-BQ7bila2.js","sources":["../../src/core/Page.js"],"sourcesContent":["/**\n * Page - Extends View with routing capabilities for MOJO framework\n * Handles URL routing, parameters, and page-specific actions\n *\n * Event Emitter notes:\n * - Uses EventEmitter via View base class.\n * - Use .emit/.on/.off/.once for all custom events.\n */\n\nimport View from '@core/View.js';\n\nclass Page extends View {\n constructor(options = {}) {\n // Set default tag name for pages\n options.tagName = options.tagName || 'main';\n options.className = options.className || 'mojo-page';\n\n // Set page ID based on page name\n const pageName = options.pageName || '';\n if (pageName && !options.id) {\n options.id = 'page_' + pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n super(options);\n\n // Core page properties from design doc\n this.pageName = options.pageName || this.constructor.pageName || '';\n this.route = options.route || this.constructor.route || '';\n this.title = options.title || this.pageName || '';\n\n // Set page ID if not already set and we have a page_name from constructor\n if (!this.id && this.constructor.pageName && !options.pageName) {\n this.id = 'page_' + this.constructor.pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n // Page metadata for event system\n this.pageIcon = options.icon || options.pageIcon || this.constructor.pageIcon || 'bi bi-file-text';\n this.displayName = options.displayName || this.constructor.displayName || this.pageName || '';\n this.pageDescription = options.pageDescription || this.constructor.pageDescription || '';\n\n // Routing state\n this.params = {};\n this.query = {};\n this.matched = false;\n this.isActive = false;\n\n // Page-specific options\n this.pageOptions = {\n title: options.title || this.pageName || 'Untitled Page',\n description: options.description || '',\n requiresAuth: options.requiresAuth || false,\n ...options.pageOptions\n };\n\n // State preservation\n this.savedState = null;\n\n console.log(`Page ${this.pageName} constructed with route: ${this.route}`);\n }\n\n /**\n * Handle route parameters - from design doc\n * @param {object} params - Route parameters\n * @param {object} query - Query string parameters\n */\n async onParams(params = {}, query = {}) {\n // const paramsChanged = JSON.stringify(params) !== JSON.stringify(this.params);\n // const queryChanged = JSON.stringify(query) !== JSON.stringify(this.query);\n\n this.params = params;\n this.query = query;\n\n // Only re-render if params actually changed and page is active\n // if (this.isActive && (paramsChanged || queryChanged)) {\n // console.log(`Page ${this.pageName} params changed, re-rendering`);\n // await this.render();\n // }\n }\n\n canEnter() {\n if (this.options.permissions) {\n const user = this.getApp().activeUser;\n if (!user || !user.hasPermission(this.options.permissions)) {\n return false;\n }\n }\n if (this.options.requiresGroup && !this.getApp().activeGroup) {\n return false;\n }\n return true;\n }\n\n /**\n * Called when entering this page (before render)\n * Override this method for initialization logic\n */\n async onEnter() {\n this.isActive = true;\n await this.onInitView();\n\n // Restore saved state if exists\n if (this.savedState) {\n this.restoreState(this.savedState);\n this.savedState = null;\n }\n\n // Set page title if provided\n if (this.pageOptions && this.pageOptions.title && typeof document !== 'undefined') {\n document.title = this.pageOptions.title;\n }\n\n // Emit activation event\n this.emit('activated', {\n page: this.getMetadata()\n });\n\n console.log(`Page ${this.pageName} entered`);\n }\n\n /**\n * Called when leaving this page (before cleanup)\n * Override this method for cleanup logic like removing listeners, clearing timers, etc.\n */\n async onExit() {\n // Save state before exit\n this.savedState = this.captureState();\n this.isActive = false;\n\n // Emit deactivation event\n this.emit('deactivated', {\n page: this.getMetadata()\n });\n console.log(`Page ${this.pageName} exiting`);\n }\n\n /**\n * Get page metadata for display and events\n * @returns {object} Page metadata\n */\n getMetadata() {\n return {\n name: this.pageName,\n displayName: this.displayName || this.pageName,\n icon: this.pageIcon,\n description: this.pageDescription,\n route: this.route,\n isActive: this.isActive\n };\n }\n\n /**\n * Handle default action - fallback from design doc\n */\n async onActionDefault(action) {\n console.log(`Default action '${action}' triggered on page: ${this.pageName}`);\n }\n\n async makeActive() {\n this.getApp().showPage(this);\n }\n\n async onActionNavigate(event, element) {\n event.preventDefault();\n const page = element.dataset.page;\n this.getApp().showPage(page);\n }\n\n /**\n * Capture current page state for preservation\n * @returns {object|null} Captured state\n */\n captureState() {\n if (!this.element) return null;\n\n return {\n scrollTop: this.element.scrollTop,\n formData: this.captureFormData(),\n custom: this.captureCustomState()\n };\n }\n\n /**\n * Restore saved state\n * @param {object} state - State to restore\n */\n restoreState(state) {\n if (!state || !this.element) return;\n\n this.element.scrollTop = state.scrollTop || 0;\n this.restoreFormData(state.formData);\n if (state.custom) {\n this.restoreCustomState(state.custom);\n }\n }\n\n /**\n * Capture form data from page\n * @returns {object} Form data\n */\n captureFormData() {\n const data = {};\n if (!this.element) return data;\n\n this.element.querySelectorAll('input, select, textarea').forEach(field => {\n if (field.name) {\n if (field.type === 'checkbox') {\n data[field.name] = field.checked;\n } else if (field.type === 'radio') {\n if (field.checked) {\n data[field.name] = field.value;\n }\n } else {\n data[field.name] = field.value;\n }\n }\n });\n\n return data;\n }\n\n /**\n * Restore form data to page\n * @param {object} formData - Form data to restore\n */\n restoreFormData(formData) {\n if (!formData || !this.element) return;\n\n Object.entries(formData).forEach(([name, value]) => {\n const field = this.element.querySelector(`[name=\"${name}\"]`);\n if (field) {\n if (field.type === 'checkbox') {\n field.checked = value;\n } else if (field.type === 'radio') {\n const radio = this.element.querySelector(`[name=\"${name}\"][value=\"${value}\"]`);\n if (radio) radio.checked = true;\n } else {\n field.value = value;\n }\n }\n });\n }\n\n /**\n * Capture custom state - override in subclasses\n * @returns {object} Custom state\n */\n captureCustomState() {\n return {};\n }\n\n /**\n * Restore custom state - override in subclasses\n * @param {object} state - Custom state to restore\n */\n restoreCustomState(state) {\n // Override in subclasses\n }\n\n\n\n /**\n * Set page metadata\n * @param {object} meta - Metadata object\n */\n setMeta(meta = {}) {\n if (typeof document === 'undefined') {\n return;\n }\n\n // Set title\n if (meta.title) {\n document.title = meta.title;\n this.pageOptions.title = meta.title;\n }\n\n // Set description\n if (meta.description) {\n let descMeta = document.querySelector('meta[name=\"description\"]');\n if (!descMeta) {\n descMeta = document.createElement('meta');\n descMeta.name = 'description';\n document.head.appendChild(descMeta);\n }\n descMeta.content = meta.description;\n this.pageOptions.description = meta.description;\n }\n\n // Set other meta tags\n Object.entries(meta).forEach(([key, value]) => {\n if (key !== 'title' && key !== 'description') {\n let metaEl = document.querySelector(`meta[name=\"${key}\"]`);\n if (!metaEl) {\n metaEl = document.createElement('meta');\n metaEl.name = key;\n document.head.appendChild(metaEl);\n }\n metaEl.content = value;\n }\n });\n }\n\n\n /**\n * Show error message with page context\n * @param {string} message - Error message\n */\n showError(message) {\n super.showError(message);\n\n // Page-specific error display can be implemented here\n if (this.element) {\n // Example: Add error to page\n const errorDiv = document.createElement('div');\n errorDiv.className = 'alert alert-danger alert-dismissible fade show';\n errorDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(errorDiv, this.element.firstChild);\n\n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (errorDiv.parentNode) {\n errorDiv.parentNode.removeChild(errorDiv);\n }\n }, 5000);\n }\n }\n\n /**\n * Show success message with page context\n * @param {string} message - Success message\n */\n showSuccess(message) {\n super.showSuccess(message);\n\n // Page-specific success display\n if (this.element) {\n const successDiv = document.createElement('div');\n successDiv.className = 'alert alert-success alert-dismissible fade show';\n successDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(successDiv, this.element.firstChild);\n\n // Auto-remove after 3 seconds\n setTimeout(() => {\n if (successDiv.parentNode) {\n successDiv.parentNode.removeChild(successDiv);\n }\n }, 3000);\n }\n }\n\n /**\n * Page-specific before render hook\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n // Set page metadata before rendering\n this.setMeta({\n title: this.pageOptions.title,\n description: this.pageOptions.description\n });\n }\n\n /**\n * Page-specific after mount hook\n */\n async onAfterMount() {\n await super.onAfterMount();\n\n // Add page-specific class to body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Page-specific before destroy hook\n */\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove page-specific class from body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Navigate to another page using the app's router\n * @param {string} route - Route to navigate to\n * @param {object} params - Route parameters\n * @param {object} options - Navigation options\n */\n navigate(route, params = {}, options = {}) {\n // Delegate to app's router\n if (this.app && this.app.router) {\n return this.app.router.navigate(route, options);\n }\n\n // Fallback to MOJO global router\n if (typeof window !== 'undefined' && window.MOJO?.router) {\n return window.MOJO.router.navigate(route, options);\n }\n\n console.error('No router available for navigation');\n }\n\n getRoute() {\n if (this.route) {\n let route = this.route;\n if (typeof route === 'string' && route.startsWith('/')) {\n route = route.substring(1);\n }\n return route;\n }\n return this.pageName;\n }\n\n syncUrl(force = true) {\n this.updateBrowserUrl(this.query, false, false);\n }\n\n updateBrowserUrl(query = null, replace = false, trigger = false) {\n this.getApp();\n // we need to do this to normalize the URL\n // const targetPath = this.app.buildPagePath(this, this.params, query);\n // const { pageName, queryParams } = this.app.router.parseInput(targetPath);\n this.app.router.updateBrowserUrl(this.getRoute(), query, replace, trigger);\n }\n\n /**\n * Static method to define a page class with metadata\n * @param {object} definition - Page class definition\n * @returns {class} Page class\n */\n static define(definition) {\n class DefinedPage extends Page {\n constructor(options = {}) {\n super({\n ...definition,\n ...options\n });\n }\n }\n\n // Copy static properties\n DefinedPage.template = definition.template;\n DefinedPage.pageName = definition.pageName;\n DefinedPage.route = definition.route;\n\n return DefinedPage;\n }\n}\n\nexport default Page;\n"],"names":["Page","View","constructor","options","tagName","className","pageName","id","toLowerCase","replace","super","this","route","title","pageIcon","icon","displayName","pageDescription","params","query","matched","isActive","pageOptions","description","requiresAuth","savedState","console","log","onParams","canEnter","permissions","user","getApp","activeUser","hasPermission","requiresGroup","activeGroup","onEnter","onInitView","restoreState","document","emit","page","getMetadata","onExit","captureState","name","onActionDefault","action","makeActive","showPage","onActionNavigate","event","element","preventDefault","dataset","scrollTop","formData","captureFormData","custom","captureCustomState","state","restoreFormData","restoreCustomState","data","querySelectorAll","forEach","field","type","checked","value","Object","entries","querySelector","radio","setMeta","meta","descMeta","createElement","head","appendChild","content","key","metaEl","showError","message","errorDiv","innerHTML","insertBefore","firstChild","setTimeout","parentNode","removeChild","showSuccess","successDiv","onBeforeRender","onAfterMount","body","classList","add","onBeforeDestroy","remove","navigate","app","router","window","MOJO","error","getRoute","startsWith","substring","syncUrl","force","updateBrowserUrl","trigger","define","definition","DefinedPage","template"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { V as View } from "./WebApp-CYCNA3GB.js";
1
+ import { V as View } from "./WebApp-D0KJTN0p.js";
2
2
  class Page extends View {
3
3
  constructor(options = {}) {
4
4
  options.tagName = options.tagName || "main";
@@ -348,4 +348,4 @@ class Page extends View {
348
348
  export {
349
349
  Page as P
350
350
  };
351
- //# sourceMappingURL=Page-D7lbK30W.js.map
351
+ //# sourceMappingURL=Page-Dn1oAANw.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Page-D7lbK30W.js","sources":["../../src/core/Page.js"],"sourcesContent":["/**\n * Page - Extends View with routing capabilities for MOJO framework\n * Handles URL routing, parameters, and page-specific actions\n *\n * Event Emitter notes:\n * - Uses EventEmitter via View base class.\n * - Use .emit/.on/.off/.once for all custom events.\n */\n\nimport View from '@core/View.js';\n\nclass Page extends View {\n constructor(options = {}) {\n // Set default tag name for pages\n options.tagName = options.tagName || 'main';\n options.className = options.className || 'mojo-page';\n\n // Set page ID based on page name\n const pageName = options.pageName || '';\n if (pageName && !options.id) {\n options.id = 'page_' + pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n super(options);\n\n // Core page properties from design doc\n this.pageName = options.pageName || this.constructor.pageName || '';\n this.route = options.route || this.constructor.route || '';\n this.title = options.title || this.pageName || '';\n\n // Set page ID if not already set and we have a page_name from constructor\n if (!this.id && this.constructor.pageName && !options.pageName) {\n this.id = 'page_' + this.constructor.pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n // Page metadata for event system\n this.pageIcon = options.icon || options.pageIcon || this.constructor.pageIcon || 'bi bi-file-text';\n this.displayName = options.displayName || this.constructor.displayName || this.pageName || '';\n this.pageDescription = options.pageDescription || this.constructor.pageDescription || '';\n\n // Routing state\n this.params = {};\n this.query = {};\n this.matched = false;\n this.isActive = false;\n\n // Page-specific options\n this.pageOptions = {\n title: options.title || this.pageName || 'Untitled Page',\n description: options.description || '',\n requiresAuth: options.requiresAuth || false,\n ...options.pageOptions\n };\n\n // State preservation\n this.savedState = null;\n\n console.log(`Page ${this.pageName} constructed with route: ${this.route}`);\n }\n\n /**\n * Handle route parameters - from design doc\n * @param {object} params - Route parameters\n * @param {object} query - Query string parameters\n */\n async onParams(params = {}, query = {}) {\n // const paramsChanged = JSON.stringify(params) !== JSON.stringify(this.params);\n // const queryChanged = JSON.stringify(query) !== JSON.stringify(this.query);\n\n this.params = params;\n this.query = query;\n\n // Only re-render if params actually changed and page is active\n // if (this.isActive && (paramsChanged || queryChanged)) {\n // console.log(`Page ${this.pageName} params changed, re-rendering`);\n // await this.render();\n // }\n }\n\n canEnter() {\n if (this.options.permissions) {\n const user = this.getApp().activeUser;\n if (!user || !user.hasPermission(this.options.permissions)) {\n return false;\n }\n }\n if (this.options.requiresGroup && !this.getApp().activeGroup) {\n return false;\n }\n return true;\n }\n\n /**\n * Called when entering this page (before render)\n * Override this method for initialization logic\n */\n async onEnter() {\n this.isActive = true;\n await this.onInitView();\n\n // Restore saved state if exists\n if (this.savedState) {\n this.restoreState(this.savedState);\n this.savedState = null;\n }\n\n // Set page title if provided\n if (this.pageOptions && this.pageOptions.title && typeof document !== 'undefined') {\n document.title = this.pageOptions.title;\n }\n\n // Emit activation event\n this.emit('activated', {\n page: this.getMetadata()\n });\n\n console.log(`Page ${this.pageName} entered`);\n }\n\n /**\n * Called when leaving this page (before cleanup)\n * Override this method for cleanup logic like removing listeners, clearing timers, etc.\n */\n async onExit() {\n // Save state before exit\n this.savedState = this.captureState();\n this.isActive = false;\n\n // Emit deactivation event\n this.emit('deactivated', {\n page: this.getMetadata()\n });\n console.log(`Page ${this.pageName} exiting`);\n }\n\n /**\n * Get page metadata for display and events\n * @returns {object} Page metadata\n */\n getMetadata() {\n return {\n name: this.pageName,\n displayName: this.displayName || this.pageName,\n icon: this.pageIcon,\n description: this.pageDescription,\n route: this.route,\n isActive: this.isActive\n };\n }\n\n /**\n * Handle default action - fallback from design doc\n */\n async onActionDefault(action) {\n console.log(`Default action '${action}' triggered on page: ${this.pageName}`);\n }\n\n async makeActive() {\n this.getApp().showPage(this);\n }\n\n async onActionNavigate(event, element) {\n event.preventDefault();\n const page = element.dataset.page;\n this.getApp().showPage(page);\n }\n\n /**\n * Capture current page state for preservation\n * @returns {object|null} Captured state\n */\n captureState() {\n if (!this.element) return null;\n\n return {\n scrollTop: this.element.scrollTop,\n formData: this.captureFormData(),\n custom: this.captureCustomState()\n };\n }\n\n /**\n * Restore saved state\n * @param {object} state - State to restore\n */\n restoreState(state) {\n if (!state || !this.element) return;\n\n this.element.scrollTop = state.scrollTop || 0;\n this.restoreFormData(state.formData);\n if (state.custom) {\n this.restoreCustomState(state.custom);\n }\n }\n\n /**\n * Capture form data from page\n * @returns {object} Form data\n */\n captureFormData() {\n const data = {};\n if (!this.element) return data;\n\n this.element.querySelectorAll('input, select, textarea').forEach(field => {\n if (field.name) {\n if (field.type === 'checkbox') {\n data[field.name] = field.checked;\n } else if (field.type === 'radio') {\n if (field.checked) {\n data[field.name] = field.value;\n }\n } else {\n data[field.name] = field.value;\n }\n }\n });\n\n return data;\n }\n\n /**\n * Restore form data to page\n * @param {object} formData - Form data to restore\n */\n restoreFormData(formData) {\n if (!formData || !this.element) return;\n\n Object.entries(formData).forEach(([name, value]) => {\n const field = this.element.querySelector(`[name=\"${name}\"]`);\n if (field) {\n if (field.type === 'checkbox') {\n field.checked = value;\n } else if (field.type === 'radio') {\n const radio = this.element.querySelector(`[name=\"${name}\"][value=\"${value}\"]`);\n if (radio) radio.checked = true;\n } else {\n field.value = value;\n }\n }\n });\n }\n\n /**\n * Capture custom state - override in subclasses\n * @returns {object} Custom state\n */\n captureCustomState() {\n return {};\n }\n\n /**\n * Restore custom state - override in subclasses\n * @param {object} state - Custom state to restore\n */\n restoreCustomState(state) {\n // Override in subclasses\n }\n\n\n\n /**\n * Set page metadata\n * @param {object} meta - Metadata object\n */\n setMeta(meta = {}) {\n if (typeof document === 'undefined') {\n return;\n }\n\n // Set title\n if (meta.title) {\n document.title = meta.title;\n this.pageOptions.title = meta.title;\n }\n\n // Set description\n if (meta.description) {\n let descMeta = document.querySelector('meta[name=\"description\"]');\n if (!descMeta) {\n descMeta = document.createElement('meta');\n descMeta.name = 'description';\n document.head.appendChild(descMeta);\n }\n descMeta.content = meta.description;\n this.pageOptions.description = meta.description;\n }\n\n // Set other meta tags\n Object.entries(meta).forEach(([key, value]) => {\n if (key !== 'title' && key !== 'description') {\n let metaEl = document.querySelector(`meta[name=\"${key}\"]`);\n if (!metaEl) {\n metaEl = document.createElement('meta');\n metaEl.name = key;\n document.head.appendChild(metaEl);\n }\n metaEl.content = value;\n }\n });\n }\n\n\n /**\n * Show error message with page context\n * @param {string} message - Error message\n */\n showError(message) {\n super.showError(message);\n\n // Page-specific error display can be implemented here\n if (this.element) {\n // Example: Add error to page\n const errorDiv = document.createElement('div');\n errorDiv.className = 'alert alert-danger alert-dismissible fade show';\n errorDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(errorDiv, this.element.firstChild);\n\n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (errorDiv.parentNode) {\n errorDiv.parentNode.removeChild(errorDiv);\n }\n }, 5000);\n }\n }\n\n /**\n * Show success message with page context\n * @param {string} message - Success message\n */\n showSuccess(message) {\n super.showSuccess(message);\n\n // Page-specific success display\n if (this.element) {\n const successDiv = document.createElement('div');\n successDiv.className = 'alert alert-success alert-dismissible fade show';\n successDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(successDiv, this.element.firstChild);\n\n // Auto-remove after 3 seconds\n setTimeout(() => {\n if (successDiv.parentNode) {\n successDiv.parentNode.removeChild(successDiv);\n }\n }, 3000);\n }\n }\n\n /**\n * Page-specific before render hook\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n // Set page metadata before rendering\n this.setMeta({\n title: this.pageOptions.title,\n description: this.pageOptions.description\n });\n }\n\n /**\n * Page-specific after mount hook\n */\n async onAfterMount() {\n await super.onAfterMount();\n\n // Add page-specific class to body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Page-specific before destroy hook\n */\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove page-specific class from body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Navigate to another page using the app's router\n * @param {string} route - Route to navigate to\n * @param {object} params - Route parameters\n * @param {object} options - Navigation options\n */\n navigate(route, params = {}, options = {}) {\n // Delegate to app's router\n if (this.app && this.app.router) {\n return this.app.router.navigate(route, options);\n }\n\n // Fallback to MOJO global router\n if (typeof window !== 'undefined' && window.MOJO?.router) {\n return window.MOJO.router.navigate(route, options);\n }\n\n console.error('No router available for navigation');\n }\n\n getRoute() {\n if (this.route) {\n let route = this.route;\n if (typeof route === 'string' && route.startsWith('/')) {\n route = route.substring(1);\n }\n return route;\n }\n return this.pageName;\n }\n\n syncUrl(force = true) {\n this.updateBrowserUrl(this.query, false, false);\n }\n\n updateBrowserUrl(query = null, replace = false, trigger = false) {\n this.getApp();\n // we need to do this to normalize the URL\n // const targetPath = this.app.buildPagePath(this, this.params, query);\n // const { pageName, queryParams } = this.app.router.parseInput(targetPath);\n this.app.router.updateBrowserUrl(this.getRoute(), query, replace, trigger);\n }\n\n /**\n * Static method to define a page class with metadata\n * @param {object} definition - Page class definition\n * @returns {class} Page class\n */\n static define(definition) {\n class DefinedPage extends Page {\n constructor(options = {}) {\n super({\n ...definition,\n ...options\n });\n }\n }\n\n // Copy static properties\n DefinedPage.template = definition.template;\n DefinedPage.pageName = definition.pageName;\n DefinedPage.route = definition.route;\n\n return DefinedPage;\n }\n}\n\nexport default Page;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Page-Dn1oAANw.js","sources":["../../src/core/Page.js"],"sourcesContent":["/**\n * Page - Extends View with routing capabilities for MOJO framework\n * Handles URL routing, parameters, and page-specific actions\n *\n * Event Emitter notes:\n * - Uses EventEmitter via View base class.\n * - Use .emit/.on/.off/.once for all custom events.\n */\n\nimport View from '@core/View.js';\n\nclass Page extends View {\n constructor(options = {}) {\n // Set default tag name for pages\n options.tagName = options.tagName || 'main';\n options.className = options.className || 'mojo-page';\n\n // Set page ID based on page name\n const pageName = options.pageName || '';\n if (pageName && !options.id) {\n options.id = 'page_' + pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n super(options);\n\n // Core page properties from design doc\n this.pageName = options.pageName || this.constructor.pageName || '';\n this.route = options.route || this.constructor.route || '';\n this.title = options.title || this.pageName || '';\n\n // Set page ID if not already set and we have a page_name from constructor\n if (!this.id && this.constructor.pageName && !options.pageName) {\n this.id = 'page_' + this.constructor.pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n // Page metadata for event system\n this.pageIcon = options.icon || options.pageIcon || this.constructor.pageIcon || 'bi bi-file-text';\n this.displayName = options.displayName || this.constructor.displayName || this.pageName || '';\n this.pageDescription = options.pageDescription || this.constructor.pageDescription || '';\n\n // Routing state\n this.params = {};\n this.query = {};\n this.matched = false;\n this.isActive = false;\n\n // Page-specific options\n this.pageOptions = {\n title: options.title || this.pageName || 'Untitled Page',\n description: options.description || '',\n requiresAuth: options.requiresAuth || false,\n ...options.pageOptions\n };\n\n // State preservation\n this.savedState = null;\n\n console.log(`Page ${this.pageName} constructed with route: ${this.route}`);\n }\n\n /**\n * Handle route parameters - from design doc\n * @param {object} params - Route parameters\n * @param {object} query - Query string parameters\n */\n async onParams(params = {}, query = {}) {\n // const paramsChanged = JSON.stringify(params) !== JSON.stringify(this.params);\n // const queryChanged = JSON.stringify(query) !== JSON.stringify(this.query);\n\n this.params = params;\n this.query = query;\n\n // Only re-render if params actually changed and page is active\n // if (this.isActive && (paramsChanged || queryChanged)) {\n // console.log(`Page ${this.pageName} params changed, re-rendering`);\n // await this.render();\n // }\n }\n\n canEnter() {\n if (this.options.permissions) {\n const user = this.getApp().activeUser;\n if (!user || !user.hasPermission(this.options.permissions)) {\n return false;\n }\n }\n if (this.options.requiresGroup && !this.getApp().activeGroup) {\n return false;\n }\n return true;\n }\n\n /**\n * Called when entering this page (before render)\n * Override this method for initialization logic\n */\n async onEnter() {\n this.isActive = true;\n await this.onInitView();\n\n // Restore saved state if exists\n if (this.savedState) {\n this.restoreState(this.savedState);\n this.savedState = null;\n }\n\n // Set page title if provided\n if (this.pageOptions && this.pageOptions.title && typeof document !== 'undefined') {\n document.title = this.pageOptions.title;\n }\n\n // Emit activation event\n this.emit('activated', {\n page: this.getMetadata()\n });\n\n console.log(`Page ${this.pageName} entered`);\n }\n\n /**\n * Called when leaving this page (before cleanup)\n * Override this method for cleanup logic like removing listeners, clearing timers, etc.\n */\n async onExit() {\n // Save state before exit\n this.savedState = this.captureState();\n this.isActive = false;\n\n // Emit deactivation event\n this.emit('deactivated', {\n page: this.getMetadata()\n });\n console.log(`Page ${this.pageName} exiting`);\n }\n\n /**\n * Get page metadata for display and events\n * @returns {object} Page metadata\n */\n getMetadata() {\n return {\n name: this.pageName,\n displayName: this.displayName || this.pageName,\n icon: this.pageIcon,\n description: this.pageDescription,\n route: this.route,\n isActive: this.isActive\n };\n }\n\n /**\n * Handle default action - fallback from design doc\n */\n async onActionDefault(action) {\n console.log(`Default action '${action}' triggered on page: ${this.pageName}`);\n }\n\n async makeActive() {\n this.getApp().showPage(this);\n }\n\n async onActionNavigate(event, element) {\n event.preventDefault();\n const page = element.dataset.page;\n this.getApp().showPage(page);\n }\n\n /**\n * Capture current page state for preservation\n * @returns {object|null} Captured state\n */\n captureState() {\n if (!this.element) return null;\n\n return {\n scrollTop: this.element.scrollTop,\n formData: this.captureFormData(),\n custom: this.captureCustomState()\n };\n }\n\n /**\n * Restore saved state\n * @param {object} state - State to restore\n */\n restoreState(state) {\n if (!state || !this.element) return;\n\n this.element.scrollTop = state.scrollTop || 0;\n this.restoreFormData(state.formData);\n if (state.custom) {\n this.restoreCustomState(state.custom);\n }\n }\n\n /**\n * Capture form data from page\n * @returns {object} Form data\n */\n captureFormData() {\n const data = {};\n if (!this.element) return data;\n\n this.element.querySelectorAll('input, select, textarea').forEach(field => {\n if (field.name) {\n if (field.type === 'checkbox') {\n data[field.name] = field.checked;\n } else if (field.type === 'radio') {\n if (field.checked) {\n data[field.name] = field.value;\n }\n } else {\n data[field.name] = field.value;\n }\n }\n });\n\n return data;\n }\n\n /**\n * Restore form data to page\n * @param {object} formData - Form data to restore\n */\n restoreFormData(formData) {\n if (!formData || !this.element) return;\n\n Object.entries(formData).forEach(([name, value]) => {\n const field = this.element.querySelector(`[name=\"${name}\"]`);\n if (field) {\n if (field.type === 'checkbox') {\n field.checked = value;\n } else if (field.type === 'radio') {\n const radio = this.element.querySelector(`[name=\"${name}\"][value=\"${value}\"]`);\n if (radio) radio.checked = true;\n } else {\n field.value = value;\n }\n }\n });\n }\n\n /**\n * Capture custom state - override in subclasses\n * @returns {object} Custom state\n */\n captureCustomState() {\n return {};\n }\n\n /**\n * Restore custom state - override in subclasses\n * @param {object} state - Custom state to restore\n */\n restoreCustomState(state) {\n // Override in subclasses\n }\n\n\n\n /**\n * Set page metadata\n * @param {object} meta - Metadata object\n */\n setMeta(meta = {}) {\n if (typeof document === 'undefined') {\n return;\n }\n\n // Set title\n if (meta.title) {\n document.title = meta.title;\n this.pageOptions.title = meta.title;\n }\n\n // Set description\n if (meta.description) {\n let descMeta = document.querySelector('meta[name=\"description\"]');\n if (!descMeta) {\n descMeta = document.createElement('meta');\n descMeta.name = 'description';\n document.head.appendChild(descMeta);\n }\n descMeta.content = meta.description;\n this.pageOptions.description = meta.description;\n }\n\n // Set other meta tags\n Object.entries(meta).forEach(([key, value]) => {\n if (key !== 'title' && key !== 'description') {\n let metaEl = document.querySelector(`meta[name=\"${key}\"]`);\n if (!metaEl) {\n metaEl = document.createElement('meta');\n metaEl.name = key;\n document.head.appendChild(metaEl);\n }\n metaEl.content = value;\n }\n });\n }\n\n\n /**\n * Show error message with page context\n * @param {string} message - Error message\n */\n showError(message) {\n super.showError(message);\n\n // Page-specific error display can be implemented here\n if (this.element) {\n // Example: Add error to page\n const errorDiv = document.createElement('div');\n errorDiv.className = 'alert alert-danger alert-dismissible fade show';\n errorDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(errorDiv, this.element.firstChild);\n\n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (errorDiv.parentNode) {\n errorDiv.parentNode.removeChild(errorDiv);\n }\n }, 5000);\n }\n }\n\n /**\n * Show success message with page context\n * @param {string} message - Success message\n */\n showSuccess(message) {\n super.showSuccess(message);\n\n // Page-specific success display\n if (this.element) {\n const successDiv = document.createElement('div');\n successDiv.className = 'alert alert-success alert-dismissible fade show';\n successDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(successDiv, this.element.firstChild);\n\n // Auto-remove after 3 seconds\n setTimeout(() => {\n if (successDiv.parentNode) {\n successDiv.parentNode.removeChild(successDiv);\n }\n }, 3000);\n }\n }\n\n /**\n * Page-specific before render hook\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n // Set page metadata before rendering\n this.setMeta({\n title: this.pageOptions.title,\n description: this.pageOptions.description\n });\n }\n\n /**\n * Page-specific after mount hook\n */\n async onAfterMount() {\n await super.onAfterMount();\n\n // Add page-specific class to body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Page-specific before destroy hook\n */\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove page-specific class from body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Navigate to another page using the app's router\n * @param {string} route - Route to navigate to\n * @param {object} params - Route parameters\n * @param {object} options - Navigation options\n */\n navigate(route, params = {}, options = {}) {\n // Delegate to app's router\n if (this.app && this.app.router) {\n return this.app.router.navigate(route, options);\n }\n\n // Fallback to MOJO global router\n if (typeof window !== 'undefined' && window.MOJO?.router) {\n return window.MOJO.router.navigate(route, options);\n }\n\n console.error('No router available for navigation');\n }\n\n getRoute() {\n if (this.route) {\n let route = this.route;\n if (typeof route === 'string' && route.startsWith('/')) {\n route = route.substring(1);\n }\n return route;\n }\n return this.pageName;\n }\n\n syncUrl(force = true) {\n this.updateBrowserUrl(this.query, false, false);\n }\n\n updateBrowserUrl(query = null, replace = false, trigger = false) {\n this.getApp();\n // we need to do this to normalize the URL\n // const targetPath = this.app.buildPagePath(this, this.params, query);\n // const { pageName, queryParams } = this.app.router.parseInput(targetPath);\n this.app.router.updateBrowserUrl(this.getRoute(), query, replace, trigger);\n }\n\n /**\n * Static method to define a page class with metadata\n * @param {object} definition - Page class definition\n * @returns {class} Page class\n */\n static define(definition) {\n class DefinedPage extends Page {\n constructor(options = {}) {\n super({\n ...definition,\n ...options\n });\n }\n }\n\n // Copy static properties\n DefinedPage.template = definition.template;\n DefinedPage.pageName = definition.pageName;\n DefinedPage.route = definition.route;\n\n return DefinedPage;\n }\n}\n\nexport default Page;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";class Token{constructor(e){this.token=e,this.payload=null,this.uid=null,this.email=null,this.name=null,this.exp=null,this.iat=null,this.isValidToken=!1,this._decode()}_decode(){if(this.token&&"string"==typeof this.token)try{const e=this.token.split(".");if(3!==e.length)return;let t=e[1].replace(/-/g,"+").replace(/_/g,"/");const s=4-t.length%4;4!==s&&(t+="=".repeat(s));const n=atob(t);this.payload=JSON.parse(n),this.uid=this.payload.uid||this.payload.sub||this.payload.user_id||null,this.email=this.payload.email||null,this.name=this.payload.name||this.payload.username||null,this.exp=this.payload.exp?new Date(1e3*this.payload.exp):null,this.iat=this.payload.iat?new Date(1e3*this.payload.iat):null,this.isValidToken=this._checkValidity()}catch(e){this.payload=null}}_checkValidity(){return!(!this.token||!this.payload)&&(!this.payload.exp||Math.floor(Date.now()/1e3)<this.payload.exp)}decode(){return this.payload}getUserId(){return this.uid}isValid(){return this.isValidToken}isExpiringSoon(e=5){if(!this.payload?.exp)return!1;const t=Math.floor(Date.now()/1e3),s=60*e;return this.payload.exp-t<=s}isExpired(){return!!this.payload?.exp&&Math.floor(Date.now()/1e3)>=this.payload.exp}getAgeMinutes(){if(!this.payload?.iat)return null;const e=Math.floor(Date.now()/1e3)-this.payload.iat;return Math.floor(e/60)}getAuthHeader(){return this.token?`Bearer ${this.token}`:null}getUserInfo(){return this.payload?{uid:this.uid,email:this.email,name:this.name,exp:this.exp,iat:this.iat}:null}}exports.TokenManager=class{constructor(){this.tokenKey="access_token",this.refreshTokenKey="refresh_token",this.tokenInstance=null}setTokens(e,t=null,s=!0){const n=s?localStorage:sessionStorage;this.tokenInstance=new Token(e),e&&n.setItem(this.tokenKey,e),t&&n.setItem(this.refreshTokenKey,t)}getToken(){return localStorage.getItem(this.tokenKey)||sessionStorage.getItem(this.tokenKey)}getRefreshToken(){return localStorage.getItem(this.refreshTokenKey)||sessionStorage.getItem(this.refreshTokenKey)}clearTokens(){localStorage.removeItem(this.tokenKey),localStorage.removeItem(this.refreshTokenKey),sessionStorage.removeItem(this.tokenKey),sessionStorage.removeItem(this.refreshTokenKey)}getTokenInstance(){const e=this.getToken();return e?(this.tokenInstance&&this.tokenInstance.token===e||(this.tokenInstance=new Token(e)),this.tokenInstance):(this.tokenInstance=null,null)}getRefreshTokenInstance(){const e=this.getRefreshToken();return e?(this._refreshTokenInstance&&this._refreshTokenInstance.token===e||(this._refreshTokenInstance=new Token(e)),this._refreshTokenInstance):(this._refreshTokenInstance=null,null)}decode(e=null){const t=e||this.getToken();return new Token(t).decode()}getUserId(){const e=this.getTokenInstance();return e?e.getUserId():null}isValid(){const e=this.getTokenInstance();return!!e&&e.isValid()}isExpiringSoon(e=5){const t=this.getTokenInstance();return!!t&&t.isExpiringSoon(e)}getAuthHeader(){const e=this.getTokenInstance();return e?e.getAuthHeader():null}getUserInfo(){const e=this.getTokenInstance();return e?e.getUserInfo():null}checkTokenStatus(){const e=this.getTokenInstance(),t=this.getRefreshTokenInstance();return e&&e.isValid()&&!e.isExpired()?e.isExpiringSoon(10)||e.getAgeMinutes()&&e.getAgeMinutes()>60?t&&t.isValid()&&!t.isExpired()?{action:"refresh",reason:"Access token expiring soon or aged"}:{action:"none",reason:"Access token expiring but refresh token invalid"}:{action:"none",reason:"All tokens valid and not expiring soon"}:t&&t.isValid()&&!t.isExpired()?{action:"refresh",reason:"Access token invalid/expired but refresh token valid"}:{action:"logout",reason:"Both access and refresh tokens are invalid/expired"}}async checkAndRefreshTokens(e){switch(this.checkTokenStatus().action){case"logout":return e.events.emit("auth:unauthorized"),this.stopAutoRefresh(),!0;case"refresh":return await this.refreshToken(e),!0;default:return!1}}startAutoRefresh(e){this.stopAutoRefresh(),this._tokenWatcher=setInterval(()=>{this.checkAndRefreshTokens(e)},6e4)}stopAutoRefresh(){this._tokenWatcher&&(clearInterval(this._tokenWatcher),this._tokenWatcher=null)}async refreshToken(e){const t=this.getRefreshTokenInstance();if(!t||!t.isValid()||t.isExpired())return e.events.emit("auth:unauthorized"),void this.stopAutoRefresh();try{const s=await e.rest.POST("/api/token/refresh",{refresh_token:t.token}),{access_token:n,refresh_token:o}=s.data.data;this.tokenInstance=null,this._refreshTokenInstance=null,this.setTokens(n,o),e.rest.setAuthToken(n),e.events.emit("auth:token:refreshed",{newToken:n,newRefreshToken:o}),console.log("Token refreshed successfully")}catch(s){401===s.status||403===s.status?(e.events.emit("auth:unauthorized"),this.stopAutoRefresh()):e.events.emit("auth:token:refresh:failed",{error:s})}}};
2
+ //# sourceMappingURL=TokenManager-BXQKyhDc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenManager-BXQKyhDc.js","sources":["../../src/core/services/TokenManager.js"],"sourcesContent":["/**\n * Token - Individual JWT token handling\n * Handles decoding, validation, and data extraction for a single token\n */\nclass Token {\n constructor(token) {\n this.token = token;\n this.payload = null;\n this.uid = null;\n this.email = null;\n this.name = null;\n this.exp = null;\n this.iat = null;\n this.isValidToken = false;\n\n this._decode();\n }\n\n /**\n * Decode JWT token payload (client-side only, no verification)\n * @private\n */\n _decode() {\n if (!this.token || typeof this.token !== 'string') {\n return;\n }\n\n try {\n const parts = this.token.split('.');\n if (parts.length !== 3) {\n return;\n }\n\n // Decode the payload (second part)\n const payload = parts[1];\n\n // Handle URL-safe base64\n let base64 = payload.replace(/-/g, '+').replace(/_/g, '/');\n const padding = 4 - (base64.length % 4);\n if (padding !== 4) {\n base64 += '='.repeat(padding);\n }\n\n const decoded = atob(base64);\n this.payload = JSON.parse(decoded);\n\n // Extract common properties\n this.uid = this.payload.uid || this.payload.sub || this.payload.user_id || null;\n this.email = this.payload.email || null;\n this.name = this.payload.name || this.payload.username || null;\n this.exp = this.payload.exp ? new Date(this.payload.exp * 1000) : null;\n this.iat = this.payload.iat ? new Date(this.payload.iat * 1000) : null;\n\n // Determine validity\n this.isValidToken = this._checkValidity();\n } catch (error) {\n this.payload = null;\n }\n }\n\n /**\n * Check token validity\n * @private\n * @returns {boolean} True if token is valid\n */\n _checkValidity() {\n if (!this.token || !this.payload) {\n return false;\n }\n\n // Check expiry if present\n if (this.payload.exp) {\n const now = Math.floor(Date.now() / 1000);\n return now < this.payload.exp;\n }\n\n // If no expiry, consider valid\n return true;\n }\n\n /**\n * Decode JWT token payload (client-side only, no verification)\n * @returns {object|null} Decoded payload or null if invalid\n */\n decode() {\n return this.payload;\n }\n\n /**\n * Get user ID from token\n * @returns {string|null} User ID or null if not found\n */\n getUserId() {\n return this.uid;\n }\n\n /**\n * Check if token is valid (exists and not expired)\n * @returns {boolean} True if token is valid\n */\n isValid() {\n return this.isValidToken;\n }\n\n /**\n * Check if token will expire soon\n * @param {number} thresholdMinutes - Minutes before expiry to consider \"soon\"\n * @returns {boolean} True if expiring soon\n */\n isExpiringSoon(thresholdMinutes = 5) {\n if (!this.payload?.exp) {\n return false;\n }\n\n const now = Math.floor(Date.now() / 1000);\n const threshold = thresholdMinutes * 60;\n return (this.payload.exp - now) <= threshold;\n }\n\n /**\n * Check if token is expired\n * @returns {boolean} True if expired\n */\n isExpired() {\n if (!this.payload?.exp) {\n return false;\n }\n\n const now = Math.floor(Date.now() / 1000);\n return now >= this.payload.exp;\n }\n\n /**\n * Get token age in minutes\n * @returns {number|null} Age in minutes since token was issued, or null if no iat\n */\n getAgeMinutes() {\n if (!this.payload?.iat) {\n return null;\n }\n const now = Math.floor(Date.now() / 1000);\n const ageSeconds = now - this.payload.iat;\n return Math.floor(ageSeconds / 60);\n }\n\n /**\n * Get authorization header value\n * @returns {string|null} Bearer token string or null if no token\n */\n getAuthHeader() {\n return this.token ? `Bearer ${this.token}` : null;\n }\n\n /**\n * Get basic user info from token\n * @returns {object|null} User info or null\n */\n getUserInfo() {\n if (!this.payload) {\n return null;\n }\n\n return {\n uid: this.uid,\n email: this.email,\n name: this.name,\n exp: this.exp,\n iat: this.iat\n };\n }\n}\n\n/**\n * TokenManager - Simplified JWT token handling for MOJO Auth\n * Focuses on core token operations: storage, validation, and user ID extraction\n */\n\nexport default class TokenManager {\n constructor() {\n this.tokenKey = 'access_token';\n this.refreshTokenKey = 'refresh_token';\n this.tokenInstance = null;\n }\n\n /**\n * Store authentication tokens\n * @param {string} token - Access token\n * @param {string} refreshToken - Refresh token (optional)\n * @param {boolean} persistent - Use localStorage if true, sessionStorage if false\n */\n setTokens(token, refreshToken = null, persistent = true) {\n const storage = persistent ? localStorage : sessionStorage;\n this.tokenInstance = new Token(token);\n if (token) {\n storage.setItem(this.tokenKey, token);\n }\n\n if (refreshToken) {\n storage.setItem(this.refreshTokenKey, refreshToken);\n }\n }\n\n /**\n * Get stored access token\n * @returns {string|null} Access token or null if not found\n */\n getToken() {\n return localStorage.getItem(this.tokenKey) ||\n sessionStorage.getItem(this.tokenKey);\n }\n\n /**\n * Get stored refresh token\n * @returns {string|null} Refresh token or null if not found\n */\n getRefreshToken() {\n return localStorage.getItem(this.refreshTokenKey) ||\n sessionStorage.getItem(this.refreshTokenKey);\n }\n\n /**\n * Clear all stored tokens\n */\n clearTokens() {\n localStorage.removeItem(this.tokenKey);\n localStorage.removeItem(this.refreshTokenKey);\n sessionStorage.removeItem(this.tokenKey);\n sessionStorage.removeItem(this.refreshTokenKey);\n }\n\n /**\n * Get Token instance for current stored token\n * @returns {Token|null} Token instance or null if no token\n */\n getTokenInstance() {\n const currentToken = this.getToken();\n\n // If no token stored, clear instance and return null\n if (!currentToken) {\n this.tokenInstance = null;\n return null;\n }\n\n // If instance doesn't exist or token changed, create new instance\n if (!this.tokenInstance || this.tokenInstance.token !== currentToken) {\n this.tokenInstance = new Token(currentToken);\n }\n\n return this.tokenInstance;\n }\n\n /**\n * Get Token instance for refresh token\n * @returns {Token|null} Token instance or null if no refresh token\n */\n getRefreshTokenInstance() {\n const currentRefreshToken = this.getRefreshToken();\n\n // If no refresh token stored, clear instance and return null\n if (!currentRefreshToken) {\n this._refreshTokenInstance = null;\n return null;\n }\n\n // If instance doesn't exist or token changed, create new instance\n if (!this._refreshTokenInstance || this._refreshTokenInstance.token !== currentRefreshToken) {\n this._refreshTokenInstance = new Token(currentRefreshToken);\n }\n\n return this._refreshTokenInstance;\n }\n\n /**\n * Decode JWT token payload (client-side only, no verification)\n * @param {string} token - JWT token\n * @returns {object|null} Decoded payload or null if invalid\n */\n decode(token = null) {\n const jwt = token || this.getToken();\n return new Token(jwt).decode();\n }\n\n /**\n * Get user ID from token\n * @returns {string|null} User ID or null if not found\n */\n getUserId() {\n const currentToken = this.getTokenInstance();\n return currentToken ? currentToken.getUserId() : null;\n }\n\n /**\n * Check if current token is valid (exists and not expired)\n * @returns {boolean} True if token is valid\n */\n isValid() {\n const currentToken = this.getTokenInstance();\n return currentToken ? currentToken.isValid() : false;\n }\n\n /**\n * Check if token will expire soon\n * @param {number} thresholdMinutes - Minutes before expiry to consider \"soon\"\n * @returns {boolean} True if expiring soon\n */\n isExpiringSoon(thresholdMinutes = 5) {\n const currentToken = this.getTokenInstance();\n return currentToken ? currentToken.isExpiringSoon(thresholdMinutes) : false;\n }\n\n /**\n * Get authorization header value\n * @returns {string|null} Bearer token string or null if no token\n */\n getAuthHeader() {\n const currentToken = this.getTokenInstance();\n return currentToken ? currentToken.getAuthHeader() : null;\n }\n\n /**\n * Get basic user info from token\n * @returns {object|null} User info or null\n */\n getUserInfo() {\n const currentToken = this.getTokenInstance();\n return currentToken ? currentToken.getUserInfo() : null;\n }\n\n /**\n * Check current token status and determine what action is needed\n * @returns {object} Status object with action and details\n */\n checkTokenStatus() {\n const token = this.getTokenInstance();\n const refreshToken = this.getRefreshTokenInstance();\n\n // If no access token or it's invalid/expired\n if (!token || !token.isValid() || token.isExpired()) {\n // Check if refresh is possible\n if (!refreshToken || !refreshToken.isValid() || refreshToken.isExpired()) {\n return {\n action: 'logout',\n reason: 'Both access and refresh tokens are invalid/expired'\n };\n }\n\n return {\n action: 'refresh',\n reason: 'Access token invalid/expired but refresh token valid'\n };\n }\n\n // Access token is valid - check if it needs refreshing soon\n if (token.isExpiringSoon(10) || (token.getAgeMinutes() && token.getAgeMinutes() > 60)) {\n // Only suggest refresh if refresh token is still valid\n if (!refreshToken || !refreshToken.isValid() || refreshToken.isExpired()) {\n return {\n action: 'none',\n reason: 'Access token expiring but refresh token invalid'\n };\n }\n\n return {\n action: 'refresh',\n reason: 'Access token expiring soon or aged'\n };\n }\n\n return {\n action: 'none',\n reason: 'All tokens valid and not expiring soon'\n };\n }\n\n /**\n * Check tokens and take appropriate action\n * @param {object} app - App instance for events and API calls\n * @returns {Promise<boolean>} True if action was taken\n */\n async checkAndRefreshTokens(app) {\n const status = this.checkTokenStatus();\n\n switch (status.action) {\n case 'logout':\n app.events.emit(\"auth:unauthorized\");\n this.stopAutoRefresh();\n return true;\n\n case 'refresh':\n await this.refreshToken(app);\n return true;\n\n default:\n return false;\n }\n }\n\n startAutoRefresh(app) {\n this.stopAutoRefresh();\n this._tokenWatcher = setInterval(() => {\n this.checkAndRefreshTokens(app);\n }, 60000);\n }\n\n stopAutoRefresh() {\n if (this._tokenWatcher) {\n clearInterval(this._tokenWatcher);\n this._tokenWatcher = null;\n }\n }\n\n async refreshToken(app) {\n const refreshTokenInstance = this.getRefreshTokenInstance();\n\n // Double-check refresh token validity before attempting refresh\n if (!refreshTokenInstance || !refreshTokenInstance.isValid() || refreshTokenInstance.isExpired()) {\n\n app.events.emit(\"auth:unauthorized\");\n this.stopAutoRefresh();\n return;\n }\n\n try {\n\n const response = await app.rest.POST('/api/token/refresh', {\n refresh_token: refreshTokenInstance.token\n });\n\n const { access_token, refresh_token } = response.data.data;\n\n // Clear old cached instances so new tokens are loaded\n this.tokenInstance = null;\n this._refreshTokenInstance = null;\n\n // Store new tokens\n this.setTokens(access_token, refresh_token);\n app.rest.setAuthToken(access_token);\n\n // Emit success event\n app.events.emit('auth:token:refreshed', {\n newToken: access_token,\n newRefreshToken: refresh_token\n });\n\n console.log('Token refreshed successfully');\n\n } catch (error) {\n\n\n // Check if it's an authentication error (refresh token invalid)\n if (error.status === 401 || error.status === 403) {\n\n app.events.emit(\"auth:unauthorized\");\n this.stopAutoRefresh();\n } else {\n // For other errors, emit specific event but don't logout\n app.events.emit('auth:token:refresh:failed', { error });\n }\n }\n }\n}\n"],"names":["Token","constructor","token","this","payload","uid","email","name","exp","iat","isValidToken","_decode","parts","split","length","base64","replace","padding","repeat","decoded","atob","JSON","parse","sub","user_id","username","Date","_checkValidity","error","Math","floor","now","decode","getUserId","isValid","isExpiringSoon","thresholdMinutes","threshold","isExpired","getAgeMinutes","ageSeconds","getAuthHeader","getUserInfo","tokenKey","refreshTokenKey","tokenInstance","setTokens","refreshToken","persistent","storage","localStorage","sessionStorage","setItem","getToken","getItem","getRefreshToken","clearTokens","removeItem","getTokenInstance","currentToken","getRefreshTokenInstance","currentRefreshToken","_refreshTokenInstance","jwt","checkTokenStatus","action","reason","checkAndRefreshTokens","app","events","emit","stopAutoRefresh","startAutoRefresh","_tokenWatcher","setInterval","clearInterval","refreshTokenInstance","response","rest","POST","refresh_token","access_token","data","setAuthToken","newToken","newRefreshToken","console","log","status"],"mappings":"aAIA,MAAMA,MACF,WAAAC,CAAYC,GACRC,KAAKD,MAAQA,EACbC,KAAKC,QAAU,KACfD,KAAKE,IAAM,KACXF,KAAKG,MAAQ,KACbH,KAAKI,KAAO,KACZJ,KAAKK,IAAM,KACXL,KAAKM,IAAM,KACXN,KAAKO,cAAe,EAEpBP,KAAKQ,SACT,CAMA,OAAAA,GACI,GAAKR,KAAKD,OAA+B,iBAAfC,KAAKD,MAI/B,IACI,MAAMU,EAAQT,KAAKD,MAAMW,MAAM,KAC/B,GAAqB,IAAjBD,EAAME,OACN,OAOJ,IAAIC,EAHYH,EAAM,GAGDI,QAAQ,KAAM,KAAKA,QAAQ,KAAM,KACtD,MAAMC,EAAU,EAAKF,EAAOD,OAAS,EACrB,IAAZG,IACAF,GAAU,IAAIG,OAAOD,IAGzB,MAAME,EAAUC,KAAKL,GACrBZ,KAAKC,QAAUiB,KAAKC,MAAMH,GAG1BhB,KAAKE,IAAMF,KAAKC,QAAQC,KAAOF,KAAKC,QAAQmB,KAAOpB,KAAKC,QAAQoB,SAAW,KAC3ErB,KAAKG,MAAQH,KAAKC,QAAQE,OAAS,KACnCH,KAAKI,KAAOJ,KAAKC,QAAQG,MAAQJ,KAAKC,QAAQqB,UAAY,KAC1DtB,KAAKK,IAAML,KAAKC,QAAQI,IAAM,IAAIkB,KAAwB,IAAnBvB,KAAKC,QAAQI,KAAc,KAClEL,KAAKM,IAAMN,KAAKC,QAAQK,IAAM,IAAIiB,KAAwB,IAAnBvB,KAAKC,QAAQK,KAAc,KAGlEN,KAAKO,aAAeP,KAAKwB,gBAC7B,OAASC,GACLzB,KAAKC,QAAU,IACnB,CACJ,CAOA,cAAAuB,GACI,SAAKxB,KAAKD,QAAUC,KAAKC,YAKrBD,KAAKC,QAAQI,KACDqB,KAAKC,MAAMJ,KAAKK,MAAQ,KACvB5B,KAAKC,QAAQI,IAKlC,CAMA,MAAAwB,GACI,OAAO7B,KAAKC,OAChB,CAMA,SAAA6B,GACI,OAAO9B,KAAKE,GAChB,CAMA,OAAA6B,GACI,OAAO/B,KAAKO,YAChB,CAOA,cAAAyB,CAAeC,EAAmB,GAC9B,IAAKjC,KAAKC,SAASI,IACf,OAAO,EAGX,MAAMuB,EAAMF,KAAKC,MAAMJ,KAAKK,MAAQ,KAC9BM,EAA+B,GAAnBD,EAClB,OAAQjC,KAAKC,QAAQI,IAAMuB,GAAQM,CACvC,CAMA,SAAAC,GACI,QAAKnC,KAAKC,SAASI,KAIPqB,KAAKC,MAAMJ,KAAKK,MAAQ,MACtB5B,KAAKC,QAAQI,GAC/B,CAMA,aAAA+B,GACI,IAAKpC,KAAKC,SAASK,IACf,OAAO,KAEX,MACM+B,EADMX,KAAKC,MAAMJ,KAAKK,MAAQ,KACX5B,KAAKC,QAAQK,IACtC,OAAOoB,KAAKC,MAAMU,EAAa,GACnC,CAMA,aAAAC,GACI,OAAOtC,KAAKD,MAAQ,UAAUC,KAAKD,QAAU,IACjD,CAMA,WAAAwC,GACI,OAAKvC,KAAKC,QAIH,CACHC,IAAKF,KAAKE,IACVC,MAAOH,KAAKG,MACZC,KAAMJ,KAAKI,KACXC,IAAKL,KAAKK,IACVC,IAAKN,KAAKM,KARH,IAUf,uBAQW,MACX,WAAAR,GACIE,KAAKwC,SAAW,eAChBxC,KAAKyC,gBAAkB,gBACvBzC,KAAK0C,cAAgB,IACzB,CAQA,SAAAC,CAAU5C,EAAO6C,EAAe,KAAMC,GAAa,GAC/C,MAAMC,EAAUD,EAAaE,aAAeC,eAC5ChD,KAAK0C,cAAgB,IAAI7C,MAAME,GAC3BA,GACA+C,EAAQG,QAAQjD,KAAKwC,SAAUzC,GAG/B6C,GACAE,EAAQG,QAAQjD,KAAKyC,gBAAiBG,EAE9C,CAMA,QAAAM,GACI,OAAOH,aAAaI,QAAQnD,KAAKwC,WAC1BQ,eAAeG,QAAQnD,KAAKwC,SACvC,CAMA,eAAAY,GACI,OAAOL,aAAaI,QAAQnD,KAAKyC,kBAC1BO,eAAeG,QAAQnD,KAAKyC,gBACvC,CAKA,WAAAY,GACIN,aAAaO,WAAWtD,KAAKwC,UAC7BO,aAAaO,WAAWtD,KAAKyC,iBAC7BO,eAAeM,WAAWtD,KAAKwC,UAC/BQ,eAAeM,WAAWtD,KAAKyC,gBACnC,CAMA,gBAAAc,GACI,MAAMC,EAAexD,KAAKkD,WAG1B,OAAKM,GAMAxD,KAAK0C,eAAiB1C,KAAK0C,cAAc3C,QAAUyD,IACpDxD,KAAK0C,cAAgB,IAAI7C,MAAM2D,IAG5BxD,KAAK0C,gBATR1C,KAAK0C,cAAgB,KACd,KASf,CAMA,uBAAAe,GACI,MAAMC,EAAsB1D,KAAKoD,kBAGjC,OAAKM,GAMA1D,KAAK2D,uBAAyB3D,KAAK2D,sBAAsB5D,QAAU2D,IACpE1D,KAAK2D,sBAAwB,IAAI9D,MAAM6D,IAGpC1D,KAAK2D,wBATR3D,KAAK2D,sBAAwB,KACtB,KASf,CAOA,MAAA9B,CAAO9B,EAAQ,MACX,MAAM6D,EAAM7D,GAASC,KAAKkD,WAC1B,OAAO,IAAIrD,MAAM+D,GAAK/B,QAC1B,CAMA,SAAAC,GACI,MAAM0B,EAAexD,KAAKuD,mBAC1B,OAAOC,EAAeA,EAAa1B,YAAc,IACrD,CAMA,OAAAC,GACI,MAAMyB,EAAexD,KAAKuD,mBAC1B,QAAOC,GAAeA,EAAazB,SACvC,CAOA,cAAAC,CAAeC,EAAmB,GAC9B,MAAMuB,EAAexD,KAAKuD,mBAC1B,QAAOC,GAAeA,EAAaxB,eAAeC,EACtD,CAMA,aAAAK,GACI,MAAMkB,EAAexD,KAAKuD,mBAC1B,OAAOC,EAAeA,EAAalB,gBAAkB,IACzD,CAMA,WAAAC,GACI,MAAMiB,EAAexD,KAAKuD,mBAC1B,OAAOC,EAAeA,EAAajB,cAAgB,IACvD,CAMA,gBAAAsB,GACI,MAAM9D,EAAQC,KAAKuD,mBACbX,EAAe5C,KAAKyD,0BAG1B,OAAK1D,GAAUA,EAAMgC,YAAahC,EAAMoC,YAgBpCpC,EAAMiC,eAAe,KAAQjC,EAAMqC,iBAAmBrC,EAAMqC,gBAAkB,GAEzEQ,GAAiBA,EAAab,YAAaa,EAAaT,YAOtD,CACH2B,OAAQ,UACRC,OAAQ,sCARD,CACHD,OAAQ,OACRC,OAAQ,mDAUb,CACHD,OAAQ,OACRC,OAAQ,0CA/BHnB,GAAiBA,EAAab,YAAaa,EAAaT,YAOtD,CACH2B,OAAQ,UACRC,OAAQ,wDARD,CACHD,OAAQ,SACRC,OAAQ,qDA8BxB,CAOA,2BAAMC,CAAsBC,GAGxB,OAFejE,KAAK6D,mBAELC,QACX,IAAK,SAGD,OAFAG,EAAIC,OAAOC,KAAK,qBAChBnE,KAAKoE,mBACE,EAEX,IAAK,UAED,aADMpE,KAAK4C,aAAaqB,IACjB,EAEX,QACI,OAAO,EAEnB,CAEA,gBAAAI,CAAiBJ,GACbjE,KAAKoE,kBACLpE,KAAKsE,cAAgBC,YAAY,KAC7BvE,KAAKgE,sBAAsBC,IAC5B,IACP,CAEA,eAAAG,GACQpE,KAAKsE,gBACLE,cAAcxE,KAAKsE,eACnBtE,KAAKsE,cAAgB,KAE7B,CAEA,kBAAM1B,CAAaqB,GACf,MAAMQ,EAAuBzE,KAAKyD,0BAGlC,IAAKgB,IAAyBA,EAAqB1C,WAAa0C,EAAqBtC,YAIjF,OAFA8B,EAAIC,OAAOC,KAAK,0BAChBnE,KAAKoE,kBAIT,IAEI,MAAMM,QAAiBT,EAAIU,KAAKC,KAAK,qBAAsB,CACvDC,cAAeJ,EAAqB1E,SAGlC+E,aAAEA,EAAAD,cAAcA,GAAkBH,EAASK,KAAKA,KAGtD/E,KAAK0C,cAAgB,KACrB1C,KAAK2D,sBAAwB,KAG7B3D,KAAK2C,UAAUmC,EAAcD,GAC7BZ,EAAIU,KAAKK,aAAaF,GAGtBb,EAAIC,OAAOC,KAAK,uBAAwB,CACpCc,SAAUH,EACVI,gBAAiBL,IAGrBM,QAAQC,IAAI,+BAEhB,OAAS3D,GAIgB,MAAjBA,EAAM4D,QAAmC,MAAjB5D,EAAM4D,QAE9BpB,EAAIC,OAAOC,KAAK,qBAChBnE,KAAKoE,mBAGLH,EAAIC,OAAOC,KAAK,4BAA6B,CAAE1C,SAEvD,CACJ"}