web-mojo 2.2.67 → 2.2.69

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 (102) hide show
  1. package/CHANGELOG.md +25 -9
  2. package/dist/admin.cjs.js +1 -1
  3. package/dist/admin.cjs.js.map +1 -1
  4. package/dist/admin.es.js +1 -1
  5. package/dist/admin.es.js.map +1 -1
  6. package/dist/auth.cjs.js +1 -1
  7. package/dist/auth.es.js +1 -1
  8. package/dist/charts.cjs.js +1 -1
  9. package/dist/charts.es.js +1 -1
  10. package/dist/chunks/ChatView-CZ3Key2k.js +2 -0
  11. package/dist/chunks/ChatView-CZ3Key2k.js.map +1 -0
  12. package/dist/chunks/ChatView-Dw-iVmht.js +2 -0
  13. package/dist/chunks/ChatView-Dw-iVmht.js.map +1 -0
  14. package/dist/chunks/{Dialog-DW7PHzUc.js → Dialog-Dhqtd9Yz.js} +2 -2
  15. package/dist/chunks/{Dialog-DW7PHzUc.js.map → Dialog-Dhqtd9Yz.js.map} +1 -1
  16. package/dist/chunks/{Dialog-jfBsXy5X.js → Dialog-t_9l2Mou.js} +2 -2
  17. package/dist/chunks/{Dialog-jfBsXy5X.js.map → Dialog-t_9l2Mou.js.map} +1 -1
  18. package/dist/chunks/Files-6eRT5k3r.js +2 -0
  19. package/dist/chunks/{Files-C-ChBvr5.js.map → Files-6eRT5k3r.js.map} +1 -1
  20. package/dist/chunks/Files-Dh_5PFBn.js +2 -0
  21. package/dist/chunks/{Files-DNbHDy43.js.map → Files-Dh_5PFBn.js.map} +1 -1
  22. package/dist/chunks/{FormView-EoB_ZdIB.js → FormView-B1CXO2t8.js} +2 -2
  23. package/dist/chunks/{FormView-EoB_ZdIB.js.map → FormView-B1CXO2t8.js.map} +1 -1
  24. package/dist/chunks/{FormView-Q_lFA0nr.js → FormView-BRHAIawp.js} +2 -2
  25. package/dist/chunks/{FormView-Q_lFA0nr.js.map → FormView-BRHAIawp.js.map} +1 -1
  26. package/dist/chunks/{MetricsMiniChartWidget-ChC5GGm6.js → MetricsMiniChartWidget-D1w608Jy.js} +2 -2
  27. package/dist/chunks/MetricsMiniChartWidget-D1w608Jy.js.map +1 -0
  28. package/dist/chunks/{MetricsMiniChartWidget-BkMjI-gz.js → MetricsMiniChartWidget-Dg1e6EQJ.js} +2 -2
  29. package/dist/chunks/MetricsMiniChartWidget-Dg1e6EQJ.js.map +1 -0
  30. package/dist/chunks/{PDFViewer-iOqYpg-6.js → PDFViewer-CDeV9OBs.js} +2 -2
  31. package/dist/chunks/{PDFViewer-iOqYpg-6.js.map → PDFViewer-CDeV9OBs.js.map} +1 -1
  32. package/dist/chunks/{PDFViewer-sFoyopz3.js → PDFViewer-D_3V8QJe.js} +2 -2
  33. package/dist/chunks/{PDFViewer-sFoyopz3.js.map → PDFViewer-D_3V8QJe.js.map} +1 -1
  34. package/dist/chunks/TableView-CI_7a-kD.js +2 -0
  35. package/dist/chunks/TableView-CI_7a-kD.js.map +1 -0
  36. package/dist/chunks/TableView-CWk5k4LQ.js +2 -0
  37. package/dist/chunks/TableView-CWk5k4LQ.js.map +1 -0
  38. package/dist/chunks/ToastService-C2tTooFn.js +3 -0
  39. package/dist/chunks/ToastService-C2tTooFn.js.map +1 -0
  40. package/dist/chunks/ToastService-nUaGVpSl.js +3 -0
  41. package/dist/chunks/ToastService-nUaGVpSl.js.map +1 -0
  42. package/dist/chunks/TokenManager-ien2XzwO.js +2 -0
  43. package/dist/chunks/TokenManager-ien2XzwO.js.map +1 -0
  44. package/dist/chunks/TokenManager-sZgt--C9.js +2 -0
  45. package/dist/chunks/TokenManager-sZgt--C9.js.map +1 -0
  46. package/dist/chunks/User-BL9M_PWB.js +2 -0
  47. package/dist/chunks/User-BL9M_PWB.js.map +1 -0
  48. package/dist/chunks/{User-BnlvMG5J.js → User-DqHG5Gr1.js} +2 -3
  49. package/dist/chunks/User-DqHG5Gr1.js.map +1 -0
  50. package/dist/chunks/UserProfileView-DnVMHcLH.js +2 -0
  51. package/dist/chunks/UserProfileView-DnVMHcLH.js.map +1 -0
  52. package/dist/chunks/UserProfileView-kupeq2rN.js +2 -0
  53. package/dist/chunks/UserProfileView-kupeq2rN.js.map +1 -0
  54. package/dist/chunks/{WebApp-Bsic6FPo.js → WebApp-Bti0Gqqo.js} +2 -2
  55. package/dist/chunks/{WebApp-Bsic6FPo.js.map → WebApp-Bti0Gqqo.js.map} +1 -1
  56. package/dist/chunks/{WebApp-B0m6JCjO.js → WebApp-CcVF73yg.js} +2 -2
  57. package/dist/chunks/{WebApp-B0m6JCjO.js.map → WebApp-CcVF73yg.js.map} +1 -1
  58. package/dist/chunks/index-Aq9ke4vg.js +2 -0
  59. package/dist/chunks/index-Aq9ke4vg.js.map +1 -0
  60. package/dist/chunks/index-Da9sT-tE.js +2 -0
  61. package/dist/chunks/index-Da9sT-tE.js.map +1 -0
  62. package/dist/chunks/{version-BY7AsEkb.js → version-D8JjsPW0.js} +2 -2
  63. package/dist/chunks/{version-BY7AsEkb.js.map → version-D8JjsPW0.js.map} +1 -1
  64. package/dist/chunks/{version-BdfRyQDm.js → version-XmirKYWA.js} +2 -2
  65. package/dist/chunks/{version-BdfRyQDm.js.map → version-XmirKYWA.js.map} +1 -1
  66. package/dist/css/web-mojo.css +1 -1
  67. package/dist/docit.cjs.js +1 -1
  68. package/dist/docit.cjs.js.map +1 -1
  69. package/dist/docit.es.js +1 -1
  70. package/dist/docit.es.js.map +1 -1
  71. package/dist/index.cjs.js +1 -1
  72. package/dist/index.cjs.js.map +1 -1
  73. package/dist/index.es.js +1 -1
  74. package/dist/index.es.js.map +1 -1
  75. package/dist/lightbox.cjs.js +1 -1
  76. package/dist/lightbox.es.js +1 -1
  77. package/dist/map.cjs.js +1 -1
  78. package/dist/map.es.js +1 -1
  79. package/dist/user-profile.cjs.js +2 -0
  80. package/dist/user-profile.cjs.js.map +1 -0
  81. package/dist/user-profile.es.js +2 -0
  82. package/dist/user-profile.es.js.map +1 -0
  83. package/dist/web-mojo.lite.iife.js +9 -6
  84. package/dist/web-mojo.lite.iife.js.map +1 -1
  85. package/dist/web-mojo.lite.iife.min.js +11 -11
  86. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  87. package/package.json +5 -1
  88. package/dist/chunks/ChatView-Cfe0ZGvr.js +0 -2
  89. package/dist/chunks/ChatView-Cfe0ZGvr.js.map +0 -1
  90. package/dist/chunks/ChatView-DuQVFrCY.js +0 -2
  91. package/dist/chunks/ChatView-DuQVFrCY.js.map +0 -1
  92. package/dist/chunks/Files-C-ChBvr5.js +0 -2
  93. package/dist/chunks/Files-DNbHDy43.js +0 -2
  94. package/dist/chunks/MetricsMiniChartWidget-BkMjI-gz.js.map +0 -1
  95. package/dist/chunks/MetricsMiniChartWidget-ChC5GGm6.js.map +0 -1
  96. package/dist/chunks/TokenManager-BYMKH_aW.js +0 -2
  97. package/dist/chunks/TokenManager-BYMKH_aW.js.map +0 -1
  98. package/dist/chunks/TokenManager-DhDUKmaw.js +0 -2
  99. package/dist/chunks/TokenManager-DhDUKmaw.js.map +0 -1
  100. package/dist/chunks/User-BnlvMG5J.js.map +0 -1
  101. package/dist/chunks/User-DSqcOwPL.js +0 -3
  102. package/dist/chunks/User-DSqcOwPL.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PDFViewer-sFoyopz3.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":["LightboxGallery","View","constructor","options","super","className","tagName","rawImages","Array","isArray","images","src","filter","Boolean","this","map","img","alt","currentIndex","startIndex","showNavigation","length","showCounter","allowKeyboard","closeOnBackdrop","fitToScreen","_keyboardHandler","handleKeyboard","bind","updateTemplateProperties","currentImage","currentNumber","total","isFirst","isLast","imageStyle","containerStyle","modeIndicator","getTemplate","onAfterRender","document","body","appendChild","element","style","overflow","addEventListener","preloadAdjacentImages","handleActionClose","close","handleActionBackdropClick","e","target","currentTarget","handleActionPrev","showPrevious","handleActionNext","showNext","handleActionImageClick","toggleImageMode","updateImage","goToImage","index","imgElement","querySelector","counterElement","prevBtn","nextBtn","showLoading","waitForImageLoad","hideLoading","textContent","disabled","updateImageDisplay","eventBus","getApp","events","emit","gallery","image","loading","display","Promise","resolve","complete","onload","onerror","preloadIndexes","push","forEach","Image","key","preventDefault","containerElement","indicatorElement","maxWidth","maxHeight","objectFit","cursor","userSelect","destroy","onBeforeDestroy","removeEventListener","parentNode","removeChild","show","lightbox","render","then","mount","window","PDFViewer","pdfUrl","title","pdfDoc","currentPage","totalPages","pageRendering","pageNumPending","scale","minScale","maxScale","scaleStep","fitMode","canvas","ctx","showControls","allowZoom","allowNavigation","showPageNumbers","isLoaded","isLoading","pdfjsWorkerPath","pdfjsCMapUrl","canvasContainer","controlsElement","statusElement","pageInput","get","overlayElement","errorElement","getContext","setupEssentialEventListeners","initializePDFJS","loadPDF","keydownHandler","handleKeyDown","resizeObserver","ResizeObserver","applyFitMode","observe","_essentialListeners","el","type","fn","_resizeObserver","pdfjsLib","loadPDFJSLibrary","GlobalWorkerOptions","workerSrc","error","console","showError","reject","script","createElement","head","handleActionFirstPage","goToPage","handleActionPrevPage","handleActionNextPage","handleActionLastPage","onChangePageInput","event","pageNumber","parseInt","value","handleActionZoomIn","setScale","handleActionZoomOut","handleActionFitPage","setFitMode","handleActionFitWidth","handleActionActualSize","handleActionDownload","downloadPDF","handleActionPrint","print","loadingTask","getDocument","url","cMapUrl","cMapPacked","promise","numPages","updatePageControls","updateStatus","renderPage","classList","add","viewer","message","page","getPage","viewport","getViewport","height","width","clearRect","renderContext","canvasContext","renderTask","pendingPage","oldScale","Math","max","min","newScale","mode","oldMode","newMode","containerRect","getBoundingClientRect","scaleX","scaleY","ctrlKey","metaKey","pageTotalElement","firstBtn","lastBtn","zoomInBtn","zoomOutBtn","currentPageElement","totalPagesElement","zoomLevelElement","round","errorMessageElement","link","href","download","click","setPDF","oldPdfUrl","remove","newPdfUrl","getCurrentPage","getTotalPages","getCurrentScale","disconnect","showDialog","size","dialogOptions","dialog","Dialog","centered","backdrop","keyboard","buttons","text","action","class","dismiss","on","hide"],"mappings":"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"}
1
+ {"version":3,"file":"PDFViewer-D_3V8QJe.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":["LightboxGallery","View","constructor","options","super","className","tagName","rawImages","Array","isArray","images","src","filter","Boolean","this","map","img","alt","currentIndex","startIndex","showNavigation","length","showCounter","allowKeyboard","closeOnBackdrop","fitToScreen","_keyboardHandler","handleKeyboard","bind","updateTemplateProperties","currentImage","currentNumber","total","isFirst","isLast","imageStyle","containerStyle","modeIndicator","getTemplate","onAfterRender","document","body","appendChild","element","style","overflow","addEventListener","preloadAdjacentImages","handleActionClose","close","handleActionBackdropClick","e","target","currentTarget","handleActionPrev","showPrevious","handleActionNext","showNext","handleActionImageClick","toggleImageMode","updateImage","goToImage","index","imgElement","querySelector","counterElement","prevBtn","nextBtn","showLoading","waitForImageLoad","hideLoading","textContent","disabled","updateImageDisplay","eventBus","getApp","events","emit","gallery","image","loading","display","Promise","resolve","complete","onload","onerror","preloadIndexes","push","forEach","Image","key","preventDefault","containerElement","indicatorElement","maxWidth","maxHeight","objectFit","cursor","userSelect","destroy","onBeforeDestroy","removeEventListener","parentNode","removeChild","show","lightbox","render","then","mount","window","PDFViewer","pdfUrl","title","pdfDoc","currentPage","totalPages","pageRendering","pageNumPending","scale","minScale","maxScale","scaleStep","fitMode","canvas","ctx","showControls","allowZoom","allowNavigation","showPageNumbers","isLoaded","isLoading","pdfjsWorkerPath","pdfjsCMapUrl","canvasContainer","controlsElement","statusElement","pageInput","get","overlayElement","errorElement","getContext","setupEssentialEventListeners","initializePDFJS","loadPDF","keydownHandler","handleKeyDown","resizeObserver","ResizeObserver","applyFitMode","observe","_essentialListeners","el","type","fn","_resizeObserver","pdfjsLib","loadPDFJSLibrary","GlobalWorkerOptions","workerSrc","error","console","showError","reject","script","createElement","head","handleActionFirstPage","goToPage","handleActionPrevPage","handleActionNextPage","handleActionLastPage","onChangePageInput","event","pageNumber","parseInt","value","handleActionZoomIn","setScale","handleActionZoomOut","handleActionFitPage","setFitMode","handleActionFitWidth","handleActionActualSize","handleActionDownload","downloadPDF","handleActionPrint","print","loadingTask","getDocument","url","cMapUrl","cMapPacked","promise","numPages","updatePageControls","updateStatus","renderPage","classList","add","viewer","message","page","getPage","viewport","getViewport","height","width","clearRect","renderContext","canvasContext","renderTask","pendingPage","oldScale","Math","max","min","newScale","mode","oldMode","newMode","containerRect","getBoundingClientRect","scaleX","scaleY","ctrlKey","metaKey","pageTotalElement","firstBtn","lastBtn","zoomInBtn","zoomOutBtn","currentPageElement","totalPagesElement","zoomLevelElement","round","errorMessageElement","link","href","download","click","setPDF","oldPdfUrl","remove","newPdfUrl","getCurrentPage","getTotalPages","getCurrentScale","disconnect","showDialog","size","dialogOptions","dialog","Dialog","centered","backdrop","keyboard","buttons","text","action","class","dismiss","on","hide"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";const t=require("./Collection-CmjTsmrP.js"),e=require("./ListView-CMZpwyyC.js"),i=require("./Rest-B1eUyLX5.js"),n=require("./Dialog-Dhqtd9Yz.js"),s=require("./FormView-B1CXO2t8.js");class Log extends t.Model{constructor(t={}){super(t,{endpoint:"/api/logs"})}}class LogList extends t.Collection{constructor(t={}){super({ModelClass:Log,endpoint:"/api/logs",size:10,...t})}}class Member extends t.Model{constructor(t={}){super(t,{endpoint:"/api/group/member"})}hasPermission(t){if(Array.isArray(t))return t.some(t=>this.hasPermission(t));const e=this.get("permissions");return!!e&&1==e[t]}async fetchForGroup(t){return await this.fetch({url:`/api/group/${t}/member`})}}class MemberList extends t.Collection{constructor(t={}){super({ModelClass:Member,endpoint:"/api/group/member",size:10,...t})}}const l={edit:{title:"Edit Membership",fields:[{name:"user.display_name",type:"text",label:"Display Name",placeholder:"Enter Display Name"},{name:"metadata.role",type:"text",label:"Role",placeholder:"Enter role"},{name:"is_active",type:"switch",label:"Is Enabled",columns:12}]}};Member.EDIT_FORM=l.edit,Member.ADD_FORM=l.create;class TableRow extends e.ListViewItem{constructor(t={}){super({tagName:"tr",className:"table-row",enableTooltips:!0,...t}),this.columns=t.columns||[],this.actions=t.actions||null,this.contextMenu=t.contextMenu||null,this.batchActions=t.batchActions||null,this.tableView=t.tableView||t.listView||null,this.editingCells=/* @__PURE__ */new Set,this.template=this.buildRowTemplate()}getResponsiveClasses(t){if(!t)return"";const e=["sm","md","lg","xl","xxl"];if("string"==typeof t)return e.includes(t)?`d-none d-${t}-table-cell`:(console.warn(`Invalid visibility breakpoint: ${t}. Valid options are: ${e.join(", ")}`),"");if("object"==typeof t){const i=[];if(t.hide){if(!e.includes(t.hide))return console.warn(`Invalid hide breakpoint: ${t.hide}. Valid options are: ${e.join(", ")}`),"";i.push(`d-table-cell d-${t.hide}-none`)}if(t.show){if(!e.includes(t.show))return console.warn(`Invalid show breakpoint: ${t.show}. Valid options are: ${e.join(", ")}`),"";t.hide?i.push(`d-${t.show}-table-cell`):i.push(`d-none d-${t.show}-table-cell`)}return i.join(" ")}return""}buildRowTemplate(){let t="";return this.tableView&&this.tableView.isSelectable()&&(t+='\n <td style="padding: 0;">\n <div class="mojo-select-cell {{#selected}}selected{{/selected}}"\n data-action="select">\n <div class="mojo-checkbox">\n <i class="bi bi-check"></i>\n </div>\n </div>\n </td>\n '),this.columns.forEach((e,i)=>{const n=[e.class||e.className||"",this.getResponsiveClasses(e.visibility),e.editable?"editable-cell":""].filter(t=>t).join(" "),s=this.buildCellTemplate(e,i);let l=e.action;!l&&e.editable?l="edit-cell":!l&&this.tableView.rowAction&&(l=this.tableView.rowAction),t+=l?`<td class="${n}" data-action="${l}" data-column="${e.key}">${s}</td>`:`<td class="${n}" data-column="${e.key}">${s}</td>`}),this.actions?t+=this.buildActionsTemplate():this.contextMenu&&(t+=this.buildContextMenuTemplate()),t}buildCellTemplate(t,e=0){const i=`model.${t.key}`,n=t.formatter||t.format;if(n){if("string"==typeof n)return`{{{${i}|${n}}}}`;if("function"==typeof n)return`<span data-formatter="${t.key}" data-formatter-id="${e}">{{${i}}}</span>`}return t.template?t.template:t.editable?`<span class="cell-content" data-field="${t.key}">{{{${i}}}}</span>`:`{{{${i}}}}`}buildActionsTemplate(){return this.actions&&0!==this.actions.length?`<td><div class="btn-group btn-group-sm">${this.actions.map(t=>{if("string"==typeof t)switch(t){case"view":return'\n <button class="btn btn-sm btn-outline-primary"\n data-action="view"\n title="View">\n <i class="bi bi-eye"></i>\n </button>\n ';case"edit":return'\n <button class="btn btn-sm btn-outline-secondary"\n data-action="edit"\n title="Edit">\n <i class="bi bi-pencil"></i>\n </button>\n ';case"delete":return'\n <button class="btn btn-sm btn-outline-danger"\n data-action="delete"\n title="Delete">\n <i class="bi bi-trash"></i>\n </button>\n ';default:return""}else if("object"==typeof t)return`\n <button class="btn btn-sm ${t.class||"btn-outline-primary"}"\n data-id="${this.model.id}"\n data-action="${t.action}"\n title="${t.label||""}">\n ${t.icon?`<i class="${t.icon}"></i>`:""}\n ${t.label&&!t.icon?t.label:""}\n </button>\n `;return""}).join("")}</div></td>`:""}buildContextMenuTemplate(){return this.contextMenu&&0!==this.contextMenu.length?`\n <td class="text-end" style="width: 1px;">\n <div class="dropdown">\n <button class="btn btn-sm btn-link border-0"\n type="button"\n data-bs-toggle="dropdown"\n aria-expanded="false"\n style="color: #6c757d;">\n <i class="bi bi-three-dots-vertical"></i>\n </button>\n <ul class="dropdown-menu dropdown-menu-end shadow-sm">\n ${this.buildContextMenuItems()}\n </ul>\n </div>\n </td>\n `:""}buildContextMenuItems(){return this.contextMenu.map(t=>{if(t.separator||t.divider)return'<li><hr class="dropdown-divider"></li>';let e="dropdown-item";return("delete"===t.action||t.danger)&&(e+=" text-danger"),t.disabled&&(e+=" disabled"),`\n <li>\n <a class="${e}" href="#"\n data-id="{{model.id}}"\n data-action="${t.action}"\n ${t.disabled?'aria-disabled="true" tabindex="-1"':""}>\n ${t.icon?`<i class="${t.icon} me-2"></i>`:""}\n ${t.label}\n </a>\n </li>\n `}).join("")}async onAfterRender(){await super.onAfterRender(),this.columns.forEach((t,e)=>{if(t.formatter&&"function"==typeof t.formatter){let n=this.element.querySelector(`[data-formatter-id="${e}"]`);if(n||(n=this.element.querySelector(`[data-formatter="${t.key}"]`)),n){const e=this.model.get?this.model.get(t.key):this.model[t.key],s={value:e,row:this.model,model:this.model,column:t,table:this.tableView,index:this.index};try{n.innerHTML=t.formatter(e,s)}catch(i){console.error(`Error formatting cell for column ${t.key}:`,i)}}}}),this.selected&&this.element.classList.add("selected");const t=this.model.get?this.model.get("id"):this.model.id;t&&this.element.setAttribute("data-id",t)}async onActionEditCell(t,e){t.stopPropagation();const i=e.getAttribute("data-column"),n=this.columns.find(t=>t.key===i);n&&n.editable&&(this.editingCells.has(i)||await this.enterEditMode(i,n,e))}async onActionRowClick(t,e){t.target.closest(".btn-group")||t.target.closest(".dropdown")||t.target.closest(".cell-editor")||(this.emit("row:click",{row:this,model:this.model,column:e.getAttribute("data-column"),event:t}),this.tableView&&this.tableView.emit("row:click",{row:this,model:this.model,column:e.getAttribute("data-column"),event:t}))}async onActionView(t,e){t.stopPropagation(),this.emit("row:view",{row:this,model:this.model,event:t}),this.tableView&&this.tableView.emit("row:view",{row:this,model:this.model,event:t})}async onActionEdit(t,e){return t.stopPropagation(),this.emit("row:edit",{row:this,model:this.model,event:t}),this.tableView&&this.tableView.emit("row:edit",{row:this,model:this.model,event:t}),!0}async onActionDelete(t,e){t.stopPropagation(),this.emit("row:delete",{row:this,model:this.model,event:t}),this.tableView&&this.tableView.emit("row:delete",{row:this,model:this.model,event:t})}async enterEditMode(t,e,i){const n=i.querySelector(".cell-content");if(!n)return;this.editingCells.add(t);const s=this.model.get?this.model.get(t):this.model[t],l=this.createCellEditor(e,s),a=n.innerHTML;n.style.display="none";const o=document.createElement("div");o.className="cell-editor",o.innerHTML=l,i.appendChild(o);const r=o.querySelector("input, select, .form-check-input");r&&(r.focus(),"text"!==r.type&&"textarea"!==r.type||r.select()),o.dataset.originalContent=a,o.dataset.columnKey=t,this.setupEditorEvents(o,t,e),this.emit("cell:edit",{row:this,model:this.model,column:t,originalValue:s})}createCellEditor(t,e){const i=t.editableOptions||{};switch(i.type){case"select":return this.createSelectEditor(i,e);case"switch":case"checkbox":return this.createSwitchEditor(i,e);case"textarea":return this.createTextareaEditor(i,e);default:return this.createTextEditor(i,e)}}createTextEditor(t,e){const i=t.placeholder||"";return`\n <div class="d-flex gap-1 align-items-center">\n <input type="${t.inputType||"text"}"\n class="form-control form-control-sm cell-input"\n value="${this.escapeHtml(e||"")}"\n placeholder="${i}">\n <button type="button" class="btn btn-sm btn-success cell-save" title="Save">\n <i class="bi bi-check"></i>\n </button>\n <button type="button" class="btn btn-sm btn-outline-secondary cell-cancel" title="Cancel">\n <i class="bi bi-x"></i>\n </button>\n </div>\n `}createTextareaEditor(t,e){const i=t.placeholder||"";return`\n <div class="d-flex gap-1">\n <textarea class="form-control form-control-sm cell-input"\n rows="${t.rows||2}"\n placeholder="${i}">${this.escapeHtml(e||"")}</textarea>\n <div class="d-flex flex-column gap-1">\n <button type="button" class="btn btn-sm btn-success cell-save" title="Save">\n <i class="bi bi-check"></i>\n </button>\n <button type="button" class="btn btn-sm btn-outline-secondary cell-cancel" title="Cancel">\n <i class="bi bi-x"></i>\n </button>\n </div>\n </div>\n `}createSelectEditor(t,e){const i=t.options||[];let n="";return i.forEach(t=>{if("string"==typeof t)n+=`<option value="${t}" ${t===e?"selected":""}>${t}</option>`;else if("object"==typeof t&&void 0!==t.value){const i=t.value===e?"selected":"";n+=`<option value="${t.value}" ${i}>${t.label||t.value}</option>`}}),`\n <div class="d-flex gap-1 align-items-center">\n <select class="form-select form-select-sm cell-input">\n ${n}\n </select>\n <button type="button" class="btn btn-sm btn-success cell-save" title="Save">\n <i class="bi bi-check"></i>\n </button>\n <button type="button" class="btn btn-sm btn-outline-secondary cell-cancel" title="Cancel">\n <i class="bi bi-x"></i>\n </button>\n </div>\n `}createSwitchEditor(t,e){const i=e?"checked":"";return`\n <div class="d-flex gap-2 align-items-center">\n <div class="form-check ${"switch"===t.type?"form-switch":""}">\n <input class="form-check-input cell-input" type="checkbox" ${i}>\n </div>\n <div class="d-flex gap-1">\n <button type="button" class="btn btn-sm btn-success cell-save" title="Save">\n <i class="bi bi-check"></i>\n </button>\n <button type="button" class="btn btn-sm btn-outline-secondary cell-cancel" title="Cancel">\n <i class="bi bi-x"></i>\n </button>\n </div>\n </div>\n `}setupEditorEvents(t,e,i){const n=t.querySelector(".cell-input"),s=t.querySelector(".cell-save"),l=t.querySelector(".cell-cancel");!n||"text"!==n.type&&"email"!==n.type&&"number"!==n.type||n.addEventListener("keydown",n=>{"Enter"===n.key?(n.preventDefault(),this.saveCellEdit(t,e,i)):"Escape"===n.key&&(n.preventDefault(),this.cancelCellEdit(t,e))}),!n||"checkbox"!==n.type&&"SELECT"!==n.tagName||!1===i.autoSave||n.addEventListener("change",()=>{this.saveCellEdit(t,e,i)}),s?.addEventListener("click",()=>{this.saveCellEdit(t,e,i)}),l?.addEventListener("click",()=>{this.cancelCellEdit(t,e)})}async saveCellEdit(t,e,i){const n=t.querySelector(".cell-input");if(!n)return;let s;s="checkbox"===n.type?n.checked:(n.tagName,n.value);const l=this.model.get?this.model.get(e):this.model[e];try{this.model.save?await this.model.save({[e]:s}):this.model[e]=s,this.exitEditMode(t,e,s),this.emit("cell:save",{row:this,model:this.model,column:e,oldValue:l,newValue:s})}catch(a){console.error("Failed to save cell edit:",a),this.emit("cell:save:error",{row:this,model:this.model,column:e,oldValue:l,newValue:s,error:a}),t.classList.add("saving-error"),setTimeout(()=>t.classList.remove("saving-error"),3e3)}}cancelCellEdit(t,e){const i=t.dataset.originalContent;this.exitEditMode(t,e,null,i),this.emit("cell:cancel",{row:this,model:this.model,column:e})}exitEditMode(t,e,n=null,s=null){const l=t.closest("td").querySelector(".cell-content");if(l){if(null!==n){const t=this.columns.find(t=>t.key===e);let s=n;t&&t.formatter&&"string"==typeof t.formatter&&(s=i.dataFormatter.pipe(n,t.formatter)),l.innerHTML=this.escapeHtml(s)}else s&&(l.innerHTML=s);l.style.display=""}t.remove(),this.editingCells.delete(e)}escapeHtml(t){if(null==t)return"";const e=document.createElement("div");return e.textContent=t,e.innerHTML}select(){super.select(),this.addClass("selected");const t=this.element?.querySelector(".mojo-select-cell");t&&t.classList.add("selected")}deselect(){super.deselect(),this.removeClass("selected");const t=this.element?.querySelector(".mojo-select-cell");t&&t.classList.remove("selected")}}const a={exact:{display:"is",description:"Exact match"},in:{display:"in",description:"Match any of the values (comma-separated)"},not:{display:"is not",description:"Does not match"},not_in:{display:"not in",description:"Does not match any of the values"},gt:{display:">",description:"Greater than"},gte:{display:">=",description:"Greater than or equal to"},lt:{display:"<",description:"Less than"},lte:{display:"<=",description:"Less than or equal to"},contains:{display:"contains",description:"Contains substring (case-sensitive)"},icontains:{display:"contains",description:"Contains substring (case-insensitive)"},startswith:{display:"starts with",description:"Starts with substring (case-sensitive)"},istartswith:{display:"starts with",description:"Starts with substring (case-insensitive)"},endswith:{display:"ends with",description:"Ends with substring (case-sensitive)"},iendswith:{display:"ends with",description:"Ends with substring (case-insensitive)"},isnull:{display:t=>"true"===t||!0===t?"is null":"is not null",description:"Check if value is null or not"},range:{display:"between",description:"Between two values (comma-separated)"}};function o(t){if(!t||"string"!=typeof t)return{field:t,lookup:null};const e=t.split("__");if(1===e.length)return{field:t,lookup:null};const i=e[e.length-1];return a[i]?{field:e.slice(0,-1).join("__"),lookup:i}:{field:t,lookup:null}}function r(t,e,i){if(!t||null==e)return"";const{field:n,lookup:s}=o(t),l=a[s];if(e&&"object"==typeof e&&!Array.isArray(e)){const t=void 0!==e.start&&null!==e.start&&""!==e.start,n=void 0!==e.end&&null!==e.end&&""!==e.end;return t||n?t&&n?`${i} between '${e.start}' and '${e.end}'`:t?`${i} from '${e.start}'`:`${i} until '${e.end}'`:`${i} is '${JSON.stringify(e)}'`}const r=Array.isArray(e)?e.join(","):String(e);if(!s||"exact"===s)return`${i} is '${r}'`;if("in"===s||"not_in"===s){const t=r.split(",").map(t=>t.trim()).filter(t=>t);if(0===t.length)return`${i} ${l.display}`;const e=t.map(t=>`'${t}'`).join(", ");return`${i} ${l.display} ${e}`}if("range"===s){const t=r.split(",").map(t=>t.trim()).filter(t=>t);return 2===t.length?`${i} between '${t[0]}' and '${t[1]}'`:`${i} ${l.display} '${r}'`}return"isnull"===s?`${i} ${"function"==typeof l.display?l.display(r):l.display}`:l?`${i} ${l.display} '${r}'`:`${i} is '${r}'`}const c={LOOKUPS:a,parseFilterKey:o,formatFilterDisplay:r,getLookupDescription:function(t){const e=a[t];return e?e.description:"Exact match"},isValidLookup:function(t){return t&&a.hasOwnProperty(t)},getAvailableLookups:function(){return Object.keys(a)},buildFilterKey:function(t,e=null){return t?e?`${t}__${e}`:t:""}};class TableView extends e.ListView{constructor(t={}){super({className:"table-view-component",itemClass:t.itemClass||TableRow,selectionMode:t.selectable?"multiple":"none",emptyMessage:t.emptyMessage||"No data available",addButtonIcon:t.addButtonIcon||"bi bi-plus-circle",...t}),this.isFullscreen=!1,this.columns=t.columns||[],this.actions=t.actions||null,this.contextMenu=t.contextMenu||null,this.batchActions=t.batchActions||null,this.searchable=!1!==t.searchable,this.sortable=!1!==t.sortable,this.filterable=!1!==t.filterable,this.paginated=!1!==t.paginated,this.clickAction=t.clickAction||"view",this.itemView=t.itemView,this.addForm=t.addForm,this.editForm=t.editForm,this.deleteTemplate=t.deleteTemplate,this.formDialogConfig=t.formDialogConfig||{},this.viewDialogOptions=t.viewDialogOptions||{},this.exportOptions=t.exportOptions||null,this.options.showExport&&!this.exportOptions&&(this.exportOptions=[{format:"csv",label:"Export as CSV",icon:"bi bi-file-earmark-spreadsheet"},{format:"json",label:"Export as JSON",icon:"bi bi-file-earmark-code"}]),this.exportSource=t.exportSource||"remote",this.filters={},this.additionalFilters=t.filters||[],this.hideActivePills=t.hideActivePills||!1,this.hideActivePillNames=t.hideActivePillNames||[],this.rowAction=t.rowAction||"row-click",this.batchBarLocation=t.batchBarLocation||"bottom",this.options.addButtonLabel=t.addButtonLabel||"Add",this.toolbarButtons=t.toolbarButtons||[],this.tableOptions={striped:!0,bordered:!1,hover:!0,responsive:!1,size:null,...t.tableOptions},this.searchPlacement=t.searchPlacement||"toolbar",this.searchPlaceholder=t.searchPlaceholder||"Search...",this.initializeColumns(),this.extractColumnFilters(),this.footerTotalColumns=this.columns.filter(t=>!0===t.footer_total),this.hasFooterTotals=this.footerTotalColumns.length>0,this.template=this.buildTableTemplate(),this.setupCollectionListeners()}setupCollectionListeners(){this.hasFooterTotals&&this.collection&&this.collection.on("reset add remove change",()=>{this.updateFooterTotals()})}initializeColumns(){this.columns.forEach(t=>{!t.key&&t.name&&(t.key=t.name),t.label||t.title||(t.label=t.key.charAt(0).toUpperCase()+t.key.slice(1))})}getResponsiveClasses(t){if(!t)return"";const e=["sm","md","lg","xl","xxl"];if("string"==typeof t)return e.includes(t)?`d-none d-${t}-table-cell`:(console.warn(`Invalid visibility breakpoint: ${t}. Valid options are: ${e.join(", ")}`),"");if("object"==typeof t){const i=[];if(t.hide){if(!e.includes(t.hide))return console.warn(`Invalid hide breakpoint: ${t.hide}. Valid options are: ${e.join(", ")}`),"";i.push(`d-table-cell d-${t.hide}-none`)}if(t.show){if(!e.includes(t.show))return console.warn(`Invalid show breakpoint: ${t.show}. Valid options are: ${e.join(", ")}`),"";t.hide?i.push(`d-${t.show}-table-cell`):i.push(`d-none d-${t.show}-table-cell`)}return i.join(" ")}return""}parseColumnKey(t){const e=t.split("|");return{fieldKey:e[0],formatter:e[1]||null}}updateFooterTotals(){if(!this.hasFooterTotals||!this.element)return;const t=this.calculateFooterTotals();let e=0;this.columns.forEach(i=>{if(i.footer_total){const n=`col_${e}`,s=this.element.querySelector(`[data-total-column="${n}"]`);if(s&&t[n]){const e=this.parseColumnKey(i.key).formatter||i.formatter;let l;l=e&&"string"==typeof e?this.formatValue(t[n].value,e):t[n].value,s.textContent=l}e++}})}formatValue(t,e){try{return i.dataFormatter.pipe(t,e)}catch(n){return console.warn("Error formatting value:",n),t}}calculateFooterTotals(){if(!this.hasFooterTotals||!this.collection||0===this.collection.length)return{};const t={};return this.footerTotalColumns.forEach((e,i)=>{const{fieldKey:n,formatter:s}=this.parseColumnKey(e.key);let l=0;this.collection.forEach(t=>{const e=t.get?t.get(n):t[n],i=parseFloat(e)||0;l+=i}),e.key,this.collection.length,t[`col_${i}`]={value:l,formatter:s||e.formatter,fieldKey:n,originalKey:e.key}}),t}extractColumnFilters(){this.filters={},this.columns.forEach(t=>{if(t.filter){const{fieldKey:e}=this.parseColumnKey(t.key);this.filters[e]=t.filter}})}isSelectable(){return this.batchActions&&this.batchActions.length>0&&"multiple"==this.selectionMode}buildTableTemplate(){const t="top"===this.batchBarLocation?this.buildBatchActionsPanel():"",e="bottom"===this.batchBarLocation?this.buildBatchActionsPanel():"";return`\n <div class="mojo-table-wrapper">\n ${this.buildToolbarTemplate()}\n ${t}\n <div class="table-container"${(()=>{const t=this.tableOptions&&null!=this.tableOptions.fontSize?this.tableOptions.fontSize:this.options&&this.options.fontSize,e="sm"===t?"0.9rem":"xs"===t?"0.8rem":t?String(t):null;return e?` style="font-size: ${e};"`:""})()}>\n {{#loading}}\n <div class="mojo-table-loading d-flex justify-content-center align-items-center py-5">\n <div class="spinner-border" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="table-empty text-center py-5">\n <i class="bi bi-inbox fa-2x mb-2 text-muted"></i>\n <p class="text-muted">{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <table class="${this.buildTableClasses()}">\n ${this.buildTableHeaderTemplate()}\n <tbody data-container="items"></tbody>\n ${this.hasFooterTotals?this.buildTableFooterTemplate():""}\n </table>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ${e}\n ${this.buildPaginationTemplate()}\n </div>\n `}buildTableClasses(){let t=["table"];return this.tableOptions.striped&&t.push("table-striped"),this.tableOptions.bordered&&t.push("table-bordered"),this.tableOptions.hover&&t.push("table-hover"),this.tableOptions.responsive&&t.push("table-responsive"),this.tableOptions.background&&t.push(`table-${this.tableOptions.background}`),"sm"===this.tableOptions.size&&t.push("table-sm"),"lg"===this.tableOptions.size&&t.push("table-lg"),t.join(" ")}buildToolbarTemplate(){return this.searchable||this.filterable?`\n <div class="table-action-buttons mb-3">\n <div class="d-flex align-items-center gap-2">\n ${this.buildActionButtonsTemplate()}\n ${this.filterable?this.buildFilterDropdownTemplate():""}\n ${this.searchable&&"toolbar"===this.searchPlacement?this.buildSearchTemplate():""}\n\n </div>\n <div data-container="filter-pills"></div>\n </div>\n `:""}buildActionButtonsTemplate(){let t=[];if(t.push('\n <button class="btn btn-sm btn-outline-secondary btn-refresh"\n data-action="refresh"\n title="Refresh">\n <i class="bi bi-arrow-clockwise"></i>\n </button>\n '),this.isFullscreenSupported()&&t.push('\n <button class="btn btn-sm btn-outline-secondary btn-fullscreen"\n data-action="toggle-fullscreen"\n title="Toggle Fullscreen">\n <i class="bi bi-fullscreen"></i>\n </button>\n '),this.options.showAdd&&t.push(`\n <button class="btn btn-sm btn-success btn-add"\n data-action="add"\n title="${this.options.addButtonLabel}">\n <i class="${this.options.addButtonIcon} me-1"></i>\n <span class="d-none d-lg-inline">${this.options.addButtonLabel}</span>\n </button>\n `),this.options.showExport)if(this.exportOptions&&this.exportOptions.length>1){const e=this.exportOptions.map(t=>`\n <li>\n <a class="dropdown-item" href="#" data-action="export" data-format="${t.format}">\n <i class="${t.icon||"bi bi-file-earmark-arrow-down"} me-2"></i>${t.label}\n </a>\n </li>\n `).join("");t.push(`\n <div class="dropdown">\n <button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button"\n data-bs-toggle="dropdown" aria-expanded="false" title="Export">\n <i class="bi bi-download me-1"></i>\n <span class="d-none d-lg-inline">Export</span>\n </button>\n <ul class="dropdown-menu">\n ${e}\n </ul>\n </div>\n `)}else{const e=this.exportOptions&&1===this.exportOptions.length?this.exportOptions[0].format:"json";t.push(`\n <button class="btn btn-sm btn-outline-secondary btn-export"\n data-action="export"\n data-format="${e}"\n title="Export">\n <i class="bi bi-download me-1"></i>\n <span class="d-none d-lg-inline">Export</span>\n </button>\n `)}return this.toolbarButtons&&this.toolbarButtons.length>0&&this.toolbarButtons.forEach((e,i)=>{const{label:n="Button",icon:s="",action:l="",handler:a=null,variant:o="outline-secondary",title:r=n,className:c="",permissions:d=null}=e;if(d&&!this.checkPermissions(d))return;const h=s?`<i class="${s} me-1"></i>`:"",u=`<span class="d-none d-lg-inline">${n}</span>`;let m="";a?m=`data-action="custom-toolbar-button" data-button-index="${i}"`:l&&(m=`data-action="${l}"`);const p=`btn btn-sm btn-${o} ${c}`.trim();t.push(`\n <button class="${p}"\n ${m}\n title="${r}">\n ${h}${u}\n </button>\n `)}),t.join("")}buildSearchTemplate(){return'\n <div class="flex-grow-1" style="max-width: 400px;">\n <div class="input-group input-group-sm">\n <span class="input-group-text">\n <i class="bi bi-search"></i>\n </span>\n <input type="search"\n class="form-control"\n placeholder="{{searchPlaceholder}}"\n data-filter="search"\n data-change-action="apply-search"\n value="{{collection.params.search}}"\n aria-label="Search">\n {{#searchValue}}\n <button class="btn btn-outline-secondary" type="button"\n data-action="clear-search"\n title="Clear search">\n <i class="bi bi-x"></i>\n </button>\n {{/searchValue}}\n </div>\n </div>\n '}buildFilterDropdownTemplate(){return this.filters&&Object.keys(this.filters).length>0||this.additionalFilters&&this.additionalFilters.length>0?`\n <div class="dropdown">\n <button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button"\n data-bs-toggle="dropdown" aria-expanded="false">\n <i class="bi bi-filter me-1"></i>\n <span class="d-none d-lg-inline">Add Filter</span>\n </button>\n <div class="dropdown-menu" style="min-width: 250px;">\n ${this.buildFilterList()}\n </div>\n </div>\n `:""}buildFilterList(){const t=this.getAllAvailableFilters(),e=this.getActiveFilters();return 0===t.length?'<div class="dropdown-item-text text-muted">No filters available</div>':`\n ${t.map(t=>{const i=e.hasOwnProperty(t.key),n=i?"active":"",s=this.getFilterIcon(t.type||t.config?.type);return`\n <button class="dropdown-item ${n}"\n data-action="add-filter"\n data-filter-key="${t.key}">\n <i class="bi bi-${s} me-2"></i>\n ${t.label}\n ${i?'<i class="bi bi-check-circle ms-auto"></i>':""}\n </button>\n `}).join("")}\n ${Object.keys(e).length>0?'\n <div class="dropdown-divider"></div>\n <button class="dropdown-item text-danger" data-action="clear-all-filters">\n <i class="bi bi-x-circle me-2"></i>Clear All Filters\n </button>\n ':""}\n `}updateFilterPills(){const t=this.element?.querySelector('[data-container="filter-pills"]');if(!t)return;this.getActiveFilters();const e=this.buildActivePills();t.innerHTML=e}updateSearchInputs(t){const e=this.element?.querySelectorAll('[data-filter="search"]');e&&e.forEach(e=>{e.value=t||""})}buildActivePills(){if(this.hideActivePills)return"";const t=this.getActiveFilters(),e=t.search&&""!==t.search.toString().trim();let i=Object.entries(t).filter(([t,e])=>e&&""!==e.toString().trim()&&"search"!==t);return this.hideActivePillNames&&this.hideActivePillNames.length>0&&(i=i.filter(([t])=>!this.hideActivePillNames.includes(t))),0!==i.length||e?`\n <div class="row mt-2">\n <div class="col-12">\n <div class="d-flex flex-wrap align-items-center">\n ${i.map(([t,e])=>{const{field:i}=o(t);return`\n <span class="badge bg-primary me-1 mb-1 py-1 px-2 position-relative" style="font-size: 0.75rem;">\n <i class="bi bi-filter me-1" style="font-size: 0.65rem;"></i>\n\n <button type="button" class="btn btn-link text-white p-0 ms-1"\n style="font-size: 0.65rem; line-height: 1;"\n data-action="edit-filter"\n data-filter="${t}"\n title="Edit filter">\n ${r(t,e,this.getFilterLabel(i))}\n </button>\n\n <button type="button" class="btn-close btn-close-white ms-1"\n style="font-size: 0.6rem; width: 0.5rem; height: 0.5rem;"\n data-action="remove-filter"\n data-filter="${t}"\n title="Remove filter">\n </button>\n </span>\n `}).join("")}\n ${i.length>1||i.length>0&&e||0===i.length&&e?'\n <button class="btn btn-sm btn-outline-secondary mb-1 py-0 px-2" style="font-size: 0.75rem;" data-action="clear-all-filters">\n <i class="bi bi-x-circle me-1" style="font-size: 0.7rem;"></i>\n <small>Clear All</small>\n </button>\n ':""}\n </div>\n </div>\n </div>\n `:""}buildTableHeaderTemplate(){let t="";return this.isSelectable()&&(t+='\n <th style="width: 40px; padding: 0;">\n <div class="mojo-select-all-cell" data-action="select-all">\n <div class="mojo-checkbox">\n <i class="bi bi-check"></i>\n </div>\n </div>\n </th>\n '),this.columns.forEach(e=>{const{fieldKey:i}=this.parseColumnKey(e.key),n=this.sortable&&!1!==e.sortable,s=this.getSortBy()===i?this.getSortDirection():null,l=this.getSortIcon(s),a=e.label||e.title||i,o=this.getResponsiveClasses(e.visibility);t+=`\n <th class="${n?"sortable":""} ${o}">\n <div class="d-flex align-items-center">\n <span>${a}</span>\n ${n?`\n <div class="dropdown d-inline-block ms-2">\n <button class="btn btn-sm btn-link p-0 text-decoration-none" type="button"\n data-bs-toggle="dropdown" aria-expanded="false"\n data-column="${i}">\n ${l}\n </button>\n <ul class="dropdown-menu dropdown-menu-end">\n <li><a class="dropdown-item ${"asc"===s?"active":""}"\n data-action="sort" data-field="${i}" data-direction="asc">\n <i class="bi bi-sort-alpha-down me-2"></i>Sort A-Z\n </a></li>\n <li><a class="dropdown-item ${"desc"===s?"active":""}"\n data-action="sort" data-field="${i}" data-direction="desc">\n <i class="bi bi-sort-alpha-down-alt me-2"></i>Sort Z-A\n </a></li>\n <li><a class="dropdown-item ${null===s?"active":""}"\n data-action="sort" data-field="${i}" data-direction="none">\n <i class="bi bi-x-circle me-2"></i>No Sort\n </a></li>\n </ul>\n </div>\n `:""}\n </div>\n </th>\n `}),this.actions?t+="<th>Actions</th>":this.contextMenu&&(t+='<th style="width: 1px;"></th>'),`\n <thead>\n <tr>\n ${t}\n </tr>\n </thead>\n `}buildTableFooterTemplate(){let t="";this.isSelectable()&&(t+="<td></td>");let e=0;return this.columns.forEach((i,n)=>{const s=this.getResponsiveClasses(i.visibility);if(i.footer_total){const n=`col_${e}`,l=this.parseColumnKey(i.key).formatter||i.formatter;let a;a=l&&"string"==typeof l?`{{{footerTotals.${n}.value|${l}}}}`:`{{footerTotals.${n}.value}}`,t+=`<td class="table-footer-total ${s}" data-total-column="${n}">${a}</td>`,e++}else t+=0===n?`<td class="table-footer-label ${s}"><strong>Totals</strong></td>`:`<td class="${s}"></td>`}),(this.actions||this.contextMenu)&&(t+="<td></td>"),`\n <tfoot>\n <tr class="table-totals-row">\n ${t}\n </tr>\n </tfoot>\n `}buildBatchActionsPanel(){if(!this.batchActions||0===this.batchActions.length)return"";if("top"===this.batchBarLocation){let t="";return this.batchActions.forEach(e=>{t+=`\n <button class="btn btn-sm btn-outline-secondary" data-action="batch-${e.action}" title="${e.label}">\n <i class="${e.icon} me-1"></i>\n <span class="d-none d-lg-inline">${e.label}</span>\n </button>\n `}),`\n <div class="batch-actions-panel-top alert alert-info d-none mb-3" role="alert">\n <div class="d-flex justify-content-between align-items-center">\n <div class="d-flex align-items-center">\n <strong class="me-2">\n <span class="batch-select-count">0</span> ${this.options.batchPanelTitle||"items"} selected\n </strong>\n </div>\n <div class="d-flex gap-2 align-items-center">\n ${t}\n <button class="btn btn-sm btn-outline-secondary" data-action="clear-selection" title="Clear Selection">\n <i class="bi bi-x-circle me-1"></i>\n <span class="d-none d-lg-inline">Clear</span>\n </button>\n </div>\n </div>\n </div>\n `}{let t="";return this.batchActions.forEach(e=>{t+=`\n <div class="batch-select-action text-center px-2" data-action="batch-${e.action}">\n <div class="batch-action-icon fs-3">\n <i class="${e.icon}"></i>\n </div>\n <div class="batch-action-title small">${e.label}</div>\n </div>\n `}),`\n <div class="batch-actions-panel rounded-start rounded-end" style="display: none;">\n <div class="batch-select-panel rounded-start rounded-end">\n <div class="row g-0">\n <div class="col-auto">\n <div class="batch-select-count rounded-start">0</div>\n </div>\n <div class="col">\n <div class="ps-2 batch-select-title">${this.options.batchPanelTitle||"Rows"}</div>\n </div>\n <div class="col">\n <div class="batch-select-actions d-flex justify-content-end">\n ${t}\n </div>\n </div>\n <div class="col-auto">\n <div class="batch-select-end rounded-end"></div>\n </div>\n </div>\n </div>\n </div>\n `}}buildPaginationTemplate(){return this.paginated?'\n <div class="table-status-bar mt-3">\n <div class="d-flex flex-column flex-lg-row justify-content-center justify-content-lg-between align-items-center gap-3">\n <div class="d-flex flex-column flex-sm-row align-items-center gap-2 gap-sm-3 text-center text-lg-start">\n <span class="text-muted">\n Showing <span data-value="start">0</span> to <span data-value="end">0</span>\n of <span data-value="total">0</span> entries\n </span>\n <div class="d-flex align-items-center">\n <label class="form-label me-2 mb-0">Show:</label>\n <select class="form-select form-select-sm" style="width: auto;" data-change-action="page-size">\n <option value="5">5</option>\n <option value="10">10</option>\n <option value="25">25</option>\n <option value="50">50</option>\n <option value="100">100</option>\n </select>\n </div>\n </div>\n <nav aria-label="Table pagination">\n <ul class="pagination pagination-sm mb-0 justify-content-center" data-container="pagination">\n \x3c!-- Pagination will be rendered here --\x3e\n </ul>\n </nav>\n </div>\n </div>\n ':""}_createItemView(t,e){const i=new this.itemClass({model:t,index:e,listView:this,tableView:this,template:this.itemTemplate,columns:this.columns,actions:this.actions,contextMenu:this.contextMenu,batchActions:this.batchActions,containerId:"items"});return this.itemViews.set(t.id,i),i.on("item:select",t=>{this._onItemSelect(t),this.updateBatchActionsPanel()}),i.on("item:deselect",t=>{this._onItemDeselect(t),this.updateBatchActionsPanel()}),i.on("row:click",this._onRowClick.bind(this)),i.on("row:view",this._onRowView.bind(this)),i.on("row:edit",this._onRowEdit.bind(this)),i.on("row:delete",this._onRowDelete.bind(this)),i.on("cell:edit",this._onCellEdit.bind(this)),i.on("cell:save",this._onCellSave.bind(this)),i.on("cell:cancel",this._onCellCancel.bind(this)),i}async onMounted(){await super.onMounted();const t=this.getActiveFilters();this.collection&&Object.keys(t).length>0&&this.updateFilterPills(),this.setupSearchClearListener()}setupSearchClearListener(){this.element&&this.element.querySelectorAll('input[type="search"][data-filter="search"]').forEach(t=>{t.addEventListener("input",t=>{""===t.target.value&&this.getActiveFilters().search&&this.onActionClearSearch(t,t.target)})})}_onRowClick(t){if(this.emit("row:click",t),this.options.onRowClick)return this.options.onRowClick(t.model,t.event);"view"===this.clickAction?this._onRowView(t):"edit"===this.clickAction&&this._onRowEdit(t)}getModelClass(t){return this.collection?.ModelClass?this.collection.ModelClass:this.collection?.model?this.collection.model:t?.constructor?t.constructor:null}getModelName(t){const e=this.getModelClass(t);return e&&(e.MODEL_NAME||e.name.replace(/Model$/,""))||"Item"}getItemViewClass(t){if(this.itemView)return this.itemView;const e=this.getModelClass(t);return e?.VIEW_CLASS?e.VIEW_CLASS:null}getAddFormConfig(t){return this.addForm||t?.ADD_FORM||this.editForm||t?.EDIT_FORM}getEditFormConfig(t){return this.editForm||t?.EDIT_FORM||this.addForm||t?.ADD_FORM}getFormDialogConfig(t){return{...t?.FORM_DIALOG_CONFIG,...this.formDialogConfig}}renderTemplateString(t,e){return t?i.Mustache.render(t,e):""}async _onRowView(t){if(this.emit("row:view",t),this.options.onItemView)return void(await this.options.onItemView(t.model,t.event));const e=this.getItemViewClass(t.model);if(e){const i=new e({model:t.model,collection:this.collection});await n.default.showDialog({header:!1,body:i,size:"lg",centered:!1,...this.getFormDialogConfig(this.getModelClass(t.model)),...this.viewDialogOptions})}else await n.default.showData({title:`View ${this.getModelName(t.model)} #${t.model.id}`,model:t.model})}async _onRowEdit(t){if(this.emit("row:edit",t),this.options.onItemEdit)return void(await this.options.onItemEdit(t.model,t.event));const e=this.getModelClass(t.model);let i=this.getEditFormConfig(e);if(i){i.fields||(i={title:`Edit ${this.getModelName(t.model)}`,fields:i});const s=await n.default.showModelForm({model:t.model,...i,...this.getFormDialogConfig(e)});if(!s)return;if(!s.success||!s?.result?.data.status)return void n.default.showError(s?.result?.data?.error||s?.result?.message||"An error occurred")}else{const e=await n.default.showDialog({title:`Edit ${this.getModelName(t.model)} #${t.model.id}`,body:new s.FormView({model:t.model,fields:this.options.formFields||[]})});if(e){const i=await t.model.save(e);if(!i.data?.status)return void n.default.showError(i.data.error||"An error occurred");await this.refresh()}}}async _onRowDelete(t){if(this.emit("row:delete",t),this.options.onItemDelete)return void(await this.options.onItemDelete(t.model,t.event));const e=this.getModelClass(t.model),i=this.deleteTemplate||e?.DELETE_TEMPLATE||'Are you sure you want to delete this {{name||"item"}}?',s=this.renderTemplateString(i,t.model);await n.default.confirm({message:s||"Are you sure you want to delete this item?",title:"Confirm Delete",confirmText:"Delete",confirmClass:"btn-danger"})&&(await t.model.destroy(),this.collection.fetch())}_onCellEdit(t){this.emit("cell:edit",t)}async _onCellSave(t){this.emit("cell:save",t)}_onCellCancel(t){this.emit("cell:cancel",t)}isFullscreenSupported(){return!!(document.fullscreenEnabled||document.mozFullScreenEnabled||document.webkitFullscreenEnabled||document.msFullscreenEnabled)}async onActionToggleFullscreen(t,e){this.isFullscreen?await this.exitFullscreen():await this.enterFullscreen()}async enterFullscreen(){try{this.element.requestFullscreen?await this.element.requestFullscreen():this.element.mozRequestFullScreen?await this.element.mozRequestFullScreen():this.element.webkitRequestFullscreen?await this.element.webkitRequestFullscreen():this.element.msRequestFullscreen&&await this.element.msRequestFullscreen(),this.isFullscreen=!0,this.element.classList.add("table-fullscreen"),this.updateFullscreenButton(),this.setupFullscreenListeners(),this.emit("table:fullscreen:enter")}catch(t){console.warn("Could not enter fullscreen:",t)}}async exitFullscreen(){try{document.exitFullscreen?await document.exitFullscreen():document.mozCancelFullScreen?await document.mozCancelFullScreen():document.webkitExitFullscreen?await document.webkitExitFullscreen():document.msExitFullscreen&&await document.msExitFullscreen(),this.isFullscreen=!1,this.element.classList.remove("table-fullscreen"),this.updateFullscreenButton(),this.emit("table:fullscreen:exit")}catch(t){console.warn("Could not exit fullscreen:",t)}}updateFullscreenButton(){const t=this.element?.querySelector(".btn-fullscreen"),e=t?.querySelector("i");t&&e&&(this.isFullscreen?(e.className="bi bi-fullscreen-exit",t.title="Exit Fullscreen"):(e.className="bi bi-fullscreen",t.title="Enter Fullscreen"))}setupFullscreenListeners(){if(this._fullscreenHandler)return;const t=()=>{!(document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement)&&this.isFullscreen&&(this.isFullscreen=!1,this.element.classList.remove("table-fullscreen"),this.updateFullscreenButton(),this.emit("table:fullscreen:exit"))};document.addEventListener("fullscreenchange",t),document.addEventListener("mozfullscreenchange",t),document.addEventListener("webkitfullscreenchange",t),document.addEventListener("msfullscreenchange",t),this._fullscreenHandler=t}cleanupFullscreenListeners(){this._fullscreenHandler&&(document.removeEventListener("fullscreenchange",this._fullscreenHandler),document.removeEventListener("mozfullscreenchange",this._fullscreenHandler),document.removeEventListener("webkitfullscreenchange",this._fullscreenHandler),document.removeEventListener("msfullscreenchange",this._fullscreenHandler),this._fullscreenHandler=null)}destroy(){this.cleanupFullscreenListeners(),super.destroy()}async onActionRefresh(t,e){await this.refresh()}async onActionAdd(t,e){if(this.options.onAdd)return this.emit("table:add",{event:t}),void(await this.options.onAdd(t));this.emit("table:add",{event:t});const i=this.getModelClass();if(!i)return void console.warn("Cannot determine Model class for add operation");let l=this.getAddFormConfig(i);if(l){const t=new i;l.fields||(l={title:`Add ${this.getModelName()}`,fields:l});const e=await n.default.showForm({model:t,...l,...this.getFormDialogConfig(i)});if(e){this.options.addRequiresActiveGroup&&(e.group=this.getApp().activeGroup.id),this.options.addRequiresActiveUser&&(e.user=this.getApp().activeUser.id),this.options.addFormDefaults&&Object.assign(e,this.options.addFormDefaults);const i=await t.save(e);if(!i?.data.status)return void n.default.showError(i?.data.error||"An error occurred");this.collection&&this.collection.add(t),await this.refresh()}}else{const t=new i,e=await n.default.showDialog({title:`Add ${this.getModelName()}`,body:new s.FormView({model:t,fields:this.options.formFields||[]})});if(e){const i=await t.save(e);if(!i?.data.status)return void n.default.showError(i.data.error||"An error occurred");this.collection&&this.collection.add(t),await this.refresh()}}}async onActionExport(t,e){const i=e.getAttribute("data-format")||"json";this.emit("table:export",{format:i,source:this.exportSource,event:t}),"remote"===this.exportSource?this.collection?await this.collection.download(i):console.warn("TableView: Cannot export from remote without a collection."):this.options.onExport?await this.options.onExport(this.collection?.toJSON()||[],i):console.warn("TableView: onExport handler not implemented for local export.")}async onActionApplySearch(t,e){const i=e.value.trim();this.collection&&(this.setFilter("search",i),this.collection.params.start=0,this.collection.restEnabled?await this.collection.fetch():this.render()),this.updateFilterPills(),this.emit("table:search",{searchTerm:i,event:t}),this.emit("params-changed")}async onActionClearSearch(t,e){this.setFilter("search",null),this.collection&&(this.collection.params.start=0,this.collection.restEnabled&&await this.collection.fetch()),await this.render(),this.updateFilterPills(),this.emit("table:search",{searchTerm:"",event:t}),this.emit("params-changed")}getSortBy(){const t=this.collection?.params?.sort;return t?t.startsWith("-")?t.slice(1):t:null}getSortDirection(){const t=this.collection?.params?.sort;return t&&t.startsWith("-")?"desc":"asc"}getSortIcon(t){return"asc"===t?'<i class="bi bi-sort-alpha-down text-primary"></i>':"desc"===t?'<i class="bi bi-sort-alpha-down-alt text-primary"></i>':'<i class="bi bi-three-dots-vertical text-muted"></i>'}async onActionSort(t,e){t.preventDefault();const i=e.getAttribute("data-field"),n=e.getAttribute("data-direction");if(this.collection){let t;if(t="none"===n?void 0:"desc"===n?`-${i}`:i,this.collection.setParams({...this.collection.params,sort:t,start:0}),this.collection.restEnabled)await this.collection.fetch();else{if(t){const e=t.startsWith("-"),i=e?t.slice(1):t;this.collection.sort((t,n)=>{const s=t.get(i),l=n.get(i);return s<l?e?1:-1:s>l?e?-1:1:0})}this.render()}}this.updateSortIcons(),this.emit("table:sort",{field:i,event:t}),this.emit("params-changed")}updateSortIcons(){if(!this.element)return;const t=this.getSortBy(),e=this.getSortDirection();this.columns.forEach(i=>{if(this.sortable&&!1!==i.sortable){const{fieldKey:n}=this.parseColumnKey(i.key),s=this.element.querySelector(`[data-bs-toggle="dropdown"][data-column="${n}"]`);if(s){const i=t===n,l=this.getSortIcon(i?e:null);s.innerHTML=l;const a=s.nextElementSibling;if(a){const s=a.querySelector(`[data-field="${n}"][data-direction="asc"]`),l=a.querySelector(`[data-field="${n}"][data-direction="desc"]`),o=a.querySelector(`[data-field="${n}"][data-direction="none"]`);s&&s.classList.toggle("active",i&&"asc"===e),l&&l.classList.toggle("active",i&&"desc"===e),o&&o.classList.toggle("active",!i||t!==n)}}}})}async onActionSelectAll(t,e){t.stopPropagation();const i=this.itemViews.size>0&&Array.from(this.itemViews.values()).every(t=>t.selected);i?this.clearSelection():this.forEachItem(t=>{t.selected||t.select()});const n=this.element?.querySelector(".mojo-select-all-cell");n&&n.classList.toggle("selected",!i),this.updateBatchActionsPanel()}async onBeforeRender(){this.searchValue=this.getActiveFilters().search||"",this.footerTotals=this.calculateFooterTotals()}async onAfterRender(){if(await super.onAfterRender(),this.hasFooterTotals&&this.updateFooterTotals(),this.paginated&&this.collection){const t=this.collection.meta?.count||this.collection.length(),e=this.collection.params?.start||0,i=this.collection.params?.size||10,n=Math.min(e+i,t),s=this.element.querySelector('[data-value="start"]'),l=this.element.querySelector('[data-value="end"]'),a=this.element.querySelector('[data-value="total"]');s&&(s.textContent=e+1),l&&(l.textContent=n),a&&(a.textContent=t);const o=this.element.querySelector('[data-change-action="page-size"]');o&&(o.value=i),this.renderPagination()}this.updateSortIcons(),this.updateFilterPills(),this.setupSearchClearListener()}renderPagination(){const t=this.element.querySelector('[data-container="pagination"]');if(!t||!this.collection)return;const e=this.collection.meta?.count||this.collection.length(),i=this.collection.params?.size||10,n=this.collection.params?.start||0,s=Math.floor(n/i)+1,l=Math.ceil(e/i);if(l<=1)return void(t.innerHTML="");const a=s>1?s-1:l,o=s<l?s+1:1,r=[];r.push(`\n <li class="page-item">\n <a class="page-link" href="#" data-action="page" data-page="${a}">\n <i class="bi bi-chevron-left"></i>\n </a>\n </li>\n `);const c=/* @__PURE__ */new Set([1,l]);for(let u=s-1;u<=s+1;u++)u>=1&&u<=l&&c.add(u);const d=Array.from(c).sort((t,e)=>t-e);let h=0;for(const u of d)h&&u-h>1&&r.push('\n <li class="page-item disabled"><span class="page-link">…</span></li>\n '),r.push(`\n <li class="page-item ${u===s?"active":""}">\n <a class="page-link" href="#" data-action="page" data-page="${u}">${u}</a>\n </li>\n `),h=u;r.push(`\n <li class="page-item">\n <a class="page-link" href="#" data-action="page" data-page="${o}">\n <i class="bi bi-chevron-right"></i>\n </a>\n </li>\n `),t.innerHTML=r.join("")}async onActionPage(t,e){t.preventDefault();const i=parseInt(e.getAttribute("data-page"),10),n=this.collection.params?.size||10,s=this.collection.meta?.count||this.collection.length(),l=Math.max(1,Math.ceil(s/n));let a=isNaN(i)?1:i;a<1&&(a=l),a>l&&(a=1),this.collection.setParams({...this.collection.params,start:(a-1)*n}),this.collection.restEnabled?await this.collection.fetch():this.render(),this.emit("table:page",{page:a,event:t}),this.emit("params-changed")}async onChangePageSize(t,e){const i=parseInt(e.value);this.collection&&(this.collection.setParams({...this.collection.params,start:0,size:i}),this.collection.restEnabled&&await this.collection.fetch(),this.render()),this.emit("table:pagesize",{size:i,event:t}),this.emit("params-changed")}getActiveFilters(){if(!this.collection?.params)return{};const{start:t,size:e,sort:i,...n}=this.collection.params,s={},l=/* @__PURE__ */new Set;return this.getAllAvailableFilters().forEach(t=>{if("daterange"===t.config.type){const e=t.key,i=t.config.startName||"dr_start",a=t.config.endName||"dr_end",o=t.config.fieldName||"dr_field";n[o]===e&&(n[i]||n[a])&&(s[e]={start:n[i]||"",end:n[a]||""},l.add(i),l.add(a),l.add(o))}}),Object.keys(n).forEach(t=>{l.has(t)||(s[t]=n[t])}),Object.keys(s).forEach(t=>{if(s.hasOwnProperty(t)){const e=`${t}__in`;s.hasOwnProperty(e)&&(delete s[t],s[e]=s[e])}}),s}setFilter(t,e){if(!this.collection)return;const i=this.getFilterConfig(t);if(i&&"daterange"===i.type){const n=i.startName||"dr_start",s=i.endName||"dr_end",l=i.fieldName||"dr_field";delete this.collection.params[n],delete this.collection.params[s],delete this.collection.params[l],e&&"object"==typeof e&&(e.start||e.end)&&(e.start&&(this.collection.params[n]=e.start),e.end&&(this.collection.params[s]=e.end),this.collection.params[l]=t)}else{const{field:i,lookup:n}=o(t);if(delete this.collection.params[t],delete this.collection.params[i],delete this.collection.params[`${i}__in`],!e||Array.isArray(e)&&0===e.length)return;Array.isArray(e)?1===e.length?this.collection.params[i]=e[0]:this.collection.params[`${i}__in`]=e.join(","):this.collection.params[t]=e}}getAllAvailableFilters(){const t=[];return this.columns.forEach(e=>{if(e.filter){const{fieldKey:i}=this.parseColumnKey(e.key);t.push({key:i,label:e.filter.label||e.label||i,type:e.filter.type,config:e.filter})}}),this.additionalFilters&&Array.isArray(this.additionalFilters)&&this.additionalFilters.forEach(e=>{t.push({key:e.name||e.key,label:e.label,type:e.type,config:e})}),t}getFilterConfig(t){const e=this.columns.find(e=>{const{fieldKey:i}=this.parseColumnKey(e.key);return i===t});if(e&&e.filter)return e.filter;if(this.additionalFilters&&Array.isArray(this.additionalFilters)){const e=this.additionalFilters.find(e=>(e.name||e.key)===t);if(e)return e}return null}getFilterLabel(t){if("search"===t)return"Search";const e=this.filters[t];if(e&&e.label)return e.label;const i=this.additionalFilters.find(e=>(e.name||e.key)===t);return i&&i.label?i.label:t.charAt(0).toUpperCase()+t.slice(1)}getFilterDisplayValue(t,e){if("search"===t)return`"${e}"`;const i=this.filters[t]||this.additionalFilters.find(e=>(e.name||e.key)===t);if(i&&"daterange"===i.type&&"object"==typeof e)return`${e.start||""} to ${e.end||""}`;if(i&&"select"===i.type&&i.options){if("object"==typeof i.options[0]){const t=i.options.find(t=>t.value===e);return t?t.label:e}return e}return e}getFilterIcon(t){return{text:"search",select:"funnel",date:"calendar",daterange:"calendar-range",number:"123",boolean:"toggle-on"}[t]||"filter"}async onActionAddFilter(t,e){const i=e.getAttribute("data-filter-key"),s=this.getFilterConfig(i),l=this.getActiveFilters()[i];if(!s)return void console.warn("No filter config found for key:",i);const a=await n.default.showForm({title:`${void 0!==l&&""!==l?"Edit":"Add"} ${this.getFilterLabel(i)} Filter`,size:"md",fields:[this.buildFilterDialogField(s,l,i)]});if(a){const t=this.extractFilterValue(s,a);this.setFilter(i,t),await this.applyFilters()}}buildFilterDialogField(t,e,i){const n={name:"filter_value",label:t.label,value:e,...t,placeholder:t.placeholder||t.placeHolder};if("daterange"===t.type){if(n.startName=n.startName||"dr_start",n.endName=n.endName||"dr_end",n.fieldName=n.fieldName||"dr_field",n.format=n.format||"YYYY-MM-DD",n.displayFormat=n.displayFormat||"MMM DD, YYYY",n.separator=n.separator||" to ",n.label=n.label||"Date Range",e&&"object"==typeof e){const t=t=>{if(!t&&0!==t)return"";if(t instanceof Date&&!isNaN(t))return t.toISOString().slice(0,10);const e=String(t).trim();if(!e)return"";if(/^-?\d+$/.test(e)){const t=Number(e),i=e.length<=10?1e3*t:t,n=new Date(i);if(!isNaN(n))return n.toISOString().slice(0,10)}const i=new Date(e);return isNaN(i)?e:i.toISOString().slice(0,10)};n.startDate=t(e.start||e.from||e.begin||""),n.endDate=t(e.end||e.to||e.finish||"")}}else if("multiselect"===t.type){let i=[];e&&(Array.isArray(e)?i=e:"string"==typeof e&&(i=e.split(",").map(t=>t.trim()).filter(t=>t))),n.value=i,n.placeholder||n.placeHolder||(t.placeholder||t.placeHolder?n.placeholder=t.placeholder||t.placeHolder:t.label&&(n.placeholder=`Select ${t.label}...`))}return n}extractFilterValue(t,e){if("daterange"===t.type){const i=t.startName||"dr_start",n=t.endName||"dr_end";return{start:e[i],end:e[n]}}return t.type,e.filter_value}async applyFilters(){if(this.collection&&(this.collection.params.start=0),this.collection?.restEnabled)try{await this.collection.fetch(),this.render()}catch(t){console.error("Failed to fetch filtered data:",t),this.render()}else this.render();this.updateFilterPills(),this.emit("params-changed")}async onActionEditFilter(t,e){const i=e.getAttribute("data-filter"),{field:s}=o(i);let l=this.getFilterConfig(s)||this.getFilterConfig(i);const a=this.getActiveFilters(),r=a[i]||a[s];if(!l)return void console.warn("No filter config found for key:",i,"or field:",s);const c={filter_value:r};if("daterange"===l.type&&r&&"object"==typeof r){const t=l.startName||"dr_start",e=l.endName||"dr_end";c[t]=r.start||"",c[e]=r.end||""}const d=await n.default.showForm({title:`Edit ${this.getFilterLabel(s)} Filter`,size:"md",data:c,fields:[this.buildFilterDialogField(l,r,s)]});if(d){const t=this.extractFilterValue(l,d);this.setFilter(i,t),await this.applyFilters()}}async onActionRemoveFilter(t,e){const i=e.getAttribute("data-filter"),{field:n}=o(i);this.setFilter(i,null),"search"===i&&this.updateSearchInputs(""),this.collection.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filter:remove",{key:i,field:n}),this.emit("params-changed")}async onActionClearAllFilters(t,e){if(!this.collection)return;const{start:i,size:n,sort:s}=this.collection.params;this.collection.params={start:i,size:n},s&&(this.collection.params.sort=s),this.updateSearchInputs(""),this.collection.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filters:clear"),this.emit("params-changed")}updateBatchActionsPanel(){if(!this.batchActions||0===this.batchActions.length)return;const t=this.getSelectedItems().length;if("top"===this.batchBarLocation){const e=this.element?.querySelector(".batch-actions-panel-top"),i=this.element?.querySelector(".batch-select-count");e&&i&&(i.textContent=t,t>0?e.classList.remove("d-none"):e.classList.add("d-none"))}else{const e=this.element?.querySelector(".batch-actions-panel"),i=this.element?.querySelector(".batch-select-count");e&&i&&(i.textContent=t,e.style.display=t>0?"block":"none")}const e=this.element?.querySelector(".mojo-select-all-cell");if(e){const t=this.itemViews.size>0&&Array.from(this.itemViews.values()).every(t=>t.selected),i=Array.from(this.itemViews.values()).some(t=>t.selected);e.classList.toggle("selected",t),e.classList.toggle("indeterminate",!t&&i);const n=e.querySelector("i");n&&(n.className=!t&&i?"bi bi-dash":"bi bi-check")}}async onActionBatch(t,e){const i=e.getAttribute("data-action").replace("batch-",""),n=this.getSelectedItems();this.emit("batch:action",{action:i,items:n,event:t})}async onActionClearSelection(t,e){this.clearSelection(),this.updateBatchActionsPanel()}async onActionCustomToolbarButton(t,e){const i=parseInt(e.getAttribute("data-button-index"),10),n=this.toolbarButtons[i];n&&"function"==typeof n.handler&&await n.handler.call(this,t,e)}}exports.DjangoLookups=c,exports.LOOKUPS=a,exports.Log=Log,exports.LogList=LogList,exports.Member=Member,exports.MemberForms=l,exports.MemberList=MemberList,exports.TableRow=TableRow,exports.TableView=TableView,exports.formatFilterDisplay=r,exports.parseFilterKey=o;
2
+ //# sourceMappingURL=TableView-CI_7a-kD.js.map