web-mojo 2.1.936 → 2.1.954

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/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +122 -229
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.cjs.js.map +1 -1
  7. package/dist/auth.es.js +7 -7
  8. package/dist/auth.es.js.map +1 -1
  9. package/dist/charts.cjs.js +1 -1
  10. package/dist/charts.es.js +7 -7
  11. package/dist/chunks/ChatView-BKa78eKF.js +2 -0
  12. package/dist/chunks/ChatView-BKa78eKF.js.map +1 -0
  13. package/dist/chunks/{ChatView-DlSxjxah.js → ChatView-Dcz7LkwL.js} +89 -574
  14. package/dist/chunks/ChatView-Dcz7LkwL.js.map +1 -0
  15. package/dist/chunks/Collection-OP7c9Zyu.js +989 -0
  16. package/dist/chunks/Collection-OP7c9Zyu.js.map +1 -0
  17. package/dist/chunks/Collection-aQF5eOUH.js +2 -0
  18. package/dist/chunks/Collection-aQF5eOUH.js.map +1 -0
  19. package/dist/chunks/ContextMenu-DV_wsr9B.js +3 -0
  20. package/dist/chunks/ContextMenu-DV_wsr9B.js.map +1 -0
  21. package/dist/chunks/ContextMenu-ixMyAUGS.js +1171 -0
  22. package/dist/chunks/ContextMenu-ixMyAUGS.js.map +1 -0
  23. package/dist/chunks/DataView-CdDY9ijM.js +2 -0
  24. package/dist/chunks/{DataView-XJbTQ5q0.js.map → DataView-CdDY9ijM.js.map} +1 -1
  25. package/dist/chunks/{DataView-Vmjx4eCr.js → DataView-OUqaLmGB.js} +2 -2
  26. package/dist/chunks/{DataView-Vmjx4eCr.js.map → DataView-OUqaLmGB.js.map} +1 -1
  27. package/dist/chunks/{Dialog-D_rAf4gQ.js → Dialog-C2mRUxga.js} +8 -6
  28. package/dist/chunks/{Dialog-D_rAf4gQ.js.map → Dialog-C2mRUxga.js.map} +1 -1
  29. package/dist/chunks/Dialog-Cl6MN8if.js +2 -0
  30. package/dist/chunks/{Dialog-BinTQTfO.js.map → Dialog-Cl6MN8if.js.map} +1 -1
  31. package/dist/chunks/FormView-BSWaXDav.js +3 -0
  32. package/dist/chunks/{FormView-TPFsq8ZX.js.map → FormView-BSWaXDav.js.map} +1 -1
  33. package/dist/chunks/{FormView-CIriLDZY.js → FormView-HWvIdFkB.js} +10 -6
  34. package/dist/chunks/FormView-HWvIdFkB.js.map +1 -0
  35. package/dist/chunks/ListView-Dcz0Gs6D.js +492 -0
  36. package/dist/chunks/ListView-Dcz0Gs6D.js.map +1 -0
  37. package/dist/chunks/ListView-eXgn0F0-.js +2 -0
  38. package/dist/chunks/ListView-eXgn0F0-.js.map +1 -0
  39. package/dist/chunks/MetricsMiniChartWidget-BkTEO87S.js +2 -0
  40. package/dist/chunks/{MetricsMiniChartWidget-sONcM0pG.js.map → MetricsMiniChartWidget-BkTEO87S.js.map} +1 -1
  41. package/dist/chunks/{MetricsMiniChartWidget-BolRZ-Ja.js → MetricsMiniChartWidget-Y70IHFIe.js} +3 -3
  42. package/dist/chunks/{MetricsMiniChartWidget-BolRZ-Ja.js.map → MetricsMiniChartWidget-Y70IHFIe.js.map} +1 -1
  43. package/dist/chunks/PDFViewer-C0aMqGJL.js +2 -0
  44. package/dist/chunks/{PDFViewer-UBhinN8A.js.map → PDFViewer-C0aMqGJL.js.map} +1 -1
  45. package/dist/chunks/{PDFViewer-D6SKOl85.js → PDFViewer-DkbYnnoV.js} +3 -3
  46. package/dist/chunks/{PDFViewer-D6SKOl85.js.map → PDFViewer-DkbYnnoV.js.map} +1 -1
  47. package/dist/chunks/Page-CvbwEoLv.js +2 -0
  48. package/dist/chunks/{Page-CnvHhwLZ.js.map → Page-CvbwEoLv.js.map} +1 -1
  49. package/dist/chunks/{Page-B7L25Omb.js → Page-Deq4y2Kq.js} +2 -2
  50. package/dist/chunks/{Page-B7L25Omb.js.map → Page-Deq4y2Kq.js.map} +1 -1
  51. package/dist/chunks/Rest-BNYqGlnP.js +2 -0
  52. package/dist/chunks/Rest-BNYqGlnP.js.map +1 -0
  53. package/dist/chunks/{WebApp-El07OMHH.js → Rest-CS4jRCAs.js} +5 -1389
  54. package/dist/chunks/Rest-CS4jRCAs.js.map +1 -0
  55. package/dist/chunks/{TopNav-CPA884W7.js → TopNav-DXLRdU0o.js} +5 -5
  56. package/dist/chunks/{TopNav-CPA884W7.js.map → TopNav-DXLRdU0o.js.map} +1 -1
  57. package/dist/chunks/TopNav-GyvI31l2.js +2 -0
  58. package/dist/chunks/{TopNav-Dcmcic-i.js.map → TopNav-GyvI31l2.js.map} +1 -1
  59. package/dist/chunks/WebApp-BAadsDpO.js +2 -0
  60. package/dist/chunks/WebApp-BAadsDpO.js.map +1 -0
  61. package/dist/chunks/WebApp-BVGZC2rj.js +1388 -0
  62. package/dist/chunks/WebApp-BVGZC2rj.js.map +1 -0
  63. package/dist/css/web-mojo.css +2 -2
  64. package/dist/docit.cjs.js +1 -1
  65. package/dist/docit.cjs.js.map +1 -1
  66. package/dist/docit.es.js +12 -10
  67. package/dist/docit.es.js.map +1 -1
  68. package/dist/index.cjs.js +1 -1
  69. package/dist/index.cjs.js.map +1 -1
  70. package/dist/index.es.js +120 -116
  71. package/dist/index.es.js.map +1 -1
  72. package/dist/lightbox.cjs.js +1 -1
  73. package/dist/lightbox.cjs.js.map +1 -1
  74. package/dist/lightbox.es.js +121 -121
  75. package/dist/lightbox.es.js.map +1 -1
  76. package/dist/map.cjs.js +2 -0
  77. package/dist/map.cjs.js.map +1 -0
  78. package/dist/map.es.js +188 -0
  79. package/dist/map.es.js.map +1 -0
  80. package/dist/timeline.cjs.js +2 -0
  81. package/dist/timeline.cjs.js.map +1 -0
  82. package/dist/timeline.es.js +225 -0
  83. package/dist/timeline.es.js.map +1 -0
  84. package/package.json +9 -1
  85. package/dist/chunks/ChatView-DlSxjxah.js.map +0 -1
  86. package/dist/chunks/ChatView-DnqrGXMC.js +0 -2
  87. package/dist/chunks/ChatView-DnqrGXMC.js.map +0 -1
  88. package/dist/chunks/ContextMenu-CE77rUmn.js +0 -2155
  89. package/dist/chunks/ContextMenu-CE77rUmn.js.map +0 -1
  90. package/dist/chunks/ContextMenu-KVxd0Kgd.js +0 -3
  91. package/dist/chunks/ContextMenu-KVxd0Kgd.js.map +0 -1
  92. package/dist/chunks/DataView-XJbTQ5q0.js +0 -2
  93. package/dist/chunks/Dialog-BinTQTfO.js +0 -2
  94. package/dist/chunks/FormView-CIriLDZY.js.map +0 -1
  95. package/dist/chunks/FormView-TPFsq8ZX.js +0 -3
  96. package/dist/chunks/MetricsMiniChartWidget-sONcM0pG.js +0 -2
  97. package/dist/chunks/PDFViewer-UBhinN8A.js +0 -2
  98. package/dist/chunks/Page-CnvHhwLZ.js +0 -2
  99. package/dist/chunks/TopNav-Dcmcic-i.js +0 -2
  100. package/dist/chunks/WebApp-El07OMHH.js.map +0 -1
  101. package/dist/chunks/WebApp-b9DQWz1d.js +0 -2
  102. package/dist/chunks/WebApp-b9DQWz1d.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"lightbox.es.js","sources":["../src/extensions/lightbox/ImageViewer.js","../src/extensions/lightbox/ImageCanvasView.js","../src/extensions/lightbox/ImageTransformView.js","../src/extensions/lightbox/ImageCropView.js","../src/extensions/lightbox/ImageFiltersView.js","../src/extensions/lightbox/ImageEditor.js","../src/extensions/lightbox/ImageUploadView.js"],"sourcesContent":["/**\n * ImageViewer - Canvas-based image viewing component with zoom, rotate, pan, and download capabilities\n * Built for the MOJO framework with full Bootstrap 5 integration\n */\n\nimport View from '@core/View.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageViewer extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-viewer ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Image properties\n this.imageUrl = options.imageUrl || options.src || '';\n this.alt = options.alt || 'Image';\n this.title = options.title || '';\n\n // Canvas properties\n this.canvas = null;\n this.context = null;\n this.image = null;\n\n // Transform state\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.minScale = 0.1;\n this.maxScale = 5;\n this.scaleStep = 0.1;\n\n // Interaction state\n this.isDragging = false;\n this.lastPointerX = 0;\n this.lastPointerY = 0;\n this.isLoaded = false;\n\n // Options\n this.showControls = options.showControls !== false;\n this.allowRotate = options.allowRotate !== false;\n this.allowZoom = options.allowZoom !== false;\n this.allowPan = options.allowPan !== false;\n this.allowDownload = options.allowDownload !== false;\n this.autoFit = options.autoFit !== false;\n\n // Elements\n this.containerElement = null;\n this.controlsElement = null;\n }\n\n async getTemplate() {\n return `\n <div class=\"image-viewer-container d-flex flex-column h-100\" data-container=\"imageContainer\">\n <div class=\"image-viewer-content flex-grow-1 position-relative\">\n <canvas class=\"image-viewer-canvas w-100 h-100\" data-container=\"canvas\"></canvas>\n <div class=\"image-viewer-overlay\">\n <div class=\"image-viewer-loading\">\n <div class=\"spinner-border text-light\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n\n {{#showControls}}\n <div class=\"image-viewer-controls position-absolute top-0 start-50 translate-middle-x mt-3\" data-container=\"controls\" style=\"z-index: 10;\">\n <div class=\"btn-group\" role=\"group\">\n {{#allowZoom}}\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"zoom-in\" title=\"Zoom In\">\n <i class=\"bi bi-zoom-in\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-dark 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-dark btn-sm\" data-action=\"zoom-fit\" title=\"Fit to Screen\">\n <i class=\"bi bi-arrows-fullscreen\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"zoom-actual\" title=\"Actual Size\">\n <i class=\"bi bi-1-square\"></i>\n </button>\n {{/allowZoom}}\n\n {{#allowRotate}}\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"rotate-left\" title=\"Rotate Left\">\n <i class=\"bi bi-arrow-counterclockwise\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"rotate-right\" title=\"Rotate Right\">\n <i class=\"bi bi-arrow-clockwise\"></i>\n </button>\n {{/allowRotate}}\n\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"reset\" title=\"Reset View\">\n <i class=\"bi bi-arrow-repeat\"></i>\n </button>\n\n {{#allowDownload}}\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"download\" title=\"Download Image\">\n <i class=\"bi bi-download\"></i>\n </button>\n {{/allowDownload}}\n </div>\n\n <div class=\"image-viewer-info\">\n <span class=\"zoom-level\">{{scale}}%</span>\n </div>\n </div>\n {{/showControls}}\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.canvas = this.element.querySelector('.image-viewer-canvas');\n this.context = this.canvas.getContext('2d');\n this.containerElement = this.element.querySelector('.image-viewer-content');\n this.controlsElement = this.element.querySelector('.image-viewer-controls');\n\n // Set up canvas\n this.setupCanvas();\n\n // Set up event listeners\n this.setupEventListeners();\n\n // Load image if provided\n if (this.imageUrl) {\n this.loadImage(this.imageUrl);\n }\n }\n\n setupCanvas() {\n if (!this.canvas || !this.containerElement) return;\n\n // Set up canvas properties first\n if (this.context) {\n this.context.imageSmoothingEnabled = true;\n this.context.imageSmoothingQuality = 'high';\n }\n\n // Delay canvas sizing to allow dialog to fully render\n setTimeout(() => {\n this.resizeCanvas();\n\n // If image was already loaded while we were waiting, render it\n if (this.isLoaded && this.image) {\n this.renderCanvas();\n }\n }, 2000); // 100ms should be enough for dialog animation\n }\n\n resizeCanvas() {\n if (!this.canvas) return;\n\n // Use reasonable viewport-based dimensions\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // Set canvas to reasonable size (80% of viewport with some padding)\n const canvasWidth = Math.floor(viewportWidth * 0.8);\n const canvasHeight = Math.floor(viewportHeight * 0.8);\n\n // Don't resize if dimensions haven't changed\n if (canvasWidth === this.canvasWidth && canvasHeight === this.canvasHeight) {\n return;\n }\n\n const dpr = window.devicePixelRatio || 1;\n\n // Store display dimensions\n this.canvasWidth = canvasWidth;\n this.canvasHeight = canvasHeight;\n\n // Set actual canvas buffer size (considering device pixel ratio)\n this.canvas.width = canvasWidth * dpr;\n this.canvas.height = canvasHeight * dpr;\n\n // Set display size via style\n this.canvas.style.width = canvasWidth + 'px';\n this.canvas.style.height = canvasHeight + 'px';\n\n // Reset transform and scale context for high DPI displays\n this.context.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n // If image is loaded, re-render it\n if (this.isLoaded && this.image) {\n this.renderCanvas();\n }\n }\n\n setupEventListeners() {\n if (!this.canvas) return;\n\n // Mouse events\n if (this.allowPan) {\n this.canvas.addEventListener('mousedown', (e) => this.handleMouseDown(e));\n document.addEventListener('mousemove', (e) => this.handleMouseMove(e));\n document.addEventListener('mouseup', (e) => this.handleMouseUp(e));\n }\n\n // Wheel events for zooming\n if (this.allowZoom) {\n this.canvas.addEventListener('wheel', (e) => this.handleWheel(e), { passive: false });\n }\n\n // Touch events\n this.canvas.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });\n this.canvas.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });\n this.canvas.addEventListener('touchend', (e) => this.handleTouchEnd(e));\n\n // Prevent context menu\n this.canvas.addEventListener('contextmenu', (e) => e.preventDefault());\n }\n\n // Action handlers\n async handleActionZoomIn() {\n this.zoomIn();\n }\n\n async handleActionZoomOut() {\n this.zoomOut();\n }\n\n async handleActionZoomFit() {\n this.fitToContainer();\n }\n\n async handleActionZoomActual() {\n this.setScale(1);\n this.renderCanvas();\n }\n\n async handleActionRotateLeft() {\n this.rotate(-90);\n }\n\n async handleActionRotateRight() {\n this.rotate(90);\n }\n\n async handleActionReset() {\n this.reset();\n }\n\n async handleActionDownload() {\n this.downloadImage();\n }\n\n // Image loading\n loadImage(imageUrl) {\n this.isLoaded = false;\n this.element.classList.remove('loaded');\n\n const img = new Image();\n img.crossOrigin = 'anonymous'; // For downloading images from other domains\n\n img.onload = () => {\n this.image = img;\n this.handleImageLoad();\n };\n\n img.onerror = () => {\n this.handleImageError();\n };\n\n img.src = imageUrl;\n }\n\n handleImageLoad() {\n this.isLoaded = true;\n this.element.classList.add('loaded');\n\n // Ensure canvas is properly sized (with delay if needed)\n const ensureCanvasReady = () => {\n // Check if canvas has dimensions\n if (!this.canvasWidth || !this.canvasHeight) {\n this.resizeCanvas();\n }\n\n // Initial setup\n if (this.autoFit) {\n this.fitToContainer();\n } else {\n this.smartFit();\n }\n\n this.renderCanvas();\n this.updateControls();\n };\n\n // If canvas dimensions are not set yet, wait for dialog to render\n if (!this.canvasWidth || !this.canvasHeight) {\n setTimeout(ensureCanvasReady, 2000); // Wait for dialog\n } else {\n requestAnimationFrame(ensureCanvasReady);\n }\n\n // Emit event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:loaded', {\n viewer: this,\n imageUrl: this.imageUrl,\n naturalWidth: this.image.naturalWidth,\n naturalHeight: this.image.naturalHeight\n });\n }\n }\n\n handleImageError() {\n console.error('Failed to load image:', this.imageUrl);\n\n // Emit error event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:error', {\n viewer: this,\n imageUrl: this.imageUrl,\n error: 'Failed to load image'\n });\n }\n }\n\n // Mouse interaction\n handleMouseDown(e) {\n if (!this.allowPan || e.button !== 0) return;\n\n e.preventDefault();\n this.isDragging = true;\n\n const rect = this.canvas.getBoundingClientRect();\n this.lastPointerX = e.clientX - rect.left;\n this.lastPointerY = e.clientY - rect.top;\n\n this.canvas.style.cursor = 'grabbing';\n }\n\n handleMouseMove(e) {\n if (!this.isDragging || !this.allowPan) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const currentX = e.clientX - rect.left;\n const currentY = e.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n\n handleMouseUp(e) {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n this.canvas.style.cursor = this.allowPan ? 'grab' : 'default';\n }\n\n handleWheel(e) {\n if (!this.allowZoom) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n const delta = e.deltaY > 0 ? -this.scaleStep * 0.5 : this.scaleStep * 0.5;\n this.zoomAtPoint(this.scale + delta, x, y);\n }\n\n // Touch events\n handleTouchStart(e) {\n if (e.touches.length === 1 && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n this.isDragging = true;\n this.lastPointerX = touch.clientX - rect.left;\n this.lastPointerY = touch.clientY - rect.top;\n }\n }\n\n handleTouchMove(e) {\n if (e.touches.length === 1 && this.isDragging && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n const currentX = touch.clientX - rect.left;\n const currentY = touch.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n }\n\n handleTouchEnd(e) {\n this.isDragging = false;\n }\n\n // Transform methods\n zoomIn() {\n this.setScale(this.scale + this.scaleStep);\n }\n\n zoomOut() {\n this.setScale(this.scale - this.scaleStep);\n }\n\n setScale(scale) {\n const oldScale = this.scale;\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, scale));\n this.renderCanvas();\n this.updateControls();\n\n // Emit scale change event\n const eventBus = this.getApp()?.events;\n if (eventBus && oldScale !== this.scale) {\n eventBus.emit('imageviewer:scale-changed', {\n viewer: this,\n oldScale,\n newScale: this.scale\n });\n }\n }\n\n zoomAtPoint(scale, x, y) {\n if (!this.image) return;\n\n const oldScale = this.scale;\n this.setScale(scale);\n\n if (oldScale !== this.scale) {\n const scaleDiff = this.scale / oldScale;\n const centerX = this.canvasWidth / 2;\n const centerY = this.canvasHeight / 2;\n\n // Adjust translation to zoom towards the point\n this.translateX = (this.translateX - (x - centerX)) * scaleDiff + (x - centerX);\n this.translateY = (this.translateY - (y - centerY)) * scaleDiff + (y - centerY);\n\n this.renderCanvas();\n }\n }\n\n pan(deltaX, deltaY) {\n this.translateX += deltaX;\n this.translateY += deltaY;\n this.renderCanvas();\n }\n\n rotate(degrees) {\n const oldRotation = this.rotation;\n this.rotation = (this.rotation + degrees) % 360;\n if (this.rotation < 0) this.rotation += 360;\n this.renderCanvas();\n\n // Emit rotation event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:rotated', {\n viewer: this,\n oldRotation,\n newRotation: this.rotation,\n degrees\n });\n }\n }\n\n center() {\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n }\n\n fitToContainer() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n const padding = 40;\n const availableWidth = this.canvasWidth - padding;\n const availableHeight = this.canvasHeight - padding;\n\n const scaleX = availableWidth / this.image.naturalWidth;\n const scaleY = availableHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n this.setScale(scale);\n this.renderCanvas();\n }\n\n smartFit() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n // If image is much larger than container, scale it down\n const padding = 80;\n const scaleX = (this.canvasWidth - padding) / this.image.naturalWidth;\n const scaleY = (this.canvasHeight - padding) / this.image.naturalHeight;\n const fitScale = Math.min(scaleX, scaleY);\n\n if (fitScale < 1) {\n this.setScale(fitScale);\n }\n\n this.renderCanvas();\n }\n\n reset() {\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n this.updateControls();\n }\n\n // Canvas rendering\n renderCanvas() {\n if (!this.context || !this.canvasWidth || !this.canvasHeight) return;\n\n // Clear canvas\n this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);\n\n if (!this.image || !this.isLoaded) return;\n\n // Save context state\n this.context.save();\n\n // Move to center and apply transforms\n this.context.translate(\n this.canvasWidth / 2 + this.translateX,\n this.canvasHeight / 2 + this.translateY\n );\n this.context.scale(this.scale, this.scale);\n this.context.rotate(this.rotation * Math.PI / 180);\n\n // Draw image centered on the transform point\n this.context.drawImage(\n this.image,\n -this.image.naturalWidth / 2,\n -this.image.naturalHeight / 2\n );\n\n // Restore context state\n this.context.restore();\n }\n\n // Download functionality\n downloadImage() {\n if (!this.canvas) return;\n\n try {\n // Create download link\n const link = document.createElement('a');\n link.download = this.getDownloadFilename();\n link.href = this.canvas.toDataURL('image/png');\n\n // Trigger download\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n\n // Emit download event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:downloaded', {\n viewer: this,\n filename: link.download\n });\n }\n } catch (error) {\n console.error('Failed to download image:', error);\n\n // Emit error event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:download-error', {\n viewer: this,\n error: error.message\n });\n }\n }\n }\n\n getDownloadFilename() {\n if (this.title) {\n return `${this.title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.png`;\n }\n\n // Try to extract filename from URL\n try {\n const url = new URL(this.imageUrl);\n const pathname = url.pathname;\n const filename = pathname.split('/').pop();\n if (filename && filename.includes('.')) {\n return filename.replace(/\\.[^.]+$/, '.png'); // Replace extension with .png\n }\n } catch (e) {\n // Invalid URL, continue with fallback\n }\n\n return 'image.png';\n }\n\n updateControls() {\n if (!this.controlsElement) return;\n\n const zoomLevel = this.controlsElement.querySelector('.zoom-level');\n if (zoomLevel) {\n zoomLevel.textContent = `${Math.round(this.scale * 100)}%`;\n }\n\n // Update button states\n const zoomInBtn = this.controlsElement.querySelector('[data-action=\"zoom-in\"]');\n const zoomOutBtn = this.controlsElement.querySelector('[data-action=\"zoom-out\"]');\n\n if (zoomInBtn) {\n zoomInBtn.disabled = this.scale >= this.maxScale;\n }\n if (zoomOutBtn) {\n zoomOutBtn.disabled = this.scale <= this.minScale;\n }\n }\n\n // Public API methods\n setImage(imageUrl, alt = '', title = '') {\n const oldImageUrl = this.imageUrl;\n this.imageUrl = imageUrl;\n this.alt = alt;\n this.title = title;\n\n this.reset();\n this.loadImage(imageUrl);\n\n // Emit image changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:image-changed', {\n viewer: this,\n oldImageUrl,\n newImageUrl: imageUrl\n });\n }\n }\n\n getCurrentState() {\n return {\n scale: this.scale,\n rotation: this.rotation,\n translateX: this.translateX,\n translateY: this.translateY\n };\n }\n\n setState(state) {\n if (state.scale !== undefined) this.scale = state.scale;\n if (state.rotation !== undefined) this.rotation = state.rotation;\n if (state.translateX !== undefined) this.translateX = state.translateX;\n if (state.translateY !== undefined) this.translateY = state.translateY;\n this.renderCanvas();\n this.updateControls();\n }\n\n async onBeforeDestroy() {\n // Clean up\n if (this.isDragging) {\n this.isDragging = false;\n }\n\n\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:destroyed', { viewer: this });\n }\n }\n\n // Static method to show image in a fullscreen dialog\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Image Viewer',\n alt = 'Image',\n size = 'fullscreen',\n showControls = true,\n allowRotate = true,\n allowZoom = true,\n allowPan = true,\n allowDownload = true,\n ...dialogOptions\n } = options;\n\n const viewer = new ImageViewer({\n imageUrl,\n alt,\n title,\n showControls,\n allowRotate,\n allowZoom,\n allowPan,\n allowDownload,\n autoFit: true\n });\n\n return Dialog.showDialog({\n title,\n body: viewer,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n buttons: [\n {\n text: 'Close',\n action: 'close',\n class: 'btn btn-secondary',\n dismiss: true\n }\n ],\n ...dialogOptions\n });\n }\n}\n\nwindow.ImageViewer = ImageViewer;\n","/**\n * ImageCanvasView - Base canvas view for image editing components\n * Provides shared canvas functionality for transform, crop, and filter views\n */\n\nimport View from '@core/View.js';\n\nexport default class ImageCanvasView extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-canvas-view ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Image properties\n this.imageUrl = options.imageUrl || options.src || '';\n this.alt = options.alt || 'Image';\n this.title = options.title || '';\n\n // Canvas properties\n this.canvas = null;\n this.context = null;\n this.image = null;\n this.canvasWidth = 0;\n this.canvasHeight = 0;\n this.maxCanvasHeightPercent = options.maxCanvasHeightPercent || 0.7;\n this.maxCanvasWidthPercent = options.maxCanvasWidthPercent || 0.8;\n // Canvas size presets with viewport awareness\n this.canvasSizes = {\n sm: { width: 400, height: 300 }, // Small - thumbnails, previews\n md: { width: 600, height: 450 }, // Medium - dialogs, cards\n lg: { width: 800, height: 600 }, // Large - main editing\n xl: { width: 1000, height: 750 }, // Extra Large - detailed work\n fullscreen: { width: 0, height: 0 }, // Special case - use viewport\n auto: { width: 0, height: 0 } // Auto-size based on image + viewport\n };\n\n // Default to auto-sizing with viewport constraints\n this.canvasSize = options.canvasSize || 'auto';\n\n // State\n this.isLoaded = false;\n this.isRendering = false;\n\n // Options\n this.autoFit = options.autoFit !== false;\n this.crossOrigin = options.crossOrigin || 'anonymous';\n }\n\n async getTemplate() {\n return `\n <div class=\"image-canvas-container d-flex flex-column h-100\">\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-canvas w-100 h-100\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.canvas = this.element.querySelector('canvas');\n this.context = this.canvas.getContext('2d');\n this.containerElement = this.element.querySelector('.image-canvas-content');\n this.loadingElement = this.element.querySelector('.image-canvas-loading');\n\n // Set up canvas\n this.setupCanvas();\n\n // Load image if provided\n if (this.imageUrl) {\n this.loadImage(this.imageUrl);\n }\n }\n\n setupCanvas() {\n if (!this.canvas || !this.containerElement) return;\n\n // Set canvas dimensions based on size preset\n this.setCanvasSize(this.canvasSize);\n\n // Simple resize listener (only for fullscreen mode)\n if (this.canvasSize === 'fullscreen') {\n this._resizeHandler = () => this.setCanvasSize('fullscreen');\n window.addEventListener('resize', this._resizeHandler);\n }\n\n // Set up canvas context\n this.context.imageSmoothingEnabled = true;\n this.context.imageSmoothingQuality = 'high';\n }\n\n setCanvasSize(size) {\n const preset = this.canvasSizes[size];\n if (!preset && size !== 'auto') return;\n\n let canvasWidth, canvasHeight;\n\n if (size === 'fullscreen') {\n // Use viewport dimensions for fullscreen\n canvasWidth = Math.min(1200, window.innerWidth * 0.9);\n canvasHeight = Math.min(900, window.innerHeight * 0.8);\n } else if (size === 'auto' || !preset) {\n // Auto-size based on image with viewport constraints\n if (this.image) {\n // Scale image to fit within viewport constraints\n const maxWidth = window.innerWidth * this.maxCanvasWidthPercent;\n const maxHeight = window.innerHeight * this.maxCanvasHeightPercent;\n\n const scaleX = maxWidth / this.image.naturalWidth;\n const scaleY = maxHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up\n\n canvasWidth = Math.floor(this.image.naturalWidth * scale);\n canvasHeight = Math.floor(this.image.naturalHeight * scale);\n\n // Ensure minimum usable size\n canvasWidth = Math.max(300, canvasWidth);\n canvasHeight = Math.max(200, canvasHeight);\n } else {\n // No image yet - use medium preset with viewport constraints\n canvasWidth = Math.min(600, window.innerWidth * this.maxCanvasWidthPercent);\n canvasHeight = Math.min(450, window.innerHeight * this.maxCanvasHeightPercent);\n }\n } else {\n // Check if preset fits within 80% viewport - if not, fall back to auto\n const maxWidth = window.innerWidth * this.maxCanvasWidthPercent;\n const maxHeight = window.innerHeight * this.maxCanvasHeightPercent;\n\n if (preset.width > maxWidth || preset.height > maxHeight) {\n // Preset is too big - fall back to auto sizing\n if (this.image) {\n const scaleX = maxWidth / this.image.naturalWidth;\n const scaleY = maxHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up\n\n canvasWidth = Math.floor(this.image.naturalWidth * scale);\n canvasHeight = Math.floor(this.image.naturalHeight * scale);\n\n // Ensure minimum usable size\n canvasWidth = Math.max(300, canvasWidth);\n canvasHeight = Math.max(200, canvasHeight);\n } else {\n // No image yet - use medium preset with viewport constraints\n canvasWidth = Math.min(600, maxWidth);\n canvasHeight = Math.min(450, maxHeight);\n }\n } else {\n // Preset fits - use it as-is\n canvasWidth = preset.width;\n canvasHeight = preset.height;\n }\n }\n\n // Final safety check (should not be needed now, but kept for robustness)\n canvasWidth = Math.min(canvasWidth, window.innerWidth * this.maxCanvasWidthPercent);\n canvasHeight = Math.min(canvasHeight, window.innerHeight * this.maxCanvasHeightPercent);\n\n // Don't resize if dimensions haven't changed significantly\n if (Math.abs(canvasWidth - this.canvasWidth) < 10 &&\n Math.abs(canvasHeight - this.canvasHeight) < 10) {\n return;\n }\n\n // Set dimensions and DPR handling\n const dpr = window.devicePixelRatio || 1;\n\n this.canvasWidth = canvasWidth;\n this.canvasHeight = canvasHeight;\n\n this.canvas.width = canvasWidth * dpr;\n this.canvas.height = canvasHeight * dpr;\n\n this.canvas.style.width = canvasWidth + 'px';\n this.canvas.style.height = canvasHeight + 'px';\n\n this.context.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (this.isLoaded) {\n this.renderCanvas();\n }\n }\n\n // Image loading\n loadImage(imageUrl) {\n if (!imageUrl) return;\n\n this.imageUrl = imageUrl;\n this.isLoaded = false;\n this.element.classList.remove('loaded');\n this.showLoading();\n\n const img = new Image();\n if (this.crossOrigin) {\n img.crossOrigin = this.crossOrigin;\n }\n\n img.onload = () => {\n this.image = img;\n this.handleImageLoad();\n };\n\n img.onerror = () => {\n this.handleImageError();\n };\n\n img.src = imageUrl;\n }\n\n handleImageLoad() {\n this.isLoaded = true;\n this.element.classList.add('loaded');\n this.hideLoading();\n\n // Initial setup\n // Resize canvas based on loaded image (especially for auto-sizing)\n if (this.canvasSize === 'auto') {\n this.setCanvasSize('auto');\n } else if (this.autoFit) {\n this.fitToContainer();\n }\n\n this.renderCanvas();\n\n // Emit load event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:loaded', {\n view: this,\n imageUrl: this.imageUrl,\n naturalWidth: this.image.naturalWidth,\n naturalHeight: this.image.naturalHeight\n });\n }\n }\n\n handleImageError() {\n console.error('Failed to load image:', this.imageUrl);\n this.hideLoading();\n\n // Emit error event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:error', {\n view: this,\n imageUrl: this.imageUrl,\n error: 'Failed to load image'\n });\n }\n }\n\n showLoading() {\n if (this.loadingElement) {\n this.loadingElement.style.display = 'block';\n }\n }\n\n hideLoading() {\n if (this.loadingElement) {\n this.loadingElement.style.display = 'none';\n }\n }\n\n // Base canvas rendering - to be extended by child classes\n renderCanvas() {\n if (!this.context || !this.canvasWidth || !this.canvasHeight || this.isRendering) return;\n\n this.isRendering = true;\n\n // Clear canvas\n this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);\n\n if (!this.image || !this.isLoaded) {\n this.isRendering = false;\n return;\n }\n\n // Save context state\n this.context.save();\n\n // Basic centered rendering - child classes can override this\n this.renderImage();\n\n // Restore context state\n this.context.restore();\n\n this.isRendering = false;\n }\n\n // Basic image rendering with smart scaling - can be overridden\n renderImage() {\n if (!this.image) return;\n\n // Calculate scale to fit image in canvas\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n // Calculate centered position\n const scaledWidth = this.image.naturalWidth * scale;\n const scaledHeight = this.image.naturalHeight * scale;\n const x = (this.canvasWidth - scaledWidth) / 2;\n const y = (this.canvasHeight - scaledHeight) / 2;\n\n // Draw scaled and centered image\n this.context.drawImage(this.image, x, y, scaledWidth, scaledHeight);\n }\n\n // Utility methods\n fitToContainer() {\n // Base implementation - child classes should override\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n const padding = 40;\n const availableWidth = this.canvasWidth - padding;\n const availableHeight = this.canvasHeight - padding;\n\n const scaleX = availableWidth / this.image.naturalWidth;\n const scaleY = availableHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n // Resize canvas to accommodate image\n if (this.canvasSize === 'auto') {\n this.setCanvasSize('auto');\n }\n\n // Child classes will implement actual scaling\n this.renderCanvas();\n }\n\n center() {\n // Base implementation - child classes should override\n this.renderCanvas();\n }\n\n reset() {\n // Base implementation - child classes should override\n this.renderCanvas();\n }\n\n // Export functionality\n exportImageData() {\n if (!this.canvas) return null;\n\n try {\n return this.canvas.toDataURL('image/png');\n } catch (error) {\n console.error('Failed to export image data:', error);\n return null;\n }\n }\n\n exportImageBlob(quality = 0.9) {\n if (!this.canvas) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n try {\n this.canvas.toBlob((blob) => {\n resolve(blob);\n }, 'image/png', quality);\n } catch (error) {\n console.error('Failed to export image blob:', error);\n resolve(null);\n }\n });\n }\n\n // Public API\n setImage(imageUrl, alt = '', title = '') {\n const oldImageUrl = this.imageUrl;\n this.alt = alt;\n this.title = title;\n\n this.loadImage(imageUrl);\n\n // Emit image changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:image-changed', {\n view: this,\n oldImageUrl,\n newImageUrl: imageUrl\n });\n }\n }\n\n getImageData() {\n return {\n imageUrl: this.imageUrl,\n alt: this.alt,\n title: this.title,\n naturalWidth: this.image?.naturalWidth || 0,\n naturalHeight: this.image?.naturalHeight || 0,\n isLoaded: this.isLoaded\n };\n }\n\n async onBeforeDestroy() {\n // Clean up\n this.isLoaded = false;\n this.isRendering = false;\n this.image = null;\n\n // Remove resize listener\n if (this._resizeHandler) {\n window.removeEventListener('resize', this._resizeHandler);\n }\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:destroyed', { view: this });\n }\n }\n}\n\nwindow.ImageCanvasView = ImageCanvasView;\n","/**\n * ImageTransformView - Canvas-based image viewer with zoom, pan, and rotation\n * Extends ImageCanvasView with transform capabilities\n */\n\nimport ImageCanvasView from './ImageCanvasView.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageTransformView extends ImageCanvasView {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-transform-view ${options.className || ''}`,\n });\n\n // Transform state\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.minScale = 0.1;\n this.maxScale = 5;\n this.scaleStep = 0.02;\n\n // Interaction state\n this.isDragging = false;\n this.lastPointerX = 0;\n this.lastPointerY = 0;\n\n // Options\n this.allowPan = options.allowPan !== false;\n this.allowZoom = options.allowZoom !== false;\n this.allowRotate = options.allowRotate !== false;\n this.allowKeyboard = options.allowKeyboard !== false;\n\n // Bind handlers for cleanup\n this._handleMouseMove = this.handleMouseMove.bind(this);\n this._handleMouseUp = this.handleMouseUp.bind(this);\n this._handleKeyboard = this.handleKeyboard.bind(this);\n\n if (!options.maxCanvasHeightPercent) {\n this.maxCanvasHeightPercent = 0.6;\n }\n }\n\n async getTemplate() {\n return `\n <div class=\"image-transform-container d-flex flex-column h-100\">\n <!-- Transform Toolbar -->\n <div class=\"image-transform-toolbar bg-light border-bottom p-2\">\n <div class=\"btn-toolbar justify-content-center\" role=\"toolbar\">\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Zoom controls\">\n <button type=\"button\" class=\"btn btn-outline-primary btn-sm\" data-action=\"zoom-in\" title=\"Zoom In\">\n <i class=\"bi bi-zoom-in\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-primary 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=\"fit-to-screen\" title=\"Fit to Screen\">\n <i class=\"bi bi-arrows-fullscreen\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"actual-size\" title=\"Actual Size\">\n <i class=\"bi bi-1-square\"></i>\n </button>\n </div>\n\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Rotate controls\">\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"rotate-left\" title=\"Rotate Left\">\n <i class=\"bi bi-arrow-counterclockwise\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"rotate-right\" title=\"Rotate Right\">\n <i class=\"bi bi-arrow-clockwise\"></i>\n </button>\n </div>\n\n <div class=\"btn-group\" role=\"group\" aria-label=\"Position controls\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"center-image\" title=\"Center Image\">\n <i class=\"bi bi-bullseye\"></i>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Canvas Area -->\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-canvas\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Set up interaction event listeners\n this.setupInteractionListeners();\n }\n\n setupInteractionListeners() {\n if (!this.canvas) return;\n\n // Mouse events\n if (this.allowPan) {\n this.canvas.addEventListener('mousedown', (e) => this.handleMouseDown(e));\n document.addEventListener('mousemove', this._handleMouseMove);\n document.addEventListener('mouseup', this._handleMouseUp);\n }\n\n // Wheel events for zooming\n if (this.allowZoom) {\n this.canvas.addEventListener('wheel', (e) => this.handleWheel(e), { passive: false });\n }\n\n // Touch events\n this.canvas.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });\n this.canvas.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });\n this.canvas.addEventListener('touchend', (e) => this.handleTouchEnd(e));\n\n // Keyboard shortcuts\n if (this.allowKeyboard) {\n document.addEventListener('keydown', this._handleKeyboard);\n }\n\n // Prevent context menu\n this.canvas.addEventListener('contextmenu', (e) => e.preventDefault());\n\n // Set cursor\n this.canvas.style.cursor = this.allowPan ? 'grab' : 'default';\n }\n\n // Override renderImage to apply transforms\n renderImage() {\n if (!this.image) return;\n\n // Apply transforms\n this.context.translate(\n this.canvasWidth / 2 + this.translateX,\n this.canvasHeight / 2 + this.translateY\n );\n this.context.scale(this.scale, this.scale);\n this.context.rotate(this.rotation * Math.PI / 180);\n\n // Draw image centered on the transform point\n this.context.drawImage(\n this.image,\n -this.image.naturalWidth / 2,\n -this.image.naturalHeight / 2\n );\n }\n\n // Mouse interaction\n handleMouseDown(e) {\n if (!this.allowPan || e.button !== 0) return;\n\n e.preventDefault();\n this.isDragging = true;\n\n const rect = this.canvas.getBoundingClientRect();\n this.lastPointerX = e.clientX - rect.left;\n this.lastPointerY = e.clientY - rect.top;\n\n this.canvas.style.cursor = 'grabbing';\n }\n\n handleMouseMove(e) {\n if (!this.isDragging || !this.allowPan) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const currentX = e.clientX - rect.left;\n const currentY = e.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n\n handleMouseUp(e) {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n this.canvas.style.cursor = this.allowPan ? 'grab' : 'default';\n }\n\n handleWheel(e) {\n if (!this.allowZoom) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n const delta = e.deltaY > 0 ? -this.scaleStep * 0.5 : this.scaleStep * 0.5;\n this.zoomAtPoint(this.scale + delta, x, y);\n }\n\n // Touch events\n handleTouchStart(e) {\n if (e.touches.length === 1 && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n this.isDragging = true;\n this.lastPointerX = touch.clientX - rect.left;\n this.lastPointerY = touch.clientY - rect.top;\n }\n }\n\n handleTouchMove(e) {\n if (e.touches.length === 1 && this.isDragging && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n const currentX = touch.clientX - rect.left;\n const currentY = touch.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n }\n\n handleTouchEnd(e) {\n this.isDragging = false;\n }\n\n // Keyboard shortcuts\n handleKeyboard(e) {\n if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;\n\n switch (e.key) {\n case '+':\n case '=':\n if (this.allowZoom) {\n e.preventDefault();\n this.zoomIn();\n }\n break;\n case '-':\n if (this.allowZoom) {\n e.preventDefault();\n this.zoomOut();\n }\n break;\n case '0':\n e.preventDefault();\n this.fitToContainer();\n break;\n case '1':\n e.preventDefault();\n this.actualSize();\n break;\n case 'r':\n case 'R':\n if (this.allowRotate) {\n e.preventDefault();\n this.rotateRight();\n }\n break;\n }\n }\n\n // Transform methods\n zoomIn() {\n this.setScale(this.scale + this.scaleStep);\n }\n\n zoomOut() {\n this.setScale(this.scale - this.scaleStep);\n }\n\n setScale(scale) {\n const oldScale = this.scale;\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, scale));\n\n if (oldScale !== this.scale) {\n this.renderCanvas();\n this.emitTransformEvent('scale-changed', { oldScale, newScale: this.scale });\n }\n }\n\n zoomAtPoint(scale, x, y) {\n if (!this.image) return;\n\n const oldScale = this.scale;\n this.setScale(scale);\n\n if (oldScale !== this.scale) {\n const scaleDiff = this.scale / oldScale;\n const centerX = this.canvasWidth / 2;\n const centerY = this.canvasHeight / 2;\n\n // Adjust translation to zoom towards the point\n this.translateX = (this.translateX - (x - centerX)) * scaleDiff + (x - centerX);\n this.translateY = (this.translateY - (y - centerY)) * scaleDiff + (y - centerY);\n\n this.renderCanvas();\n }\n }\n\n pan(deltaX, deltaY) {\n this.translateX += deltaX;\n this.translateY += deltaY;\n this.renderCanvas();\n this.emitTransformEvent('panned', { deltaX, deltaY });\n }\n\n rotate(degrees) {\n const oldRotation = this.rotation;\n this.rotation = (this.rotation + degrees) % 360;\n if (this.rotation < 0) this.rotation += 360;\n\n this.renderCanvas();\n this.emitTransformEvent('rotated', { oldRotation, newRotation: this.rotation, degrees });\n }\n\n rotateLeft() {\n this.rotate(-90);\n }\n\n rotateRight() {\n this.rotate(90);\n }\n\n center() {\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n this.emitTransformEvent('centered');\n }\n\n actualSize() {\n this.setScale(1);\n this.center();\n }\n\n // Override fitToContainer with actual scaling logic\n fitToContainer() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n const padding = 40;\n const availableWidth = this.canvasWidth - padding;\n const availableHeight = this.canvasHeight - padding;\n\n const scaleX = availableWidth / this.image.naturalWidth;\n const scaleY = availableHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n this.setScale(scale);\n this.center();\n }\n\n smartFit() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n // If image is much larger than canvas, scale it down\n const padding = 80;\n const scaleX = (this.canvasWidth - padding) / this.image.naturalWidth;\n const scaleY = (this.canvasHeight - padding) / this.image.naturalHeight;\n const fitScale = Math.min(scaleX, scaleY);\n\n if (fitScale < 1) {\n this.setScale(fitScale);\n }\n\n this.center();\n }\n\n // Override reset with transform-specific logic\n reset() {\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n this.emitTransformEvent('reset');\n }\n\n // Override handleImageLoad to apply initial transforms\n handleImageLoad() {\n super.handleImageLoad();\n\n if (this.autoFit) {\n this.fitToContainer();\n } else {\n this.smartFit();\n }\n }\n\n // State management\n getTransformState() {\n return {\n scale: this.scale,\n rotation: this.rotation,\n translateX: this.translateX,\n translateY: this.translateY\n };\n }\n\n setTransformState(state) {\n if (state.scale !== undefined) this.scale = state.scale;\n if (state.rotation !== undefined) this.rotation = state.rotation;\n if (state.translateX !== undefined) this.translateX = state.translateX;\n if (state.translateY !== undefined) this.translateY = state.translateY;\n this.renderCanvas();\n }\n\n // Event emission\n emitTransformEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imagetransform:${type}`, {\n view: this,\n transform: this.getTransformState(),\n ...data\n });\n }\n }\n\n // Action handlers for toolbar buttons\n async handleActionZoomIn() {\n this.zoomIn();\n }\n\n async handleActionZoomOut() {\n this.zoomOut();\n }\n\n async handleActionFitToScreen() {\n this.fitToContainer();\n }\n\n async handleActionActualSize() {\n this.actualSize();\n }\n\n async handleActionRotateLeft() {\n this.rotateLeft();\n }\n\n async handleActionRotateRight() {\n this.rotateRight();\n }\n\n async handleActionCenterImage() {\n this.center();\n }\n\n // Cleanup\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Clean up interaction listeners\n if (this.isDragging) {\n this.isDragging = false;\n }\n\n // Remove document listeners\n document.removeEventListener('mousemove', this._handleMouseMove);\n document.removeEventListener('mouseup', this._handleMouseUp);\n document.removeEventListener('keydown', this._handleKeyboard);\n\n this.emitTransformEvent('destroyed');\n }\n\n // Static method to show transform view in a dialog for standalone testing\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Transform Image',\n alt = 'Image',\n size = 'xl',\n allowPan = true,\n allowZoom = true,\n allowRotate = true,\n ...dialogOptions\n } = options;\n\n const transformView = new ImageTransformView({\n imageUrl,\n alt,\n title,\n allowPan,\n allowZoom,\n allowRotate\n });\n\n const dialog = new Dialog({\n title,\n body: transformView,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n noBodyPadding: true,\n maxCanvasHeightPercent: 0.5,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Apply Transform',\n action: 'apply-transform',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', view: transformView });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:apply-transform', async () => {\n const imageData = transformView.exportImageData();\n dialog.hide();\n resolve({\n action: 'transform',\n view: transformView,\n data: imageData,\n transformState: transformView.getTransformState()\n });\n });\n });\n }\n}\n\nwindow.ImageTransformView = Image\n","/**\n * ImageCropView - Canvas-based image cropping with interactive selection\n * Extends ImageCanvasView with crop functionality\n */\n\nimport ImageCanvasView from './ImageCanvasView.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageCropView extends ImageCanvasView {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-crop-view ${options.className || ''}`,\n });\n\n // Store original image URL for reset functionality\n this.originalImageUrl = options.imageUrl;\n\n // Crop state\n this.cropMode = false;\n this.cropBox = { x: 0, y: 0, width: 0, height: 0 };\n this.aspectRatio = options.aspectRatio || null; // null for free crop, number for fixed ratio\n this.minCropSize = options.minCropSize || 50;\n this.fixedCropSize = options.fixedCropSize || null; // { width: number, height: number } for fixed size crop\n this.cropAndScale = options.cropAndScale || null; // { width: number, height: number } for aspect ratio + scaling\n\n // Interaction state\n this.isDragging = false;\n this.isResizing = false;\n this.dragHandle = null;\n this.dragStartImageX = 0; // Drag start in image coordinates\n this.dragStartImageY = 0; // Drag start in image coordinates\n this.initialCropBox = null;\n this.newCropStart = null; // For creating new crop boxes\n\n // Handle positions for resizing\n this.handles = {\n 'nw': { cursor: 'nw-resize', x: 0, y: 0 },\n 'ne': { cursor: 'ne-resize', x: 1, y: 0 },\n 'sw': { cursor: 'sw-resize', x: 0, y: 1 },\n 'se': { cursor: 'se-resize', x: 1, y: 1 },\n 'n': { cursor: 'n-resize', x: 0.5, y: 0 },\n 's': { cursor: 's-resize', x: 0.5, y: 1 },\n 'w': { cursor: 'w-resize', x: 0, y: 0.5 },\n 'e': { cursor: 'e-resize', x: 1, y: 0.5 }\n };\n\n // Options\n this.handleSize = options.handleSize || 12;\n this.showGrid = options.showGrid !== false;\n this.showToolbar = options.showToolbar !== false; // Default to true - show toolbar\n this.autoFit = options.autoFit !== false; // Default to true - auto-fit large images\n\n // Image positioning on canvas\n this.imageOffsetX = 0;\n this.imageOffsetY = 0;\n\n // Bind handlers for cleanup\n this._handleMouseMove = this.handleMouseMove.bind(this);\n this._handleMouseUp = this.handleMouseUp.bind(this);\n if (!options.maxCanvasHeightPercent && this.showToolbar) {\n this.maxCanvasHeightPercent = 0.6;\n }\n }\n\n // Coordinate conversion helpers\n imageToCanvas(imageCoords) {\n if (!this.image) return imageCoords;\n\n // Calculate scale and positioning of image on canvas (same as renderImage)\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let imageScale;\n if (this.autoFit) {\n imageScale = Math.min(scaleX, scaleY, 1); // Scale down if needed, but don't scale up\n } else {\n imageScale = 1; // Always show at actual size (1:1)\n }\n\n const scaledImageWidth = this.image.naturalWidth * imageScale;\n const scaledImageHeight = this.image.naturalHeight * imageScale;\n const imageX = (this.canvasWidth - scaledImageWidth) / 2;\n const imageY = (this.canvasHeight - scaledImageHeight) / 2;\n\n return {\n x: imageCoords.x * imageScale + imageX,\n y: imageCoords.y * imageScale + imageY,\n width: imageCoords.width * imageScale,\n height: imageCoords.height * imageScale\n };\n }\n\n canvasToImage(canvasCoords) {\n if (!this.image) return canvasCoords;\n\n // Calculate scale and positioning of image on canvas (same as renderImage)\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let imageScale;\n if (this.autoFit) {\n imageScale = Math.min(scaleX, scaleY, 1); // Scale down if needed, but don't scale up\n } else {\n imageScale = 1; // Always show at actual size (1:1)\n }\n\n const scaledImageWidth = this.image.naturalWidth * imageScale;\n const scaledImageHeight = this.image.naturalHeight * imageScale;\n const imageX = (this.canvasWidth - scaledImageWidth) / 2;\n const imageY = (this.canvasHeight - scaledImageHeight) / 2;\n\n return {\n x: (canvasCoords.x - imageX) / imageScale,\n y: (canvasCoords.y - imageY) / imageScale,\n width: canvasCoords.width / imageScale,\n height: canvasCoords.height / imageScale\n };\n }\n\n pointCanvasToImage(canvasX, canvasY) {\n const result = this.canvasToImage({ x: canvasX, y: canvasY, width: 0, height: 0 });\n return { x: result.x, y: result.y };\n }\n\n async getTemplate() {\n return `\n <div class=\"image-crop-container d-flex flex-column h-100\">\n {{#showToolbar}}\n <!-- Crop Toolbar -->\n <div class=\"image-crop-toolbar bg-light border-bottom p-2\">\n <div class=\"btn-toolbar justify-content-center\" role=\"toolbar\">\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Aspect ratio\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" title=\"Aspect Ratio\">\n <i class=\"bi bi-aspect-ratio\"></i> Ratio\n </button>\n <ul class=\"dropdown-menu\">\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"free\">Free</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"1\">1:1 Square</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"1.333\">4:3</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"1.777\">16:9</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"0.75\">3:4 Portrait</a></li>\n </ul>\n </div>\n\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Fit mode\">\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"toggle-auto-fit\" title=\"Toggle Auto-fit\">\n <i class=\"bi bi-arrows-fullscreen\"></i> <span class=\"auto-fit-text\">Fit</span>\n </button>\n </div>\n\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Crop actions\">\n <button type=\"button\" class=\"btn btn-success btn-sm\" data-action=\"apply-crop\" title=\"Apply Crop\">\n <i class=\"bi bi-check\"></i> Apply\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"reset-crop\" title=\"Reset Crop\">\n <i class=\"bi bi-arrow-repeat\"></i> Reset\n </button>\n </div>\n </div>\n </div>\n {{/showToolbar}}\n\n <!-- Canvas Area -->\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-crop-canvas\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Set up crop interaction listeners\n this.setupCropListeners();\n\n // Initialize autoFit button state\n this.updateAutoFitButtonState();\n }\n\n\n\n updateAutoFitButtonState() {\n // Skip if toolbar is hidden\n if (!this.showToolbar) return;\n\n const button = this.element.querySelector('[data-action=\"toggle-auto-fit\"]');\n const textSpan = button?.querySelector('.auto-fit-text');\n\n if (button && textSpan) {\n if (this.autoFit) {\n button.classList.remove('btn-outline-warning');\n button.classList.add('btn-outline-info');\n button.title = 'Toggle Auto-fit (currently: fit to canvas)';\n textSpan.textContent = 'Fit';\n } else {\n button.classList.remove('btn-outline-info');\n button.classList.add('btn-outline-warning');\n button.title = 'Toggle Auto-fit (currently: actual size)';\n textSpan.textContent = '1:1';\n }\n }\n }\n\n handleImageLoad() {\n // Call parent method first\n super.handleImageLoad();\n\n // Calculate image offset for coordinate conversion\n this.updateImageOffset();\n\n // Start crop mode once image is loaded and canvas is ready\n // Use a small delay to ensure canvas dimensions are properly set\n setTimeout(() => {\n if (this.isLoaded && this.canvasWidth > 0 && this.canvasHeight > 0) {\n this.startCropMode();\n }\n }, 10);\n }\n\n updateImageOffset() {\n if (!this.image) return;\n\n // Calculate scale and positioning (same as renderImage)\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let scale;\n if (this.autoFit) {\n // Auto-fit: scale down if image is larger than canvas, but don't scale up\n scale = Math.min(scaleX, scaleY, 1);\n } else {\n // No auto-fit: always show at actual size (1:1)\n scale = 1;\n }\n\n const scaledWidth = this.image.naturalWidth * scale;\n const scaledHeight = this.image.naturalHeight * scale;\n\n // Store offset and scale for coordinate conversions\n this.imageOffsetX = (this.canvasWidth - scaledWidth) / 2;\n this.imageOffsetY = (this.canvasHeight - scaledHeight) / 2;\n this.imageScale = scale;\n\n console.log('Updated image offset:', this.imageOffsetX, this.imageOffsetY, 'scale:', this.imageScale, 'autoFit:', this.autoFit);\n }\n\n // Override setCanvasSize to update image offset when canvas is resized\n setCanvasSize(size) {\n super.setCanvasSize(size);\n\n // Update image offset after canvas resize\n if (this.image && this.isLoaded) {\n this.updateImageOffset();\n }\n }\n\n // Override renderImage to scale and center the image (consistent with coordinate conversion)\n renderImage() {\n if (!this.image) return;\n\n // Calculate scale to fit image in canvas\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let scale;\n if (this.autoFit) {\n // Auto-fit: scale down if image is larger than canvas, but don't scale up\n scale = Math.min(scaleX, scaleY, 1);\n } else {\n // No auto-fit: always show at actual size (1:1)\n scale = 1;\n }\n\n // Calculate centered position\n const scaledWidth = this.image.naturalWidth * scale;\n const scaledHeight = this.image.naturalHeight * scale;\n const x = (this.canvasWidth - scaledWidth) / 2;\n const y = (this.canvasHeight - scaledHeight) / 2;\n\n // Draw scaled and centered image\n this.context.drawImage(this.image, x, y, scaledWidth, scaledHeight);\n }\n\n setupCropListeners() {\n if (!this.canvas) return;\n\n // Mouse events for crop interaction\n this.canvas.addEventListener('mousedown', (e) => this.handleMouseDown(e));\n document.addEventListener('mousemove', this._handleMouseMove);\n document.addEventListener('mouseup', this._handleMouseUp);\n\n // Touch events\n this.canvas.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });\n this.canvas.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });\n this.canvas.addEventListener('touchend', (e) => this.handleTouchEnd(e));\n\n // Set default cursor\n this.canvas.style.cursor = 'crosshair';\n }\n\n // Override renderCanvas to include crop overlay\n renderCanvas() {\n super.renderCanvas();\n\n if (this.cropMode) {\n this.renderCropOverlay();\n }\n }\n\n renderCropOverlay() {\n if (!this.cropMode || !this.cropBox) return;\n\n // Convert crop box from image coordinates to canvas coordinates\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n // Save context state\n this.context.save();\n\n // Create crop hole - fill entire canvas then clear crop area\n this.context.globalAlpha = 0.5;\n this.context.fillStyle = '#000000';\n this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight);\n\n // Clear crop area (creates transparent hole)\n this.context.globalCompositeOperation = 'destination-out';\n this.context.fillRect(\n canvasBox.x,\n canvasBox.y,\n canvasBox.width,\n canvasBox.height\n );\n\n // Reset composite operation\n this.context.globalCompositeOperation = 'source-over';\n\n // Draw crop box border\n this.context.globalAlpha = 1.0;\n this.context.strokeStyle = 'rgba(255, 255, 255, 0.9)';\n this.context.lineWidth = 2;\n this.context.strokeRect(\n canvasBox.x,\n canvasBox.y,\n canvasBox.width,\n canvasBox.height\n );\n\n // Draw grid lines if enabled\n if (this.showGrid) {\n this.drawGrid();\n }\n\n // Draw resize handles\n this.drawHandles();\n\n // Restore context state\n this.context.restore();\n }\n\n // Override parent's exportImageBlob to export only the cropped area without overlay\n exportImageBlob(quality = 0.9) {\n if (!this.canvas || !this.image || !this.isLoaded || !this.cropMode) {\n // Fallback to parent implementation if crop mode not active\n return super.exportImageBlob(quality);\n }\n\n return new Promise((resolve) => {\n try {\n console.log('[ImageCropView] Exporting cropped image without overlay');\n console.log('[ImageCropView] Crop box:', this.cropBox);\n \n // Calculate the actual crop area in image coordinates\n const cropArea = {\n x: Math.max(0, Math.min(this.cropBox.x, this.image.naturalWidth)),\n y: Math.max(0, Math.min(this.cropBox.y, this.image.naturalHeight)),\n width: Math.min(this.cropBox.width, this.image.naturalWidth - this.cropBox.x),\n height: Math.min(this.cropBox.height, this.image.naturalHeight - this.cropBox.y)\n };\n\n console.log('[ImageCropView] Crop area in image coords:', cropArea);\n\n // Handle cropAndScale option\n let outputWidth = cropArea.width;\n let outputHeight = cropArea.height;\n \n if (this.cropAndScale) {\n outputWidth = this.cropAndScale.width;\n outputHeight = this.cropAndScale.height;\n console.log('[ImageCropView] Scaling to:', outputWidth, 'x', outputHeight);\n }\n\n // Create temporary canvas for cropped image\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = outputWidth;\n tempCanvas.height = outputHeight;\n const tempContext = tempCanvas.getContext('2d');\n\n // Draw the cropped portion of the image\n tempContext.drawImage(\n this.image,\n cropArea.x, cropArea.y, cropArea.width, cropArea.height, // Source rectangle\n 0, 0, outputWidth, outputHeight // Destination rectangle\n );\n\n // Export the cropped image\n tempCanvas.toBlob((blob) => {\n console.log('[ImageCropView] Successfully exported cropped image blob:', blob?.size, 'bytes');\n resolve(blob);\n }, 'image/png', quality);\n } catch (error) {\n console.error('Failed to export cropped image blob:', error);\n resolve(null);\n }\n });\n }\n\n drawGrid() {\n // Convert crop box to canvas coordinates for grid rendering\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n this.context.globalAlpha = 0.6;\n this.context.strokeStyle = 'rgba(255, 255, 255, 0.7)';\n this.context.lineWidth = 1;\n\n const thirdW = canvasBox.width / 3;\n const thirdH = canvasBox.height / 3;\n\n // Vertical lines\n for (let i = 1; i < 3; i++) {\n const x = canvasBox.x + (thirdW * i);\n this.context.beginPath();\n this.context.moveTo(x, canvasBox.y);\n this.context.lineTo(x, canvasBox.y + canvasBox.height);\n this.context.stroke();\n }\n\n // Horizontal lines\n for (let i = 1; i < 3; i++) {\n const y = canvasBox.y + (thirdH * i);\n this.context.beginPath();\n this.context.moveTo(canvasBox.x, y);\n this.context.lineTo(canvasBox.x + canvasBox.width, y);\n this.context.stroke();\n }\n }\n\n drawHandles() {\n // Don't draw resize handles for fixed crop size\n if (this.fixedCropSize) return;\n\n // Convert crop box to canvas coordinates for handle rendering\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n this.context.globalAlpha = 1.0;\n this.context.fillStyle = '#ffffff';\n this.context.strokeStyle = '#000000';\n this.context.lineWidth = 1;\n\n Object.keys(this.handles).forEach(handleName => {\n const handle = this.handles[handleName];\n const centerX = canvasBox.x + (canvasBox.width * handle.x);\n const centerY = canvasBox.y + (canvasBox.height * handle.y);\n const x = centerX - this.handleSize / 2;\n const y = centerY - this.handleSize / 2;\n\n // Draw handle\n this.context.fillRect(x, y, this.handleSize, this.handleSize);\n this.context.strokeRect(x, y, this.handleSize, this.handleSize);\n });\n }\n\n // Mouse interaction\n handleMouseDown(e) {\n if (!this.cropMode) return;\n\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n // Convert canvas coordinates to image coordinates for storage\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n this.dragStartImageX = imagePoint.x;\n this.dragStartImageY = imagePoint.y;\n this.initialCropBox = { ...this.cropBox };\n\n if (this.fixedCropSize) {\n // For fixed crop size, only allow moving the crop box\n if (this.isPointInCropBox(canvasX, canvasY)) {\n\n this.isDragging = true;\n this.canvas.style.cursor = 'move';\n }\n } else {\n // Check if clicking on a resize handle\n const handle = this.getHandleAt(canvasX, canvasY);\n\n if (handle) {\n\n this.isResizing = true;\n this.dragHandle = handle;\n this.canvas.style.cursor = this.handles[handle].cursor;\n } else if (this.isPointInCropBox(canvasX, canvasY)) {\n // Clicking inside crop box - start moving\n\n this.isDragging = true;\n this.canvas.style.cursor = 'move';\n } else {\n // Clicking outside - start new crop box\n\n this.startNewCrop(imagePoint.x, imagePoint.y);\n }\n }\n }\n\n handleMouseMove(e) {\n if (!this.cropMode) return;\n\n const rect = this.canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n if (this.isResizing && this.dragHandle) {\n this.resizeCropBox(canvasX, canvasY);\n } else if (this.isDragging) {\n this.moveCropBox(canvasX, canvasY);\n } else if (!this.isDragging && !this.isResizing) {\n // Update cursor based on what's under mouse\n this.updateCursor(canvasX, canvasY);\n }\n }\n\n handleMouseUp(e) {\n if (!this.cropMode) return;\n\n this.isDragging = false;\n this.isResizing = false;\n this.dragHandle = null;\n this.initialCropBox = null;\n this.newCropStart = null; // Clear new crop state\n\n const rect = this.canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n this.updateCursor(canvasX, canvasY);\n }\n\n // Touch events\n handleTouchStart(e) {\n if (!this.cropMode || e.touches.length !== 1) return;\n\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n const _x = touch.clientX - rect.left;\n const _y = touch.clientY - rect.top;\n\n // Convert touch to mouse event\n this.handleMouseDown({ clientX: touch.clientX, clientY: touch.clientY, preventDefault: () => {} });\n }\n\n handleTouchMove(_e) {\n if (!this.cropMode || _e.touches.length !== 1) return;\n\n _e.preventDefault();\n const touch = _e.touches[0];\n\n // Convert touch to mouse event\n this.handleMouseMove({ clientX: touch.clientX, clientY: touch.clientY });\n }\n\n handleTouchEnd(_e) {\n if (!this.cropMode) return;\n\n this.handleMouseUp({});\n }\n\n // Crop utility methods\n getHandleAt(canvasX, canvasY) {\n const hitAreaPadding = 4; // Extra pixels around handle for easier clicking\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n for (const [handleName, handle] of Object.entries(this.handles)) {\n // Calculate center position the same way as drawing\n const handleCenterX = canvasBox.x + (canvasBox.width * handle.x);\n const handleCenterY = canvasBox.y + (canvasBox.height * handle.y);\n\n // Create expanded hit area around the center\n const hitAreaSize = this.handleSize + hitAreaPadding;\n const handleX = handleCenterX - hitAreaSize / 2;\n const handleY = handleCenterY - hitAreaSize / 2;\n\n if (canvasX >= handleX && canvasX <= handleX + hitAreaSize &&\n canvasY >= handleY && canvasY <= handleY + hitAreaSize) {\n return handleName;\n }\n }\n return null;\n }\n\n isPointInCropBox(canvasX, canvasY) {\n // Convert canvas coordinates to image coordinates and check if point is in crop box\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n return imagePoint.x >= this.cropBox.x && imagePoint.x <= this.cropBox.x + this.cropBox.width &&\n imagePoint.y >= this.cropBox.y && imagePoint.y <= this.cropBox.y + this.cropBox.height;\n }\n\n updateCursor(canvasX, canvasY) {\n if (!this.cropMode) return;\n\n // Image is at (0,0) so canvas coordinates = image coordinates\n const imageX = canvasX;\n const imageY = canvasY;\n\n if (this.fixedCropSize) {\n // For fixed size crops, only show move cursor when over crop box\n if (this.isPointInCropBox(imageX, imageY)) {\n this.canvas.style.cursor = 'move';\n } else {\n this.canvas.style.cursor = 'default';\n }\n } else {\n const handle = this.getHandleAt(canvasX, canvasY);\n if (handle) {\n this.canvas.style.cursor = this.handles[handle].cursor;\n } else if (this.isPointInCropBox(imageX, imageY)) {\n this.canvas.style.cursor = 'move';\n } else {\n this.canvas.style.cursor = 'crosshair';\n }\n }\n }\n\n startNewCrop(x, y) {\n // Store the initial click point for proper rectangle creation\n this.newCropStart = { x: x, y: y };\n this.cropBox = {\n x: x,\n y: y,\n width: 0,\n height: 0\n };\n this.isResizing = true;\n this.dragHandle = 'se'; // Start with bottom-right handle\n }\n\n resizeCropBox(canvasX, canvasY) {\n if (!this.dragHandle) return;\n\n // Convert canvas coordinates to image coordinates\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n\n // Handle new crop creation differently\n if (this.newCropStart) {\n // Creating new crop box - calculate from start point to current mouse position\n const startX = this.newCropStart.x;\n const startY = this.newCropStart.y;\n\n this.cropBox = {\n x: Math.min(startX, imagePoint.x),\n y: Math.min(startY, imagePoint.y),\n width: Math.abs(imagePoint.x - startX),\n height: Math.abs(imagePoint.y - startY)\n };\n\n // Apply aspect ratio constraint if set\n if (this.aspectRatio) {\n this.constrainToAspectRatio(this.cropBox, 'se');\n }\n\n // Ensure minimum size\n if (this.cropBox.width < this.minCropSize) {\n this.cropBox.width = this.minCropSize;\n }\n if (this.cropBox.height < this.minCropSize) {\n this.cropBox.height = this.minCropSize;\n }\n\n this.constrainCropBox(this.cropBox);\n return;\n }\n\n // Normal handle resizing\n if (!this.initialCropBox) return;\n\n // Calculate deltas in image coordinates\n const deltaX = imagePoint.x - this.dragStartImageX;\n const deltaY = imagePoint.y - this.dragStartImageY;\n\n let newBox = { ...this.initialCropBox };\n\n // Apply resize based on handle\n switch (this.dragHandle) {\n case 'nw':\n newBox.x += deltaX;\n newBox.y += deltaY;\n newBox.width -= deltaX;\n newBox.height -= deltaY;\n break;\n case 'ne':\n newBox.y += deltaY;\n newBox.width += deltaX;\n newBox.height -= deltaY;\n break;\n case 'sw':\n newBox.x += deltaX;\n newBox.width -= deltaX;\n newBox.height += deltaY;\n break;\n case 'se':\n newBox.width += deltaX;\n newBox.height += deltaY;\n break;\n case 'n':\n newBox.y += deltaY;\n newBox.height -= deltaY;\n break;\n case 's':\n newBox.height += deltaY;\n break;\n case 'w':\n newBox.x += deltaX;\n newBox.width -= deltaX;\n break;\n case 'e':\n newBox.width += deltaX;\n break;\n }\n\n // Apply aspect ratio constraint if set\n if (this.aspectRatio) {\n this.constrainToAspectRatio(newBox, this.dragHandle);\n }\n\n this.constrainCropBox(newBox);\n\n this.cropBox = newBox;\n this.renderCanvas();\n }\n\n moveCropBox(canvasX, canvasY) {\n if (!this.initialCropBox) return;\n\n // Convert to image coordinates and calculate deltas\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n const deltaX = imagePoint.x - this.dragStartImageX;\n const deltaY = imagePoint.y - this.dragStartImageY;\n\n let newBox = {\n x: this.initialCropBox.x + deltaX,\n y: this.initialCropBox.y + deltaY,\n width: this.initialCropBox.width,\n height: this.initialCropBox.height\n };\n\n // Keep within image bounds\n if (this.image) {\n newBox.x = Math.max(0, Math.min(this.image.naturalWidth - newBox.width, newBox.x));\n newBox.y = Math.max(0, Math.min(this.image.naturalHeight - newBox.height, newBox.y));\n }\n\n this.cropBox = newBox;\n this.renderCanvas();\n }\n\n constrainToAspectRatio(box, handle) {\n // Use cropAndScale aspect ratio if set, otherwise use explicit aspectRatio\n let ratio = this.aspectRatio;\n if (this.cropAndScale) {\n ratio = this.cropAndScale.width / this.cropAndScale.height;\n }\n\n if (!ratio) return;\n\n // Store anchor points based on handle\n let anchorX, anchorY;\n\n if (['nw', 'ne', 'sw', 'se'].includes(handle)) {\n // Corner handles - determine which corner stays fixed\n switch (handle) {\n case 'nw':\n // Bottom-right corner stays fixed\n anchorX = box.x + box.width;\n anchorY = box.y + box.height;\n break;\n case 'ne':\n // Bottom-left corner stays fixed\n anchorX = box.x;\n anchorY = box.y + box.height;\n break;\n case 'sw':\n // Top-right corner stays fixed\n anchorX = box.x + box.width;\n anchorY = box.y;\n break;\n case 'se':\n // Top-left corner stays fixed\n anchorX = box.x;\n anchorY = box.y;\n break;\n }\n\n // Adjust dimensions to match aspect ratio\n if (box.width / box.height > ratio) {\n box.width = box.height * ratio;\n } else {\n box.height = box.width / ratio;\n }\n\n // Adjust position to keep anchor point fixed\n switch (handle) {\n case 'nw':\n box.x = anchorX - box.width;\n box.y = anchorY - box.height;\n break;\n case 'ne':\n box.x = anchorX;\n box.y = anchorY - box.height;\n break;\n case 'sw':\n box.x = anchorX - box.width;\n box.y = anchorY;\n break;\n case 'se':\n box.x = anchorX;\n box.y = anchorY;\n break;\n }\n } else if (['n', 's'].includes(handle)) {\n // Vertical handles - adjust width to match height, keep horizontal center\n const centerX = box.x + box.width / 2;\n box.width = box.height * ratio;\n box.x = centerX - box.width / 2;\n } else if (['w', 'e'].includes(handle)) {\n // Horizontal handles - adjust height to match width, keep vertical center\n const centerY = box.y + box.height / 2;\n box.height = box.width / ratio;\n box.y = centerY - box.height / 2;\n }\n }\n\n constrainCropBox(box) {\n // Ensure minimum size\n box.width = Math.max(this.minCropSize, box.width);\n box.height = Math.max(this.minCropSize, box.height);\n\n // Keep within image bounds\n if (this.image) {\n if (box.x < 0) {\n box.width += box.x;\n box.x = 0;\n }\n if (box.y < 0) {\n box.height += box.y;\n box.y = 0;\n }\n if (box.x + box.width > this.image.naturalWidth) {\n box.width = this.image.naturalWidth - box.x;\n }\n if (box.y + box.height > this.image.naturalHeight) {\n box.height = this.image.naturalHeight - box.y;\n }\n }\n\n // Ensure non-negative dimensions\n box.width = Math.max(0, box.width);\n box.height = Math.max(0, box.height);\n }\n\n // Public API\n startCropMode() {\n // Make this method idempotent - safe to call multiple times\n if (this.cropMode) {\n console.log('Crop mode already active, skipping initialization');\n return;\n }\n\n this.cropMode = true;\n this.initializeCropBox();\n\n console.log('Crop mode started - SE handle should be at buffer coords (100, 100)');\n\n this.renderCanvas();\n this.emitCropEvent('crop-started');\n }\n\n exitCropMode() {\n this.cropMode = false;\n this.isDragging = false;\n this.isResizing = false;\n this.dragHandle = null;\n this.canvas.style.cursor = 'default';\n this.renderCanvas();\n this.emitCropEvent('crop-exited');\n }\n\n initializeCropBox() {\n if (!this.canvasWidth || !this.canvasHeight || !this.image) return;\n\n // Create default crop box - check for fixed size first\n const imageWidth = this.image.naturalWidth;\n const imageHeight = this.image.naturalHeight;\n\n let cropWidth, cropHeight;\n\n if (this.fixedCropSize) {\n // Use fixed crop size\n cropWidth = this.fixedCropSize.width;\n cropHeight = this.fixedCropSize.height;\n } else {\n // Use 80% of image size as default\n cropWidth = Math.floor(imageWidth * 0.8);\n cropHeight = Math.floor(imageHeight * 0.8);\n\n // Apply aspect ratio constraint if set\n let aspectRatio = this.aspectRatio;\n\n // If cropAndScale is set, calculate aspect ratio from target dimensions\n if (this.cropAndScale) {\n aspectRatio = this.cropAndScale.width / this.cropAndScale.height;\n }\n this.aspectRatio = aspectRatio;\n\n if (aspectRatio) {\n if (cropWidth / cropHeight > aspectRatio) {\n cropWidth = cropHeight * aspectRatio;\n } else {\n cropHeight = cropWidth / aspectRatio;\n }\n }\n\n // Ensure minimum size\n cropWidth = Math.max(this.minCropSize || 50, cropWidth);\n cropHeight = Math.max(this.minCropSize || 50, cropHeight);\n }\n\n // Center the crop box in the image\n const x = Math.floor((imageWidth - cropWidth) / 2);\n const y = Math.floor((imageHeight - cropHeight) / 2);\n\n this.cropBox = {\n x: x, // relative to image, not canvas\n y: y, // relative to image, not canvas\n width: cropWidth,\n height: cropHeight\n };\n\n\n }\n\n setAspectRatio(ratio) {\n this.aspectRatio = ratio;\n if (this.cropMode) {\n this.initializeCropBox();\n this.renderCanvas();\n }\n this.emitCropEvent('aspect-ratio-changed', { aspectRatio: ratio });\n }\n\n getCropData() {\n if (!this.cropBox || !this.image) return null;\n\n // Since cropBox is now stored in image coordinates, no conversion needed\n return {\n x: Math.max(0, Math.min(this.cropBox.x, this.image.naturalWidth)),\n y: Math.max(0, Math.min(this.cropBox.y, this.image.naturalHeight)),\n width: Math.min(this.cropBox.width, this.image.naturalWidth - this.cropBox.x),\n height: Math.min(this.cropBox.height, this.image.naturalHeight - this.cropBox.y),\n originalWidth: this.image.naturalWidth,\n originalHeight: this.image.naturalHeight\n };\n }\n\n async applyCrop() {\n const cropData = this.getCropData();\n if (!cropData || !this.image) {\n return null;\n }\n\n // Create new canvas for cropped image\n const croppedCanvas = document.createElement('canvas');\n const croppedContext = croppedCanvas.getContext('2d');\n\n // Set canvas size based on cropAndScale or crop dimensions\n if (this.cropAndScale) {\n // Use cropAndScale target dimensions\n croppedCanvas.width = this.cropAndScale.width;\n croppedCanvas.height = this.cropAndScale.height;\n\n // Draw cropped portion scaled to fit target dimensions\n croppedContext.drawImage(\n this.image,\n cropData.x,\n cropData.y,\n cropData.width,\n cropData.height,\n 0,\n 0,\n this.cropAndScale.width,\n this.cropAndScale.height\n );\n } else {\n // Use actual crop dimensions (no scaling)\n croppedCanvas.width = cropData.width;\n croppedCanvas.height = cropData.height;\n\n // Draw cropped portion at original size\n croppedContext.drawImage(\n this.image,\n cropData.x,\n cropData.y,\n cropData.width,\n cropData.height,\n 0,\n 0,\n cropData.width,\n cropData.height\n );\n }\n\n const croppedImageData = croppedCanvas.toDataURL('image/png');\n\n return {\n canvas: croppedCanvas,\n imageData: croppedImageData,\n cropData: cropData\n };\n }\n\n // Event emission\n emitCropEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imagecrop:${type}`, {\n view: this,\n cropBox: this.cropBox,\n aspectRatio: this.aspectRatio,\n ...data\n });\n }\n }\n\n // Toolbar control methods\n showToolbarElement() {\n if (!this.showToolbar) {\n this.showToolbar = true;\n const toolbar = this.element.querySelector('.image-crop-toolbar');\n if (toolbar) {\n toolbar.style.display = 'block';\n }\n this.updateAutoFitButtonState();\n }\n }\n\n hideToolbarElement() {\n if (this.showToolbar) {\n this.showToolbar = false;\n const toolbar = this.element.querySelector('.image-crop-toolbar');\n if (toolbar) {\n toolbar.style.display = 'none';\n }\n }\n }\n\n toggleToolbarElement() {\n if (this.showToolbar) {\n this.hideToolbarElement();\n } else {\n this.showToolbarElement();\n }\n }\n\n // Cleanup\n // Action handlers for toolbar buttons\n async onPassThruActionSetAspectRatio(e, el) {\n const ratio = el.getAttribute('data-ratio');\n const aspectRatio = ratio === 'free' ? null : parseFloat(ratio);\n this.setAspectRatio(aspectRatio);\n }\n\n async handleActionApplyCrop() {\n if (this.cropMode) {\n const result = await this.applyCrop();\n if (result && result.imageData) {\n // Load the cropped image as the new image\n this.loadImage(result.imageData);\n\n // Exit crop mode since we've applied the crop\n this.exitCropMode();\n\n // Emit the crop applied event\n this.emitCropEvent('crop-applied', { result });\n }\n }\n }\n\n async handleActionToggleAutoFit() {\n // Skip if toolbar is hidden\n if (!this.showToolbar) return;\n\n this.autoFit = !this.autoFit;\n\n // Update button state\n this.updateAutoFitButtonState();\n\n // Re-render with new scaling\n this.updateImageOffset();\n this.renderCanvas();\n\n this.emitCropEvent('auto-fit-changed', { autoFit: this.autoFit });\n }\n\n async handleActionResetCrop() {\n // Exit crop mode first\n if (this.cropMode) {\n this.exitCropMode();\n }\n\n // Reload the original image\n if (this.originalImageUrl) {\n await this.loadImage(this.originalImageUrl);\n }\n\n // Enter crop mode and initialize crop box\n this.startCropMode();\n this.emitCropEvent('crop-reset');\n }\n\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Clean up crop state\n this.cropMode = false;\n this.isDragging = false;\n this.isResizing = false;\n\n // Remove document listeners\n document.removeEventListener('mousemove', this._handleMouseMove);\n document.removeEventListener('mouseup', this._handleMouseUp);\n\n this.emitCropEvent('destroyed');\n }\n\n // Static method to show crop view in a dialog for standalone testing\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Crop Image',\n alt = 'Image',\n size = 'xl',\n aspectRatio = null,\n minCropSize = 50,\n showGrid = true,\n showToolbar = false,\n autoFit = true,\n fixedCropSize = null,\n cropAndScale = null,\n canvasSize = size || 'auto',\n ...dialogOptions\n } = options;\n\n const cropView = new ImageCropView({\n imageUrl,\n alt,\n title,\n aspectRatio,\n minCropSize,\n canvasSize: canvasSize || size || 'md',\n fixedCropSize,\n cropAndScale,\n showGrid,\n showToolbar,\n autoFit\n });\n\n const dialog = new Dialog({\n title,\n body: cropView,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n noBodyPadding: true,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Apply Crop',\n action: 'apply-crop',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n dialog.show();\n\n // Wait for dialog to be fully rendered and canvas to be properly sized\n const initializeCrop = () => {\n // Re-setup canvas after dialog is rendered\n if (cropView.setupCanvas) {\n cropView.setupCanvas();\n }\n\n // Wait for image to load, then start crop mode\n if (cropView.isLoaded && cropView.canvasWidth > 0) {\n cropView.startCropMode();\n } else {\n const checkReady = setInterval(() => {\n if (cropView.isLoaded && cropView.canvasWidth > 0) {\n clearInterval(checkReady);\n cropView.startCropMode();\n }\n }, 100);\n\n // Clear interval after 5 seconds to prevent infinite loop\n setTimeout(() => clearInterval(checkReady), 5000);\n }\n };\n\n // Use the dialog's 'shown' event to ensure it's fully rendered\n dialog.on('shown', initializeCrop);\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', view: cropView });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:apply-crop', async () => {\n let result;\n\n if (cropView.cropMode && cropView.cropBox) {\n // Crop mode is active - apply the crop\n result = await cropView.applyCrop();\n } else {\n // No active crop box - return current canvas image as-is\n const currentImageData = cropView.canvas.toDataURL('image/png');\n result = {\n canvas: cropView.canvas,\n imageData: currentImageData,\n cropData: null // No crop was applied\n };\n }\n\n dialog.hide();\n resolve({\n action: 'crop',\n view: cropView,\n data: result?.imageData,\n cropData: result?.cropData\n });\n });\n });\n }\n}\n\n// Make it available globally for testing\nwindow.ImageCropView = ImageCropView;\n","/**\n * ImageFiltersView - Canvas-based image viewer with filter effects\n * Extends ImageCanvasView with brightness, contrast, saturation and other filters\n */\n\nimport ImageCanvasView from './ImageCanvasView.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageFiltersView extends ImageCanvasView {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-filters-view ${options.className || ''}`,\n });\n\n // Filter state\n this.filters = {\n brightness: 100,\n contrast: 100,\n saturation: 100,\n hue: 0,\n blur: 0,\n grayscale: 0,\n sepia: 0\n };\n\n // UI Options (default to true for better usability)\n this.showControls = options.showControls ?? true;\n this.allowReset = options.allowReset ?? true;\n this.showPresets = options.showPresets ?? true;\n this.showBasicControls = options.showBasicControls ?? true;\n this.showAdvancedControls = options.showAdvancedControls ?? true;\n this.controlsInDropdowns = options.controlsInDropdowns ?? true;\n\n // Preset effects using CSS filters only\n this.presetEffects = {\n none: { name: 'Original', filters: {} },\n blackWhite: { name: 'Black & White', filters: { grayscale: 100 } },\n sepia: { name: 'Sepia', filters: { sepia: 100 } },\n vintage: { name: 'Vintage', filters: { sepia: 60, contrast: 110, brightness: 110, saturation: 80 } },\n cool: { name: 'Cool Tones', filters: { hue: 200, saturation: 120, brightness: 95 } },\n warm: { name: 'Warm Tones', filters: { hue: 25, saturation: 110, brightness: 105 } },\n vibrant: { name: 'Vibrant', filters: { brightness: 105, contrast: 115, saturation: 140, hue: 5 } },\n dramatic: { name: 'Dramatic', filters: { brightness: 90, contrast: 150, saturation: 120 } },\n soft: { name: 'Soft', filters: { brightness: 110, contrast: 85, blur: 1 } }\n };\n\n this.currentPreset = 'none';\n }\n\n async getTemplate() {\n return `\n <div class=\"image-filters-container d-flex flex-column h-100\">\n {{#showControls}}\n <!-- Filter Toolbar -->\n <div class=\"image-filters-toolbar bg-light border-bottom p-2\">\n <div class=\"btn-toolbar justify-content-center flex-wrap\" role=\"toolbar\">\n\n {{#showPresets}}\n <!-- Preset Effects -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Preset effects\">\n <div class=\"dropdown\">\n <button type=\"button\" class=\"btn btn-outline-primary btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" aria-expanded=\"false\" title=\"Preset Effects\">\n <i class=\"bi bi-palette\"></i> Effects\n </button>\n <ul class=\"dropdown-menu\">\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"none\">Original</a></li>\n <li><hr class=\"dropdown-divider\"></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"blackWhite\">Black & White</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"sepia\">Sepia</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"vintage\">Vintage</a></li>\n <li><hr class=\"dropdown-divider\"></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"cool\">Cool Tones</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"warm\">Warm Tones</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"vibrant\">Vibrant</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"dramatic\">Dramatic</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"soft\">Soft</a></li>\n </ul>\n </div>\n </div>\n {{/showPresets}}\n\n {{#showBasicControls}}\n {{#controlsInDropdowns}}\n <!-- Basic Controls in Dropdown -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Basic controls\">\n <div class=\"dropdown\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" aria-expanded=\"false\" title=\"Basic Adjustments\">\n <i class=\"bi bi-sliders\"></i> Basic\n </button>\n <div class=\"dropdown-menu p-3\" style=\"min-width: 300px;\">\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Brightness</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.brightness}}\"\n data-change-action=\"filter-change\" data-filter=\"brightness\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"brightness\">{{filters.brightness}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Contrast</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.contrast}}\"\n data-change-action=\"filter-change\" data-filter=\"contrast\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"contrast\">{{filters.contrast}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"mb-0\">\n <label class=\"form-label small fw-bold\">Saturation</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.saturation}}\"\n data-change-action=\"filter-change\" data-filter=\"saturation\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"saturation\">{{filters.saturation}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n </div>\n </div>\n </div>\n {{/controlsInDropdowns}}\n {{/showBasicControls}}\n\n {{#showAdvancedControls}}\n {{#controlsInDropdowns}}\n <!-- Advanced Controls in Dropdown -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Advanced controls\">\n <div class=\"dropdown\">\n <button type=\"button\" class=\"btn btn-outline-warning btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" aria-expanded=\"false\" title=\"Advanced Adjustments\">\n <i class=\"bi bi-gear\"></i> Advanced\n </button>\n <div class=\"dropdown-menu p-3\" style=\"min-width: 300px;\">\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Hue</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"360\" value=\"{{filters.hue}}\"\n data-change-action=\"filter-change\" data-filter=\"hue\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0°</small>\n <small class=\"text-muted filter-value\" data-filter=\"hue\">{{filters.hue}}°</small>\n <small class=\"text-muted\">360°</small>\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Blur</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"10\" value=\"{{filters.blur}}\"\n data-change-action=\"filter-change\" data-filter=\"blur\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0px</small>\n <small class=\"text-muted filter-value\" data-filter=\"blur\">{{filters.blur}}px</small>\n <small class=\"text-muted\">10px</small>\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Grayscale</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.grayscale}}\"\n data-change-action=\"filter-change\" data-filter=\"grayscale\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"grayscale\">{{filters.grayscale}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n <div class=\"mb-0\">\n <label class=\"form-label small fw-bold\">Sepia</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.sepia}}\"\n data-change-action=\"filter-change\" data-filter=\"sepia\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"sepia\">{{filters.sepia}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n </div>\n </div>\n </div>\n {{/controlsInDropdowns}}\n {{/showAdvancedControls}}\n\n {{#allowReset}}\n <!-- Reset & Preview Controls -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Reset controls\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"reset-filters\" title=\"Reset All Filters\">\n <i class=\"bi bi-arrow-repeat\"></i> Reset\n </button>\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"preview-original\" title=\"Preview Original\"\n onmousedown=\"this.dataset.previewing='true'\"\n onmouseup=\"this.dataset.previewing='false'\"\n onmouseleave=\"this.dataset.previewing='false'\">\n <i class=\"bi bi-eye\"></i> Original\n </button>\n </div>\n {{/allowReset}}\n\n </div>\n </div>\n {{/showControls}}\n\n <!-- Canvas Area -->\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-filters-canvas\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n\n {{#showControls}}\n {{^controlsInDropdowns}}\n <!-- Expanded Controls Panel (when not in dropdowns) -->\n <div class=\"image-filters-controls bg-light border-top p-3\" data-container=\"controls\" style=\"max-height: 300px; overflow-y: auto;\">\n <div class=\"row g-3\">\n {{#showBasicControls}}\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Brightness</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.brightness}}\"\n data-change-action=\"filter-change\" data-filter=\"brightness\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"brightness\">{{filters.brightness}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Contrast</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.contrast}}\"\n data-change-action=\"filter-change\" data-filter=\"contrast\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"contrast\">{{filters.contrast}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Saturation</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.saturation}}\"\n data-change-action=\"filter-change\" data-filter=\"saturation\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"saturation\">{{filters.saturation}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n {{/showBasicControls}}\n\n {{#showAdvancedControls}}\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Hue</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"360\" value=\"{{filters.hue}}\"\n data-change-action=\"filter-change\" data-filter=\"hue\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0°</small>\n <small class=\"text-muted filter-value\" data-filter=\"hue\">{{filters.hue}}°</small>\n <small class=\"text-muted\">360°</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Blur</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"10\" value=\"{{filters.blur}}\"\n data-change-action=\"filter-change\" data-filter=\"blur\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0px</small>\n <small class=\"text-muted filter-value\" data-filter=\"blur\">{{filters.blur}}px</small>\n <small class=\"text-muted\">10px</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Grayscale</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.grayscale}}\"\n data-change-action=\"filter-change\" data-filter=\"grayscale\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"grayscale\">{{filters.grayscale}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Sepia</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.sepia}}\"\n data-change-action=\"filter-change\" data-filter=\"sepia\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"sepia\">{{filters.sepia}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n {{/showAdvancedControls}}\n </div>\n </div>\n {{/controlsInDropdowns}}\n {{/showControls}}\n </div>\n `;\n }\n\n\n\n\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Cache control elements\n this.controlsElement = this.element.querySelector('.image-filters-controls');\n }\n\n // Override canvas sizing for container-aware dimensions\n setupCanvas() {\n if (!this.canvas || !this.containerElement) return;\n\n // Use container-aware sizing for dialogs and embedded contexts\n this.setCanvasSize(this.canvasSize);\n\n // Simple resize listener (only for fullscreen mode or container changes)\n if (this.canvasSize === 'fullscreen' || this.canvasSize === 'auto') {\n this._resizeHandler = () => this.setCanvasSize(this.canvasSize);\n window.addEventListener('resize', this._resizeHandler);\n }\n\n // Set up canvas context\n this.context.imageSmoothingEnabled = true;\n this.context.imageSmoothingQuality = 'high';\n }\n\n // Override setCanvasSize to be more container-aware for dialogs\n setCanvasSize(size) {\n if (!this.canvas || !this.containerElement) return;\n\n // For 'auto' sizing, be more aware of the actual container\n if (size === 'auto') {\n const container = this.containerElement;\n let availableWidth = container.clientWidth - 40;\n let availableHeight = container.clientHeight - 40;\n\n // If container doesn't have explicit dimensions, walk up DOM\n if (availableWidth <= 40 || availableHeight <= 40) {\n let parent = container.parentElement;\n while (parent && (parent.clientWidth <= 40 || parent.clientHeight <= 40)) {\n parent = parent.parentElement;\n\n // Stop at common container types\n if (parent && (\n parent.classList.contains('modal-body') ||\n parent.classList.contains('card-body') ||\n parent.classList.contains('dialog-body') ||\n parent.tagName === 'MAIN' ||\n parent.tagName === 'BODY'\n )) {\n break;\n }\n }\n\n if (parent) {\n availableWidth = parent.clientWidth - 80;\n availableHeight = parent.clientHeight - 80;\n }\n }\n\n // If we have valid container dimensions, use them\n if (availableWidth > 100 && availableHeight > 100) {\n let canvasWidth, canvasHeight;\n\n if (this.image) {\n const imageAspect = this.image.naturalWidth / this.image.naturalHeight;\n const availableAspect = availableWidth / availableHeight;\n\n if (imageAspect > availableAspect) {\n canvasWidth = availableWidth;\n canvasHeight = availableWidth / imageAspect;\n } else {\n canvasHeight = availableHeight;\n canvasWidth = availableHeight * imageAspect;\n }\n\n // Ensure minimum size\n canvasWidth = Math.max(300, Math.floor(canvasWidth));\n canvasHeight = Math.max(200, Math.floor(canvasHeight));\n } else {\n // No image yet - use available space with reasonable limits\n canvasWidth = Math.min(600, Math.max(300, availableWidth));\n canvasHeight = Math.min(450, Math.max(200, availableHeight));\n }\n\n // Apply the calculated size\n this.applyCanvasSize(canvasWidth, canvasHeight);\n return;\n }\n }\n\n // Fallback to parent class sizing for all other cases\n super.setCanvasSize(size);\n }\n\n // Helper method to apply calculated canvas size\n applyCanvasSize(canvasWidth, canvasHeight) {\n // Don't resize if dimensions haven't changed significantly\n if (Math.abs(canvasWidth - this.canvasWidth) < 10 &&\n Math.abs(canvasHeight - this.canvasHeight) < 10) {\n return;\n }\n\n const dpr = window.devicePixelRatio || 1;\n\n this.canvasWidth = canvasWidth;\n this.canvasHeight = canvasHeight;\n\n this.canvas.width = canvasWidth * dpr;\n this.canvas.height = canvasHeight * dpr;\n\n this.canvas.style.width = canvasWidth + 'px';\n this.canvas.style.height = canvasHeight + 'px';\n\n this.context.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (this.isLoaded) {\n this.renderCanvas();\n }\n }\n\n // Override image loading to re-render with current filters\n async loadImage(imageUrl) {\n await super.loadImage(imageUrl);\n\n // Re-render with current filters\n this.renderCanvas();\n }\n\n // Override renderImage to apply filters consistently\n renderImage() {\n if (!this.image) return;\n\n // Apply CSS filters to context (includes both slider values and preset effects)\n this.context.filter = this.getFilterString();\n\n // Calculate scale to fit image in canvas (consistent with new sizing system)\n const imageScale = Math.min(\n this.canvasWidth / this.image.naturalWidth,\n this.canvasHeight / this.image.naturalHeight\n );\n\n const scaledWidth = this.image.naturalWidth * imageScale;\n const scaledHeight = this.image.naturalHeight * imageScale;\n const x = (this.canvasWidth - scaledWidth) / 2;\n const y = (this.canvasHeight - scaledHeight) / 2;\n\n // Draw scaled and centered image\n this.context.drawImage(this.image, x, y, scaledWidth, scaledHeight);\n\n // Reset filter\n this.context.filter = 'none';\n }\n\n // Get combined filter values from both sliders and current preset\n getCombinedFilters() {\n const combined = { ...this.filters };\n\n // Apply preset filters on top of slider values\n if (this.currentPreset !== 'none' && this.presetEffects[this.currentPreset]) {\n const presetFilters = this.presetEffects[this.currentPreset].filters;\n if (presetFilters) {\n Object.assign(combined, presetFilters);\n }\n }\n\n return combined;\n }\n\n getFilterString() {\n const filters = this.getCombinedFilters();\n\n if (!this.hasFilters() && this.currentPreset === 'none') return 'none';\n\n return [\n `brightness(${filters.brightness}%)`,\n `contrast(${filters.contrast}%)`,\n `saturate(${filters.saturation}%)`,\n `hue-rotate(${filters.hue}deg)`,\n `blur(${filters.blur}px)`,\n `grayscale(${filters.grayscale}%)`,\n `sepia(${filters.sepia}%)`\n ].join(' ');\n }\n\n hasFilters() {\n return this.filters.brightness !== 100 ||\n this.filters.contrast !== 100 ||\n this.filters.saturation !== 100 ||\n this.filters.hue !== 0 ||\n this.filters.blur !== 0 ||\n this.filters.grayscale !== 0 ||\n this.filters.sepia !== 0;\n }\n\n // Action Handlers\n async onPassThruActionResetFilters() {\n this.resetFilters();\n }\n\n async onPassThruActionApplyPreset(e, el) {\n e.preventDefault();\n const presetName = el.getAttribute('data-preset');\n if (presetName && this.presetEffects[presetName]) {\n this.applyPreset(presetName);\n }\n }\n\n async onPassThruActionPreviewOriginal(e, el) {\n const isPreviewing = el.dataset.previewing === 'true';\n\n if (isPreviewing) {\n // Show original (no filters)\n this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);\n this.context.filter = 'none';\n const x = (this.canvasWidth - this.image.naturalWidth) / 2;\n const y = (this.canvasHeight - this.image.naturalHeight) / 2;\n this.context.drawImage(this.image, x, y);\n } else {\n // Show with filters\n this.renderCanvas();\n }\n }\n\n // Change Handler for filter sliders\n async onChangeFilterChange(e, el) {\n const filterName = el.getAttribute('data-filter');\n const value = parseFloat(el.value);\n\n this.updateFilter(filterName, value);\n }\n\n // Filter methods\n updateFilter(name, value) {\n if (!(name in this.filters)) return;\n\n const oldValue = this.filters[name];\n this.filters[name] = value;\n\n // Update the display value\n this.updateFilterDisplay(name, value);\n\n // Re-render with new filters\n this.renderCanvas();\n\n // Emit filter change event\n this.emitFilterEvent('filter-changed', {\n filter: name,\n oldValue,\n newValue: value,\n allFilters: { ...this.filters }\n });\n }\n\n updateFilterDisplay(name, value) {\n const valueElement = this.element.querySelector(`[data-filter=\"${name}\"].filter-value`);\n if (valueElement) {\n const unit = name === 'hue' ? '°' : name === 'blur' ? 'px' : '%';\n valueElement.textContent = `${value}${unit}`;\n }\n }\n\n resetFilters() {\n const oldFilters = { ...this.filters };\n const oldPreset = this.currentPreset;\n\n this.filters = {\n brightness: 100,\n contrast: 100,\n saturation: 100,\n hue: 0,\n blur: 0,\n grayscale: 0,\n sepia: 0\n };\n\n // Reset preset\n this.currentPreset = 'none';\n\n // Update all input values and displays\n this.updateAllFilterInputs();\n\n // Re-render\n this.renderCanvas();\n\n // Emit reset event\n this.emitFilterEvent('filters-reset', {\n oldFilters,\n newFilters: { ...this.filters },\n oldPreset,\n newPreset: this.currentPreset\n });\n }\n\n updateAllFilterInputs() {\n Object.keys(this.filters).forEach(filterName => {\n const input = this.element.querySelector(`[data-filter=\"${filterName}\"][type=\"range\"]`);\n if (input) {\n input.value = this.filters[filterName];\n this.updateFilterDisplay(filterName, this.filters[filterName]);\n }\n });\n }\n\n // Enhanced preset system\n applyPreset(presetName) {\n if (!this.presetEffects[presetName]) return;\n\n const preset = this.presetEffects[presetName];\n\n // Set current preset\n this.currentPreset = presetName;\n\n // Set current preset (CSS filters will handle the effect)\n this.currentPreset = presetName;\n\n // Re-render\n this.renderCanvas();\n\n this.emitFilterEvent('preset-applied', { preset: presetName, filters: { ...this.filters } });\n }\n\n\n\n // State management\n getFilterState() {\n return { ...this.filters };\n }\n\n setFilterState(filters) {\n this.filters = { ...this.filters, ...filters };\n this.updateAllFilterInputs();\n this.renderCanvas();\n this.emitFilterEvent('filters-set', { filters: { ...this.filters } });\n }\n\n // Export with filters applied\n exportFilteredImageData() {\n if (!this.canvas) return null;\n\n // The canvas already has filters applied from renderImage\n return this.exportImageData();\n }\n\n async exportFilteredImageBlob(quality = 0.9) {\n if (!this.canvas) return null;\n\n // The canvas already has filters applied from renderImage\n return this.exportImageBlob(quality);\n }\n\n // Create a new canvas with original image + filters applied\n createFilteredCanvas() {\n if (!this.image) return null;\n\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('2d');\n\n canvas.width = this.image.naturalWidth;\n canvas.height = this.image.naturalHeight;\n\n // Apply filters and draw original image\n context.filter = this.getFilterString();\n context.drawImage(this.image, 0, 0);\n context.filter = 'none';\n\n return canvas;\n }\n\n // Event emission\n emitFilterEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imagefilters:${type}`, {\n view: this,\n hasFilters: this.hasFilters(),\n filterString: this.getFilterString(),\n ...data\n });\n }\n }\n\n // Override handleImageLoad to emit filter-ready event\n handleImageLoad() {\n super.handleImageLoad();\n this.emitFilterEvent('ready', { filters: { ...this.filters } });\n }\n\n // Cleanup\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove resize listener\n if (this._resizeHandler) {\n window.removeEventListener('resize', this._resizeHandler);\n }\n\n this.emitFilterEvent('destroyed');\n }\n\n // Static method to show filters view in a dialog for standalone testing\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Apply Filters',\n alt = 'Image',\n size = 'xl',\n showControls = true,\n allowReset = true,\n showPresets = true,\n showBasicControls = true,\n showAdvancedControls = true,\n controlsInDropdowns = true,\n canvasSize = 'auto',\n autoFit = true,\n crossOrigin = 'anonymous',\n ...dialogOptions\n } = options;\n\n const filtersView = new ImageFiltersView({\n imageUrl,\n alt,\n title,\n canvasSize,\n autoFit,\n crossOrigin,\n showControls,\n allowReset,\n showPresets,\n showBasicControls,\n showAdvancedControls,\n controlsInDropdowns\n });\n\n const dialog = new Dialog({\n title,\n body: filtersView,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n noBodyPadding: true,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Apply Filters',\n action: 'apply-filters',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', view: filtersView });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:apply-filters', async () => {\n const imageData = filtersView.exportFilteredImageData();\n dialog.hide();\n resolve({\n action: 'filters',\n view: filtersView,\n data: imageData,\n filterState: filtersView.getFilterState()\n });\n });\n });\n }\n}\n\nwindow.ImageFiltersView = ImageFiltersView;\n","/**\n * ImageEditor - Modular parent container for image editing functionality\n * Manages child views: ImageTransformView, ImageCropView, ImageFiltersView\n */\n\nimport View from '@core/View.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\nimport ImageTransformView from './ImageTransformView.js';\nimport ImageCropView from './ImageCropView.js';\nimport ImageFiltersView from './ImageFiltersView.js';\n\nexport default class ImageEditor extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-editor ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Image properties\n this.imageUrl = options.imageUrl || options.src || '';\n this.alt = options.alt || 'Image';\n this.title = options.title || '';\n \n // Current edited image data (preserved across mode switches)\n this.currentImageData = null;\n\n // Current editing mode\n this.currentMode = options.startMode || 'transform'; // 'transform', 'crop', 'filters'\n\n // History for undo/redo\n this.history = [];\n this.historyIndex = -1;\n this.maxHistory = options.maxHistory || 20;\n\n // Template properties (set directly on instance for Mustache)\n this.showToolbar = options.showToolbar !== false;\n this.allowTransform = options.allowTransform !== false;\n this.allowCrop = options.allowCrop !== false;\n this.allowFilters = options.allowFilters !== false;\n this.allowExport = options.allowExport !== false;\n this.allowHistory = options.allowHistory !== false;\n\n // Current active view (created on demand)\n this.currentView = null;\n\n // State\n this.isInitialized = false;\n }\n\n async getTemplate() {\n return `\n <div class=\"image-editor-container d-flex flex-column h-100\">\n {{#showToolbar}}\n <!-- Toolbar -->\n <div class=\"image-editor-toolbar bg-light border-bottom p-3\" data-container=\"toolbar\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <!-- Mode Buttons -->\n <div class=\"btn-group\" role=\"group\" aria-label=\"Editing modes\">\n {{#allowTransform}}\n <button type=\"button\" class=\"btn btn-outline-primary mode-btn\"\n data-action=\"switch-mode\" data-mode=\"transform\"\n title=\"Transform: Zoom, Pan, Rotate\">\n <i class=\"bi bi-arrows-move\"></i> Transform\n </button>\n {{/allowTransform}}\n\n {{#allowCrop}}\n <button type=\"button\" class=\"btn btn-outline-primary mode-btn\"\n data-action=\"switch-mode\" data-mode=\"crop\"\n title=\"Crop: Select and crop image\">\n <i class=\"bi bi-crop\"></i> Crop\n </button>\n {{/allowCrop}}\n\n {{#allowFilters}}\n <button type=\"button\" class=\"btn btn-outline-primary mode-btn\"\n data-action=\"switch-mode\" data-mode=\"filters\"\n title=\"Filters: Brightness, Contrast, Effects\">\n <i class=\"bi bi-palette\"></i> Filters\n </button>\n {{/allowFilters}}\n </div>\n\n <!-- Action Buttons -->\n <div class=\"btn-group\" role=\"group\" aria-label=\"Actions\">\n {{#allowHistory}}\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\"\n data-action=\"undo\" title=\"Undo\" disabled>\n <i class=\"bi bi-arrow-counterclockwise\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\"\n data-action=\"redo\" title=\"Redo\" disabled>\n <i class=\"bi bi-arrow-clockwise\"></i>\n </button>\n {{/allowHistory}}\n\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\"\n data-action=\"reset\" title=\"Reset All Changes\">\n <i class=\"bi bi-arrow-repeat\"></i>\n </button>\n\n {{#allowExport}}\n <button type=\"button\" class=\"btn btn-success btn-sm\"\n data-action=\"export\" title=\"Export Image\">\n <i class=\"bi bi-download\"></i> Export\n </button>\n {{/allowExport}}\n </div>\n </div>\n\n\n </div>\n {{/showToolbar}}\n\n <!-- Main editing area where child views will be mounted -->\n <div class=\"image-editor-workspace flex-grow-1 position-relative\" data-container=\"image-workspace\">\n <!-- Child views will be added here dynamically -->\n </div>\n\n <!-- Status bar -->\n <div class=\"image-editor-status bg-light border-top p-2\" data-container=\"status\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <small class=\"text-muted\">\n Mode: <span class=\"current-mode fw-bold\">Transform</span>\n </small>\n <small class=\"text-muted\">\n <span class=\"image-info\">Ready</span>\n </small>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.toolbarElement = this.element.querySelector('.image-editor-toolbar');\n this.workspaceElement = this.element.querySelector('.image-editor-workspace');\n this.statusElement = this.element.querySelector('.image-editor-status');\n\n\n // Set up event listeners for child views\n this.setupChildViewEvents();\n\n // Set initial mode\n await this.switchMode(this.currentMode, true);\n\n // Initialize history\n this.saveState();\n\n this.isInitialized = true;\n }\n\n createChildView(mode) {\n // Use the edited image data if available, otherwise use original\n const imageToUse = this.currentImageData || this.imageUrl;\n console.log('[ImageEditor] Creating', mode, 'view with:', \n this.currentImageData ? 'preserved canvas data' : 'original image');\n \n const childOptions = {\n parent: this,\n containerId: \"image-workspace\",\n imageUrl: imageToUse,\n alt: this.alt,\n title: this.title\n };\n\n switch (mode) {\n case 'transform':\n if (!this.allowTransform) return null;\n return new ImageTransformView({\n ...childOptions,\n allowPan: true,\n allowZoom: true,\n allowRotate: true\n });\n case 'crop':\n if (!this.allowCrop) return null;\n return new ImageCropView({\n ...childOptions,\n showGrid: true,\n minCropSize: 50\n });\n case 'filters':\n if (!this.allowFilters) return null;\n return new ImageFiltersView({\n ...childOptions,\n showControls: true,\n allowReset: true\n });\n default:\n return null;\n }\n }\n\n setupChildViewEvents() {\n const eventBus = this.getApp()?.events;\n if (!eventBus) return;\n\n // Listen to child view events for history tracking\n eventBus.on('imagetransform:scale-changed', () => this.saveState());\n eventBus.on('imagetransform:rotated', () => this.saveState());\n eventBus.on('imagetransform:reset', () => this.saveState());\n\n // Crop applied permanently changes the image, so capture it\n eventBus.on('imagecrop:crop-applied', (data) => {\n // Store the cropped image as the current edited state\n const imageData = this.getCurrentImageData();\n if (imageData) {\n console.log('[ImageEditor] Crop applied - updating preserved canvas data');\n this.currentImageData = imageData;\n }\n this.saveState();\n \n // Provide user feedback\n this.updateStatus('Crop applied successfully');\n \n // Update the history buttons since we saved state\n this.updateHistoryButtons();\n });\n\n eventBus.on('imagefilters:filter-changed', () => {\n this.saveState();\n this.updateStatus('Filter applied');\n });\n \n eventBus.on('imagefilters:filters-reset', () => {\n this.saveState();\n this.updateStatus('Filters reset');\n });\n }\n\n // Action handlers\n async handleActionSwitchMode(e, el) {\n const mode = el.getAttribute('data-mode');\n await this.switchMode(mode);\n }\n\n\n\n async handleActionUndo() {\n this.undo();\n }\n\n async handleActionRedo() {\n this.redo();\n }\n\n async handleActionReset() {\n await this.resetAll();\n }\n\n async handleActionExport() {\n const result = await this.exportImage();\n if (result) {\n this.updateStatus('Image exported successfully');\n }\n }\n\n // Mode management\n async switchMode(mode, force=false) {\n if (mode === this.currentMode && !force) return;\n\n // Capture current canvas state before destroying view\n if (this.currentView && !force) {\n // Get the current edited image data using the consistent method\n const imageData = this.getCurrentImageData();\n \n // Store it for the next view\n if (imageData) {\n console.log('[ImageEditor] Preserving canvas state from', this.currentMode, 'mode');\n this.currentImageData = imageData;\n } else {\n console.log('[ImageEditor] No canvas data to preserve from', this.currentMode, 'mode');\n }\n } else if (force) {\n console.log('[ImageEditor] Force mode switch - not preserving canvas state');\n }\n\n // Destroy current view if it exists\n if (this.currentView) {\n await this.currentView.destroy();\n this.currentView = null;\n }\n\n\n\n // Update button states\n const modeButtons = this.element.querySelectorAll('.mode-btn');\n modeButtons.forEach(btn => {\n btn.classList.remove('active');\n if (btn.getAttribute('data-mode') === mode) {\n btn.classList.add('active');\n }\n });\n\n // Create and render new view\n this.currentMode = mode;\n this.currentView = this.createChildView(mode);\n\n if (this.currentView) {\n await this.currentView.render();\n\n // Mode-specific initialization\n if (mode === 'crop' && this.currentView.startCropMode) {\n this.currentView.startCropMode();\n this.updateStatus('Click and drag to select crop area');\n } else if (mode === 'transform') {\n this.updateStatus('Use controls to transform the image');\n } else if (mode === 'filters') {\n this.updateStatus('Adjust filters to enhance the image');\n }\n }\n\n // Update status\n this.updateCurrentModeDisplay();\n\n // Emit mode change event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageeditor:mode-changed', {\n editor: this,\n mode: mode,\n currentView: this.currentView\n });\n }\n }\n\n updateCurrentModeDisplay() {\n const modeDisplay = this.element.querySelector('.current-mode');\n if (modeDisplay) {\n modeDisplay.textContent = this.currentMode.charAt(0).toUpperCase() + this.currentMode.slice(1);\n }\n }\n\n updateStatus(message) {\n const infoDisplay = this.element.querySelector('.image-info');\n if (infoDisplay) {\n infoDisplay.textContent = message;\n }\n }\n\n // History management\n saveState() {\n if (!this.isInitialized) return;\n\n const state = {\n mode: this.currentMode,\n transform: this.currentView?.getTransformState?.(),\n filters: this.currentView?.getFilterState?.(),\n imageData: this.currentImageData,\n timestamp: Date.now()\n };\n\n // Remove any states after current index (when undoing then making new changes)\n this.history = this.history.slice(0, this.historyIndex + 1);\n\n // Add new state\n this.history.push(state);\n this.historyIndex = this.history.length - 1;\n\n // Keep within max history limit\n if (this.history.length > this.maxHistory) {\n this.history.shift();\n this.historyIndex--;\n }\n\n this.updateHistoryButtons();\n }\n\n undo() {\n if (this.historyIndex > 0) {\n this.historyIndex--;\n this.restoreState(this.history[this.historyIndex]);\n }\n }\n\n redo() {\n if (this.historyIndex < this.history.length - 1) {\n this.historyIndex++;\n this.restoreState(this.history[this.historyIndex]);\n }\n }\n\n async restoreState(state) {\n // Restore the image data if it exists\n if (state.imageData) {\n console.log('[ImageEditor] Restoring preserved canvas data from history');\n this.currentImageData = state.imageData;\n }\n \n // Switch to the mode from the state \n await this.switchMode(state.mode, true); // Force to use the restored image data\n\n // Restore state for current view\n if (this.currentView) {\n if (state.transform && this.currentView.setTransformState) {\n this.currentView.setTransformState(state.transform);\n }\n if (state.filters && this.currentView.setFilterState) {\n this.currentView.setFilterState(state.filters);\n }\n }\n\n this.updateHistoryButtons();\n this.updateStatus(`Restored to ${state.mode} mode`);\n }\n\n updateHistoryButtons() {\n const undoBtn = this.element.querySelector('[data-action=\"undo\"]');\n const redoBtn = this.element.querySelector('[data-action=\"redo\"]');\n\n if (undoBtn) undoBtn.disabled = this.historyIndex <= 0;\n if (redoBtn) redoBtn.disabled = this.historyIndex >= this.history.length - 1;\n }\n\n async resetAll() {\n // Clear the edited image data to reset to original\n console.log('[ImageEditor] Resetting - clearing preserved canvas data');\n this.currentImageData = null;\n \n // Reset current view\n if (this.currentView && this.currentView.reset) {\n this.currentView.reset();\n }\n\n // Switch back to transform mode with force flag to use original image\n await this.switchMode('transform', true);\n\n // Clear history and save new state\n this.history = [];\n this.historyIndex = -1;\n this.saveState();\n\n this.updateStatus('All changes reset');\n }\n\n // Export functionality\n async exportImage() {\n if (!this.currentView) return null;\n\n try {\n let imageData = null;\n\n // Get the processed image from the current view\n imageData = this.getCurrentImageData();\n\n if (imageData) {\n // Trigger download\n const link = document.createElement('a');\n link.download = this.getExportFilename();\n link.href = imageData;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n\n // Emit export event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageeditor:exported', {\n editor: this,\n imageData: imageData,\n filename: link.download\n });\n }\n\n return { imageData, filename: link.download };\n }\n } catch (error) {\n console.error('Export failed:', error);\n this.updateStatus('Export failed');\n }\n\n return null;\n }\n\n getExportFilename() {\n const timestamp = new Date().toISOString().slice(0, 19).replace(/[:\\-]/g, '');\n return `edited-image-${timestamp}.png`;\n }\n\n // Public API\n async setImage(imageUrl, alt = '', title = '') {\n console.log('[ImageEditor] Setting new image - clearing preserved canvas data');\n this.imageUrl = imageUrl;\n this.alt = alt;\n this.title = title;\n \n // Clear any edited data\n this.currentImageData = null;\n\n // Update current view\n if (this.currentView && this.currentView.setImage) {\n this.currentView.setImage(imageUrl, alt, title);\n }\n\n // Reset state\n await this.resetAll();\n }\n\n getCurrentImageData() {\n if (!this.currentView) return null;\n \n // Get the current edited image data based on view type\n let imageData = null;\n if (this.currentView.exportImageData) {\n imageData = this.currentView.exportImageData();\n } else if (this.currentView.exportFilteredImageData) {\n imageData = this.currentView.exportFilteredImageData();\n }\n \n return imageData || null;\n }\n\n // Cleanup\n async onBeforeDestroy() {\n // Clean up current view\n if (this.currentView) {\n await this.currentView.destroy();\n this.currentView = null;\n }\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageeditor:destroyed', { editor: this });\n }\n }\n\n // Static method to show editor in a fullscreen dialog\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Image Editor',\n alt = 'Image',\n size = 'fullscreen',\n showToolbar = true,\n allowTransform = true,\n allowCrop = true,\n allowFilters = true,\n allowExport = true,\n ...dialogOptions\n } = options;\n\n const editor = new ImageEditor({\n imageUrl,\n alt,\n title,\n showToolbar,\n allowTransform,\n allowCrop,\n allowFilters,\n allowExport\n });\n\n const dialog = new Dialog({\n title,\n body: editor,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Export & Close',\n action: 'export-close',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n window.lastDialog = dialog;\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', editor });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:export-close', async () => {\n const result = await editor.exportImage();\n dialog.hide();\n resolve({\n action: 'export',\n editor,\n data: result?.imageData,\n filename: result?.filename\n });\n });\n });\n }\n}\n\nwindow.ImageEditor = ImageEditor;\n","/**\n * ImageUploadView - Drag and drop image upload component\n * Provides file selection, preview, and upload functionality\n */\n\nimport View from '@core/View.js';\n\nexport default class ImageUploadView extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-upload-view ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Upload options\n this.autoUpload = options.autoUpload || false;\n this.acceptedTypes = options.acceptedTypes || ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];\n this.maxFileSize = options.maxFileSize || 10 * 1024 * 1024; // 10MB default\n this.uploadUrl = options.uploadUrl || null;\n this.onUpload = options.onUpload || null; // Callback function\n\n // State\n this.selectedFile = null;\n this.isUploading = false;\n this.previewUrl = null;\n\n // Bind handlers for cleanup\n this._handleDragOver = this.handleDragOver.bind(this);\n this._handleDragLeave = this.handleDragLeave.bind(this);\n this._handleDrop = this.handleDrop.bind(this);\n this._handleFileSelect = this.handleFileSelect.bind(this);\n this._preventDefaults = this.preventDefaults.bind(this);\n }\n\n async getTemplate() {\n return `\n <div class=\"image-upload-container\">\n <!-- Drop Zone -->\n <div class=\"upload-drop-zone border-2 border-dashed rounded p-4 text-center position-relative\" \n style=\"border-color: #dee2e6; min-height: 200px; transition: all 0.2s ease;\">\n \n <!-- Default State -->\n <div class=\"upload-prompt\">\n <i class=\"bi bi-cloud-upload text-muted\" style=\"font-size: 3rem;\"></i>\n <h5 class=\"mt-3 text-muted\">Drop your image here</h5>\n <p class=\"text-muted mb-3\">or</p>\n <button type=\"button\" class=\"btn btn-outline-primary\" data-action=\"select-file\">\n <i class=\"bi bi-folder2-open\"></i> Choose File\n </button>\n <input type=\"file\" class=\"upload-file-input d-none\" accept=\"image/*\" multiple=\"false\">\n <div class=\"mt-3\">\n <small class=\"text-muted\">Supported: JPEG, PNG, GIF, WebP (max ${Math.round(this.maxFileSize / 1024 / 1024)}MB)</small>\n </div>\n </div>\n \n <!-- Preview State -->\n <div class=\"upload-preview d-none\">\n <div class=\"preview-image-container mb-3\">\n <img class=\"preview-image img-fluid rounded shadow-sm\" style=\"max-height: 300px; max-width: 100%;\">\n </div>\n <div class=\"preview-info\">\n <div class=\"file-name fw-bold mb-2 text-truncate\"></div>\n <div class=\"file-details text-muted small mb-3\"></div>\n <div class=\"upload-actions\">\n {{#autoUpload}}\n <button type=\"button\" class=\"btn btn-outline-secondary\" data-action=\"clear\">\n <i class=\"bi bi-x\"></i> Clear\n </button>\n {{/autoUpload}}\n {{^autoUpload}}\n <button type=\"button\" class=\"btn btn-success me-2\" data-action=\"upload\">\n <i class=\"bi bi-cloud-arrow-up\"></i> Upload\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary\" data-action=\"clear\">\n <i class=\"bi bi-x\"></i> Clear\n </button>\n {{/autoUpload}}\n </div>\n </div>\n </div>\n \n <!-- Loading State -->\n <div class=\"upload-loading d-none\">\n <div class=\"spinner-border text-primary mb-3\" role=\"status\">\n <span class=\"visually-hidden\">Uploading...</span>\n </div>\n <div class=\"upload-progress\">\n <div class=\"progress mb-2\" style=\"height: 8px;\">\n <div class=\"progress-bar progress-bar-striped progress-bar-animated\" \n role=\"progressbar\" style=\"width: 0%\"></div>\n </div>\n <small class=\"text-muted upload-status\">Uploading...</small>\n </div>\n </div>\n </div>\n \n <!-- Upload Result -->\n <div class=\"upload-result mt-3 d-none\">\n <div class=\"alert\" role=\"alert\"></div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.dropZone = this.element.querySelector('.upload-drop-zone');\n this.fileInput = this.element.querySelector('.upload-file-input');\n this.promptElement = this.element.querySelector('.upload-prompt');\n this.previewElement = this.element.querySelector('.upload-preview');\n this.loadingElement = this.element.querySelector('.upload-loading');\n this.resultElement = this.element.querySelector('.upload-result');\n this.previewImage = this.element.querySelector('.preview-image');\n this.fileName = this.element.querySelector('.file-name');\n this.fileDetails = this.element.querySelector('.file-details');\n this.progressBar = this.element.querySelector('.progress-bar');\n this.uploadStatus = this.element.querySelector('.upload-status');\n\n // Set up event listeners\n this.setupEventListeners();\n }\n\n setupEventListeners() {\n // Drag and drop events\n this.dropZone.addEventListener('dragenter', this._preventDefaults);\n this.dropZone.addEventListener('dragover', this._handleDragOver);\n this.dropZone.addEventListener('dragleave', this._handleDragLeave);\n this.dropZone.addEventListener('drop', this._handleDrop);\n\n // File input change\n this.fileInput.addEventListener('change', this._handleFileSelect);\n\n // Prevent default drag behaviors on document\n ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {\n document.addEventListener(eventName, this._preventDefaults);\n });\n }\n\n preventDefaults(e) {\n e.preventDefault();\n e.stopPropagation();\n }\n\n handleDragOver(e) {\n this.preventDefaults(e);\n this.dropZone.classList.add('border-primary', 'bg-light');\n this.dropZone.style.borderColor = '#0d6efd';\n }\n\n handleDragLeave(e) {\n this.preventDefaults(e);\n \n // Only remove styles if we're actually leaving the drop zone\n if (!this.dropZone.contains(e.relatedTarget)) {\n this.dropZone.classList.remove('border-primary', 'bg-light');\n this.dropZone.style.borderColor = '#dee2e6';\n }\n }\n\n async handleDrop(e) {\n this.preventDefaults(e);\n \n this.dropZone.classList.remove('border-primary', 'bg-light');\n this.dropZone.style.borderColor = '#dee2e6';\n \n const files = Array.from(e.dataTransfer.files);\n if (files.length > 0) {\n await this.processFile(files[0]);\n }\n }\n\n async handleFileSelect(e) {\n const files = Array.from(e.target.files);\n if (files.length > 0) {\n await this.processFile(files[0]);\n }\n }\n\n async processFile(file) {\n // Validate file\n const validation = this.validateFile(file);\n if (!validation.valid) {\n this.showError(validation.error);\n return;\n }\n\n this.selectedFile = file;\n \n // Show preview\n await this.showPreview(file);\n \n // Auto upload if enabled\n if (this.autoUpload) {\n setTimeout(() => this.uploadFile(), 100); // Small delay to show preview\n }\n }\n\n validateFile(file) {\n // Check file type\n if (!this.acceptedTypes.includes(file.type)) {\n return {\n valid: false,\n error: `File type \"${file.type}\" is not supported. Please use: ${this.acceptedTypes.map(t => t.split('/')[1].toUpperCase()).join(', ')}`\n };\n }\n\n // Check file size\n if (file.size > this.maxFileSize) {\n return {\n valid: false,\n error: `File size (${this.formatFileSize(file.size)}) exceeds maximum allowed size (${this.formatFileSize(this.maxFileSize)})`\n };\n }\n\n return { valid: true };\n }\n\n async showPreview(file) {\n // Create preview URL\n if (this.previewUrl) {\n URL.revokeObjectURL(this.previewUrl);\n }\n this.previewUrl = URL.createObjectURL(file);\n\n // Update preview elements\n this.previewImage.src = this.previewUrl;\n this.fileName.textContent = file.name;\n this.fileDetails.textContent = `${this.formatFileSize(file.size)} • ${file.type.split('/')[1].toUpperCase()}`;\n\n // Show preview, hide prompt\n this.promptElement.classList.add('d-none');\n this.previewElement.classList.remove('d-none');\n\n // Clear any previous results\n this.hideResult();\n\n // Emit preview event\n this.emitUploadEvent('preview', { file, previewUrl: this.previewUrl });\n }\n\n async uploadFile() {\n if (!this.selectedFile || this.isUploading) return;\n\n this.isUploading = true;\n this.showLoading();\n\n try {\n let result;\n\n if (this.onUpload && typeof this.onUpload === 'function') {\n // Use callback function\n result = await this.onUpload(this.selectedFile, this.updateProgress.bind(this));\n } else if (this.uploadUrl) {\n // Use built-in upload to URL\n result = await this.uploadToUrl(this.selectedFile);\n } else {\n throw new Error('No upload method configured. Provide either uploadUrl or onUpload callback.');\n }\n\n this.showSuccess('File uploaded successfully!');\n this.emitUploadEvent('upload-success', { file: this.selectedFile, result });\n\n } catch (error) {\n console.error('Upload failed:', error);\n this.showError(`Upload failed: ${error.message}`);\n this.emitUploadEvent('upload-error', { file: this.selectedFile, error });\n } finally {\n this.isUploading = false;\n this.hideLoading();\n }\n }\n\n async uploadToUrl(file) {\n return new Promise((resolve, reject) => {\n const formData = new FormData();\n formData.append('image', file);\n\n const xhr = new XMLHttpRequest();\n\n // Progress handler\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n const progress = Math.round((e.loaded / e.total) * 100);\n this.updateProgress(progress);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const response = JSON.parse(xhr.responseText);\n resolve(response);\n } catch (e) {\n resolve({ success: true, response: xhr.responseText });\n }\n } else {\n reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Network error occurred'));\n });\n\n xhr.addEventListener('timeout', () => {\n reject(new Error('Upload timeout'));\n });\n\n xhr.open('POST', this.uploadUrl);\n xhr.timeout = 30000; // 30 second timeout\n xhr.send(formData);\n });\n }\n\n updateProgress(percent) {\n if (this.progressBar) {\n this.progressBar.style.width = `${percent}%`;\n this.progressBar.setAttribute('aria-valuenow', percent);\n }\n if (this.uploadStatus) {\n this.uploadStatus.textContent = `Uploading... ${percent}%`;\n }\n }\n\n showLoading() {\n this.previewElement.classList.add('d-none');\n this.loadingElement.classList.remove('d-none');\n this.updateProgress(0);\n }\n\n hideLoading() {\n this.loadingElement.classList.add('d-none');\n if (!this.autoUpload || this.selectedFile) {\n this.previewElement.classList.remove('d-none');\n }\n }\n\n showSuccess(message) {\n this.showResult('success', message);\n }\n\n showError(message) {\n this.showResult('danger', message);\n }\n\n showResult(type, message) {\n const alertElement = this.resultElement.querySelector('.alert');\n const icon = type === 'success' ? 'check-circle-fill' : 'exclamation-triangle-fill';\n \n alertElement.className = `alert alert-${type}`;\n alertElement.innerHTML = `\n <i class=\"bi bi-${icon} me-2\"></i>\n ${message}\n `;\n\n this.resultElement.classList.remove('d-none');\n\n // Auto-hide success messages after 5 seconds\n if (type === 'success') {\n setTimeout(() => this.hideResult(), 5000);\n }\n }\n\n hideResult() {\n this.resultElement.classList.add('d-none');\n }\n\n clearFile() {\n // Clean up\n if (this.previewUrl) {\n URL.revokeObjectURL(this.previewUrl);\n this.previewUrl = null;\n }\n\n this.selectedFile = null;\n this.isUploading = false;\n this.fileInput.value = '';\n\n // Reset UI\n this.previewElement.classList.add('d-none');\n this.loadingElement.classList.add('d-none');\n this.promptElement.classList.remove('d-none');\n this.hideResult();\n\n this.emitUploadEvent('cleared');\n }\n\n formatFileSize(bytes) {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n }\n\n emitUploadEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imageupload:${type}`, {\n view: this,\n ...data\n });\n }\n }\n\n // Action handlers\n async handleActionSelectFile() {\n this.fileInput.click();\n }\n\n async handleActionUpload() {\n await this.uploadFile();\n }\n\n async handleActionClear() {\n this.clearFile();\n }\n\n // Cleanup\n async onBeforeDestroy() {\n // Clean up preview URL\n if (this.previewUrl) {\n URL.revokeObjectURL(this.previewUrl);\n this.previewUrl = null;\n }\n\n // Remove event listeners\n if (this.dropZone) {\n this.dropZone.removeEventListener('dragenter', this._preventDefaults);\n this.dropZone.removeEventListener('dragover', this._handleDragOver);\n this.dropZone.removeEventListener('dragleave', this._handleDragLeave);\n this.dropZone.removeEventListener('drop', this._handleDrop);\n }\n\n if (this.fileInput) {\n this.fileInput.removeEventListener('change', this._handleFileSelect);\n }\n\n // Remove document listeners\n ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {\n document.removeEventListener(eventName, this._preventDefaults);\n });\n\n this.emitUploadEvent('destroyed');\n }\n}\n\nwindow.ImageUploadView = ImageUploadView;"],"names":["e"],"mappings":"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"}
1
+ {"version":3,"file":"lightbox.es.js","sources":["../src/extensions/lightbox/ImageViewer.js","../src/extensions/lightbox/ImageCanvasView.js","../src/extensions/lightbox/ImageTransformView.js","../src/extensions/lightbox/ImageCropView.js","../src/extensions/lightbox/ImageFiltersView.js","../src/extensions/lightbox/ImageEditor.js","../src/extensions/lightbox/ImageUploadView.js"],"sourcesContent":["/**\n * ImageViewer - Canvas-based image viewing component with zoom, rotate, pan, and download capabilities\n * Built for the MOJO framework with full Bootstrap 5 integration\n */\n\nimport View from '@core/View.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageViewer extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-viewer ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Image properties\n this.imageUrl = options.imageUrl || options.src || '';\n this.alt = options.alt || 'Image';\n this.title = options.title || '';\n\n // Canvas properties\n this.canvas = null;\n this.context = null;\n this.image = null;\n\n // Transform state\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.minScale = 0.1;\n this.maxScale = 5;\n this.scaleStep = 0.1;\n\n // Interaction state\n this.isDragging = false;\n this.lastPointerX = 0;\n this.lastPointerY = 0;\n this.isLoaded = false;\n\n // Options\n this.showControls = options.showControls !== false;\n this.allowRotate = options.allowRotate !== false;\n this.allowZoom = options.allowZoom !== false;\n this.allowPan = options.allowPan !== false;\n this.allowDownload = options.allowDownload !== false;\n this.autoFit = options.autoFit !== false;\n\n // Elements\n this.containerElement = null;\n this.controlsElement = null;\n }\n\n async getTemplate() {\n return `\n <div class=\"image-viewer-container d-flex flex-column h-100\" data-container=\"imageContainer\">\n <div class=\"image-viewer-content flex-grow-1 position-relative\">\n <canvas class=\"image-viewer-canvas w-100 h-100\" data-container=\"canvas\"></canvas>\n <div class=\"image-viewer-overlay\">\n <div class=\"image-viewer-loading\">\n <div class=\"spinner-border text-light\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n\n {{#showControls}}\n <div class=\"image-viewer-controls position-absolute top-0 start-50 translate-middle-x mt-3\" data-container=\"controls\" style=\"z-index: 10;\">\n <div class=\"btn-group\" role=\"group\">\n {{#allowZoom}}\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"zoom-in\" title=\"Zoom In\">\n <i class=\"bi bi-zoom-in\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-dark 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-dark btn-sm\" data-action=\"zoom-fit\" title=\"Fit to Screen\">\n <i class=\"bi bi-arrows-fullscreen\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"zoom-actual\" title=\"Actual Size\">\n <i class=\"bi bi-1-square\"></i>\n </button>\n {{/allowZoom}}\n\n {{#allowRotate}}\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"rotate-left\" title=\"Rotate Left\">\n <i class=\"bi bi-arrow-counterclockwise\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"rotate-right\" title=\"Rotate Right\">\n <i class=\"bi bi-arrow-clockwise\"></i>\n </button>\n {{/allowRotate}}\n\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"reset\" title=\"Reset View\">\n <i class=\"bi bi-arrow-repeat\"></i>\n </button>\n\n {{#allowDownload}}\n <button type=\"button\" class=\"btn btn-dark btn-sm\" data-action=\"download\" title=\"Download Image\">\n <i class=\"bi bi-download\"></i>\n </button>\n {{/allowDownload}}\n </div>\n\n <div class=\"image-viewer-info\">\n <span class=\"zoom-level\">{{scale}}%</span>\n </div>\n </div>\n {{/showControls}}\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.canvas = this.element.querySelector('.image-viewer-canvas');\n this.context = this.canvas.getContext('2d');\n this.containerElement = this.element.querySelector('.image-viewer-content');\n this.controlsElement = this.element.querySelector('.image-viewer-controls');\n\n // Set up canvas\n this.setupCanvas();\n\n // Set up event listeners\n this.setupEventListeners();\n\n // Load image if provided\n if (this.imageUrl) {\n this.loadImage(this.imageUrl);\n }\n }\n\n setupCanvas() {\n if (!this.canvas || !this.containerElement) return;\n\n // Set up canvas properties first\n if (this.context) {\n this.context.imageSmoothingEnabled = true;\n this.context.imageSmoothingQuality = 'high';\n }\n\n // Delay canvas sizing to allow dialog to fully render\n setTimeout(() => {\n this.resizeCanvas();\n\n // If image was already loaded while we were waiting, render it\n if (this.isLoaded && this.image) {\n this.renderCanvas();\n }\n }, 2000); // 100ms should be enough for dialog animation\n }\n\n resizeCanvas() {\n if (!this.canvas) return;\n\n // Use reasonable viewport-based dimensions\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // Set canvas to reasonable size (80% of viewport with some padding)\n const canvasWidth = Math.floor(viewportWidth * 0.8);\n const canvasHeight = Math.floor(viewportHeight * 0.8);\n\n // Don't resize if dimensions haven't changed\n if (canvasWidth === this.canvasWidth && canvasHeight === this.canvasHeight) {\n return;\n }\n\n const dpr = window.devicePixelRatio || 1;\n\n // Store display dimensions\n this.canvasWidth = canvasWidth;\n this.canvasHeight = canvasHeight;\n\n // Set actual canvas buffer size (considering device pixel ratio)\n this.canvas.width = canvasWidth * dpr;\n this.canvas.height = canvasHeight * dpr;\n\n // Set display size via style\n this.canvas.style.width = canvasWidth + 'px';\n this.canvas.style.height = canvasHeight + 'px';\n\n // Reset transform and scale context for high DPI displays\n this.context.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n // If image is loaded, re-render it\n if (this.isLoaded && this.image) {\n this.renderCanvas();\n }\n }\n\n setupEventListeners() {\n if (!this.canvas) return;\n\n // Mouse events\n if (this.allowPan) {\n this.canvas.addEventListener('mousedown', (e) => this.handleMouseDown(e));\n document.addEventListener('mousemove', (e) => this.handleMouseMove(e));\n document.addEventListener('mouseup', (e) => this.handleMouseUp(e));\n }\n\n // Wheel events for zooming\n if (this.allowZoom) {\n this.canvas.addEventListener('wheel', (e) => this.handleWheel(e), { passive: false });\n }\n\n // Touch events\n this.canvas.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });\n this.canvas.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });\n this.canvas.addEventListener('touchend', (e) => this.handleTouchEnd(e));\n\n // Prevent context menu\n this.canvas.addEventListener('contextmenu', (e) => e.preventDefault());\n }\n\n // Action handlers\n async handleActionZoomIn() {\n this.zoomIn();\n }\n\n async handleActionZoomOut() {\n this.zoomOut();\n }\n\n async handleActionZoomFit() {\n this.fitToContainer();\n }\n\n async handleActionZoomActual() {\n this.setScale(1);\n this.renderCanvas();\n }\n\n async handleActionRotateLeft() {\n this.rotate(-90);\n }\n\n async handleActionRotateRight() {\n this.rotate(90);\n }\n\n async handleActionReset() {\n this.reset();\n }\n\n async handleActionDownload() {\n this.downloadImage();\n }\n\n // Image loading\n loadImage(imageUrl) {\n this.isLoaded = false;\n this.element.classList.remove('loaded');\n\n const img = new Image();\n img.crossOrigin = 'anonymous'; // For downloading images from other domains\n\n img.onload = () => {\n this.image = img;\n this.handleImageLoad();\n };\n\n img.onerror = () => {\n this.handleImageError();\n };\n\n img.src = imageUrl;\n }\n\n handleImageLoad() {\n this.isLoaded = true;\n this.element.classList.add('loaded');\n\n // Ensure canvas is properly sized (with delay if needed)\n const ensureCanvasReady = () => {\n // Check if canvas has dimensions\n if (!this.canvasWidth || !this.canvasHeight) {\n this.resizeCanvas();\n }\n\n // Initial setup\n if (this.autoFit) {\n this.fitToContainer();\n } else {\n this.smartFit();\n }\n\n this.renderCanvas();\n this.updateControls();\n };\n\n // If canvas dimensions are not set yet, wait for dialog to render\n if (!this.canvasWidth || !this.canvasHeight) {\n setTimeout(ensureCanvasReady, 2000); // Wait for dialog\n } else {\n requestAnimationFrame(ensureCanvasReady);\n }\n\n // Emit event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:loaded', {\n viewer: this,\n imageUrl: this.imageUrl,\n naturalWidth: this.image.naturalWidth,\n naturalHeight: this.image.naturalHeight\n });\n }\n }\n\n handleImageError() {\n console.error('Failed to load image:', this.imageUrl);\n\n // Emit error event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:error', {\n viewer: this,\n imageUrl: this.imageUrl,\n error: 'Failed to load image'\n });\n }\n }\n\n // Mouse interaction\n handleMouseDown(e) {\n if (!this.allowPan || e.button !== 0) return;\n\n e.preventDefault();\n this.isDragging = true;\n\n const rect = this.canvas.getBoundingClientRect();\n this.lastPointerX = e.clientX - rect.left;\n this.lastPointerY = e.clientY - rect.top;\n\n this.canvas.style.cursor = 'grabbing';\n }\n\n handleMouseMove(e) {\n if (!this.isDragging || !this.allowPan) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const currentX = e.clientX - rect.left;\n const currentY = e.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n\n handleMouseUp(e) {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n this.canvas.style.cursor = this.allowPan ? 'grab' : 'default';\n }\n\n handleWheel(e) {\n if (!this.allowZoom) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n const delta = e.deltaY > 0 ? -this.scaleStep * 0.5 : this.scaleStep * 0.5;\n this.zoomAtPoint(this.scale + delta, x, y);\n }\n\n // Touch events\n handleTouchStart(e) {\n if (e.touches.length === 1 && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n this.isDragging = true;\n this.lastPointerX = touch.clientX - rect.left;\n this.lastPointerY = touch.clientY - rect.top;\n }\n }\n\n handleTouchMove(e) {\n if (e.touches.length === 1 && this.isDragging && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n const currentX = touch.clientX - rect.left;\n const currentY = touch.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n }\n\n handleTouchEnd(e) {\n this.isDragging = false;\n }\n\n // Transform methods\n zoomIn() {\n this.setScale(this.scale + this.scaleStep);\n }\n\n zoomOut() {\n this.setScale(this.scale - this.scaleStep);\n }\n\n setScale(scale) {\n const oldScale = this.scale;\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, scale));\n this.renderCanvas();\n this.updateControls();\n\n // Emit scale change event\n const eventBus = this.getApp()?.events;\n if (eventBus && oldScale !== this.scale) {\n eventBus.emit('imageviewer:scale-changed', {\n viewer: this,\n oldScale,\n newScale: this.scale\n });\n }\n }\n\n zoomAtPoint(scale, x, y) {\n if (!this.image) return;\n\n const oldScale = this.scale;\n this.setScale(scale);\n\n if (oldScale !== this.scale) {\n const scaleDiff = this.scale / oldScale;\n const centerX = this.canvasWidth / 2;\n const centerY = this.canvasHeight / 2;\n\n // Adjust translation to zoom towards the point\n this.translateX = (this.translateX - (x - centerX)) * scaleDiff + (x - centerX);\n this.translateY = (this.translateY - (y - centerY)) * scaleDiff + (y - centerY);\n\n this.renderCanvas();\n }\n }\n\n pan(deltaX, deltaY) {\n this.translateX += deltaX;\n this.translateY += deltaY;\n this.renderCanvas();\n }\n\n rotate(degrees) {\n const oldRotation = this.rotation;\n this.rotation = (this.rotation + degrees) % 360;\n if (this.rotation < 0) this.rotation += 360;\n this.renderCanvas();\n\n // Emit rotation event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:rotated', {\n viewer: this,\n oldRotation,\n newRotation: this.rotation,\n degrees\n });\n }\n }\n\n center() {\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n }\n\n fitToContainer() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n const padding = 40;\n const availableWidth = this.canvasWidth - padding;\n const availableHeight = this.canvasHeight - padding;\n\n const scaleX = availableWidth / this.image.naturalWidth;\n const scaleY = availableHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n this.setScale(scale);\n this.renderCanvas();\n }\n\n smartFit() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n // If image is much larger than container, scale it down\n const padding = 80;\n const scaleX = (this.canvasWidth - padding) / this.image.naturalWidth;\n const scaleY = (this.canvasHeight - padding) / this.image.naturalHeight;\n const fitScale = Math.min(scaleX, scaleY);\n\n if (fitScale < 1) {\n this.setScale(fitScale);\n }\n\n this.renderCanvas();\n }\n\n reset() {\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n this.updateControls();\n }\n\n // Canvas rendering\n renderCanvas() {\n if (!this.context || !this.canvasWidth || !this.canvasHeight) return;\n\n // Clear canvas\n this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);\n\n if (!this.image || !this.isLoaded) return;\n\n // Save context state\n this.context.save();\n\n // Move to center and apply transforms\n this.context.translate(\n this.canvasWidth / 2 + this.translateX,\n this.canvasHeight / 2 + this.translateY\n );\n this.context.scale(this.scale, this.scale);\n this.context.rotate(this.rotation * Math.PI / 180);\n\n // Draw image centered on the transform point\n this.context.drawImage(\n this.image,\n -this.image.naturalWidth / 2,\n -this.image.naturalHeight / 2\n );\n\n // Restore context state\n this.context.restore();\n }\n\n // Download functionality\n downloadImage() {\n if (!this.canvas) return;\n\n try {\n // Create download link\n const link = document.createElement('a');\n link.download = this.getDownloadFilename();\n link.href = this.canvas.toDataURL('image/png');\n\n // Trigger download\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n\n // Emit download event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:downloaded', {\n viewer: this,\n filename: link.download\n });\n }\n } catch (error) {\n console.error('Failed to download image:', error);\n\n // Emit error event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:download-error', {\n viewer: this,\n error: error.message\n });\n }\n }\n }\n\n getDownloadFilename() {\n if (this.title) {\n return `${this.title.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.png`;\n }\n\n // Try to extract filename from URL\n try {\n const url = new URL(this.imageUrl);\n const pathname = url.pathname;\n const filename = pathname.split('/').pop();\n if (filename && filename.includes('.')) {\n return filename.replace(/\\.[^.]+$/, '.png'); // Replace extension with .png\n }\n } catch (e) {\n // Invalid URL, continue with fallback\n }\n\n return 'image.png';\n }\n\n updateControls() {\n if (!this.controlsElement) return;\n\n const zoomLevel = this.controlsElement.querySelector('.zoom-level');\n if (zoomLevel) {\n zoomLevel.textContent = `${Math.round(this.scale * 100)}%`;\n }\n\n // Update button states\n const zoomInBtn = this.controlsElement.querySelector('[data-action=\"zoom-in\"]');\n const zoomOutBtn = this.controlsElement.querySelector('[data-action=\"zoom-out\"]');\n\n if (zoomInBtn) {\n zoomInBtn.disabled = this.scale >= this.maxScale;\n }\n if (zoomOutBtn) {\n zoomOutBtn.disabled = this.scale <= this.minScale;\n }\n }\n\n // Public API methods\n setImage(imageUrl, alt = '', title = '') {\n const oldImageUrl = this.imageUrl;\n this.imageUrl = imageUrl;\n this.alt = alt;\n this.title = title;\n\n this.reset();\n this.loadImage(imageUrl);\n\n // Emit image changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:image-changed', {\n viewer: this,\n oldImageUrl,\n newImageUrl: imageUrl\n });\n }\n }\n\n getCurrentState() {\n return {\n scale: this.scale,\n rotation: this.rotation,\n translateX: this.translateX,\n translateY: this.translateY\n };\n }\n\n setState(state) {\n if (state.scale !== undefined) this.scale = state.scale;\n if (state.rotation !== undefined) this.rotation = state.rotation;\n if (state.translateX !== undefined) this.translateX = state.translateX;\n if (state.translateY !== undefined) this.translateY = state.translateY;\n this.renderCanvas();\n this.updateControls();\n }\n\n async onBeforeDestroy() {\n // Clean up\n if (this.isDragging) {\n this.isDragging = false;\n }\n\n\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageviewer:destroyed', { viewer: this });\n }\n }\n\n // Static method to show image in a fullscreen dialog\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Image Viewer',\n alt = 'Image',\n size = 'fullscreen',\n showControls = true,\n allowRotate = true,\n allowZoom = true,\n allowPan = true,\n allowDownload = true,\n ...dialogOptions\n } = options;\n\n const viewer = new ImageViewer({\n imageUrl,\n alt,\n title,\n showControls,\n allowRotate,\n allowZoom,\n allowPan,\n allowDownload,\n autoFit: true\n });\n\n return Dialog.showDialog({\n title,\n body: viewer,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n buttons: [\n {\n text: 'Close',\n action: 'close',\n class: 'btn btn-secondary',\n dismiss: true\n }\n ],\n ...dialogOptions\n });\n }\n}\n\nwindow.ImageViewer = ImageViewer;\n","/**\n * ImageCanvasView - Base canvas view for image editing components\n * Provides shared canvas functionality for transform, crop, and filter views\n */\n\nimport View from '@core/View.js';\n\nexport default class ImageCanvasView extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-canvas-view ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Image properties\n this.imageUrl = options.imageUrl || options.src || '';\n this.alt = options.alt || 'Image';\n this.title = options.title || '';\n\n // Canvas properties\n this.canvas = null;\n this.context = null;\n this.image = null;\n this.canvasWidth = 0;\n this.canvasHeight = 0;\n this.maxCanvasHeightPercent = options.maxCanvasHeightPercent || 0.7;\n this.maxCanvasWidthPercent = options.maxCanvasWidthPercent || 0.8;\n // Canvas size presets with viewport awareness\n this.canvasSizes = {\n sm: { width: 400, height: 300 }, // Small - thumbnails, previews\n md: { width: 600, height: 450 }, // Medium - dialogs, cards\n lg: { width: 800, height: 600 }, // Large - main editing\n xl: { width: 1000, height: 750 }, // Extra Large - detailed work\n fullscreen: { width: 0, height: 0 }, // Special case - use viewport\n auto: { width: 0, height: 0 } // Auto-size based on image + viewport\n };\n\n // Default to auto-sizing with viewport constraints\n this.canvasSize = options.canvasSize || 'auto';\n\n // State\n this.isLoaded = false;\n this.isRendering = false;\n\n // Options\n this.autoFit = options.autoFit !== false;\n this.crossOrigin = options.crossOrigin || 'anonymous';\n }\n\n async getTemplate() {\n return `\n <div class=\"image-canvas-container d-flex flex-column h-100\">\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-canvas w-100 h-100\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.canvas = this.element.querySelector('canvas');\n this.context = this.canvas.getContext('2d');\n this.containerElement = this.element.querySelector('.image-canvas-content');\n this.loadingElement = this.element.querySelector('.image-canvas-loading');\n\n // Set up canvas\n this.setupCanvas();\n\n // Load image if provided\n if (this.imageUrl) {\n this.loadImage(this.imageUrl);\n }\n }\n\n setupCanvas() {\n if (!this.canvas || !this.containerElement) return;\n\n // Set canvas dimensions based on size preset\n this.setCanvasSize(this.canvasSize);\n\n // Simple resize listener (only for fullscreen mode)\n if (this.canvasSize === 'fullscreen') {\n this._resizeHandler = () => this.setCanvasSize('fullscreen');\n window.addEventListener('resize', this._resizeHandler);\n }\n\n // Set up canvas context\n this.context.imageSmoothingEnabled = true;\n this.context.imageSmoothingQuality = 'high';\n }\n\n setCanvasSize(size) {\n const preset = this.canvasSizes[size];\n if (!preset && size !== 'auto') return;\n\n let canvasWidth, canvasHeight;\n\n if (size === 'fullscreen') {\n // Use viewport dimensions for fullscreen\n canvasWidth = Math.min(1200, window.innerWidth * 0.9);\n canvasHeight = Math.min(900, window.innerHeight * 0.8);\n } else if (size === 'auto' || !preset) {\n // Auto-size based on image with viewport constraints\n if (this.image) {\n // Scale image to fit within viewport constraints\n const maxWidth = window.innerWidth * this.maxCanvasWidthPercent;\n const maxHeight = window.innerHeight * this.maxCanvasHeightPercent;\n\n const scaleX = maxWidth / this.image.naturalWidth;\n const scaleY = maxHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up\n\n canvasWidth = Math.floor(this.image.naturalWidth * scale);\n canvasHeight = Math.floor(this.image.naturalHeight * scale);\n\n // Ensure minimum usable size\n canvasWidth = Math.max(300, canvasWidth);\n canvasHeight = Math.max(200, canvasHeight);\n } else {\n // No image yet - use medium preset with viewport constraints\n canvasWidth = Math.min(600, window.innerWidth * this.maxCanvasWidthPercent);\n canvasHeight = Math.min(450, window.innerHeight * this.maxCanvasHeightPercent);\n }\n } else {\n // Check if preset fits within 80% viewport - if not, fall back to auto\n const maxWidth = window.innerWidth * this.maxCanvasWidthPercent;\n const maxHeight = window.innerHeight * this.maxCanvasHeightPercent;\n\n if (preset.width > maxWidth || preset.height > maxHeight) {\n // Preset is too big - fall back to auto sizing\n if (this.image) {\n const scaleX = maxWidth / this.image.naturalWidth;\n const scaleY = maxHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up\n\n canvasWidth = Math.floor(this.image.naturalWidth * scale);\n canvasHeight = Math.floor(this.image.naturalHeight * scale);\n\n // Ensure minimum usable size\n canvasWidth = Math.max(300, canvasWidth);\n canvasHeight = Math.max(200, canvasHeight);\n } else {\n // No image yet - use medium preset with viewport constraints\n canvasWidth = Math.min(600, maxWidth);\n canvasHeight = Math.min(450, maxHeight);\n }\n } else {\n // Preset fits - use it as-is\n canvasWidth = preset.width;\n canvasHeight = preset.height;\n }\n }\n\n // Final safety check (should not be needed now, but kept for robustness)\n canvasWidth = Math.min(canvasWidth, window.innerWidth * this.maxCanvasWidthPercent);\n canvasHeight = Math.min(canvasHeight, window.innerHeight * this.maxCanvasHeightPercent);\n\n // Don't resize if dimensions haven't changed significantly\n if (Math.abs(canvasWidth - this.canvasWidth) < 10 &&\n Math.abs(canvasHeight - this.canvasHeight) < 10) {\n return;\n }\n\n // Set dimensions and DPR handling\n const dpr = window.devicePixelRatio || 1;\n\n this.canvasWidth = canvasWidth;\n this.canvasHeight = canvasHeight;\n\n this.canvas.width = canvasWidth * dpr;\n this.canvas.height = canvasHeight * dpr;\n\n this.canvas.style.width = canvasWidth + 'px';\n this.canvas.style.height = canvasHeight + 'px';\n\n this.context.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (this.isLoaded) {\n this.renderCanvas();\n }\n }\n\n // Image loading\n loadImage(imageUrl) {\n if (!imageUrl) return;\n\n this.imageUrl = imageUrl;\n this.isLoaded = false;\n this.element.classList.remove('loaded');\n this.showLoading();\n\n const img = new Image();\n if (this.crossOrigin) {\n img.crossOrigin = this.crossOrigin;\n }\n\n img.onload = () => {\n this.image = img;\n this.handleImageLoad();\n };\n\n img.onerror = () => {\n this.handleImageError();\n };\n\n img.src = imageUrl;\n }\n\n handleImageLoad() {\n this.isLoaded = true;\n this.element.classList.add('loaded');\n this.hideLoading();\n\n // Initial setup\n // Resize canvas based on loaded image (especially for auto-sizing)\n if (this.canvasSize === 'auto') {\n this.setCanvasSize('auto');\n } else if (this.autoFit) {\n this.fitToContainer();\n }\n\n this.renderCanvas();\n\n // Emit load event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:loaded', {\n view: this,\n imageUrl: this.imageUrl,\n naturalWidth: this.image.naturalWidth,\n naturalHeight: this.image.naturalHeight\n });\n }\n }\n\n handleImageError() {\n console.error('Failed to load image:', this.imageUrl);\n this.hideLoading();\n\n // Emit error event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:error', {\n view: this,\n imageUrl: this.imageUrl,\n error: 'Failed to load image'\n });\n }\n }\n\n showLoading() {\n if (this.loadingElement) {\n this.loadingElement.style.display = 'block';\n }\n }\n\n hideLoading() {\n if (this.loadingElement) {\n this.loadingElement.style.display = 'none';\n }\n }\n\n // Base canvas rendering - to be extended by child classes\n renderCanvas() {\n if (!this.context || !this.canvasWidth || !this.canvasHeight || this.isRendering) return;\n\n this.isRendering = true;\n\n // Clear canvas\n this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);\n\n if (!this.image || !this.isLoaded) {\n this.isRendering = false;\n return;\n }\n\n // Save context state\n this.context.save();\n\n // Basic centered rendering - child classes can override this\n this.renderImage();\n\n // Restore context state\n this.context.restore();\n\n this.isRendering = false;\n }\n\n // Basic image rendering with smart scaling - can be overridden\n renderImage() {\n if (!this.image) return;\n\n // Calculate scale to fit image in canvas\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n // Calculate centered position\n const scaledWidth = this.image.naturalWidth * scale;\n const scaledHeight = this.image.naturalHeight * scale;\n const x = (this.canvasWidth - scaledWidth) / 2;\n const y = (this.canvasHeight - scaledHeight) / 2;\n\n // Draw scaled and centered image\n this.context.drawImage(this.image, x, y, scaledWidth, scaledHeight);\n }\n\n // Utility methods\n fitToContainer() {\n // Base implementation - child classes should override\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n const padding = 40;\n const availableWidth = this.canvasWidth - padding;\n const availableHeight = this.canvasHeight - padding;\n\n const scaleX = availableWidth / this.image.naturalWidth;\n const scaleY = availableHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n // Resize canvas to accommodate image\n if (this.canvasSize === 'auto') {\n this.setCanvasSize('auto');\n }\n\n // Child classes will implement actual scaling\n this.renderCanvas();\n }\n\n center() {\n // Base implementation - child classes should override\n this.renderCanvas();\n }\n\n reset() {\n // Base implementation - child classes should override\n this.renderCanvas();\n }\n\n // Export functionality\n exportImageData() {\n if (!this.canvas) return null;\n\n try {\n return this.canvas.toDataURL('image/png');\n } catch (error) {\n console.error('Failed to export image data:', error);\n return null;\n }\n }\n\n exportImageBlob(quality = 0.9) {\n if (!this.canvas) return Promise.resolve(null);\n\n return new Promise((resolve) => {\n try {\n this.canvas.toBlob((blob) => {\n resolve(blob);\n }, 'image/png', quality);\n } catch (error) {\n console.error('Failed to export image blob:', error);\n resolve(null);\n }\n });\n }\n\n // Public API\n setImage(imageUrl, alt = '', title = '') {\n const oldImageUrl = this.imageUrl;\n this.alt = alt;\n this.title = title;\n\n this.loadImage(imageUrl);\n\n // Emit image changed event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:image-changed', {\n view: this,\n oldImageUrl,\n newImageUrl: imageUrl\n });\n }\n }\n\n getImageData() {\n return {\n imageUrl: this.imageUrl,\n alt: this.alt,\n title: this.title,\n naturalWidth: this.image?.naturalWidth || 0,\n naturalHeight: this.image?.naturalHeight || 0,\n isLoaded: this.isLoaded\n };\n }\n\n async onBeforeDestroy() {\n // Clean up\n this.isLoaded = false;\n this.isRendering = false;\n this.image = null;\n\n // Remove resize listener\n if (this._resizeHandler) {\n window.removeEventListener('resize', this._resizeHandler);\n }\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imagecanvas:destroyed', { view: this });\n }\n }\n}\n\nwindow.ImageCanvasView = ImageCanvasView;\n","/**\n * ImageTransformView - Canvas-based image viewer with zoom, pan, and rotation\n * Extends ImageCanvasView with transform capabilities\n */\n\nimport ImageCanvasView from './ImageCanvasView.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageTransformView extends ImageCanvasView {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-transform-view ${options.className || ''}`,\n });\n\n // Transform state\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.minScale = 0.1;\n this.maxScale = 5;\n this.scaleStep = 0.02;\n\n // Interaction state\n this.isDragging = false;\n this.lastPointerX = 0;\n this.lastPointerY = 0;\n\n // Options\n this.allowPan = options.allowPan !== false;\n this.allowZoom = options.allowZoom !== false;\n this.allowRotate = options.allowRotate !== false;\n this.allowKeyboard = options.allowKeyboard !== false;\n\n // Bind handlers for cleanup\n this._handleMouseMove = this.handleMouseMove.bind(this);\n this._handleMouseUp = this.handleMouseUp.bind(this);\n this._handleKeyboard = this.handleKeyboard.bind(this);\n\n if (!options.maxCanvasHeightPercent) {\n this.maxCanvasHeightPercent = 0.6;\n }\n }\n\n async getTemplate() {\n return `\n <div class=\"image-transform-container d-flex flex-column h-100\">\n <!-- Transform Toolbar -->\n <div class=\"image-transform-toolbar bg-light border-bottom p-2\">\n <div class=\"btn-toolbar justify-content-center\" role=\"toolbar\">\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Zoom controls\">\n <button type=\"button\" class=\"btn btn-outline-primary btn-sm\" data-action=\"zoom-in\" title=\"Zoom In\">\n <i class=\"bi bi-zoom-in\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-primary 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=\"fit-to-screen\" title=\"Fit to Screen\">\n <i class=\"bi bi-arrows-fullscreen\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"actual-size\" title=\"Actual Size\">\n <i class=\"bi bi-1-square\"></i>\n </button>\n </div>\n\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Rotate controls\">\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"rotate-left\" title=\"Rotate Left\">\n <i class=\"bi bi-arrow-counterclockwise\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"rotate-right\" title=\"Rotate Right\">\n <i class=\"bi bi-arrow-clockwise\"></i>\n </button>\n </div>\n\n <div class=\"btn-group\" role=\"group\" aria-label=\"Position controls\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"center-image\" title=\"Center Image\">\n <i class=\"bi bi-bullseye\"></i>\n </button>\n </div>\n </div>\n </div>\n\n <!-- Canvas Area -->\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-canvas\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Set up interaction event listeners\n this.setupInteractionListeners();\n }\n\n setupInteractionListeners() {\n if (!this.canvas) return;\n\n // Mouse events\n if (this.allowPan) {\n this.canvas.addEventListener('mousedown', (e) => this.handleMouseDown(e));\n document.addEventListener('mousemove', this._handleMouseMove);\n document.addEventListener('mouseup', this._handleMouseUp);\n }\n\n // Wheel events for zooming\n if (this.allowZoom) {\n this.canvas.addEventListener('wheel', (e) => this.handleWheel(e), { passive: false });\n }\n\n // Touch events\n this.canvas.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });\n this.canvas.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });\n this.canvas.addEventListener('touchend', (e) => this.handleTouchEnd(e));\n\n // Keyboard shortcuts\n if (this.allowKeyboard) {\n document.addEventListener('keydown', this._handleKeyboard);\n }\n\n // Prevent context menu\n this.canvas.addEventListener('contextmenu', (e) => e.preventDefault());\n\n // Set cursor\n this.canvas.style.cursor = this.allowPan ? 'grab' : 'default';\n }\n\n // Override renderImage to apply transforms\n renderImage() {\n if (!this.image) return;\n\n // Apply transforms\n this.context.translate(\n this.canvasWidth / 2 + this.translateX,\n this.canvasHeight / 2 + this.translateY\n );\n this.context.scale(this.scale, this.scale);\n this.context.rotate(this.rotation * Math.PI / 180);\n\n // Draw image centered on the transform point\n this.context.drawImage(\n this.image,\n -this.image.naturalWidth / 2,\n -this.image.naturalHeight / 2\n );\n }\n\n // Mouse interaction\n handleMouseDown(e) {\n if (!this.allowPan || e.button !== 0) return;\n\n e.preventDefault();\n this.isDragging = true;\n\n const rect = this.canvas.getBoundingClientRect();\n this.lastPointerX = e.clientX - rect.left;\n this.lastPointerY = e.clientY - rect.top;\n\n this.canvas.style.cursor = 'grabbing';\n }\n\n handleMouseMove(e) {\n if (!this.isDragging || !this.allowPan) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const currentX = e.clientX - rect.left;\n const currentY = e.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n\n handleMouseUp(e) {\n if (!this.isDragging) return;\n\n this.isDragging = false;\n this.canvas.style.cursor = this.allowPan ? 'grab' : 'default';\n }\n\n handleWheel(e) {\n if (!this.allowZoom) return;\n\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n const delta = e.deltaY > 0 ? -this.scaleStep * 0.5 : this.scaleStep * 0.5;\n this.zoomAtPoint(this.scale + delta, x, y);\n }\n\n // Touch events\n handleTouchStart(e) {\n if (e.touches.length === 1 && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n this.isDragging = true;\n this.lastPointerX = touch.clientX - rect.left;\n this.lastPointerY = touch.clientY - rect.top;\n }\n }\n\n handleTouchMove(e) {\n if (e.touches.length === 1 && this.isDragging && this.allowPan) {\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n\n const currentX = touch.clientX - rect.left;\n const currentY = touch.clientY - rect.top;\n\n const deltaX = currentX - this.lastPointerX;\n const deltaY = currentY - this.lastPointerY;\n\n this.pan(deltaX, deltaY);\n\n this.lastPointerX = currentX;\n this.lastPointerY = currentY;\n }\n }\n\n handleTouchEnd(e) {\n this.isDragging = false;\n }\n\n // Keyboard shortcuts\n handleKeyboard(e) {\n if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;\n\n switch (e.key) {\n case '+':\n case '=':\n if (this.allowZoom) {\n e.preventDefault();\n this.zoomIn();\n }\n break;\n case '-':\n if (this.allowZoom) {\n e.preventDefault();\n this.zoomOut();\n }\n break;\n case '0':\n e.preventDefault();\n this.fitToContainer();\n break;\n case '1':\n e.preventDefault();\n this.actualSize();\n break;\n case 'r':\n case 'R':\n if (this.allowRotate) {\n e.preventDefault();\n this.rotateRight();\n }\n break;\n }\n }\n\n // Transform methods\n zoomIn() {\n this.setScale(this.scale + this.scaleStep);\n }\n\n zoomOut() {\n this.setScale(this.scale - this.scaleStep);\n }\n\n setScale(scale) {\n const oldScale = this.scale;\n this.scale = Math.max(this.minScale, Math.min(this.maxScale, scale));\n\n if (oldScale !== this.scale) {\n this.renderCanvas();\n this.emitTransformEvent('scale-changed', { oldScale, newScale: this.scale });\n }\n }\n\n zoomAtPoint(scale, x, y) {\n if (!this.image) return;\n\n const oldScale = this.scale;\n this.setScale(scale);\n\n if (oldScale !== this.scale) {\n const scaleDiff = this.scale / oldScale;\n const centerX = this.canvasWidth / 2;\n const centerY = this.canvasHeight / 2;\n\n // Adjust translation to zoom towards the point\n this.translateX = (this.translateX - (x - centerX)) * scaleDiff + (x - centerX);\n this.translateY = (this.translateY - (y - centerY)) * scaleDiff + (y - centerY);\n\n this.renderCanvas();\n }\n }\n\n pan(deltaX, deltaY) {\n this.translateX += deltaX;\n this.translateY += deltaY;\n this.renderCanvas();\n this.emitTransformEvent('panned', { deltaX, deltaY });\n }\n\n rotate(degrees) {\n const oldRotation = this.rotation;\n this.rotation = (this.rotation + degrees) % 360;\n if (this.rotation < 0) this.rotation += 360;\n\n this.renderCanvas();\n this.emitTransformEvent('rotated', { oldRotation, newRotation: this.rotation, degrees });\n }\n\n rotateLeft() {\n this.rotate(-90);\n }\n\n rotateRight() {\n this.rotate(90);\n }\n\n center() {\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n this.emitTransformEvent('centered');\n }\n\n actualSize() {\n this.setScale(1);\n this.center();\n }\n\n // Override fitToContainer with actual scaling logic\n fitToContainer() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n const padding = 40;\n const availableWidth = this.canvasWidth - padding;\n const availableHeight = this.canvasHeight - padding;\n\n const scaleX = availableWidth / this.image.naturalWidth;\n const scaleY = availableHeight / this.image.naturalHeight;\n const scale = Math.min(scaleX, scaleY, 1); // Don't scale up beyond 100%\n\n this.setScale(scale);\n this.center();\n }\n\n smartFit() {\n if (!this.image || !this.canvasWidth || !this.canvasHeight) return;\n\n // If image is much larger than canvas, scale it down\n const padding = 80;\n const scaleX = (this.canvasWidth - padding) / this.image.naturalWidth;\n const scaleY = (this.canvasHeight - padding) / this.image.naturalHeight;\n const fitScale = Math.min(scaleX, scaleY);\n\n if (fitScale < 1) {\n this.setScale(fitScale);\n }\n\n this.center();\n }\n\n // Override reset with transform-specific logic\n reset() {\n this.scale = 1;\n this.rotation = 0;\n this.translateX = 0;\n this.translateY = 0;\n this.renderCanvas();\n this.emitTransformEvent('reset');\n }\n\n // Override handleImageLoad to apply initial transforms\n handleImageLoad() {\n super.handleImageLoad();\n\n if (this.autoFit) {\n this.fitToContainer();\n } else {\n this.smartFit();\n }\n }\n\n // State management\n getTransformState() {\n return {\n scale: this.scale,\n rotation: this.rotation,\n translateX: this.translateX,\n translateY: this.translateY\n };\n }\n\n setTransformState(state) {\n if (state.scale !== undefined) this.scale = state.scale;\n if (state.rotation !== undefined) this.rotation = state.rotation;\n if (state.translateX !== undefined) this.translateX = state.translateX;\n if (state.translateY !== undefined) this.translateY = state.translateY;\n this.renderCanvas();\n }\n\n // Event emission\n emitTransformEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imagetransform:${type}`, {\n view: this,\n transform: this.getTransformState(),\n ...data\n });\n }\n }\n\n // Action handlers for toolbar buttons\n async handleActionZoomIn() {\n this.zoomIn();\n }\n\n async handleActionZoomOut() {\n this.zoomOut();\n }\n\n async handleActionFitToScreen() {\n this.fitToContainer();\n }\n\n async handleActionActualSize() {\n this.actualSize();\n }\n\n async handleActionRotateLeft() {\n this.rotateLeft();\n }\n\n async handleActionRotateRight() {\n this.rotateRight();\n }\n\n async handleActionCenterImage() {\n this.center();\n }\n\n // Cleanup\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Clean up interaction listeners\n if (this.isDragging) {\n this.isDragging = false;\n }\n\n // Remove document listeners\n document.removeEventListener('mousemove', this._handleMouseMove);\n document.removeEventListener('mouseup', this._handleMouseUp);\n document.removeEventListener('keydown', this._handleKeyboard);\n\n this.emitTransformEvent('destroyed');\n }\n\n // Static method to show transform view in a dialog for standalone testing\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Transform Image',\n alt = 'Image',\n size = 'xl',\n allowPan = true,\n allowZoom = true,\n allowRotate = true,\n ...dialogOptions\n } = options;\n\n const transformView = new ImageTransformView({\n imageUrl,\n alt,\n title,\n allowPan,\n allowZoom,\n allowRotate\n });\n\n const dialog = new Dialog({\n title,\n body: transformView,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n noBodyPadding: true,\n maxCanvasHeightPercent: 0.5,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Apply Transform',\n action: 'apply-transform',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', view: transformView });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:apply-transform', async () => {\n const imageData = transformView.exportImageData();\n dialog.hide();\n resolve({\n action: 'transform',\n view: transformView,\n data: imageData,\n transformState: transformView.getTransformState()\n });\n });\n });\n }\n}\n\nwindow.ImageTransformView = Image\n","/**\n * ImageCropView - Canvas-based image cropping with interactive selection\n * Extends ImageCanvasView with crop functionality\n */\n\nimport ImageCanvasView from './ImageCanvasView.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageCropView extends ImageCanvasView {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-crop-view ${options.className || ''}`,\n });\n\n // Store original image URL for reset functionality\n this.originalImageUrl = options.imageUrl;\n\n // Crop state\n this.cropMode = false;\n this.cropBox = { x: 0, y: 0, width: 0, height: 0 };\n this.aspectRatio = options.aspectRatio || null; // null for free crop, number for fixed ratio\n this.minCropSize = options.minCropSize || 50;\n this.fixedCropSize = options.fixedCropSize || null; // { width: number, height: number } for fixed size crop\n this.cropAndScale = options.cropAndScale || null; // { width: number, height: number } for aspect ratio + scaling\n\n // Interaction state\n this.isDragging = false;\n this.isResizing = false;\n this.dragHandle = null;\n this.dragStartImageX = 0; // Drag start in image coordinates\n this.dragStartImageY = 0; // Drag start in image coordinates\n this.initialCropBox = null;\n this.newCropStart = null; // For creating new crop boxes\n\n // Handle positions for resizing\n this.handles = {\n 'nw': { cursor: 'nw-resize', x: 0, y: 0 },\n 'ne': { cursor: 'ne-resize', x: 1, y: 0 },\n 'sw': { cursor: 'sw-resize', x: 0, y: 1 },\n 'se': { cursor: 'se-resize', x: 1, y: 1 },\n 'n': { cursor: 'n-resize', x: 0.5, y: 0 },\n 's': { cursor: 's-resize', x: 0.5, y: 1 },\n 'w': { cursor: 'w-resize', x: 0, y: 0.5 },\n 'e': { cursor: 'e-resize', x: 1, y: 0.5 }\n };\n\n // Options\n this.handleSize = options.handleSize || 12;\n this.showGrid = options.showGrid !== false;\n this.showToolbar = options.showToolbar !== false; // Default to true - show toolbar\n this.autoFit = options.autoFit !== false; // Default to true - auto-fit large images\n\n // Image positioning on canvas\n this.imageOffsetX = 0;\n this.imageOffsetY = 0;\n\n // Bind handlers for cleanup\n this._handleMouseMove = this.handleMouseMove.bind(this);\n this._handleMouseUp = this.handleMouseUp.bind(this);\n if (!options.maxCanvasHeightPercent && this.showToolbar) {\n this.maxCanvasHeightPercent = 0.6;\n }\n }\n\n // Coordinate conversion helpers\n imageToCanvas(imageCoords) {\n if (!this.image) return imageCoords;\n\n // Calculate scale and positioning of image on canvas (same as renderImage)\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let imageScale;\n if (this.autoFit) {\n imageScale = Math.min(scaleX, scaleY, 1); // Scale down if needed, but don't scale up\n } else {\n imageScale = 1; // Always show at actual size (1:1)\n }\n\n const scaledImageWidth = this.image.naturalWidth * imageScale;\n const scaledImageHeight = this.image.naturalHeight * imageScale;\n const imageX = (this.canvasWidth - scaledImageWidth) / 2;\n const imageY = (this.canvasHeight - scaledImageHeight) / 2;\n\n return {\n x: imageCoords.x * imageScale + imageX,\n y: imageCoords.y * imageScale + imageY,\n width: imageCoords.width * imageScale,\n height: imageCoords.height * imageScale\n };\n }\n\n canvasToImage(canvasCoords) {\n if (!this.image) return canvasCoords;\n\n // Calculate scale and positioning of image on canvas (same as renderImage)\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let imageScale;\n if (this.autoFit) {\n imageScale = Math.min(scaleX, scaleY, 1); // Scale down if needed, but don't scale up\n } else {\n imageScale = 1; // Always show at actual size (1:1)\n }\n\n const scaledImageWidth = this.image.naturalWidth * imageScale;\n const scaledImageHeight = this.image.naturalHeight * imageScale;\n const imageX = (this.canvasWidth - scaledImageWidth) / 2;\n const imageY = (this.canvasHeight - scaledImageHeight) / 2;\n\n return {\n x: (canvasCoords.x - imageX) / imageScale,\n y: (canvasCoords.y - imageY) / imageScale,\n width: canvasCoords.width / imageScale,\n height: canvasCoords.height / imageScale\n };\n }\n\n pointCanvasToImage(canvasX, canvasY) {\n const result = this.canvasToImage({ x: canvasX, y: canvasY, width: 0, height: 0 });\n return { x: result.x, y: result.y };\n }\n\n async getTemplate() {\n return `\n <div class=\"image-crop-container d-flex flex-column h-100\">\n {{#showToolbar}}\n <!-- Crop Toolbar -->\n <div class=\"image-crop-toolbar bg-light border-bottom p-2\">\n <div class=\"btn-toolbar justify-content-center\" role=\"toolbar\">\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Aspect ratio\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" title=\"Aspect Ratio\">\n <i class=\"bi bi-aspect-ratio\"></i> Ratio\n </button>\n <ul class=\"dropdown-menu\">\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"free\">Free</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"1\">1:1 Square</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"1.333\">4:3</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"1.777\">16:9</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"set-aspect-ratio\" data-ratio=\"0.75\">3:4 Portrait</a></li>\n </ul>\n </div>\n\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Fit mode\">\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"toggle-auto-fit\" title=\"Toggle Auto-fit\">\n <i class=\"bi bi-arrows-fullscreen\"></i> <span class=\"auto-fit-text\">Fit</span>\n </button>\n </div>\n\n <div class=\"btn-group me-2\" role=\"group\" aria-label=\"Crop actions\">\n <button type=\"button\" class=\"btn btn-success btn-sm\" data-action=\"apply-crop\" title=\"Apply Crop\">\n <i class=\"bi bi-check\"></i> Apply\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"reset-crop\" title=\"Reset Crop\">\n <i class=\"bi bi-arrow-repeat\"></i> Reset\n </button>\n </div>\n </div>\n </div>\n {{/showToolbar}}\n\n <!-- Canvas Area -->\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-crop-canvas\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Set up crop interaction listeners\n this.setupCropListeners();\n\n // Initialize autoFit button state\n this.updateAutoFitButtonState();\n }\n\n\n\n updateAutoFitButtonState() {\n // Skip if toolbar is hidden\n if (!this.showToolbar) return;\n\n const button = this.element.querySelector('[data-action=\"toggle-auto-fit\"]');\n const textSpan = button?.querySelector('.auto-fit-text');\n\n if (button && textSpan) {\n if (this.autoFit) {\n button.classList.remove('btn-outline-warning');\n button.classList.add('btn-outline-info');\n button.title = 'Toggle Auto-fit (currently: fit to canvas)';\n textSpan.textContent = 'Fit';\n } else {\n button.classList.remove('btn-outline-info');\n button.classList.add('btn-outline-warning');\n button.title = 'Toggle Auto-fit (currently: actual size)';\n textSpan.textContent = '1:1';\n }\n }\n }\n\n handleImageLoad() {\n // Call parent method first\n super.handleImageLoad();\n\n // Calculate image offset for coordinate conversion\n this.updateImageOffset();\n\n // Start crop mode once image is loaded and canvas is ready\n // Use a small delay to ensure canvas dimensions are properly set\n setTimeout(() => {\n if (this.isLoaded && this.canvasWidth > 0 && this.canvasHeight > 0) {\n this.startCropMode();\n }\n }, 10);\n }\n\n updateImageOffset() {\n if (!this.image) return;\n\n // Calculate scale and positioning (same as renderImage)\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let scale;\n if (this.autoFit) {\n // Auto-fit: scale down if image is larger than canvas, but don't scale up\n scale = Math.min(scaleX, scaleY, 1);\n } else {\n // No auto-fit: always show at actual size (1:1)\n scale = 1;\n }\n\n const scaledWidth = this.image.naturalWidth * scale;\n const scaledHeight = this.image.naturalHeight * scale;\n\n // Store offset and scale for coordinate conversions\n this.imageOffsetX = (this.canvasWidth - scaledWidth) / 2;\n this.imageOffsetY = (this.canvasHeight - scaledHeight) / 2;\n this.imageScale = scale;\n\n console.log('Updated image offset:', this.imageOffsetX, this.imageOffsetY, 'scale:', this.imageScale, 'autoFit:', this.autoFit);\n }\n\n // Override setCanvasSize to update image offset when canvas is resized\n setCanvasSize(size) {\n super.setCanvasSize(size);\n\n // Update image offset after canvas resize\n if (this.image && this.isLoaded) {\n this.updateImageOffset();\n }\n }\n\n // Override renderImage to scale and center the image (consistent with coordinate conversion)\n renderImage() {\n if (!this.image) return;\n\n // Calculate scale to fit image in canvas\n const scaleX = this.canvasWidth / this.image.naturalWidth;\n const scaleY = this.canvasHeight / this.image.naturalHeight;\n\n let scale;\n if (this.autoFit) {\n // Auto-fit: scale down if image is larger than canvas, but don't scale up\n scale = Math.min(scaleX, scaleY, 1);\n } else {\n // No auto-fit: always show at actual size (1:1)\n scale = 1;\n }\n\n // Calculate centered position\n const scaledWidth = this.image.naturalWidth * scale;\n const scaledHeight = this.image.naturalHeight * scale;\n const x = (this.canvasWidth - scaledWidth) / 2;\n const y = (this.canvasHeight - scaledHeight) / 2;\n\n // Draw scaled and centered image\n this.context.drawImage(this.image, x, y, scaledWidth, scaledHeight);\n }\n\n setupCropListeners() {\n if (!this.canvas) return;\n\n // Mouse events for crop interaction\n this.canvas.addEventListener('mousedown', (e) => this.handleMouseDown(e));\n document.addEventListener('mousemove', this._handleMouseMove);\n document.addEventListener('mouseup', this._handleMouseUp);\n\n // Touch events\n this.canvas.addEventListener('touchstart', (e) => this.handleTouchStart(e), { passive: false });\n this.canvas.addEventListener('touchmove', (e) => this.handleTouchMove(e), { passive: false });\n this.canvas.addEventListener('touchend', (e) => this.handleTouchEnd(e));\n\n // Set default cursor\n this.canvas.style.cursor = 'crosshair';\n }\n\n // Override renderCanvas to include crop overlay\n renderCanvas() {\n super.renderCanvas();\n\n if (this.cropMode) {\n this.renderCropOverlay();\n }\n }\n\n renderCropOverlay() {\n if (!this.cropMode || !this.cropBox) return;\n\n // Convert crop box from image coordinates to canvas coordinates\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n // Save context state\n this.context.save();\n\n // Create crop hole - fill entire canvas then clear crop area\n this.context.globalAlpha = 0.5;\n this.context.fillStyle = '#000000';\n this.context.fillRect(0, 0, this.canvasWidth, this.canvasHeight);\n\n // Clear crop area (creates transparent hole)\n this.context.globalCompositeOperation = 'destination-out';\n this.context.fillRect(\n canvasBox.x,\n canvasBox.y,\n canvasBox.width,\n canvasBox.height\n );\n\n // Reset composite operation\n this.context.globalCompositeOperation = 'source-over';\n\n // Draw crop box border\n this.context.globalAlpha = 1.0;\n this.context.strokeStyle = 'rgba(255, 255, 255, 0.9)';\n this.context.lineWidth = 2;\n this.context.strokeRect(\n canvasBox.x,\n canvasBox.y,\n canvasBox.width,\n canvasBox.height\n );\n\n // Draw grid lines if enabled\n if (this.showGrid) {\n this.drawGrid();\n }\n\n // Draw resize handles\n this.drawHandles();\n\n // Restore context state\n this.context.restore();\n }\n\n // Override parent's exportImageBlob to export only the cropped area without overlay\n exportImageBlob(quality = 0.9) {\n if (!this.canvas || !this.image || !this.isLoaded || !this.cropMode) {\n // Fallback to parent implementation if crop mode not active\n return super.exportImageBlob(quality);\n }\n\n return new Promise((resolve) => {\n try {\n console.log('[ImageCropView] Exporting cropped image without overlay');\n console.log('[ImageCropView] Crop box:', this.cropBox);\n \n // Calculate the actual crop area in image coordinates\n const cropArea = {\n x: Math.max(0, Math.min(this.cropBox.x, this.image.naturalWidth)),\n y: Math.max(0, Math.min(this.cropBox.y, this.image.naturalHeight)),\n width: Math.min(this.cropBox.width, this.image.naturalWidth - this.cropBox.x),\n height: Math.min(this.cropBox.height, this.image.naturalHeight - this.cropBox.y)\n };\n\n console.log('[ImageCropView] Crop area in image coords:', cropArea);\n\n // Handle cropAndScale option\n let outputWidth = cropArea.width;\n let outputHeight = cropArea.height;\n \n if (this.cropAndScale) {\n outputWidth = this.cropAndScale.width;\n outputHeight = this.cropAndScale.height;\n console.log('[ImageCropView] Scaling to:', outputWidth, 'x', outputHeight);\n }\n\n // Create temporary canvas for cropped image\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = outputWidth;\n tempCanvas.height = outputHeight;\n const tempContext = tempCanvas.getContext('2d');\n\n // Draw the cropped portion of the image\n tempContext.drawImage(\n this.image,\n cropArea.x, cropArea.y, cropArea.width, cropArea.height, // Source rectangle\n 0, 0, outputWidth, outputHeight // Destination rectangle\n );\n\n // Export the cropped image\n tempCanvas.toBlob((blob) => {\n console.log('[ImageCropView] Successfully exported cropped image blob:', blob?.size, 'bytes');\n resolve(blob);\n }, 'image/png', quality);\n } catch (error) {\n console.error('Failed to export cropped image blob:', error);\n resolve(null);\n }\n });\n }\n\n drawGrid() {\n // Convert crop box to canvas coordinates for grid rendering\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n this.context.globalAlpha = 0.6;\n this.context.strokeStyle = 'rgba(255, 255, 255, 0.7)';\n this.context.lineWidth = 1;\n\n const thirdW = canvasBox.width / 3;\n const thirdH = canvasBox.height / 3;\n\n // Vertical lines\n for (let i = 1; i < 3; i++) {\n const x = canvasBox.x + (thirdW * i);\n this.context.beginPath();\n this.context.moveTo(x, canvasBox.y);\n this.context.lineTo(x, canvasBox.y + canvasBox.height);\n this.context.stroke();\n }\n\n // Horizontal lines\n for (let i = 1; i < 3; i++) {\n const y = canvasBox.y + (thirdH * i);\n this.context.beginPath();\n this.context.moveTo(canvasBox.x, y);\n this.context.lineTo(canvasBox.x + canvasBox.width, y);\n this.context.stroke();\n }\n }\n\n drawHandles() {\n // Don't draw resize handles for fixed crop size\n if (this.fixedCropSize) return;\n\n // Convert crop box to canvas coordinates for handle rendering\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n this.context.globalAlpha = 1.0;\n this.context.fillStyle = '#ffffff';\n this.context.strokeStyle = '#000000';\n this.context.lineWidth = 1;\n\n Object.keys(this.handles).forEach(handleName => {\n const handle = this.handles[handleName];\n const centerX = canvasBox.x + (canvasBox.width * handle.x);\n const centerY = canvasBox.y + (canvasBox.height * handle.y);\n const x = centerX - this.handleSize / 2;\n const y = centerY - this.handleSize / 2;\n\n // Draw handle\n this.context.fillRect(x, y, this.handleSize, this.handleSize);\n this.context.strokeRect(x, y, this.handleSize, this.handleSize);\n });\n }\n\n // Mouse interaction\n handleMouseDown(e) {\n if (!this.cropMode) return;\n\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n // Convert canvas coordinates to image coordinates for storage\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n this.dragStartImageX = imagePoint.x;\n this.dragStartImageY = imagePoint.y;\n this.initialCropBox = { ...this.cropBox };\n\n if (this.fixedCropSize) {\n // For fixed crop size, only allow moving the crop box\n if (this.isPointInCropBox(canvasX, canvasY)) {\n\n this.isDragging = true;\n this.canvas.style.cursor = 'move';\n }\n } else {\n // Check if clicking on a resize handle\n const handle = this.getHandleAt(canvasX, canvasY);\n\n if (handle) {\n\n this.isResizing = true;\n this.dragHandle = handle;\n this.canvas.style.cursor = this.handles[handle].cursor;\n } else if (this.isPointInCropBox(canvasX, canvasY)) {\n // Clicking inside crop box - start moving\n\n this.isDragging = true;\n this.canvas.style.cursor = 'move';\n } else {\n // Clicking outside - start new crop box\n\n this.startNewCrop(imagePoint.x, imagePoint.y);\n }\n }\n }\n\n handleMouseMove(e) {\n if (!this.cropMode) return;\n\n const rect = this.canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n if (this.isResizing && this.dragHandle) {\n this.resizeCropBox(canvasX, canvasY);\n } else if (this.isDragging) {\n this.moveCropBox(canvasX, canvasY);\n } else if (!this.isDragging && !this.isResizing) {\n // Update cursor based on what's under mouse\n this.updateCursor(canvasX, canvasY);\n }\n }\n\n handleMouseUp(e) {\n if (!this.cropMode) return;\n\n this.isDragging = false;\n this.isResizing = false;\n this.dragHandle = null;\n this.initialCropBox = null;\n this.newCropStart = null; // Clear new crop state\n\n const rect = this.canvas.getBoundingClientRect();\n const canvasX = e.clientX - rect.left;\n const canvasY = e.clientY - rect.top;\n\n this.updateCursor(canvasX, canvasY);\n }\n\n // Touch events\n handleTouchStart(e) {\n if (!this.cropMode || e.touches.length !== 1) return;\n\n e.preventDefault();\n const touch = e.touches[0];\n const rect = this.canvas.getBoundingClientRect();\n const _x = touch.clientX - rect.left;\n const _y = touch.clientY - rect.top;\n\n // Convert touch to mouse event\n this.handleMouseDown({ clientX: touch.clientX, clientY: touch.clientY, preventDefault: () => {} });\n }\n\n handleTouchMove(_e) {\n if (!this.cropMode || _e.touches.length !== 1) return;\n\n _e.preventDefault();\n const touch = _e.touches[0];\n\n // Convert touch to mouse event\n this.handleMouseMove({ clientX: touch.clientX, clientY: touch.clientY });\n }\n\n handleTouchEnd(_e) {\n if (!this.cropMode) return;\n\n this.handleMouseUp({});\n }\n\n // Crop utility methods\n getHandleAt(canvasX, canvasY) {\n const hitAreaPadding = 4; // Extra pixels around handle for easier clicking\n const canvasBox = this.imageToCanvas(this.cropBox);\n\n for (const [handleName, handle] of Object.entries(this.handles)) {\n // Calculate center position the same way as drawing\n const handleCenterX = canvasBox.x + (canvasBox.width * handle.x);\n const handleCenterY = canvasBox.y + (canvasBox.height * handle.y);\n\n // Create expanded hit area around the center\n const hitAreaSize = this.handleSize + hitAreaPadding;\n const handleX = handleCenterX - hitAreaSize / 2;\n const handleY = handleCenterY - hitAreaSize / 2;\n\n if (canvasX >= handleX && canvasX <= handleX + hitAreaSize &&\n canvasY >= handleY && canvasY <= handleY + hitAreaSize) {\n return handleName;\n }\n }\n return null;\n }\n\n isPointInCropBox(canvasX, canvasY) {\n // Convert canvas coordinates to image coordinates and check if point is in crop box\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n return imagePoint.x >= this.cropBox.x && imagePoint.x <= this.cropBox.x + this.cropBox.width &&\n imagePoint.y >= this.cropBox.y && imagePoint.y <= this.cropBox.y + this.cropBox.height;\n }\n\n updateCursor(canvasX, canvasY) {\n if (!this.cropMode) return;\n\n // Image is at (0,0) so canvas coordinates = image coordinates\n const imageX = canvasX;\n const imageY = canvasY;\n\n if (this.fixedCropSize) {\n // For fixed size crops, only show move cursor when over crop box\n if (this.isPointInCropBox(imageX, imageY)) {\n this.canvas.style.cursor = 'move';\n } else {\n this.canvas.style.cursor = 'default';\n }\n } else {\n const handle = this.getHandleAt(canvasX, canvasY);\n if (handle) {\n this.canvas.style.cursor = this.handles[handle].cursor;\n } else if (this.isPointInCropBox(imageX, imageY)) {\n this.canvas.style.cursor = 'move';\n } else {\n this.canvas.style.cursor = 'crosshair';\n }\n }\n }\n\n startNewCrop(x, y) {\n // Store the initial click point for proper rectangle creation\n this.newCropStart = { x: x, y: y };\n this.cropBox = {\n x: x,\n y: y,\n width: 0,\n height: 0\n };\n this.isResizing = true;\n this.dragHandle = 'se'; // Start with bottom-right handle\n }\n\n resizeCropBox(canvasX, canvasY) {\n if (!this.dragHandle) return;\n\n // Convert canvas coordinates to image coordinates\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n\n // Handle new crop creation differently\n if (this.newCropStart) {\n // Creating new crop box - calculate from start point to current mouse position\n const startX = this.newCropStart.x;\n const startY = this.newCropStart.y;\n\n this.cropBox = {\n x: Math.min(startX, imagePoint.x),\n y: Math.min(startY, imagePoint.y),\n width: Math.abs(imagePoint.x - startX),\n height: Math.abs(imagePoint.y - startY)\n };\n\n // Apply aspect ratio constraint if set\n if (this.aspectRatio) {\n this.constrainToAspectRatio(this.cropBox, 'se');\n }\n\n // Ensure minimum size\n if (this.cropBox.width < this.minCropSize) {\n this.cropBox.width = this.minCropSize;\n }\n if (this.cropBox.height < this.minCropSize) {\n this.cropBox.height = this.minCropSize;\n }\n\n this.constrainCropBox(this.cropBox);\n return;\n }\n\n // Normal handle resizing\n if (!this.initialCropBox) return;\n\n // Calculate deltas in image coordinates\n const deltaX = imagePoint.x - this.dragStartImageX;\n const deltaY = imagePoint.y - this.dragStartImageY;\n\n let newBox = { ...this.initialCropBox };\n\n // Apply resize based on handle\n switch (this.dragHandle) {\n case 'nw':\n newBox.x += deltaX;\n newBox.y += deltaY;\n newBox.width -= deltaX;\n newBox.height -= deltaY;\n break;\n case 'ne':\n newBox.y += deltaY;\n newBox.width += deltaX;\n newBox.height -= deltaY;\n break;\n case 'sw':\n newBox.x += deltaX;\n newBox.width -= deltaX;\n newBox.height += deltaY;\n break;\n case 'se':\n newBox.width += deltaX;\n newBox.height += deltaY;\n break;\n case 'n':\n newBox.y += deltaY;\n newBox.height -= deltaY;\n break;\n case 's':\n newBox.height += deltaY;\n break;\n case 'w':\n newBox.x += deltaX;\n newBox.width -= deltaX;\n break;\n case 'e':\n newBox.width += deltaX;\n break;\n }\n\n // Apply aspect ratio constraint if set\n if (this.aspectRatio) {\n this.constrainToAspectRatio(newBox, this.dragHandle);\n }\n\n this.constrainCropBox(newBox);\n\n this.cropBox = newBox;\n this.renderCanvas();\n }\n\n moveCropBox(canvasX, canvasY) {\n if (!this.initialCropBox) return;\n\n // Convert to image coordinates and calculate deltas\n const imagePoint = this.pointCanvasToImage(canvasX, canvasY);\n const deltaX = imagePoint.x - this.dragStartImageX;\n const deltaY = imagePoint.y - this.dragStartImageY;\n\n let newBox = {\n x: this.initialCropBox.x + deltaX,\n y: this.initialCropBox.y + deltaY,\n width: this.initialCropBox.width,\n height: this.initialCropBox.height\n };\n\n // Keep within image bounds\n if (this.image) {\n newBox.x = Math.max(0, Math.min(this.image.naturalWidth - newBox.width, newBox.x));\n newBox.y = Math.max(0, Math.min(this.image.naturalHeight - newBox.height, newBox.y));\n }\n\n this.cropBox = newBox;\n this.renderCanvas();\n }\n\n constrainToAspectRatio(box, handle) {\n // Use cropAndScale aspect ratio if set, otherwise use explicit aspectRatio\n let ratio = this.aspectRatio;\n if (this.cropAndScale) {\n ratio = this.cropAndScale.width / this.cropAndScale.height;\n }\n\n if (!ratio) return;\n\n // Store anchor points based on handle\n let anchorX, anchorY;\n\n if (['nw', 'ne', 'sw', 'se'].includes(handle)) {\n // Corner handles - determine which corner stays fixed\n switch (handle) {\n case 'nw':\n // Bottom-right corner stays fixed\n anchorX = box.x + box.width;\n anchorY = box.y + box.height;\n break;\n case 'ne':\n // Bottom-left corner stays fixed\n anchorX = box.x;\n anchorY = box.y + box.height;\n break;\n case 'sw':\n // Top-right corner stays fixed\n anchorX = box.x + box.width;\n anchorY = box.y;\n break;\n case 'se':\n // Top-left corner stays fixed\n anchorX = box.x;\n anchorY = box.y;\n break;\n }\n\n // Adjust dimensions to match aspect ratio\n if (box.width / box.height > ratio) {\n box.width = box.height * ratio;\n } else {\n box.height = box.width / ratio;\n }\n\n // Adjust position to keep anchor point fixed\n switch (handle) {\n case 'nw':\n box.x = anchorX - box.width;\n box.y = anchorY - box.height;\n break;\n case 'ne':\n box.x = anchorX;\n box.y = anchorY - box.height;\n break;\n case 'sw':\n box.x = anchorX - box.width;\n box.y = anchorY;\n break;\n case 'se':\n box.x = anchorX;\n box.y = anchorY;\n break;\n }\n } else if (['n', 's'].includes(handle)) {\n // Vertical handles - adjust width to match height, keep horizontal center\n const centerX = box.x + box.width / 2;\n box.width = box.height * ratio;\n box.x = centerX - box.width / 2;\n } else if (['w', 'e'].includes(handle)) {\n // Horizontal handles - adjust height to match width, keep vertical center\n const centerY = box.y + box.height / 2;\n box.height = box.width / ratio;\n box.y = centerY - box.height / 2;\n }\n }\n\n constrainCropBox(box) {\n // Ensure minimum size\n box.width = Math.max(this.minCropSize, box.width);\n box.height = Math.max(this.minCropSize, box.height);\n\n // Keep within image bounds\n if (this.image) {\n if (box.x < 0) {\n box.width += box.x;\n box.x = 0;\n }\n if (box.y < 0) {\n box.height += box.y;\n box.y = 0;\n }\n if (box.x + box.width > this.image.naturalWidth) {\n box.width = this.image.naturalWidth - box.x;\n }\n if (box.y + box.height > this.image.naturalHeight) {\n box.height = this.image.naturalHeight - box.y;\n }\n }\n\n // Ensure non-negative dimensions\n box.width = Math.max(0, box.width);\n box.height = Math.max(0, box.height);\n }\n\n // Public API\n startCropMode() {\n // Make this method idempotent - safe to call multiple times\n if (this.cropMode) {\n console.log('Crop mode already active, skipping initialization');\n return;\n }\n\n this.cropMode = true;\n this.initializeCropBox();\n\n console.log('Crop mode started - SE handle should be at buffer coords (100, 100)');\n\n this.renderCanvas();\n this.emitCropEvent('crop-started');\n }\n\n exitCropMode() {\n this.cropMode = false;\n this.isDragging = false;\n this.isResizing = false;\n this.dragHandle = null;\n this.canvas.style.cursor = 'default';\n this.renderCanvas();\n this.emitCropEvent('crop-exited');\n }\n\n initializeCropBox() {\n if (!this.canvasWidth || !this.canvasHeight || !this.image) return;\n\n // Create default crop box - check for fixed size first\n const imageWidth = this.image.naturalWidth;\n const imageHeight = this.image.naturalHeight;\n\n let cropWidth, cropHeight;\n\n if (this.fixedCropSize) {\n // Use fixed crop size\n cropWidth = this.fixedCropSize.width;\n cropHeight = this.fixedCropSize.height;\n } else {\n // Use 80% of image size as default\n cropWidth = Math.floor(imageWidth * 0.8);\n cropHeight = Math.floor(imageHeight * 0.8);\n\n // Apply aspect ratio constraint if set\n let aspectRatio = this.aspectRatio;\n\n // If cropAndScale is set, calculate aspect ratio from target dimensions\n if (this.cropAndScale) {\n aspectRatio = this.cropAndScale.width / this.cropAndScale.height;\n }\n this.aspectRatio = aspectRatio;\n\n if (aspectRatio) {\n if (cropWidth / cropHeight > aspectRatio) {\n cropWidth = cropHeight * aspectRatio;\n } else {\n cropHeight = cropWidth / aspectRatio;\n }\n }\n\n // Ensure minimum size\n cropWidth = Math.max(this.minCropSize || 50, cropWidth);\n cropHeight = Math.max(this.minCropSize || 50, cropHeight);\n }\n\n // Center the crop box in the image\n const x = Math.floor((imageWidth - cropWidth) / 2);\n const y = Math.floor((imageHeight - cropHeight) / 2);\n\n this.cropBox = {\n x: x, // relative to image, not canvas\n y: y, // relative to image, not canvas\n width: cropWidth,\n height: cropHeight\n };\n\n\n }\n\n setAspectRatio(ratio) {\n this.aspectRatio = ratio;\n if (this.cropMode) {\n this.initializeCropBox();\n this.renderCanvas();\n }\n this.emitCropEvent('aspect-ratio-changed', { aspectRatio: ratio });\n }\n\n getCropData() {\n if (!this.cropBox || !this.image) return null;\n\n // Since cropBox is now stored in image coordinates, no conversion needed\n return {\n x: Math.max(0, Math.min(this.cropBox.x, this.image.naturalWidth)),\n y: Math.max(0, Math.min(this.cropBox.y, this.image.naturalHeight)),\n width: Math.min(this.cropBox.width, this.image.naturalWidth - this.cropBox.x),\n height: Math.min(this.cropBox.height, this.image.naturalHeight - this.cropBox.y),\n originalWidth: this.image.naturalWidth,\n originalHeight: this.image.naturalHeight\n };\n }\n\n async applyCrop() {\n const cropData = this.getCropData();\n if (!cropData || !this.image) {\n return null;\n }\n\n // Create new canvas for cropped image\n const croppedCanvas = document.createElement('canvas');\n const croppedContext = croppedCanvas.getContext('2d');\n\n // Set canvas size based on cropAndScale or crop dimensions\n if (this.cropAndScale) {\n // Use cropAndScale target dimensions\n croppedCanvas.width = this.cropAndScale.width;\n croppedCanvas.height = this.cropAndScale.height;\n\n // Draw cropped portion scaled to fit target dimensions\n croppedContext.drawImage(\n this.image,\n cropData.x,\n cropData.y,\n cropData.width,\n cropData.height,\n 0,\n 0,\n this.cropAndScale.width,\n this.cropAndScale.height\n );\n } else {\n // Use actual crop dimensions (no scaling)\n croppedCanvas.width = cropData.width;\n croppedCanvas.height = cropData.height;\n\n // Draw cropped portion at original size\n croppedContext.drawImage(\n this.image,\n cropData.x,\n cropData.y,\n cropData.width,\n cropData.height,\n 0,\n 0,\n cropData.width,\n cropData.height\n );\n }\n\n const croppedImageData = croppedCanvas.toDataURL('image/png');\n\n return {\n canvas: croppedCanvas,\n imageData: croppedImageData,\n cropData: cropData\n };\n }\n\n // Event emission\n emitCropEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imagecrop:${type}`, {\n view: this,\n cropBox: this.cropBox,\n aspectRatio: this.aspectRatio,\n ...data\n });\n }\n }\n\n // Toolbar control methods\n showToolbarElement() {\n if (!this.showToolbar) {\n this.showToolbar = true;\n const toolbar = this.element.querySelector('.image-crop-toolbar');\n if (toolbar) {\n toolbar.style.display = 'block';\n }\n this.updateAutoFitButtonState();\n }\n }\n\n hideToolbarElement() {\n if (this.showToolbar) {\n this.showToolbar = false;\n const toolbar = this.element.querySelector('.image-crop-toolbar');\n if (toolbar) {\n toolbar.style.display = 'none';\n }\n }\n }\n\n toggleToolbarElement() {\n if (this.showToolbar) {\n this.hideToolbarElement();\n } else {\n this.showToolbarElement();\n }\n }\n\n // Cleanup\n // Action handlers for toolbar buttons\n async onPassThruActionSetAspectRatio(e, el) {\n const ratio = el.getAttribute('data-ratio');\n const aspectRatio = ratio === 'free' ? null : parseFloat(ratio);\n this.setAspectRatio(aspectRatio);\n }\n\n async handleActionApplyCrop() {\n if (this.cropMode) {\n const result = await this.applyCrop();\n if (result && result.imageData) {\n // Load the cropped image as the new image\n this.loadImage(result.imageData);\n\n // Exit crop mode since we've applied the crop\n this.exitCropMode();\n\n // Emit the crop applied event\n this.emitCropEvent('crop-applied', { result });\n }\n }\n }\n\n async handleActionToggleAutoFit() {\n // Skip if toolbar is hidden\n if (!this.showToolbar) return;\n\n this.autoFit = !this.autoFit;\n\n // Update button state\n this.updateAutoFitButtonState();\n\n // Re-render with new scaling\n this.updateImageOffset();\n this.renderCanvas();\n\n this.emitCropEvent('auto-fit-changed', { autoFit: this.autoFit });\n }\n\n async handleActionResetCrop() {\n // Exit crop mode first\n if (this.cropMode) {\n this.exitCropMode();\n }\n\n // Reload the original image\n if (this.originalImageUrl) {\n await this.loadImage(this.originalImageUrl);\n }\n\n // Enter crop mode and initialize crop box\n this.startCropMode();\n this.emitCropEvent('crop-reset');\n }\n\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Clean up crop state\n this.cropMode = false;\n this.isDragging = false;\n this.isResizing = false;\n\n // Remove document listeners\n document.removeEventListener('mousemove', this._handleMouseMove);\n document.removeEventListener('mouseup', this._handleMouseUp);\n\n this.emitCropEvent('destroyed');\n }\n\n // Static method to show crop view in a dialog for standalone testing\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Crop Image',\n alt = 'Image',\n size = 'xl',\n aspectRatio = null,\n minCropSize = 50,\n showGrid = true,\n showToolbar = false,\n autoFit = true,\n fixedCropSize = null,\n cropAndScale = null,\n canvasSize = size || 'auto',\n ...dialogOptions\n } = options;\n\n const cropView = new ImageCropView({\n imageUrl,\n alt,\n title,\n aspectRatio,\n minCropSize,\n canvasSize: canvasSize || size || 'md',\n fixedCropSize,\n cropAndScale,\n showGrid,\n showToolbar,\n autoFit\n });\n\n const dialog = new Dialog({\n title,\n body: cropView,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n noBodyPadding: true,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Apply Crop',\n action: 'apply-crop',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n dialog.show();\n\n // Wait for dialog to be fully rendered and canvas to be properly sized\n const initializeCrop = () => {\n // Re-setup canvas after dialog is rendered\n if (cropView.setupCanvas) {\n cropView.setupCanvas();\n }\n\n // Wait for image to load, then start crop mode\n if (cropView.isLoaded && cropView.canvasWidth > 0) {\n cropView.startCropMode();\n } else {\n const checkReady = setInterval(() => {\n if (cropView.isLoaded && cropView.canvasWidth > 0) {\n clearInterval(checkReady);\n cropView.startCropMode();\n }\n }, 100);\n\n // Clear interval after 5 seconds to prevent infinite loop\n setTimeout(() => clearInterval(checkReady), 5000);\n }\n };\n\n // Use the dialog's 'shown' event to ensure it's fully rendered\n dialog.on('shown', initializeCrop);\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', view: cropView });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:apply-crop', async () => {\n let result;\n\n if (cropView.cropMode && cropView.cropBox) {\n // Crop mode is active - apply the crop\n result = await cropView.applyCrop();\n } else {\n // No active crop box - return current canvas image as-is\n const currentImageData = cropView.canvas.toDataURL('image/png');\n result = {\n canvas: cropView.canvas,\n imageData: currentImageData,\n cropData: null // No crop was applied\n };\n }\n\n dialog.hide();\n resolve({\n action: 'crop',\n view: cropView,\n data: result?.imageData,\n cropData: result?.cropData\n });\n });\n });\n }\n}\n\n// Make it available globally for testing\nwindow.ImageCropView = ImageCropView;\n","/**\n * ImageFiltersView - Canvas-based image viewer with filter effects\n * Extends ImageCanvasView with brightness, contrast, saturation and other filters\n */\n\nimport ImageCanvasView from './ImageCanvasView.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\n\nexport default class ImageFiltersView extends ImageCanvasView {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-filters-view ${options.className || ''}`,\n });\n\n // Filter state\n this.filters = {\n brightness: 100,\n contrast: 100,\n saturation: 100,\n hue: 0,\n blur: 0,\n grayscale: 0,\n sepia: 0\n };\n\n // UI Options (default to true for better usability)\n this.showControls = options.showControls ?? true;\n this.allowReset = options.allowReset ?? true;\n this.showPresets = options.showPresets ?? true;\n this.showBasicControls = options.showBasicControls ?? true;\n this.showAdvancedControls = options.showAdvancedControls ?? true;\n this.controlsInDropdowns = options.controlsInDropdowns ?? true;\n\n // Preset effects using CSS filters only\n this.presetEffects = {\n none: { name: 'Original', filters: {} },\n blackWhite: { name: 'Black & White', filters: { grayscale: 100 } },\n sepia: { name: 'Sepia', filters: { sepia: 100 } },\n vintage: { name: 'Vintage', filters: { sepia: 60, contrast: 110, brightness: 110, saturation: 80 } },\n cool: { name: 'Cool Tones', filters: { hue: 200, saturation: 120, brightness: 95 } },\n warm: { name: 'Warm Tones', filters: { hue: 25, saturation: 110, brightness: 105 } },\n vibrant: { name: 'Vibrant', filters: { brightness: 105, contrast: 115, saturation: 140, hue: 5 } },\n dramatic: { name: 'Dramatic', filters: { brightness: 90, contrast: 150, saturation: 120 } },\n soft: { name: 'Soft', filters: { brightness: 110, contrast: 85, blur: 1 } }\n };\n\n this.currentPreset = 'none';\n }\n\n async getTemplate() {\n return `\n <div class=\"image-filters-container d-flex flex-column h-100\">\n {{#showControls}}\n <!-- Filter Toolbar -->\n <div class=\"image-filters-toolbar bg-light border-bottom p-2\">\n <div class=\"btn-toolbar justify-content-center flex-wrap\" role=\"toolbar\">\n\n {{#showPresets}}\n <!-- Preset Effects -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Preset effects\">\n <div class=\"dropdown\">\n <button type=\"button\" class=\"btn btn-outline-primary btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" aria-expanded=\"false\" title=\"Preset Effects\">\n <i class=\"bi bi-palette\"></i> Effects\n </button>\n <ul class=\"dropdown-menu\">\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"none\">Original</a></li>\n <li><hr class=\"dropdown-divider\"></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"blackWhite\">Black & White</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"sepia\">Sepia</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"vintage\">Vintage</a></li>\n <li><hr class=\"dropdown-divider\"></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"cool\">Cool Tones</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"warm\">Warm Tones</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"vibrant\">Vibrant</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"dramatic\">Dramatic</a></li>\n <li><a class=\"dropdown-item\" href=\"#\" data-action=\"apply-preset\" data-preset=\"soft\">Soft</a></li>\n </ul>\n </div>\n </div>\n {{/showPresets}}\n\n {{#showBasicControls}}\n {{#controlsInDropdowns}}\n <!-- Basic Controls in Dropdown -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Basic controls\">\n <div class=\"dropdown\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" aria-expanded=\"false\" title=\"Basic Adjustments\">\n <i class=\"bi bi-sliders\"></i> Basic\n </button>\n <div class=\"dropdown-menu p-3\" style=\"min-width: 300px;\">\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Brightness</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.brightness}}\"\n data-change-action=\"filter-change\" data-filter=\"brightness\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"brightness\">{{filters.brightness}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Contrast</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.contrast}}\"\n data-change-action=\"filter-change\" data-filter=\"contrast\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"contrast\">{{filters.contrast}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"mb-0\">\n <label class=\"form-label small fw-bold\">Saturation</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.saturation}}\"\n data-change-action=\"filter-change\" data-filter=\"saturation\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"saturation\">{{filters.saturation}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n </div>\n </div>\n </div>\n {{/controlsInDropdowns}}\n {{/showBasicControls}}\n\n {{#showAdvancedControls}}\n {{#controlsInDropdowns}}\n <!-- Advanced Controls in Dropdown -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Advanced controls\">\n <div class=\"dropdown\">\n <button type=\"button\" class=\"btn btn-outline-warning btn-sm dropdown-toggle\"\n data-bs-toggle=\"dropdown\" aria-expanded=\"false\" title=\"Advanced Adjustments\">\n <i class=\"bi bi-gear\"></i> Advanced\n </button>\n <div class=\"dropdown-menu p-3\" style=\"min-width: 300px;\">\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Hue</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"360\" value=\"{{filters.hue}}\"\n data-change-action=\"filter-change\" data-filter=\"hue\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0°</small>\n <small class=\"text-muted filter-value\" data-filter=\"hue\">{{filters.hue}}°</small>\n <small class=\"text-muted\">360°</small>\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Blur</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"10\" value=\"{{filters.blur}}\"\n data-change-action=\"filter-change\" data-filter=\"blur\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0px</small>\n <small class=\"text-muted filter-value\" data-filter=\"blur\">{{filters.blur}}px</small>\n <small class=\"text-muted\">10px</small>\n </div>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label small fw-bold\">Grayscale</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.grayscale}}\"\n data-change-action=\"filter-change\" data-filter=\"grayscale\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"grayscale\">{{filters.grayscale}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n <div class=\"mb-0\">\n <label class=\"form-label small fw-bold\">Sepia</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.sepia}}\"\n data-change-action=\"filter-change\" data-filter=\"sepia\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"sepia\">{{filters.sepia}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n </div>\n </div>\n </div>\n {{/controlsInDropdowns}}\n {{/showAdvancedControls}}\n\n {{#allowReset}}\n <!-- Reset & Preview Controls -->\n <div class=\"btn-group me-2 mb-2\" role=\"group\" aria-label=\"Reset controls\">\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\" data-action=\"reset-filters\" title=\"Reset All Filters\">\n <i class=\"bi bi-arrow-repeat\"></i> Reset\n </button>\n <button type=\"button\" class=\"btn btn-outline-info btn-sm\" data-action=\"preview-original\" title=\"Preview Original\"\n onmousedown=\"this.dataset.previewing='true'\"\n onmouseup=\"this.dataset.previewing='false'\"\n onmouseleave=\"this.dataset.previewing='false'\">\n <i class=\"bi bi-eye\"></i> Original\n </button>\n </div>\n {{/allowReset}}\n\n </div>\n </div>\n {{/showControls}}\n\n <!-- Canvas Area -->\n <div class=\"image-canvas-content flex-grow-1 position-relative d-flex justify-content-center align-items-center\">\n <canvas class=\"image-filters-canvas\" data-container=\"canvas\"></canvas>\n\n <!-- Loading Overlay -->\n <div class=\"image-canvas-loading position-absolute top-50 start-50 translate-middle\"\n style=\"display: none; z-index: 10;\">\n <div class=\"spinner-border text-primary\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n </div>\n\n {{#showControls}}\n {{^controlsInDropdowns}}\n <!-- Expanded Controls Panel (when not in dropdowns) -->\n <div class=\"image-filters-controls bg-light border-top p-3\" data-container=\"controls\" style=\"max-height: 300px; overflow-y: auto;\">\n <div class=\"row g-3\">\n {{#showBasicControls}}\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Brightness</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.brightness}}\"\n data-change-action=\"filter-change\" data-filter=\"brightness\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"brightness\">{{filters.brightness}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Contrast</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.contrast}}\"\n data-change-action=\"filter-change\" data-filter=\"contrast\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"contrast\">{{filters.contrast}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Saturation</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"200\" value=\"{{filters.saturation}}\"\n data-change-action=\"filter-change\" data-filter=\"saturation\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"saturation\">{{filters.saturation}}%</small>\n <small class=\"text-muted\">200%</small>\n </div>\n </div>\n {{/showBasicControls}}\n\n {{#showAdvancedControls}}\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Hue</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"360\" value=\"{{filters.hue}}\"\n data-change-action=\"filter-change\" data-filter=\"hue\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0°</small>\n <small class=\"text-muted filter-value\" data-filter=\"hue\">{{filters.hue}}°</small>\n <small class=\"text-muted\">360°</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Blur</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"10\" value=\"{{filters.blur}}\"\n data-change-action=\"filter-change\" data-filter=\"blur\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0px</small>\n <small class=\"text-muted filter-value\" data-filter=\"blur\">{{filters.blur}}px</small>\n <small class=\"text-muted\">10px</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Grayscale</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.grayscale}}\"\n data-change-action=\"filter-change\" data-filter=\"grayscale\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"grayscale\">{{filters.grayscale}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n <div class=\"col-md-6 col-lg-4\">\n <label class=\"form-label small fw-bold\">Sepia</label>\n <input type=\"range\" class=\"form-range\"\n min=\"0\" max=\"100\" value=\"{{filters.sepia}}\"\n data-change-action=\"filter-change\" data-filter=\"sepia\">\n <div class=\"d-flex justify-content-between\">\n <small class=\"text-muted\">0%</small>\n <small class=\"text-muted filter-value\" data-filter=\"sepia\">{{filters.sepia}}%</small>\n <small class=\"text-muted\">100%</small>\n </div>\n </div>\n {{/showAdvancedControls}}\n </div>\n </div>\n {{/controlsInDropdowns}}\n {{/showControls}}\n </div>\n `;\n }\n\n\n\n\n\n async onAfterRender() {\n await super.onAfterRender();\n\n // Cache control elements\n this.controlsElement = this.element.querySelector('.image-filters-controls');\n }\n\n // Override canvas sizing for container-aware dimensions\n setupCanvas() {\n if (!this.canvas || !this.containerElement) return;\n\n // Use container-aware sizing for dialogs and embedded contexts\n this.setCanvasSize(this.canvasSize);\n\n // Simple resize listener (only for fullscreen mode or container changes)\n if (this.canvasSize === 'fullscreen' || this.canvasSize === 'auto') {\n this._resizeHandler = () => this.setCanvasSize(this.canvasSize);\n window.addEventListener('resize', this._resizeHandler);\n }\n\n // Set up canvas context\n this.context.imageSmoothingEnabled = true;\n this.context.imageSmoothingQuality = 'high';\n }\n\n // Override setCanvasSize to be more container-aware for dialogs\n setCanvasSize(size) {\n if (!this.canvas || !this.containerElement) return;\n\n // For 'auto' sizing, be more aware of the actual container\n if (size === 'auto') {\n const container = this.containerElement;\n let availableWidth = container.clientWidth - 40;\n let availableHeight = container.clientHeight - 40;\n\n // If container doesn't have explicit dimensions, walk up DOM\n if (availableWidth <= 40 || availableHeight <= 40) {\n let parent = container.parentElement;\n while (parent && (parent.clientWidth <= 40 || parent.clientHeight <= 40)) {\n parent = parent.parentElement;\n\n // Stop at common container types\n if (parent && (\n parent.classList.contains('modal-body') ||\n parent.classList.contains('card-body') ||\n parent.classList.contains('dialog-body') ||\n parent.tagName === 'MAIN' ||\n parent.tagName === 'BODY'\n )) {\n break;\n }\n }\n\n if (parent) {\n availableWidth = parent.clientWidth - 80;\n availableHeight = parent.clientHeight - 80;\n }\n }\n\n // If we have valid container dimensions, use them\n if (availableWidth > 100 && availableHeight > 100) {\n let canvasWidth, canvasHeight;\n\n if (this.image) {\n const imageAspect = this.image.naturalWidth / this.image.naturalHeight;\n const availableAspect = availableWidth / availableHeight;\n\n if (imageAspect > availableAspect) {\n canvasWidth = availableWidth;\n canvasHeight = availableWidth / imageAspect;\n } else {\n canvasHeight = availableHeight;\n canvasWidth = availableHeight * imageAspect;\n }\n\n // Ensure minimum size\n canvasWidth = Math.max(300, Math.floor(canvasWidth));\n canvasHeight = Math.max(200, Math.floor(canvasHeight));\n } else {\n // No image yet - use available space with reasonable limits\n canvasWidth = Math.min(600, Math.max(300, availableWidth));\n canvasHeight = Math.min(450, Math.max(200, availableHeight));\n }\n\n // Apply the calculated size\n this.applyCanvasSize(canvasWidth, canvasHeight);\n return;\n }\n }\n\n // Fallback to parent class sizing for all other cases\n super.setCanvasSize(size);\n }\n\n // Helper method to apply calculated canvas size\n applyCanvasSize(canvasWidth, canvasHeight) {\n // Don't resize if dimensions haven't changed significantly\n if (Math.abs(canvasWidth - this.canvasWidth) < 10 &&\n Math.abs(canvasHeight - this.canvasHeight) < 10) {\n return;\n }\n\n const dpr = window.devicePixelRatio || 1;\n\n this.canvasWidth = canvasWidth;\n this.canvasHeight = canvasHeight;\n\n this.canvas.width = canvasWidth * dpr;\n this.canvas.height = canvasHeight * dpr;\n\n this.canvas.style.width = canvasWidth + 'px';\n this.canvas.style.height = canvasHeight + 'px';\n\n this.context.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (this.isLoaded) {\n this.renderCanvas();\n }\n }\n\n // Override image loading to re-render with current filters\n async loadImage(imageUrl) {\n await super.loadImage(imageUrl);\n\n // Re-render with current filters\n this.renderCanvas();\n }\n\n // Override renderImage to apply filters consistently\n renderImage() {\n if (!this.image) return;\n\n // Apply CSS filters to context (includes both slider values and preset effects)\n this.context.filter = this.getFilterString();\n\n // Calculate scale to fit image in canvas (consistent with new sizing system)\n const imageScale = Math.min(\n this.canvasWidth / this.image.naturalWidth,\n this.canvasHeight / this.image.naturalHeight\n );\n\n const scaledWidth = this.image.naturalWidth * imageScale;\n const scaledHeight = this.image.naturalHeight * imageScale;\n const x = (this.canvasWidth - scaledWidth) / 2;\n const y = (this.canvasHeight - scaledHeight) / 2;\n\n // Draw scaled and centered image\n this.context.drawImage(this.image, x, y, scaledWidth, scaledHeight);\n\n // Reset filter\n this.context.filter = 'none';\n }\n\n // Get combined filter values from both sliders and current preset\n getCombinedFilters() {\n const combined = { ...this.filters };\n\n // Apply preset filters on top of slider values\n if (this.currentPreset !== 'none' && this.presetEffects[this.currentPreset]) {\n const presetFilters = this.presetEffects[this.currentPreset].filters;\n if (presetFilters) {\n Object.assign(combined, presetFilters);\n }\n }\n\n return combined;\n }\n\n getFilterString() {\n const filters = this.getCombinedFilters();\n\n if (!this.hasFilters() && this.currentPreset === 'none') return 'none';\n\n return [\n `brightness(${filters.brightness}%)`,\n `contrast(${filters.contrast}%)`,\n `saturate(${filters.saturation}%)`,\n `hue-rotate(${filters.hue}deg)`,\n `blur(${filters.blur}px)`,\n `grayscale(${filters.grayscale}%)`,\n `sepia(${filters.sepia}%)`\n ].join(' ');\n }\n\n hasFilters() {\n return this.filters.brightness !== 100 ||\n this.filters.contrast !== 100 ||\n this.filters.saturation !== 100 ||\n this.filters.hue !== 0 ||\n this.filters.blur !== 0 ||\n this.filters.grayscale !== 0 ||\n this.filters.sepia !== 0;\n }\n\n // Action Handlers\n async onPassThruActionResetFilters() {\n this.resetFilters();\n }\n\n async onPassThruActionApplyPreset(e, el) {\n e.preventDefault();\n const presetName = el.getAttribute('data-preset');\n if (presetName && this.presetEffects[presetName]) {\n this.applyPreset(presetName);\n }\n }\n\n async onPassThruActionPreviewOriginal(e, el) {\n const isPreviewing = el.dataset.previewing === 'true';\n\n if (isPreviewing) {\n // Show original (no filters)\n this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);\n this.context.filter = 'none';\n const x = (this.canvasWidth - this.image.naturalWidth) / 2;\n const y = (this.canvasHeight - this.image.naturalHeight) / 2;\n this.context.drawImage(this.image, x, y);\n } else {\n // Show with filters\n this.renderCanvas();\n }\n }\n\n // Change Handler for filter sliders\n async onChangeFilterChange(e, el) {\n const filterName = el.getAttribute('data-filter');\n const value = parseFloat(el.value);\n\n this.updateFilter(filterName, value);\n }\n\n // Filter methods\n updateFilter(name, value) {\n if (!(name in this.filters)) return;\n\n const oldValue = this.filters[name];\n this.filters[name] = value;\n\n // Update the display value\n this.updateFilterDisplay(name, value);\n\n // Re-render with new filters\n this.renderCanvas();\n\n // Emit filter change event\n this.emitFilterEvent('filter-changed', {\n filter: name,\n oldValue,\n newValue: value,\n allFilters: { ...this.filters }\n });\n }\n\n updateFilterDisplay(name, value) {\n const valueElement = this.element.querySelector(`[data-filter=\"${name}\"].filter-value`);\n if (valueElement) {\n const unit = name === 'hue' ? '°' : name === 'blur' ? 'px' : '%';\n valueElement.textContent = `${value}${unit}`;\n }\n }\n\n resetFilters() {\n const oldFilters = { ...this.filters };\n const oldPreset = this.currentPreset;\n\n this.filters = {\n brightness: 100,\n contrast: 100,\n saturation: 100,\n hue: 0,\n blur: 0,\n grayscale: 0,\n sepia: 0\n };\n\n // Reset preset\n this.currentPreset = 'none';\n\n // Update all input values and displays\n this.updateAllFilterInputs();\n\n // Re-render\n this.renderCanvas();\n\n // Emit reset event\n this.emitFilterEvent('filters-reset', {\n oldFilters,\n newFilters: { ...this.filters },\n oldPreset,\n newPreset: this.currentPreset\n });\n }\n\n updateAllFilterInputs() {\n Object.keys(this.filters).forEach(filterName => {\n const input = this.element.querySelector(`[data-filter=\"${filterName}\"][type=\"range\"]`);\n if (input) {\n input.value = this.filters[filterName];\n this.updateFilterDisplay(filterName, this.filters[filterName]);\n }\n });\n }\n\n // Enhanced preset system\n applyPreset(presetName) {\n if (!this.presetEffects[presetName]) return;\n\n const preset = this.presetEffects[presetName];\n\n // Set current preset\n this.currentPreset = presetName;\n\n // Set current preset (CSS filters will handle the effect)\n this.currentPreset = presetName;\n\n // Re-render\n this.renderCanvas();\n\n this.emitFilterEvent('preset-applied', { preset: presetName, filters: { ...this.filters } });\n }\n\n\n\n // State management\n getFilterState() {\n return { ...this.filters };\n }\n\n setFilterState(filters) {\n this.filters = { ...this.filters, ...filters };\n this.updateAllFilterInputs();\n this.renderCanvas();\n this.emitFilterEvent('filters-set', { filters: { ...this.filters } });\n }\n\n // Export with filters applied\n exportFilteredImageData() {\n if (!this.canvas) return null;\n\n // The canvas already has filters applied from renderImage\n return this.exportImageData();\n }\n\n async exportFilteredImageBlob(quality = 0.9) {\n if (!this.canvas) return null;\n\n // The canvas already has filters applied from renderImage\n return this.exportImageBlob(quality);\n }\n\n // Create a new canvas with original image + filters applied\n createFilteredCanvas() {\n if (!this.image) return null;\n\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('2d');\n\n canvas.width = this.image.naturalWidth;\n canvas.height = this.image.naturalHeight;\n\n // Apply filters and draw original image\n context.filter = this.getFilterString();\n context.drawImage(this.image, 0, 0);\n context.filter = 'none';\n\n return canvas;\n }\n\n // Event emission\n emitFilterEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imagefilters:${type}`, {\n view: this,\n hasFilters: this.hasFilters(),\n filterString: this.getFilterString(),\n ...data\n });\n }\n }\n\n // Override handleImageLoad to emit filter-ready event\n handleImageLoad() {\n super.handleImageLoad();\n this.emitFilterEvent('ready', { filters: { ...this.filters } });\n }\n\n // Cleanup\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove resize listener\n if (this._resizeHandler) {\n window.removeEventListener('resize', this._resizeHandler);\n }\n\n this.emitFilterEvent('destroyed');\n }\n\n // Static method to show filters view in a dialog for standalone testing\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Apply Filters',\n alt = 'Image',\n size = 'xl',\n showControls = true,\n allowReset = true,\n showPresets = true,\n showBasicControls = true,\n showAdvancedControls = true,\n controlsInDropdowns = true,\n canvasSize = 'auto',\n autoFit = true,\n crossOrigin = 'anonymous',\n ...dialogOptions\n } = options;\n\n const filtersView = new ImageFiltersView({\n imageUrl,\n alt,\n title,\n canvasSize,\n autoFit,\n crossOrigin,\n showControls,\n allowReset,\n showPresets,\n showBasicControls,\n showAdvancedControls,\n controlsInDropdowns\n });\n\n const dialog = new Dialog({\n title,\n body: filtersView,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n noBodyPadding: true,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Apply Filters',\n action: 'apply-filters',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', view: filtersView });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:apply-filters', async () => {\n const imageData = filtersView.exportFilteredImageData();\n dialog.hide();\n resolve({\n action: 'filters',\n view: filtersView,\n data: imageData,\n filterState: filtersView.getFilterState()\n });\n });\n });\n }\n}\n\nwindow.ImageFiltersView = ImageFiltersView;\n","/**\n * ImageEditor - Modular parent container for image editing functionality\n * Manages child views: ImageTransformView, ImageCropView, ImageFiltersView\n */\n\nimport View from '@core/View.js';\nimport Dialog from '@core/views/feedback/Dialog.js';\nimport ImageTransformView from './ImageTransformView.js';\nimport ImageCropView from './ImageCropView.js';\nimport ImageFiltersView from './ImageFiltersView.js';\n\nexport default class ImageEditor extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-editor ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Image properties\n this.imageUrl = options.imageUrl || options.src || '';\n this.alt = options.alt || 'Image';\n this.title = options.title || '';\n \n // Current edited image data (preserved across mode switches)\n this.currentImageData = null;\n\n // Current editing mode\n this.currentMode = options.startMode || 'transform'; // 'transform', 'crop', 'filters'\n\n // History for undo/redo\n this.history = [];\n this.historyIndex = -1;\n this.maxHistory = options.maxHistory || 20;\n\n // Template properties (set directly on instance for Mustache)\n this.showToolbar = options.showToolbar !== false;\n this.allowTransform = options.allowTransform !== false;\n this.allowCrop = options.allowCrop !== false;\n this.allowFilters = options.allowFilters !== false;\n this.allowExport = options.allowExport !== false;\n this.allowHistory = options.allowHistory !== false;\n\n // Current active view (created on demand)\n this.currentView = null;\n\n // State\n this.isInitialized = false;\n }\n\n async getTemplate() {\n return `\n <div class=\"image-editor-container d-flex flex-column h-100\">\n {{#showToolbar}}\n <!-- Toolbar -->\n <div class=\"image-editor-toolbar bg-light border-bottom p-3\" data-container=\"toolbar\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <!-- Mode Buttons -->\n <div class=\"btn-group\" role=\"group\" aria-label=\"Editing modes\">\n {{#allowTransform}}\n <button type=\"button\" class=\"btn btn-outline-primary mode-btn\"\n data-action=\"switch-mode\" data-mode=\"transform\"\n title=\"Transform: Zoom, Pan, Rotate\">\n <i class=\"bi bi-arrows-move\"></i> Transform\n </button>\n {{/allowTransform}}\n\n {{#allowCrop}}\n <button type=\"button\" class=\"btn btn-outline-primary mode-btn\"\n data-action=\"switch-mode\" data-mode=\"crop\"\n title=\"Crop: Select and crop image\">\n <i class=\"bi bi-crop\"></i> Crop\n </button>\n {{/allowCrop}}\n\n {{#allowFilters}}\n <button type=\"button\" class=\"btn btn-outline-primary mode-btn\"\n data-action=\"switch-mode\" data-mode=\"filters\"\n title=\"Filters: Brightness, Contrast, Effects\">\n <i class=\"bi bi-palette\"></i> Filters\n </button>\n {{/allowFilters}}\n </div>\n\n <!-- Action Buttons -->\n <div class=\"btn-group\" role=\"group\" aria-label=\"Actions\">\n {{#allowHistory}}\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\"\n data-action=\"undo\" title=\"Undo\" disabled>\n <i class=\"bi bi-arrow-counterclockwise\"></i>\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\"\n data-action=\"redo\" title=\"Redo\" disabled>\n <i class=\"bi bi-arrow-clockwise\"></i>\n </button>\n {{/allowHistory}}\n\n <button type=\"button\" class=\"btn btn-outline-secondary btn-sm\"\n data-action=\"reset\" title=\"Reset All Changes\">\n <i class=\"bi bi-arrow-repeat\"></i>\n </button>\n\n {{#allowExport}}\n <button type=\"button\" class=\"btn btn-success btn-sm\"\n data-action=\"export\" title=\"Export Image\">\n <i class=\"bi bi-download\"></i> Export\n </button>\n {{/allowExport}}\n </div>\n </div>\n\n\n </div>\n {{/showToolbar}}\n\n <!-- Main editing area where child views will be mounted -->\n <div class=\"image-editor-workspace flex-grow-1 position-relative\" data-container=\"image-workspace\">\n <!-- Child views will be added here dynamically -->\n </div>\n\n <!-- Status bar -->\n <div class=\"image-editor-status bg-light border-top p-2\" data-container=\"status\">\n <div class=\"d-flex justify-content-between align-items-center\">\n <small class=\"text-muted\">\n Mode: <span class=\"current-mode fw-bold\">Transform</span>\n </small>\n <small class=\"text-muted\">\n <span class=\"image-info\">Ready</span>\n </small>\n </div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.toolbarElement = this.element.querySelector('.image-editor-toolbar');\n this.workspaceElement = this.element.querySelector('.image-editor-workspace');\n this.statusElement = this.element.querySelector('.image-editor-status');\n\n\n // Set up event listeners for child views\n this.setupChildViewEvents();\n\n // Set initial mode\n await this.switchMode(this.currentMode, true);\n\n // Initialize history\n this.saveState();\n\n this.isInitialized = true;\n }\n\n createChildView(mode) {\n // Use the edited image data if available, otherwise use original\n const imageToUse = this.currentImageData || this.imageUrl;\n console.log('[ImageEditor] Creating', mode, 'view with:', \n this.currentImageData ? 'preserved canvas data' : 'original image');\n \n const childOptions = {\n parent: this,\n containerId: \"image-workspace\",\n imageUrl: imageToUse,\n alt: this.alt,\n title: this.title\n };\n\n switch (mode) {\n case 'transform':\n if (!this.allowTransform) return null;\n return new ImageTransformView({\n ...childOptions,\n allowPan: true,\n allowZoom: true,\n allowRotate: true\n });\n case 'crop':\n if (!this.allowCrop) return null;\n return new ImageCropView({\n ...childOptions,\n showGrid: true,\n minCropSize: 50\n });\n case 'filters':\n if (!this.allowFilters) return null;\n return new ImageFiltersView({\n ...childOptions,\n showControls: true,\n allowReset: true\n });\n default:\n return null;\n }\n }\n\n setupChildViewEvents() {\n const eventBus = this.getApp()?.events;\n if (!eventBus) return;\n\n // Listen to child view events for history tracking\n eventBus.on('imagetransform:scale-changed', () => this.saveState());\n eventBus.on('imagetransform:rotated', () => this.saveState());\n eventBus.on('imagetransform:reset', () => this.saveState());\n\n // Crop applied permanently changes the image, so capture it\n eventBus.on('imagecrop:crop-applied', (data) => {\n // Store the cropped image as the current edited state\n const imageData = this.getCurrentImageData();\n if (imageData) {\n console.log('[ImageEditor] Crop applied - updating preserved canvas data');\n this.currentImageData = imageData;\n }\n this.saveState();\n \n // Provide user feedback\n this.updateStatus('Crop applied successfully');\n \n // Update the history buttons since we saved state\n this.updateHistoryButtons();\n });\n\n eventBus.on('imagefilters:filter-changed', () => {\n this.saveState();\n this.updateStatus('Filter applied');\n });\n \n eventBus.on('imagefilters:filters-reset', () => {\n this.saveState();\n this.updateStatus('Filters reset');\n });\n }\n\n // Action handlers\n async handleActionSwitchMode(e, el) {\n const mode = el.getAttribute('data-mode');\n await this.switchMode(mode);\n }\n\n\n\n async handleActionUndo() {\n this.undo();\n }\n\n async handleActionRedo() {\n this.redo();\n }\n\n async handleActionReset() {\n await this.resetAll();\n }\n\n async handleActionExport() {\n const result = await this.exportImage();\n if (result) {\n this.updateStatus('Image exported successfully');\n }\n }\n\n // Mode management\n async switchMode(mode, force=false) {\n if (mode === this.currentMode && !force) return;\n\n // Capture current canvas state before destroying view\n if (this.currentView && !force) {\n // Get the current edited image data using the consistent method\n const imageData = this.getCurrentImageData();\n \n // Store it for the next view\n if (imageData) {\n console.log('[ImageEditor] Preserving canvas state from', this.currentMode, 'mode');\n this.currentImageData = imageData;\n } else {\n console.log('[ImageEditor] No canvas data to preserve from', this.currentMode, 'mode');\n }\n } else if (force) {\n console.log('[ImageEditor] Force mode switch - not preserving canvas state');\n }\n\n // Destroy current view if it exists\n if (this.currentView) {\n await this.currentView.destroy();\n this.currentView = null;\n }\n\n\n\n // Update button states\n const modeButtons = this.element.querySelectorAll('.mode-btn');\n modeButtons.forEach(btn => {\n btn.classList.remove('active');\n if (btn.getAttribute('data-mode') === mode) {\n btn.classList.add('active');\n }\n });\n\n // Create and render new view\n this.currentMode = mode;\n this.currentView = this.createChildView(mode);\n\n if (this.currentView) {\n await this.currentView.render();\n\n // Mode-specific initialization\n if (mode === 'crop' && this.currentView.startCropMode) {\n this.currentView.startCropMode();\n this.updateStatus('Click and drag to select crop area');\n } else if (mode === 'transform') {\n this.updateStatus('Use controls to transform the image');\n } else if (mode === 'filters') {\n this.updateStatus('Adjust filters to enhance the image');\n }\n }\n\n // Update status\n this.updateCurrentModeDisplay();\n\n // Emit mode change event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageeditor:mode-changed', {\n editor: this,\n mode: mode,\n currentView: this.currentView\n });\n }\n }\n\n updateCurrentModeDisplay() {\n const modeDisplay = this.element.querySelector('.current-mode');\n if (modeDisplay) {\n modeDisplay.textContent = this.currentMode.charAt(0).toUpperCase() + this.currentMode.slice(1);\n }\n }\n\n updateStatus(message) {\n const infoDisplay = this.element.querySelector('.image-info');\n if (infoDisplay) {\n infoDisplay.textContent = message;\n }\n }\n\n // History management\n saveState() {\n if (!this.isInitialized) return;\n\n const state = {\n mode: this.currentMode,\n transform: this.currentView?.getTransformState?.(),\n filters: this.currentView?.getFilterState?.(),\n imageData: this.currentImageData,\n timestamp: Date.now()\n };\n\n // Remove any states after current index (when undoing then making new changes)\n this.history = this.history.slice(0, this.historyIndex + 1);\n\n // Add new state\n this.history.push(state);\n this.historyIndex = this.history.length - 1;\n\n // Keep within max history limit\n if (this.history.length > this.maxHistory) {\n this.history.shift();\n this.historyIndex--;\n }\n\n this.updateHistoryButtons();\n }\n\n undo() {\n if (this.historyIndex > 0) {\n this.historyIndex--;\n this.restoreState(this.history[this.historyIndex]);\n }\n }\n\n redo() {\n if (this.historyIndex < this.history.length - 1) {\n this.historyIndex++;\n this.restoreState(this.history[this.historyIndex]);\n }\n }\n\n async restoreState(state) {\n // Restore the image data if it exists\n if (state.imageData) {\n console.log('[ImageEditor] Restoring preserved canvas data from history');\n this.currentImageData = state.imageData;\n }\n \n // Switch to the mode from the state \n await this.switchMode(state.mode, true); // Force to use the restored image data\n\n // Restore state for current view\n if (this.currentView) {\n if (state.transform && this.currentView.setTransformState) {\n this.currentView.setTransformState(state.transform);\n }\n if (state.filters && this.currentView.setFilterState) {\n this.currentView.setFilterState(state.filters);\n }\n }\n\n this.updateHistoryButtons();\n this.updateStatus(`Restored to ${state.mode} mode`);\n }\n\n updateHistoryButtons() {\n const undoBtn = this.element.querySelector('[data-action=\"undo\"]');\n const redoBtn = this.element.querySelector('[data-action=\"redo\"]');\n\n if (undoBtn) undoBtn.disabled = this.historyIndex <= 0;\n if (redoBtn) redoBtn.disabled = this.historyIndex >= this.history.length - 1;\n }\n\n async resetAll() {\n // Clear the edited image data to reset to original\n console.log('[ImageEditor] Resetting - clearing preserved canvas data');\n this.currentImageData = null;\n \n // Reset current view\n if (this.currentView && this.currentView.reset) {\n this.currentView.reset();\n }\n\n // Switch back to transform mode with force flag to use original image\n await this.switchMode('transform', true);\n\n // Clear history and save new state\n this.history = [];\n this.historyIndex = -1;\n this.saveState();\n\n this.updateStatus('All changes reset');\n }\n\n // Export functionality\n async exportImage() {\n if (!this.currentView) return null;\n\n try {\n let imageData = null;\n\n // Get the processed image from the current view\n imageData = this.getCurrentImageData();\n\n if (imageData) {\n // Trigger download\n const link = document.createElement('a');\n link.download = this.getExportFilename();\n link.href = imageData;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n\n // Emit export event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageeditor:exported', {\n editor: this,\n imageData: imageData,\n filename: link.download\n });\n }\n\n return { imageData, filename: link.download };\n }\n } catch (error) {\n console.error('Export failed:', error);\n this.updateStatus('Export failed');\n }\n\n return null;\n }\n\n getExportFilename() {\n const timestamp = new Date().toISOString().slice(0, 19).replace(/[:\\-]/g, '');\n return `edited-image-${timestamp}.png`;\n }\n\n // Public API\n async setImage(imageUrl, alt = '', title = '') {\n console.log('[ImageEditor] Setting new image - clearing preserved canvas data');\n this.imageUrl = imageUrl;\n this.alt = alt;\n this.title = title;\n \n // Clear any edited data\n this.currentImageData = null;\n\n // Update current view\n if (this.currentView && this.currentView.setImage) {\n this.currentView.setImage(imageUrl, alt, title);\n }\n\n // Reset state\n await this.resetAll();\n }\n\n getCurrentImageData() {\n if (!this.currentView) return null;\n \n // Get the current edited image data based on view type\n let imageData = null;\n if (this.currentView.exportImageData) {\n imageData = this.currentView.exportImageData();\n } else if (this.currentView.exportFilteredImageData) {\n imageData = this.currentView.exportFilteredImageData();\n }\n \n return imageData || null;\n }\n\n // Cleanup\n async onBeforeDestroy() {\n // Clean up current view\n if (this.currentView) {\n await this.currentView.destroy();\n this.currentView = null;\n }\n\n // Emit destroy event\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit('imageeditor:destroyed', { editor: this });\n }\n }\n\n // Static method to show editor in a fullscreen dialog\n static async showDialog(imageUrl, options = {}) {\n const {\n title = 'Image Editor',\n alt = 'Image',\n size = 'fullscreen',\n showToolbar = true,\n allowTransform = true,\n allowCrop = true,\n allowFilters = true,\n allowExport = true,\n ...dialogOptions\n } = options;\n\n const editor = new ImageEditor({\n imageUrl,\n alt,\n title,\n showToolbar,\n allowTransform,\n allowCrop,\n allowFilters,\n allowExport\n });\n\n const dialog = new Dialog({\n title,\n body: editor,\n size,\n centered: true,\n backdrop: 'static',\n keyboard: true,\n buttons: [\n {\n text: 'Cancel',\n action: 'cancel',\n class: 'btn btn-secondary',\n dismiss: true\n },\n {\n text: 'Export & Close',\n action: 'export-close',\n class: 'btn btn-primary'\n }\n ],\n ...dialogOptions\n });\n\n // Render and mount\n await dialog.render(true, document.body);\n\n // Show the dialog\n window.lastDialog = dialog;\n dialog.show();\n\n return new Promise((resolve) => {\n dialog.on('hidden', () => {\n dialog.destroy();\n resolve({ action: 'cancel', editor });\n });\n\n dialog.on('action:cancel', () => {\n dialog.hide();\n });\n\n dialog.on('action:export-close', async () => {\n const result = await editor.exportImage();\n dialog.hide();\n resolve({\n action: 'export',\n editor,\n data: result?.imageData,\n filename: result?.filename\n });\n });\n });\n }\n}\n\nwindow.ImageEditor = ImageEditor;\n","/**\n * ImageUploadView - Drag and drop image upload component\n * Provides file selection, preview, and upload functionality\n */\n\nimport View from '@core/View.js';\n\nexport default class ImageUploadView extends View {\n constructor(options = {}) {\n super({\n ...options,\n className: `image-upload-view ${options.className || ''}`,\n tagName: 'div'\n });\n\n // Upload options\n this.autoUpload = options.autoUpload || false;\n this.acceptedTypes = options.acceptedTypes || ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];\n this.maxFileSize = options.maxFileSize || 10 * 1024 * 1024; // 10MB default\n this.uploadUrl = options.uploadUrl || null;\n this.onUpload = options.onUpload || null; // Callback function\n\n // State\n this.selectedFile = null;\n this.isUploading = false;\n this.previewUrl = null;\n\n // Bind handlers for cleanup\n this._handleDragOver = this.handleDragOver.bind(this);\n this._handleDragLeave = this.handleDragLeave.bind(this);\n this._handleDrop = this.handleDrop.bind(this);\n this._handleFileSelect = this.handleFileSelect.bind(this);\n this._preventDefaults = this.preventDefaults.bind(this);\n }\n\n async getTemplate() {\n return `\n <div class=\"image-upload-container\">\n <!-- Drop Zone -->\n <div class=\"upload-drop-zone border-2 border-dashed rounded p-4 text-center position-relative\" \n style=\"border-color: #dee2e6; min-height: 200px; transition: all 0.2s ease;\">\n \n <!-- Default State -->\n <div class=\"upload-prompt\">\n <i class=\"bi bi-cloud-upload text-muted\" style=\"font-size: 3rem;\"></i>\n <h5 class=\"mt-3 text-muted\">Drop your image here</h5>\n <p class=\"text-muted mb-3\">or</p>\n <button type=\"button\" class=\"btn btn-outline-primary\" data-action=\"select-file\">\n <i class=\"bi bi-folder2-open\"></i> Choose File\n </button>\n <input type=\"file\" class=\"upload-file-input d-none\" accept=\"image/*\" multiple=\"false\">\n <div class=\"mt-3\">\n <small class=\"text-muted\">Supported: JPEG, PNG, GIF, WebP (max ${Math.round(this.maxFileSize / 1024 / 1024)}MB)</small>\n </div>\n </div>\n \n <!-- Preview State -->\n <div class=\"upload-preview d-none\">\n <div class=\"preview-image-container mb-3\">\n <img class=\"preview-image img-fluid rounded shadow-sm\" style=\"max-height: 300px; max-width: 100%;\">\n </div>\n <div class=\"preview-info\">\n <div class=\"file-name fw-bold mb-2 text-truncate\"></div>\n <div class=\"file-details text-muted small mb-3\"></div>\n <div class=\"upload-actions\">\n {{#autoUpload}}\n <button type=\"button\" class=\"btn btn-outline-secondary\" data-action=\"clear\">\n <i class=\"bi bi-x\"></i> Clear\n </button>\n {{/autoUpload}}\n {{^autoUpload}}\n <button type=\"button\" class=\"btn btn-success me-2\" data-action=\"upload\">\n <i class=\"bi bi-cloud-arrow-up\"></i> Upload\n </button>\n <button type=\"button\" class=\"btn btn-outline-secondary\" data-action=\"clear\">\n <i class=\"bi bi-x\"></i> Clear\n </button>\n {{/autoUpload}}\n </div>\n </div>\n </div>\n \n <!-- Loading State -->\n <div class=\"upload-loading d-none\">\n <div class=\"spinner-border text-primary mb-3\" role=\"status\">\n <span class=\"visually-hidden\">Uploading...</span>\n </div>\n <div class=\"upload-progress\">\n <div class=\"progress mb-2\" style=\"height: 8px;\">\n <div class=\"progress-bar progress-bar-striped progress-bar-animated\" \n role=\"progressbar\" style=\"width: 0%\"></div>\n </div>\n <small class=\"text-muted upload-status\">Uploading...</small>\n </div>\n </div>\n </div>\n \n <!-- Upload Result -->\n <div class=\"upload-result mt-3 d-none\">\n <div class=\"alert\" role=\"alert\"></div>\n </div>\n </div>\n `;\n }\n\n async onAfterRender() {\n // Cache DOM elements\n this.dropZone = this.element.querySelector('.upload-drop-zone');\n this.fileInput = this.element.querySelector('.upload-file-input');\n this.promptElement = this.element.querySelector('.upload-prompt');\n this.previewElement = this.element.querySelector('.upload-preview');\n this.loadingElement = this.element.querySelector('.upload-loading');\n this.resultElement = this.element.querySelector('.upload-result');\n this.previewImage = this.element.querySelector('.preview-image');\n this.fileName = this.element.querySelector('.file-name');\n this.fileDetails = this.element.querySelector('.file-details');\n this.progressBar = this.element.querySelector('.progress-bar');\n this.uploadStatus = this.element.querySelector('.upload-status');\n\n // Set up event listeners\n this.setupEventListeners();\n }\n\n setupEventListeners() {\n // Drag and drop events\n this.dropZone.addEventListener('dragenter', this._preventDefaults);\n this.dropZone.addEventListener('dragover', this._handleDragOver);\n this.dropZone.addEventListener('dragleave', this._handleDragLeave);\n this.dropZone.addEventListener('drop', this._handleDrop);\n\n // File input change\n this.fileInput.addEventListener('change', this._handleFileSelect);\n\n // Prevent default drag behaviors on document\n ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {\n document.addEventListener(eventName, this._preventDefaults);\n });\n }\n\n preventDefaults(e) {\n e.preventDefault();\n e.stopPropagation();\n }\n\n handleDragOver(e) {\n this.preventDefaults(e);\n this.dropZone.classList.add('border-primary', 'bg-light');\n this.dropZone.style.borderColor = '#0d6efd';\n }\n\n handleDragLeave(e) {\n this.preventDefaults(e);\n \n // Only remove styles if we're actually leaving the drop zone\n if (!this.dropZone.contains(e.relatedTarget)) {\n this.dropZone.classList.remove('border-primary', 'bg-light');\n this.dropZone.style.borderColor = '#dee2e6';\n }\n }\n\n async handleDrop(e) {\n this.preventDefaults(e);\n \n this.dropZone.classList.remove('border-primary', 'bg-light');\n this.dropZone.style.borderColor = '#dee2e6';\n \n const files = Array.from(e.dataTransfer.files);\n if (files.length > 0) {\n await this.processFile(files[0]);\n }\n }\n\n async handleFileSelect(e) {\n const files = Array.from(e.target.files);\n if (files.length > 0) {\n await this.processFile(files[0]);\n }\n }\n\n async processFile(file) {\n // Validate file\n const validation = this.validateFile(file);\n if (!validation.valid) {\n this.showError(validation.error);\n return;\n }\n\n this.selectedFile = file;\n \n // Show preview\n await this.showPreview(file);\n \n // Auto upload if enabled\n if (this.autoUpload) {\n setTimeout(() => this.uploadFile(), 100); // Small delay to show preview\n }\n }\n\n validateFile(file) {\n // Check file type\n if (!this.acceptedTypes.includes(file.type)) {\n return {\n valid: false,\n error: `File type \"${file.type}\" is not supported. Please use: ${this.acceptedTypes.map(t => t.split('/')[1].toUpperCase()).join(', ')}`\n };\n }\n\n // Check file size\n if (file.size > this.maxFileSize) {\n return {\n valid: false,\n error: `File size (${this.formatFileSize(file.size)}) exceeds maximum allowed size (${this.formatFileSize(this.maxFileSize)})`\n };\n }\n\n return { valid: true };\n }\n\n async showPreview(file) {\n // Create preview URL\n if (this.previewUrl) {\n URL.revokeObjectURL(this.previewUrl);\n }\n this.previewUrl = URL.createObjectURL(file);\n\n // Update preview elements\n this.previewImage.src = this.previewUrl;\n this.fileName.textContent = file.name;\n this.fileDetails.textContent = `${this.formatFileSize(file.size)} • ${file.type.split('/')[1].toUpperCase()}`;\n\n // Show preview, hide prompt\n this.promptElement.classList.add('d-none');\n this.previewElement.classList.remove('d-none');\n\n // Clear any previous results\n this.hideResult();\n\n // Emit preview event\n this.emitUploadEvent('preview', { file, previewUrl: this.previewUrl });\n }\n\n async uploadFile() {\n if (!this.selectedFile || this.isUploading) return;\n\n this.isUploading = true;\n this.showLoading();\n\n try {\n let result;\n\n if (this.onUpload && typeof this.onUpload === 'function') {\n // Use callback function\n result = await this.onUpload(this.selectedFile, this.updateProgress.bind(this));\n } else if (this.uploadUrl) {\n // Use built-in upload to URL\n result = await this.uploadToUrl(this.selectedFile);\n } else {\n throw new Error('No upload method configured. Provide either uploadUrl or onUpload callback.');\n }\n\n this.showSuccess('File uploaded successfully!');\n this.emitUploadEvent('upload-success', { file: this.selectedFile, result });\n\n } catch (error) {\n console.error('Upload failed:', error);\n this.showError(`Upload failed: ${error.message}`);\n this.emitUploadEvent('upload-error', { file: this.selectedFile, error });\n } finally {\n this.isUploading = false;\n this.hideLoading();\n }\n }\n\n async uploadToUrl(file) {\n return new Promise((resolve, reject) => {\n const formData = new FormData();\n formData.append('image', file);\n\n const xhr = new XMLHttpRequest();\n\n // Progress handler\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n const progress = Math.round((e.loaded / e.total) * 100);\n this.updateProgress(progress);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const response = JSON.parse(xhr.responseText);\n resolve(response);\n } catch (e) {\n resolve({ success: true, response: xhr.responseText });\n }\n } else {\n reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Network error occurred'));\n });\n\n xhr.addEventListener('timeout', () => {\n reject(new Error('Upload timeout'));\n });\n\n xhr.open('POST', this.uploadUrl);\n xhr.timeout = 30000; // 30 second timeout\n xhr.send(formData);\n });\n }\n\n updateProgress(percent) {\n if (this.progressBar) {\n this.progressBar.style.width = `${percent}%`;\n this.progressBar.setAttribute('aria-valuenow', percent);\n }\n if (this.uploadStatus) {\n this.uploadStatus.textContent = `Uploading... ${percent}%`;\n }\n }\n\n showLoading() {\n this.previewElement.classList.add('d-none');\n this.loadingElement.classList.remove('d-none');\n this.updateProgress(0);\n }\n\n hideLoading() {\n this.loadingElement.classList.add('d-none');\n if (!this.autoUpload || this.selectedFile) {\n this.previewElement.classList.remove('d-none');\n }\n }\n\n showSuccess(message) {\n this.showResult('success', message);\n }\n\n showError(message) {\n this.showResult('danger', message);\n }\n\n showResult(type, message) {\n const alertElement = this.resultElement.querySelector('.alert');\n const icon = type === 'success' ? 'check-circle-fill' : 'exclamation-triangle-fill';\n \n alertElement.className = `alert alert-${type}`;\n alertElement.innerHTML = `\n <i class=\"bi bi-${icon} me-2\"></i>\n ${message}\n `;\n\n this.resultElement.classList.remove('d-none');\n\n // Auto-hide success messages after 5 seconds\n if (type === 'success') {\n setTimeout(() => this.hideResult(), 5000);\n }\n }\n\n hideResult() {\n this.resultElement.classList.add('d-none');\n }\n\n clearFile() {\n // Clean up\n if (this.previewUrl) {\n URL.revokeObjectURL(this.previewUrl);\n this.previewUrl = null;\n }\n\n this.selectedFile = null;\n this.isUploading = false;\n this.fileInput.value = '';\n\n // Reset UI\n this.previewElement.classList.add('d-none');\n this.loadingElement.classList.add('d-none');\n this.promptElement.classList.remove('d-none');\n this.hideResult();\n\n this.emitUploadEvent('cleared');\n }\n\n formatFileSize(bytes) {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n }\n\n emitUploadEvent(type, data = {}) {\n const eventBus = this.getApp()?.events;\n if (eventBus) {\n eventBus.emit(`imageupload:${type}`, {\n view: this,\n ...data\n });\n }\n }\n\n // Action handlers\n async handleActionSelectFile() {\n this.fileInput.click();\n }\n\n async handleActionUpload() {\n await this.uploadFile();\n }\n\n async handleActionClear() {\n this.clearFile();\n }\n\n // Cleanup\n async onBeforeDestroy() {\n // Clean up preview URL\n if (this.previewUrl) {\n URL.revokeObjectURL(this.previewUrl);\n this.previewUrl = null;\n }\n\n // Remove event listeners\n if (this.dropZone) {\n this.dropZone.removeEventListener('dragenter', this._preventDefaults);\n this.dropZone.removeEventListener('dragover', this._handleDragOver);\n this.dropZone.removeEventListener('dragleave', this._handleDragLeave);\n this.dropZone.removeEventListener('drop', this._handleDrop);\n }\n\n if (this.fileInput) {\n this.fileInput.removeEventListener('change', this._handleFileSelect);\n }\n\n // Remove document listeners\n ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {\n document.removeEventListener(eventName, this._preventDefaults);\n });\n\n this.emitUploadEvent('destroyed');\n }\n}\n\nwindow.ImageUploadView = ImageUploadView;"],"names":[],"mappings":"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CvB;AAAA,EAEA,MAAM,cAAc;AAClB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0QT;AAAA,EAMA,MAAM,gBAAgB;AACpB,UAAM,MAAM,cAAa;AAGzB,SAAK,kBAAkB,KAAK,QAAQ,cAAc,yBAAyB;AAAA,EAC7E;AAAA;AAAA,EAGA,cAAc;AACZ,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,iBAAkB;AAG5C,SAAK,cAAc,KAAK,UAAU;AAGlC,QAAI,KAAK,eAAe,gBAAgB,KAAK,eAAe,QAAQ;AAClE,WAAK,iBAAiB,MAAM,KAAK,cAAc,KAAK,UAAU;AAC9D,aAAO,iBAAiB,UAAU,KAAK,cAAc;AAAA,IACvD;AAGA,SAAK,QAAQ,wBAAwB;AACrC,SAAK,QAAQ,wBAAwB;AAAA,EACvC;AAAA;AAAA,EAGA,cAAc,MAAM;AAClB,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,iBAAkB;AAG5C,QAAI,SAAS,QAAQ;AACnB,YAAM,YAAY,KAAK;AACvB,UAAI,iBAAiB,UAAU,cAAc;AAC7C,UAAI,kBAAkB,UAAU,eAAe;AAG/C,UAAI,kBAAkB,MAAM,mBAAmB,IAAI;AACjD,YAAI,SAAS,UAAU;AACvB,eAAO,WAAW,OAAO,eAAe,MAAM,OAAO,gBAAgB,KAAK;AACxE,mBAAS,OAAO;AAGhB,cAAI,WACF,OAAO,UAAU,SAAS,YAAY,KACtC,OAAO,UAAU,SAAS,WAAW,KACrC,OAAO,UAAU,SAAS,aAAa,KACvC,OAAO,YAAY,UACnB,OAAO,YAAY,SAClB;AACD;AAAA,UACF;AAAA,QACF;AAEA,YAAI,QAAQ;AACV,2BAAiB,OAAO,cAAc;AACtC,4BAAkB,OAAO,eAAe;AAAA,QAC1C;AAAA,MACF;AAGA,UAAI,iBAAiB,OAAO,kBAAkB,KAAK;AACjD,YAAI,aAAa;AAEjB,YAAI,KAAK,OAAO;AACd,gBAAM,cAAc,KAAK,MAAM,eAAe,KAAK,MAAM;AACzD,gBAAM,kBAAkB,iBAAiB;AAEzC,cAAI,cAAc,iBAAiB;AACjC,0BAAc;AACd,2BAAe,iBAAiB;AAAA,UAClC,OAAO;AACL,2BAAe;AACf,0BAAc,kBAAkB;AAAA,UAClC;AAGA,wBAAc,KAAK,IAAI,KAAK,KAAK,MAAM,WAAW,CAAC;AACnD,yBAAe,KAAK,IAAI,KAAK,KAAK,MAAM,YAAY,CAAC;AAAA,QACvD,OAAO;AAEL,wBAAc,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,cAAc,CAAC;AACzD,yBAAe,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,CAAC;AAAA,QAC7D;AAGA,aAAK,gBAAgB,aAAa,YAAY;AAC9C;AAAA,MACF;AAAA,IACF;AAGA,UAAM,cAAc,IAAI;AAAA,EAC1B;AAAA;AAAA,EAGA,gBAAgB,aAAa,cAAc;AAEzC,QAAI,KAAK,IAAI,cAAc,KAAK,WAAW,IAAI,MAC3C,KAAK,IAAI,eAAe,KAAK,YAAY,IAAI,IAAI;AACnD;AAAA,IACF;AAEA,UAAM,MAAM,OAAO,oBAAoB;AAEvC,SAAK,cAAc;AACnB,SAAK,eAAe;AAEpB,SAAK,OAAO,QAAQ,cAAc;AAClC,SAAK,OAAO,SAAS,eAAe;AAEpC,SAAK,OAAO,MAAM,QAAQ,cAAc;AACxC,SAAK,OAAO,MAAM,SAAS,eAAe;AAE1C,SAAK,QAAQ,aAAa,KAAK,GAAG,GAAG,KAAK,GAAG,CAAC;AAE9C,QAAI,KAAK,UAAU;AACjB,WAAK,aAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,UAAU,UAAU;AACxB,UAAM,MAAM,UAAU,QAAQ;AAG9B,SAAK,aAAY;AAAA,EACnB;AAAA;AAAA,EAGA,cAAc;AACZ,QAAI,CAAC,KAAK,MAAO;AAGjB,SAAK,QAAQ,SAAS,KAAK,gBAAe;AAG1C,UAAM,aAAa,KAAK;AAAA,MACtB,KAAK,cAAc,KAAK,MAAM;AAAA,MAC9B,KAAK,eAAe,KAAK,MAAM;AAAA,IACrC;AAEI,UAAM,cAAc,KAAK,MAAM,eAAe;AAC9C,UAAM,eAAe,KAAK,MAAM,gBAAgB;AAChD,UAAM,KAAK,KAAK,cAAc,eAAe;AAC7C,UAAM,KAAK,KAAK,eAAe,gBAAgB;AAG/C,SAAK,QAAQ,UAAU,KAAK,OAAO,GAAG,GAAG,aAAa,YAAY;AAGlE,SAAK,QAAQ,SAAS;AAAA,EACxB;AAAA;AAAA,EAGA,qBAAqB;AACnB,UAAM,WAAW,EAAE,GAAG,KAAK,QAAO;AAGlC,QAAI,KAAK,kBAAkB,UAAU,KAAK,cAAc,KAAK,aAAa,GAAG;AAC3E,YAAM,gBAAgB,KAAK,cAAc,KAAK,aAAa,EAAE;AAC7D,UAAI,eAAe;AACjB,eAAO,OAAO,UAAU,aAAa;AAAA,MACvC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,kBAAkB;AAChB,UAAM,UAAU,KAAK,mBAAkB;AAEvC,QAAI,CAAC,KAAK,WAAU,KAAM,KAAK,kBAAkB,OAAQ,QAAO;AAEhE,WAAO;AAAA,MACL,cAAc,QAAQ,UAAU;AAAA,MAChC,YAAY,QAAQ,QAAQ;AAAA,MAC5B,YAAY,QAAQ,UAAU;AAAA,MAC9B,cAAc,QAAQ,GAAG;AAAA,MACzB,QAAQ,QAAQ,IAAI;AAAA,MACpB,aAAa,QAAQ,SAAS;AAAA,MAC9B,SAAS,QAAQ,KAAK;AAAA,IAC5B,EAAM,KAAK,GAAG;AAAA,EACZ;AAAA,EAEA,aAAa;AACX,WAAO,KAAK,QAAQ,eAAe,OAC5B,KAAK,QAAQ,aAAa,OAC1B,KAAK,QAAQ,eAAe,OAC5B,KAAK,QAAQ,QAAQ,KACrB,KAAK,QAAQ,SAAS,KACtB,KAAK,QAAQ,cAAc,KAC3B,KAAK,QAAQ,UAAU;AAAA,EAChC;AAAA;AAAA,EAGA,MAAM,+BAA+B;AACnC,SAAK,aAAY;AAAA,EACnB;AAAA,EAEA,MAAM,4BAA4B,GAAG,IAAI;AACrC,MAAE,eAAc;AAClB,UAAM,aAAa,GAAG,aAAa,aAAa;AAChD,QAAI,cAAc,KAAK,cAAc,UAAU,GAAG;AAChD,WAAK,YAAY,UAAU;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,gCAAgC,GAAG,IAAI;AAC3C,UAAM,eAAe,GAAG,QAAQ,eAAe;AAE/C,QAAI,cAAc;AAEhB,WAAK,QAAQ,UAAU,GAAG,GAAG,KAAK,aAAa,KAAK,YAAY;AAChE,WAAK,QAAQ,SAAS;AACtB,YAAM,KAAK,KAAK,cAAc,KAAK,MAAM,gBAAgB;AACzD,YAAM,KAAK,KAAK,eAAe,KAAK,MAAM,iBAAiB;AAC3D,WAAK,QAAQ,UAAU,KAAK,OAAO,GAAG,CAAC;AAAA,IACzC,OAAO;AAEL,WAAK,aAAY;AAAA,IACnB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,qBAAqB,GAAG,IAAI;AAChC,UAAM,aAAa,GAAG,aAAa,aAAa;AAChD,UAAM,QAAQ,WAAW,GAAG,KAAK;AAEjC,SAAK,aAAa,YAAY,KAAK;AAAA,EACrC;AAAA;AAAA,EAGA,aAAa,MAAM,OAAO;AACxB,QAAI,EAAE,QAAQ,KAAK,SAAU;AAE7B,UAAM,WAAW,KAAK,QAAQ,IAAI;AAClC,SAAK,QAAQ,IAAI,IAAI;AAGrB,SAAK,oBAAoB,MAAM,KAAK;AAGpC,SAAK,aAAY;AAGjB,SAAK,gBAAgB,kBAAkB;AAAA,MACrC,QAAQ;AAAA,MACR;AAAA,MACA,UAAU;AAAA,MACV,YAAY,EAAE,GAAG,KAAK,QAAO;AAAA,IACnC,CAAK;AAAA,EACH;AAAA,EAEA,oBAAoB,MAAM,OAAO;AAC/B,UAAM,eAAe,KAAK,QAAQ,cAAc,iBAAiB,IAAI,iBAAiB;AACtF,QAAI,cAAc;AAChB,YAAM,OAAO,SAAS,QAAQ,MAAM,SAAS,SAAS,OAAO;AAC7D,mBAAa,cAAc,GAAG,KAAK,GAAG,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,eAAe;AACb,UAAM,aAAa,EAAE,GAAG,KAAK,QAAO;AACpC,UAAM,YAAY,KAAK;AAEvB,SAAK,UAAU;AAAA,MACb,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,KAAK;AAAA,MACL,MAAM;AAAA,MACN,WAAW;AAAA,MACX,OAAO;AAAA,IACb;AAGI,SAAK,gBAAgB;AAGrB,SAAK,sBAAqB;AAG1B,SAAK,aAAY;AAGjB,SAAK,gBAAgB,iBAAiB;AAAA,MACpC;AAAA,MACA,YAAY,EAAE,GAAG,KAAK,QAAO;AAAA,MAC7B;AAAA,MACA,WAAW,KAAK;AAAA,IACtB,CAAK;AAAA,EACH;AAAA,EAEA,wBAAwB;AACtB,WAAO,KAAK,KAAK,OAAO,EAAE,QAAQ,gBAAc;AAC9C,YAAM,QAAQ,KAAK,QAAQ,cAAc,iBAAiB,UAAU,kBAAkB;AACtF,UAAI,OAAO;AACT,cAAM,QAAQ,KAAK,QAAQ,UAAU;AACrC,aAAK,oBAAoB,YAAY,KAAK,QAAQ,UAAU,CAAC;AAAA,MAC/D;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,YAAY,YAAY;AACtB,QAAI,CAAC,KAAK,cAAc,UAAU,EAAG;AAEtB,SAAK,cAAc,UAAU;AAG5C,SAAK,gBAAgB;AAGrB,SAAK,gBAAgB;AAGrB,SAAK,aAAY;AAEjB,SAAK,gBAAgB,kBAAkB,EAAE,QAAQ,YAAY,SAAS,EAAE,GAAG,KAAK,QAAO,GAAI;AAAA,EAC7F;AAAA;AAAA,EAKA,iBAAiB;AACf,WAAO,EAAE,GAAG,KAAK,QAAO;AAAA,EAC1B;AAAA,EAEA,eAAe,SAAS;AACtB,SAAK,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,QAAO;AAC5C,SAAK,sBAAqB;AAC1B,SAAK,aAAY;AACjB,SAAK,gBAAgB,eAAe,EAAE,SAAS,EAAE,GAAG,KAAK,QAAO,GAAI;AAAA,EACtE;AAAA;AAAA,EAGA,0BAA0B;AACxB,QAAI,CAAC,KAAK,OAAQ,QAAO;AAGzB,WAAO,KAAK,gBAAe;AAAA,EAC7B;AAAA,EAEA,MAAM,wBAAwB,UAAU,KAAK;AAC3C,QAAI,CAAC,KAAK,OAAQ,QAAO;AAGzB,WAAO,KAAK,gBAAgB,OAAO;AAAA,EACrC;AAAA;AAAA,EAGA,uBAAuB;AACrB,QAAI,CAAC,KAAK,MAAO,QAAO;AAExB,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,UAAM,UAAU,OAAO,WAAW,IAAI;AAEtC,WAAO,QAAQ,KAAK,MAAM;AAC1B,WAAO,SAAS,KAAK,MAAM;AAG3B,YAAQ,SAAS,KAAK,gBAAe;AACrC,YAAQ,UAAU,KAAK,OAAO,GAAG,CAAC;AAClC,YAAQ,SAAS;AAEjB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,gBAAgB,MAAM,OAAO,IAAI;AAC/B,UAAM,WAAW,KAAK,OAAM,GAAI;AAChC,QAAI,UAAU;AACZ,eAAS,KAAK,gBAAgB,IAAI,IAAI;AAAA,QACpC,MAAM;AAAA,QACN,YAAY,KAAK,WAAU;AAAA,QAC3B,cAAc,KAAK,gBAAe;AAAA,QAClC,GAAG;AAAA,MACX,CAAO;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,kBAAkB;AAChB,UAAM,gBAAe;AACrB,SAAK,gBAAgB,SAAS,EAAE,SAAS,EAAE,GAAG,KAAK,QAAO,GAAI;AAAA,EAChE;AAAA;AAAA,EAGA,MAAM,kBAAkB;AACtB,UAAM,MAAM,gBAAe;AAG3B,QAAI,KAAK,gBAAgB;AACvB,aAAO,oBAAoB,UAAU,KAAK,cAAc;AAAA,IAC1D;AAEA,SAAK,gBAAgB,WAAW;AAAA,EAClC;AAAA;AAAA,EAGA,aAAa,WAAW,UAAU,UAAU,IAAI;AAC9C,UAAM;AAAA,MACJ,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,eAAe;AAAA,MACf,aAAa;AAAA,MACb,cAAc;AAAA,MACd,oBAAoB;AAAA,MACpB,uBAAuB;AAAA,MACvB,sBAAsB;AAAA,MACtB,aAAa;AAAA,MACb,UAAU;AAAA,MACV,cAAc;AAAA,MACd,GAAG;AAAA,IACT,IAAQ;AAEJ,UAAM,cAAc,IAAI,iBAAiB;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACN,CAAK;AAED,UAAM,SAAS,IAAI,OAAO;AAAA,MACxB;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,eAAe;AAAA,MACf,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,SAAS;AAAA,QACnB;AAAA,QACQ;AAAA,UACE,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,OAAO;AAAA,QACjB;AAAA,MACA;AAAA,MACM,GAAG;AAAA,IACT,CAAK;AAGD,UAAM,OAAO,OAAO,MAAM,SAAS,IAAI;AAGvC,WAAO,KAAI;AAEX,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,aAAO,GAAG,UAAU,MAAM;AACxB,eAAO,QAAO;AACd,gBAAQ,EAAE,QAAQ,UAAU,MAAM,YAAW,CAAE;AAAA,MACjD,CAAC;AAED,aAAO,GAAG,iBAAiB,MAAM;AAC/B,eAAO,KAAI;AAAA,MACb,CAAC;AAED,aAAO,GAAG,wBAAwB,YAAY;AAC5C,cAAM,YAAY,YAAY,wBAAuB;AACrD,eAAO,KAAI;AACX,gBAAQ;AAAA,UACN,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,MAAM;AAAA,UACN,aAAa,YAAY,eAAc;AAAA,QACjD,CAAS;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAEA,OAAO,mBAAmB;AC9xBX,MAAM,oBAAoB,KAAK;AAAA,EAC5C,YAAY,UAAU,IAAI;AACxB,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,WAAW,gBAAgB,QAAQ,aAAa,EAAE;AAAA,MAClD,SAAS;AAAA,IACf,CAAK;AAGD,SAAK,WAAW,QAAQ,YAAY,QAAQ,OAAO;AACnD,SAAK,MAAM,QAAQ,OAAO;AAC1B,SAAK,QAAQ,QAAQ,SAAS;AAG9B,SAAK,mBAAmB;AAGxB,SAAK,cAAc,QAAQ,aAAa;AAGxC,SAAK,UAAU,CAAA;AACf,SAAK,eAAe;AACpB,SAAK,aAAa,QAAQ,cAAc;AAGxC,SAAK,cAAc,QAAQ,gBAAgB;AAC3C,SAAK,iBAAiB,QAAQ,mBAAmB;AACjD,SAAK,YAAY,QAAQ,cAAc;AACvC,SAAK,eAAe,QAAQ,iBAAiB;AAC7C,SAAK,cAAc,QAAQ,gBAAgB;AAC3C,SAAK,eAAe,QAAQ,iBAAiB;AAG7C,SAAK,cAAc;AAGnB,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,MAAM,cAAc;AAClB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkFT;AAAA,EAEA,MAAM,gBAAgB;AAEpB,SAAK,iBAAiB,KAAK,QAAQ,cAAc,uBAAuB;AACxE,SAAK,mBAAmB,KAAK,QAAQ,cAAc,yBAAyB;AAC5E,SAAK,gBAAgB,KAAK,QAAQ,cAAc,sBAAsB;AAItE,SAAK,qBAAoB;AAGzB,UAAM,KAAK,WAAW,KAAK,aAAa,IAAI;AAG5C,SAAK,UAAS;AAEd,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,gBAAgB,MAAM;AAEpB,UAAM,aAAa,KAAK,oBAAoB,KAAK;AACjD,YAAQ;AAAA,MAAI;AAAA,MAA0B;AAAA,MAAM;AAAA,MAC1C,KAAK,mBAAmB,0BAA0B;AAAA,IAAgB;AAEpE,UAAM,eAAe;AAAA,MACnB,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,UAAU;AAAA,MACV,KAAK,KAAK;AAAA,MACV,OAAO,KAAK;AAAA,IAClB;AAEI,YAAQ,MAAI;AAAA,MACV,KAAK;AACH,YAAI,CAAC,KAAK,eAAgB,QAAO;AACjC,eAAO,IAAI,mBAAmB;AAAA,UAC5B,GAAG;AAAA,UACH,UAAU;AAAA,UACV,WAAW;AAAA,UACX,aAAa;AAAA,QACvB,CAAS;AAAA,MACH,KAAK;AACH,YAAI,CAAC,KAAK,UAAW,QAAO;AAC5B,eAAO,IAAI,cAAc;AAAA,UACvB,GAAG;AAAA,UACH,UAAU;AAAA,UACV,aAAa;AAAA,QACvB,CAAS;AAAA,MACH,KAAK;AACH,YAAI,CAAC,KAAK,aAAc,QAAO;AAC/B,eAAO,IAAI,iBAAiB;AAAA,UAC1B,GAAG;AAAA,UACH,cAAc;AAAA,UACd,YAAY;AAAA,QACtB,CAAS;AAAA,MACH;AACE,eAAO;AAAA,IACf;AAAA,EACE;AAAA,EAEA,uBAAuB;AACrB,UAAM,WAAW,KAAK,OAAM,GAAI;AAChC,QAAI,CAAC,SAAU;AAGf,aAAS,GAAG,gCAAgC,MAAM,KAAK,UAAS,CAAE;AAClE,aAAS,GAAG,0BAA0B,MAAM,KAAK,UAAS,CAAE;AAC5D,aAAS,GAAG,wBAAwB,MAAM,KAAK,UAAS,CAAE;AAG1D,aAAS,GAAG,0BAA0B,CAAC,SAAS;AAE9C,YAAM,YAAY,KAAK,oBAAmB;AAC1C,UAAI,WAAW;AACb,gBAAQ,IAAI,6DAA6D;AACzE,aAAK,mBAAmB;AAAA,MAC1B;AACA,WAAK,UAAS;AAGd,WAAK,aAAa,2BAA2B;AAG7C,WAAK,qBAAoB;AAAA,IAC3B,CAAC;AAED,aAAS,GAAG,+BAA+B,MAAM;AAC/C,WAAK,UAAS;AACd,WAAK,aAAa,gBAAgB;AAAA,IACpC,CAAC;AAED,aAAS,GAAG,8BAA8B,MAAM;AAC9C,WAAK,UAAS;AACd,WAAK,aAAa,eAAe;AAAA,IACnC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,uBAAuB,GAAG,IAAI;AAClC,UAAM,OAAO,GAAG,aAAa,WAAW;AACxC,UAAM,KAAK,WAAW,IAAI;AAAA,EAC5B;AAAA,EAIA,MAAM,mBAAmB;AACvB,SAAK,KAAI;AAAA,EACX;AAAA,EAEA,MAAM,mBAAmB;AACvB,SAAK,KAAI;AAAA,EACX;AAAA,EAEA,MAAM,oBAAoB;AACxB,UAAM,KAAK,SAAQ;AAAA,EACrB;AAAA,EAEA,MAAM,qBAAqB;AACzB,UAAM,SAAS,MAAM,KAAK,YAAW;AACrC,QAAI,QAAQ;AACV,WAAK,aAAa,6BAA6B;AAAA,IACjD;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,WAAW,MAAM,QAAM,OAAO;AAClC,QAAI,SAAS,KAAK,eAAe,CAAC,MAAO;AAGzC,QAAI,KAAK,eAAe,CAAC,OAAO;AAE9B,YAAM,YAAY,KAAK,oBAAmB;AAG1C,UAAI,WAAW;AACb,gBAAQ,IAAI,8CAA8C,KAAK,aAAa,MAAM;AAClF,aAAK,mBAAmB;AAAA,MAC1B,OAAO;AACL,gBAAQ,IAAI,iDAAiD,KAAK,aAAa,MAAM;AAAA,MACvF;AAAA,IACF,WAAW,OAAO;AAChB,cAAQ,IAAI,+DAA+D;AAAA,IAC7E;AAGA,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,QAAO;AAC9B,WAAK,cAAc;AAAA,IACrB;AAKA,UAAM,cAAc,KAAK,QAAQ,iBAAiB,WAAW;AAC7D,gBAAY,QAAQ,SAAO;AACzB,UAAI,UAAU,OAAO,QAAQ;AAC7B,UAAI,IAAI,aAAa,WAAW,MAAM,MAAM;AAC1C,YAAI,UAAU,IAAI,QAAQ;AAAA,MAC5B;AAAA,IACF,CAAC;AAGD,SAAK,cAAc;AACnB,SAAK,cAAc,KAAK,gBAAgB,IAAI;AAE5C,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,OAAM;AAG7B,UAAI,SAAS,UAAU,KAAK,YAAY,eAAe;AACrD,aAAK,YAAY,cAAa;AAC9B,aAAK,aAAa,oCAAoC;AAAA,MACxD,WAAW,SAAS,aAAa;AAC/B,aAAK,aAAa,qCAAqC;AAAA,MACzD,WAAW,SAAS,WAAW;AAC7B,aAAK,aAAa,qCAAqC;AAAA,MACzD;AAAA,IACF;AAGA,SAAK,yBAAwB;AAG7B,UAAM,WAAW,KAAK,OAAM,GAAI;AAChC,QAAI,UAAU;AACZ,eAAS,KAAK,4BAA4B;AAAA,QACxC,QAAQ;AAAA,QACR;AAAA,QACA,aAAa,KAAK;AAAA,MAC1B,CAAO;AAAA,IACH;AAAA,EACF;AAAA,EAEA,2BAA2B;AACzB,UAAM,cAAc,KAAK,QAAQ,cAAc,eAAe;AAC9D,QAAI,aAAa;AACf,kBAAY,cAAc,KAAK,YAAY,OAAO,CAAC,EAAE,YAAW,IAAK,KAAK,YAAY,MAAM,CAAC;AAAA,IAC/F;AAAA,EACF;AAAA,EAEA,aAAa,SAAS;AACpB,UAAM,cAAc,KAAK,QAAQ,cAAc,aAAa;AAC5D,QAAI,aAAa;AACf,kBAAY,cAAc;AAAA,IAC5B;AAAA,EACF;AAAA;AAAA,EAGA,YAAY;AACV,QAAI,CAAC,KAAK,cAAe;AAEzB,UAAM,QAAQ;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,WAAW,KAAK,aAAa,oBAAiB;AAAA,MAC9C,SAAS,KAAK,aAAa,iBAAc;AAAA,MACzC,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK,IAAG;AAAA,IACzB;AAGI,SAAK,UAAU,KAAK,QAAQ,MAAM,GAAG,KAAK,eAAe,CAAC;AAG1D,SAAK,QAAQ,KAAK,KAAK;AACvB,SAAK,eAAe,KAAK,QAAQ,SAAS;AAG1C,QAAI,KAAK,QAAQ,SAAS,KAAK,YAAY;AACzC,WAAK,QAAQ,MAAK;AAClB,WAAK;AAAA,IACP;AAEA,SAAK,qBAAoB;AAAA,EAC3B;AAAA,EAEA,OAAO;AACL,QAAI,KAAK,eAAe,GAAG;AACzB,WAAK;AACL,WAAK,aAAa,KAAK,QAAQ,KAAK,YAAY,CAAC;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,OAAO;AACL,QAAI,KAAK,eAAe,KAAK,QAAQ,SAAS,GAAG;AAC/C,WAAK;AACL,WAAK,aAAa,KAAK,QAAQ,KAAK,YAAY,CAAC;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,OAAO;AAExB,QAAI,MAAM,WAAW;AACnB,cAAQ,IAAI,4DAA4D;AACxE,WAAK,mBAAmB,MAAM;AAAA,IAChC;AAGA,UAAM,KAAK,WAAW,MAAM,MAAM,IAAI;AAGtC,QAAI,KAAK,aAAa;AACpB,UAAI,MAAM,aAAa,KAAK,YAAY,mBAAmB;AACzD,aAAK,YAAY,kBAAkB,MAAM,SAAS;AAAA,MACpD;AACA,UAAI,MAAM,WAAW,KAAK,YAAY,gBAAgB;AACpD,aAAK,YAAY,eAAe,MAAM,OAAO;AAAA,MAC/C;AAAA,IACF;AAEA,SAAK,qBAAoB;AACzB,SAAK,aAAa,eAAe,MAAM,IAAI,OAAO;AAAA,EACpD;AAAA,EAEA,uBAAuB;AACrB,UAAM,UAAU,KAAK,QAAQ,cAAc,sBAAsB;AACjE,UAAM,UAAU,KAAK,QAAQ,cAAc,sBAAsB;AAEjE,QAAI,QAAS,SAAQ,WAAW,KAAK,gBAAgB;AACrD,QAAI,QAAS,SAAQ,WAAW,KAAK,gBAAgB,KAAK,QAAQ,SAAS;AAAA,EAC7E;AAAA,EAEA,MAAM,WAAW;AAEf,YAAQ,IAAI,0DAA0D;AACtE,SAAK,mBAAmB;AAGxB,QAAI,KAAK,eAAe,KAAK,YAAY,OAAO;AAC9C,WAAK,YAAY,MAAK;AAAA,IACxB;AAGA,UAAM,KAAK,WAAW,aAAa,IAAI;AAGvC,SAAK,UAAU,CAAA;AACf,SAAK,eAAe;AACpB,SAAK,UAAS;AAEd,SAAK,aAAa,mBAAmB;AAAA,EACvC;AAAA;AAAA,EAGA,MAAM,cAAc;AAClB,QAAI,CAAC,KAAK,YAAa,QAAO;AAE9B,QAAI;AACF,UAAI,YAAY;AAGhB,kBAAY,KAAK,oBAAmB;AAEpC,UAAI,WAAW;AAEb,cAAM,OAAO,SAAS,cAAc,GAAG;AACvC,aAAK,WAAW,KAAK,kBAAiB;AACtC,aAAK,OAAO;AACZ,iBAAS,KAAK,YAAY,IAAI;AAC9B,aAAK,MAAK;AACV,iBAAS,KAAK,YAAY,IAAI;AAG9B,cAAM,WAAW,KAAK,OAAM,GAAI;AAChC,YAAI,UAAU;AACZ,mBAAS,KAAK,wBAAwB;AAAA,YACpC,QAAQ;AAAA,YACR;AAAA,YACA,UAAU,KAAK;AAAA,UAC3B,CAAW;AAAA,QACH;AAEA,eAAO,EAAE,WAAW,UAAU,KAAK,SAAQ;AAAA,MAC7C;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,kBAAkB,KAAK;AACrC,WAAK,aAAa,eAAe;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,oBAAoB;AAClB,UAAM,aAAY,oBAAI,KAAI,GAAG,YAAW,EAAG,MAAM,GAAG,EAAE,EAAE,QAAQ,UAAU,EAAE;AAC5E,WAAO,gBAAgB,SAAS;AAAA,EAClC;AAAA;AAAA,EAGA,MAAM,SAAS,UAAU,MAAM,IAAI,QAAQ,IAAI;AAC7C,YAAQ,IAAI,kEAAkE;AAC9E,SAAK,WAAW;AAChB,SAAK,MAAM;AACX,SAAK,QAAQ;AAGb,SAAK,mBAAmB;AAGxB,QAAI,KAAK,eAAe,KAAK,YAAY,UAAU;AACjD,WAAK,YAAY,SAAS,UAAU,KAAK,KAAK;AAAA,IAChD;AAGA,UAAM,KAAK,SAAQ;AAAA,EACrB;AAAA,EAEA,sBAAsB;AACpB,QAAI,CAAC,KAAK,YAAa,QAAO;AAG9B,QAAI,YAAY;AAChB,QAAI,KAAK,YAAY,iBAAiB;AACpC,kBAAY,KAAK,YAAY,gBAAe;AAAA,IAC9C,WAAW,KAAK,YAAY,yBAAyB;AACnD,kBAAY,KAAK,YAAY,wBAAuB;AAAA,IACtD;AAEA,WAAO,aAAa;AAAA,EACtB;AAAA;AAAA,EAGA,MAAM,kBAAkB;AAEtB,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK,YAAY,QAAO;AAC9B,WAAK,cAAc;AAAA,IACrB;AAGA,UAAM,WAAW,KAAK,OAAM,GAAI;AAChC,QAAI,UAAU;AACZ,eAAS,KAAK,yBAAyB,EAAE,QAAQ,KAAI,CAAE;AAAA,IACzD;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,WAAW,UAAU,UAAU,IAAI;AAC9C,UAAM;AAAA,MACJ,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,cAAc;AAAA,MACd,GAAG;AAAA,IACT,IAAQ;AAEJ,UAAM,SAAS,IAAI,YAAY;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACN,CAAK;AAED,UAAM,SAAS,IAAI,OAAO;AAAA,MACxB;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,SAAS;AAAA,QACnB;AAAA,QACQ;AAAA,UACE,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,OAAO;AAAA,QACjB;AAAA,MACA;AAAA,MACM,GAAG;AAAA,IACT,CAAK;AAGD,UAAM,OAAO,OAAO,MAAM,SAAS,IAAI;AAGvC,WAAO,aAAa;AACpB,WAAO,KAAI;AAEX,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,aAAO,GAAG,UAAU,MAAM;AACxB,eAAO,QAAO;AACd,gBAAQ,EAAE,QAAQ,UAAU,OAAM,CAAE;AAAA,MACtC,CAAC;AAED,aAAO,GAAG,iBAAiB,MAAM;AAC/B,eAAO,KAAI;AAAA,MACb,CAAC;AAED,aAAO,GAAG,uBAAuB,YAAY;AAC3C,cAAM,SAAS,MAAM,OAAO,YAAW;AACvC,eAAO,KAAI;AACX,gBAAQ;AAAA,UACN,QAAQ;AAAA,UACR;AAAA,UACA,MAAM,QAAQ;AAAA,UACd,UAAU,QAAQ;AAAA,QAC5B,CAAS;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAEA,OAAO,cAAc;AC1lBN,MAAM,wBAAwB,KAAK;AAAA,EAChD,YAAY,UAAU,IAAI;AACxB,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,WAAW,qBAAqB,QAAQ,aAAa,EAAE;AAAA,MACvD,SAAS;AAAA,IACf,CAAK;AAGD,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,gBAAgB,QAAQ,iBAAiB,CAAC,cAAc,aAAa,aAAa,YAAY;AACnG,SAAK,cAAc,QAAQ,eAAe,KAAK,OAAO;AACtD,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,WAAW,QAAQ,YAAY;AAGpC,SAAK,eAAe;AACpB,SAAK,cAAc;AACnB,SAAK,aAAa;AAGlB,SAAK,kBAAkB,KAAK,eAAe,KAAK,IAAI;AACpD,SAAK,mBAAmB,KAAK,gBAAgB,KAAK,IAAI;AACtD,SAAK,cAAc,KAAK,WAAW,KAAK,IAAI;AAC5C,SAAK,oBAAoB,KAAK,iBAAiB,KAAK,IAAI;AACxD,SAAK,mBAAmB,KAAK,gBAAgB,KAAK,IAAI;AAAA,EACxD;AAAA,EAEA,MAAM,cAAc;AAClB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+EAgBoE,KAAK,MAAM,KAAK,cAAc,OAAO,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmDvH;AAAA,EAEA,MAAM,gBAAgB;AAEpB,SAAK,WAAW,KAAK,QAAQ,cAAc,mBAAmB;AAC9D,SAAK,YAAY,KAAK,QAAQ,cAAc,oBAAoB;AAChE,SAAK,gBAAgB,KAAK,QAAQ,cAAc,gBAAgB;AAChE,SAAK,iBAAiB,KAAK,QAAQ,cAAc,iBAAiB;AAClE,SAAK,iBAAiB,KAAK,QAAQ,cAAc,iBAAiB;AAClE,SAAK,gBAAgB,KAAK,QAAQ,cAAc,gBAAgB;AAChE,SAAK,eAAe,KAAK,QAAQ,cAAc,gBAAgB;AAC/D,SAAK,WAAW,KAAK,QAAQ,cAAc,YAAY;AACvD,SAAK,cAAc,KAAK,QAAQ,cAAc,eAAe;AAC7D,SAAK,cAAc,KAAK,QAAQ,cAAc,eAAe;AAC7D,SAAK,eAAe,KAAK,QAAQ,cAAc,gBAAgB;AAG/D,SAAK,oBAAmB;AAAA,EAC1B;AAAA,EAEA,sBAAsB;AAEpB,SAAK,SAAS,iBAAiB,aAAa,KAAK,gBAAgB;AACjE,SAAK,SAAS,iBAAiB,YAAY,KAAK,eAAe;AAC/D,SAAK,SAAS,iBAAiB,aAAa,KAAK,gBAAgB;AACjE,SAAK,SAAS,iBAAiB,QAAQ,KAAK,WAAW;AAGvD,SAAK,UAAU,iBAAiB,UAAU,KAAK,iBAAiB;AAGhE,KAAC,aAAa,YAAY,aAAa,MAAM,EAAE,QAAQ,eAAa;AAClE,eAAS,iBAAiB,WAAW,KAAK,gBAAgB;AAAA,IAC5D,CAAC;AAAA,EACH;AAAA,EAEA,gBAAgB,GAAG;AACjB,MAAE,eAAc;AAChB,MAAE,gBAAe;AAAA,EACnB;AAAA,EAEA,eAAe,GAAG;AAChB,SAAK,gBAAgB,CAAC;AACtB,SAAK,SAAS,UAAU,IAAI,kBAAkB,UAAU;AACxD,SAAK,SAAS,MAAM,cAAc;AAAA,EACpC;AAAA,EAEA,gBAAgB,GAAG;AACjB,SAAK,gBAAgB,CAAC;AAGtB,QAAI,CAAC,KAAK,SAAS,SAAS,EAAE,aAAa,GAAG;AAC5C,WAAK,SAAS,UAAU,OAAO,kBAAkB,UAAU;AAC3D,WAAK,SAAS,MAAM,cAAc;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,GAAG;AAClB,SAAK,gBAAgB,CAAC;AAEtB,SAAK,SAAS,UAAU,OAAO,kBAAkB,UAAU;AAC3D,SAAK,SAAS,MAAM,cAAc;AAElC,UAAM,QAAQ,MAAM,KAAK,EAAE,aAAa,KAAK;AAC7C,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM,KAAK,YAAY,MAAM,CAAC,CAAC;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,GAAG;AACxB,UAAM,QAAQ,MAAM,KAAK,EAAE,OAAO,KAAK;AACvC,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM,KAAK,YAAY,MAAM,CAAC,CAAC;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,MAAM;AAEtB,UAAM,aAAa,KAAK,aAAa,IAAI;AACzC,QAAI,CAAC,WAAW,OAAO;AACrB,WAAK,UAAU,WAAW,KAAK;AAC/B;AAAA,IACF;AAEA,SAAK,eAAe;AAGpB,UAAM,KAAK,YAAY,IAAI;AAG3B,QAAI,KAAK,YAAY;AACnB,iBAAW,MAAM,KAAK,WAAU,GAAI,GAAG;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,aAAa,MAAM;AAEjB,QAAI,CAAC,KAAK,cAAc,SAAS,KAAK,IAAI,GAAG;AAC3C,aAAO;AAAA,QACL,OAAO;AAAA,QACP,OAAO,cAAc,KAAK,IAAI,mCAAmC,KAAK,cAAc,IAAI,OAAK,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;AAAA,MAC9I;AAAA,IACI;AAGA,QAAI,KAAK,OAAO,KAAK,aAAa;AAChC,aAAO;AAAA,QACL,OAAO;AAAA,QACP,OAAO,cAAc,KAAK,eAAe,KAAK,IAAI,CAAC,mCAAmC,KAAK,eAAe,KAAK,WAAW,CAAC;AAAA,MACnI;AAAA,IACI;AAEA,WAAO,EAAE,OAAO,KAAI;AAAA,EACtB;AAAA,EAEA,MAAM,YAAY,MAAM;AAEtB,QAAI,KAAK,YAAY;AACnB,UAAI,gBAAgB,KAAK,UAAU;AAAA,IACrC;AACA,SAAK,aAAa,IAAI,gBAAgB,IAAI;AAG1C,SAAK,aAAa,MAAM,KAAK;AAC7B,SAAK,SAAS,cAAc,KAAK;AACjC,SAAK,YAAY,cAAc,GAAG,KAAK,eAAe,KAAK,IAAI,CAAC,MAAM,KAAK,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE,YAAW,CAAE;AAG3G,SAAK,cAAc,UAAU,IAAI,QAAQ;AACzC,SAAK,eAAe,UAAU,OAAO,QAAQ;AAG7C,SAAK,WAAU;AAGf,SAAK,gBAAgB,WAAW,EAAE,MAAM,YAAY,KAAK,YAAY;AAAA,EACvE;AAAA,EAEA,MAAM,aAAa;AACjB,QAAI,CAAC,KAAK,gBAAgB,KAAK,YAAa;AAE5C,SAAK,cAAc;AACnB,SAAK,YAAW;AAEhB,QAAI;AACF,UAAI;AAEJ,UAAI,KAAK,YAAY,OAAO,KAAK,aAAa,YAAY;AAExD,iBAAS,MAAM,KAAK,SAAS,KAAK,cAAc,KAAK,eAAe,KAAK,IAAI,CAAC;AAAA,MAChF,WAAW,KAAK,WAAW;AAEzB,iBAAS,MAAM,KAAK,YAAY,KAAK,YAAY;AAAA,MACnD,OAAO;AACL,cAAM,IAAI,MAAM,6EAA6E;AAAA,MAC/F;AAEA,WAAK,YAAY,6BAA6B;AAC9C,WAAK,gBAAgB,kBAAkB,EAAE,MAAM,KAAK,cAAc,QAAQ;AAAA,IAE5E,SAAS,OAAO;AACd,cAAQ,MAAM,kBAAkB,KAAK;AACrC,WAAK,UAAU,kBAAkB,MAAM,OAAO,EAAE;AAChD,WAAK,gBAAgB,gBAAgB,EAAE,MAAM,KAAK,cAAc,OAAO;AAAA,IACzE,UAAC;AACC,WAAK,cAAc;AACnB,WAAK,YAAW;AAAA,IAClB;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,MAAM;AACtB,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,WAAW,IAAI,SAAQ;AAC7B,eAAS,OAAO,SAAS,IAAI;AAE7B,YAAM,MAAM,IAAI,eAAc;AAG9B,UAAI,OAAO,iBAAiB,YAAY,CAAC,MAAM;AAC7C,YAAI,EAAE,kBAAkB;AACtB,gBAAM,WAAW,KAAK,MAAO,EAAE,SAAS,EAAE,QAAS,GAAG;AACtD,eAAK,eAAe,QAAQ;AAAA,QAC9B;AAAA,MACF,CAAC;AAED,UAAI,iBAAiB,QAAQ,MAAM;AACjC,YAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AACzC,cAAI;AACF,kBAAM,WAAW,KAAK,MAAM,IAAI,YAAY;AAC5C,oBAAQ,QAAQ;AAAA,UAClB,SAAS,GAAG;AACV,oBAAQ,EAAE,SAAS,MAAM,UAAU,IAAI,cAAc;AAAA,UACvD;AAAA,QACF,OAAO;AACL,iBAAO,IAAI,MAAM,QAAQ,IAAI,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;AAAA,QAC3D;AAAA,MACF,CAAC;AAED,UAAI,iBAAiB,SAAS,MAAM;AAClC,eAAO,IAAI,MAAM,wBAAwB,CAAC;AAAA,MAC5C,CAAC;AAED,UAAI,iBAAiB,WAAW,MAAM;AACpC,eAAO,IAAI,MAAM,gBAAgB,CAAC;AAAA,MACpC,CAAC;AAED,UAAI,KAAK,QAAQ,KAAK,SAAS;AAC/B,UAAI,UAAU;AACd,UAAI,KAAK,QAAQ;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,eAAe,SAAS;AACtB,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,MAAM,QAAQ,GAAG,OAAO;AACzC,WAAK,YAAY,aAAa,iBAAiB,OAAO;AAAA,IACxD;AACA,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,cAAc,gBAAgB,OAAO;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,cAAc;AACZ,SAAK,eAAe,UAAU,IAAI,QAAQ;AAC1C,SAAK,eAAe,UAAU,OAAO,QAAQ;AAC7C,SAAK,eAAe,CAAC;AAAA,EACvB;AAAA,EAEA,cAAc;AACZ,SAAK,eAAe,UAAU,IAAI,QAAQ;AAC1C,QAAI,CAAC,KAAK,cAAc,KAAK,cAAc;AACzC,WAAK,eAAe,UAAU,OAAO,QAAQ;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,YAAY,SAAS;AACnB,SAAK,WAAW,WAAW,OAAO;AAAA,EACpC;AAAA,EAEA,UAAU,SAAS;AACjB,SAAK,WAAW,UAAU,OAAO;AAAA,EACnC;AAAA,EAEA,WAAW,MAAM,SAAS;AACxB,UAAM,eAAe,KAAK,cAAc,cAAc,QAAQ;AAC9D,UAAM,OAAO,SAAS,YAAY,sBAAsB;AAExD,iBAAa,YAAY,eAAe,IAAI;AAC5C,iBAAa,YAAY;AAAA,wBACL,IAAI;AAAA,QACpB,OAAO;AAAA;AAGX,SAAK,cAAc,UAAU,OAAO,QAAQ;AAG5C,QAAI,SAAS,WAAW;AACtB,iBAAW,MAAM,KAAK,WAAU,GAAI,GAAI;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,aAAa;AACX,SAAK,cAAc,UAAU,IAAI,QAAQ;AAAA,EAC3C;AAAA,EAEA,YAAY;AAEV,QAAI,KAAK,YAAY;AACnB,UAAI,gBAAgB,KAAK,UAAU;AACnC,WAAK,aAAa;AAAA,IACpB;AAEA,SAAK,eAAe;AACpB,SAAK,cAAc;AACnB,SAAK,UAAU,QAAQ;AAGvB,SAAK,eAAe,UAAU,IAAI,QAAQ;AAC1C,SAAK,eAAe,UAAU,IAAI,QAAQ;AAC1C,SAAK,cAAc,UAAU,OAAO,QAAQ;AAC5C,SAAK,WAAU;AAEf,SAAK,gBAAgB,SAAS;AAAA,EAChC;AAAA,EAEA,eAAe,OAAO;AACpB,QAAI,UAAU,EAAG,QAAO;AACxB,UAAM,IAAI;AACV,UAAM,QAAQ,CAAC,SAAS,MAAM,MAAM,IAAI;AACxC,UAAM,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAClD,WAAO,YAAY,QAAQ,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM,CAAC;AAAA,EACxE;AAAA,EAEA,gBAAgB,MAAM,OAAO,IAAI;AAC/B,UAAM,WAAW,KAAK,OAAM,GAAI;AAChC,QAAI,UAAU;AACZ,eAAS,KAAK,eAAe,IAAI,IAAI;AAAA,QACnC,MAAM;AAAA,QACN,GAAG;AAAA,MACX,CAAO;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,yBAAyB;AAC7B,SAAK,UAAU,MAAK;AAAA,EACtB;AAAA,EAEA,MAAM,qBAAqB;AACzB,UAAM,KAAK,WAAU;AAAA,EACvB;AAAA,EAEA,MAAM,oBAAoB;AACxB,SAAK,UAAS;AAAA,EAChB;AAAA;AAAA,EAGA,MAAM,kBAAkB;AAEtB,QAAI,KAAK,YAAY;AACnB,UAAI,gBAAgB,KAAK,UAAU;AACnC,WAAK,aAAa;AAAA,IACpB;AAGA,QAAI,KAAK,UAAU;AACjB,WAAK,SAAS,oBAAoB,aAAa,KAAK,gBAAgB;AACpE,WAAK,SAAS,oBAAoB,YAAY,KAAK,eAAe;AAClE,WAAK,SAAS,oBAAoB,aAAa,KAAK,gBAAgB;AACpE,WAAK,SAAS,oBAAoB,QAAQ,KAAK,WAAW;AAAA,IAC5D;AAEA,QAAI,KAAK,WAAW;AAClB,WAAK,UAAU,oBAAoB,UAAU,KAAK,iBAAiB;AAAA,IACrE;AAGA,KAAC,aAAa,YAAY,aAAa,MAAM,EAAE,QAAQ,eAAa;AAClE,eAAS,oBAAoB,WAAW,KAAK,gBAAgB;AAAA,IAC/D,CAAC;AAED,SAAK,gBAAgB,WAAW;AAAA,EAClC;AACF;AAEA,OAAO,kBAAkB;"}