web-mojo 2.1.1044 → 2.1.1087

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 (86) 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 +14 -14
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.es.js +1 -1
  7. package/dist/charts.cjs.js +1 -1
  8. package/dist/charts.cjs.js.map +1 -1
  9. package/dist/charts.css +319 -0
  10. package/dist/charts.es.js +555 -3
  11. package/dist/charts.es.js.map +1 -1
  12. package/dist/chunks/{ChatView-Bvkdj-lq.js → ChatView-BnC15uoD.js} +2 -2
  13. package/dist/chunks/{ChatView-Bvkdj-lq.js.map → ChatView-BnC15uoD.js.map} +1 -1
  14. package/dist/chunks/{ChatView-DBgQzOyI.js → ChatView-D-5lHZ5H.js} +7 -7
  15. package/dist/chunks/{ChatView-DBgQzOyI.js.map → ChatView-D-5lHZ5H.js.map} +1 -1
  16. package/dist/chunks/{Collection-DD1_31eh.js → Collection-B64LJ92k.js} +2 -2
  17. package/dist/chunks/{Collection-DD1_31eh.js.map → Collection-B64LJ92k.js.map} +1 -1
  18. package/dist/chunks/{Collection-DaTm-2LH.js → Collection-CsAk0UhA.js} +2 -2
  19. package/dist/chunks/{Collection-DaTm-2LH.js.map → Collection-CsAk0UhA.js.map} +1 -1
  20. package/dist/chunks/{ContextMenu-snx9Dd1s.js → ContextMenu-CfMAB33c.js} +2 -2
  21. package/dist/chunks/{ContextMenu-snx9Dd1s.js.map → ContextMenu-CfMAB33c.js.map} +1 -1
  22. package/dist/chunks/{ContextMenu-hQH_6Pyi.js → ContextMenu-Cvls3QC_.js} +3 -3
  23. package/dist/chunks/{ContextMenu-hQH_6Pyi.js.map → ContextMenu-Cvls3QC_.js.map} +1 -1
  24. package/dist/chunks/{DataView-D7j4IWyS.js → DataView-DESqBxT-.js} +2 -2
  25. package/dist/chunks/{DataView-D7j4IWyS.js.map → DataView-DESqBxT-.js.map} +1 -1
  26. package/dist/chunks/{DataView-CWejLV3B.js → DataView-QXyfcg2M.js} +2 -2
  27. package/dist/chunks/{DataView-CWejLV3B.js.map → DataView-QXyfcg2M.js.map} +1 -1
  28. package/dist/chunks/Dialog-BfXN-fFA.js +2 -0
  29. package/dist/chunks/Dialog-BfXN-fFA.js.map +1 -0
  30. package/dist/chunks/{Dialog-BcJG5Vta.js → Dialog-DHUsZ92-.js} +20 -6
  31. package/dist/chunks/Dialog-DHUsZ92-.js.map +1 -0
  32. package/dist/chunks/{FormView-BClEkzmE.js → FormView-DGRmcKUG.js} +282 -123
  33. package/dist/chunks/FormView-DGRmcKUG.js.map +1 -0
  34. package/dist/chunks/FormView-KGvr68ju.js +3 -0
  35. package/dist/chunks/FormView-KGvr68ju.js.map +1 -0
  36. package/dist/chunks/{ListView-BrsQ26R6.js → ListView-BGJG4GYH.js} +3 -3
  37. package/dist/chunks/{ListView-BrsQ26R6.js.map → ListView-BGJG4GYH.js.map} +1 -1
  38. package/dist/chunks/{ListView-BRGiITfD.js → ListView-BpGEatee.js} +2 -2
  39. package/dist/chunks/{ListView-BRGiITfD.js.map → ListView-BpGEatee.js.map} +1 -1
  40. package/dist/chunks/{MetricsMiniChartWidget-DALWxrzu.js → MetricsMiniChartWidget-BKbFGvXG.js} +4 -4
  41. package/dist/chunks/{MetricsMiniChartWidget-DALWxrzu.js.map → MetricsMiniChartWidget-BKbFGvXG.js.map} +1 -1
  42. package/dist/chunks/{MetricsMiniChartWidget-CN1HPnWf.js → MetricsMiniChartWidget-BNdGuSZV.js} +2 -2
  43. package/dist/chunks/{MetricsMiniChartWidget-CN1HPnWf.js.map → MetricsMiniChartWidget-BNdGuSZV.js.map} +1 -1
  44. package/dist/chunks/{PDFViewer-CgdSGU1n.js → PDFViewer-BIBNhuWY.js} +3 -3
  45. package/dist/chunks/{PDFViewer-CgdSGU1n.js.map → PDFViewer-BIBNhuWY.js.map} +1 -1
  46. package/dist/chunks/{PDFViewer-DtJIlPXi.js → PDFViewer-nZAQQScE.js} +2 -2
  47. package/dist/chunks/{PDFViewer-DtJIlPXi.js.map → PDFViewer-nZAQQScE.js.map} +1 -1
  48. package/dist/chunks/Rest-BpDyhFfG.js +2 -0
  49. package/dist/chunks/Rest-BpDyhFfG.js.map +1 -0
  50. package/dist/chunks/{Rest-CS4jRCAs.js → Rest-DpbPbmra.js} +96 -5
  51. package/dist/chunks/Rest-DpbPbmra.js.map +1 -0
  52. package/dist/chunks/{TokenManager-DIEFCQ3B.js → TokenManager-BWc_pRpg.js} +2 -2
  53. package/dist/chunks/{TokenManager-DIEFCQ3B.js.map → TokenManager-BWc_pRpg.js.map} +1 -1
  54. package/dist/chunks/{TokenManager-BanwFrq7.js → TokenManager-N3e5wDu1.js} +5 -5
  55. package/dist/chunks/{TokenManager-BanwFrq7.js.map → TokenManager-N3e5wDu1.js.map} +1 -1
  56. package/dist/chunks/{WebSocketClient-D-5DJoMX.js → WebSocketClient-DghNkEyO.js} +2 -2
  57. package/dist/chunks/{WebSocketClient-D-5DJoMX.js.map → WebSocketClient-DghNkEyO.js.map} +1 -1
  58. package/dist/chunks/{WebSocketClient-DzcqAmho.js → WebSocketClient-E08hfP5f.js} +2 -2
  59. package/dist/chunks/{WebSocketClient-DzcqAmho.js.map → WebSocketClient-E08hfP5f.js.map} +1 -1
  60. package/dist/chunks/{version-WMgX72-y.js → version-CKPqwcQJ.js} +2 -2
  61. package/dist/chunks/{version-WMgX72-y.js.map → version-CKPqwcQJ.js.map} +1 -1
  62. package/dist/chunks/{version-BaFu2yii.js → version-Dtwh-YkD.js} +4 -4
  63. package/dist/chunks/{version-BaFu2yii.js.map → version-Dtwh-YkD.js.map} +1 -1
  64. package/dist/css/web-mojo.css +1 -1
  65. package/dist/docit.cjs.js +1 -1
  66. package/dist/docit.es.js +6 -6
  67. package/dist/index.cjs.js +1 -1
  68. package/dist/index.es.js +15 -15
  69. package/dist/lightbox.cjs.js +1 -1
  70. package/dist/lightbox.es.js +5 -5
  71. package/dist/map.cjs.js +1 -1
  72. package/dist/map.cjs.js.map +1 -1
  73. package/dist/map.es.js +82 -3
  74. package/dist/map.es.js.map +1 -1
  75. package/dist/timeline.cjs.js +1 -1
  76. package/dist/timeline.es.js +4 -4
  77. package/package.json +1 -1
  78. package/dist/chunks/Dialog-7T8ENHYD.js +0 -2
  79. package/dist/chunks/Dialog-7T8ENHYD.js.map +0 -1
  80. package/dist/chunks/Dialog-BcJG5Vta.js.map +0 -1
  81. package/dist/chunks/FormView-BClEkzmE.js.map +0 -1
  82. package/dist/chunks/FormView-nulck4nL.js +0 -3
  83. package/dist/chunks/FormView-nulck4nL.js.map +0 -1
  84. package/dist/chunks/Rest-BNYqGlnP.js +0 -2
  85. package/dist/chunks/Rest-BNYqGlnP.js.map +0 -1
  86. package/dist/chunks/Rest-CS4jRCAs.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"map.cjs.js","sources":["../src/extensions/map/MapView.js"],"sourcesContent":["/**\n * MapView - Interactive map component using Leaflet\n * \n * Features:\n * - Display single or multiple markers\n * - Auto-zoom to fit markers\n * - Customizable marker popups\n * - Support for different tile layers\n * \n * @example\n * const mapView = new MapView({\n * markers: [\n * { lat: 37.422, lng: -122.084, popup: 'Mountain View, CA' }\n * ],\n * zoom: 10,\n * height: 400\n * });\n */\n\nimport View from '@core/View.js';\n\nclass MapView extends View {\n constructor(options = {}) {\n super({\n className: 'map-view',\n ...options\n });\n\n this.markers = options.markers || [];\n this.center = options.center || null;\n this.zoom = options.zoom || 13;\n this.height = options.height || 400;\n this.showZoomControl = options.showZoomControl !== false;\n this.tileLayer = options.tileLayer || 'osm'; // 'osm', 'satellite', 'terrain'\n \n this.map = null;\n this.leafletMarkers = [];\n\n this.template = `\n <div class=\"map-container\">\n <div id=\"map-{{id}}\" style=\"height: {{height}}px; width: 100%; border-radius: 0.375rem; border: 1px solid #dee2e6;\"></div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await this.loadLeaflet();\n await this.initializeMap();\n }\n\n async loadLeaflet() {\n // Check if Leaflet is already loaded\n if (window.L) return;\n\n // Load Leaflet CSS and wait for it\n const cssLoaded = new Promise((resolve) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';\n link.onload = resolve;\n link.onerror = resolve; // Continue even if CSS fails\n document.head.appendChild(link);\n });\n\n // Load Leaflet JS\n const jsLoaded = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n\n // Wait for both CSS and JS to load\n await Promise.all([cssLoaded, jsLoaded]);\n }\n\n getTileLayerUrl() {\n const tileLayers = {\n // Standard street maps\n osm: {\n url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',\n attribution: '© OpenStreetMap contributors',\n maxZoom: 19\n },\n \n // Satellite imagery\n satellite: {\n url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n attribution: '© Esri',\n maxZoom: 19\n },\n \n // Terrain and topographic\n terrain: {\n url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',\n attribution: '© OpenTopoMap contributors',\n maxZoom: 17\n },\n \n // Dark mode styles\n dark: {\n url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n \n // Light/minimal styles\n light: {\n url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n \n // Watercolor artistic style\n watercolor: {\n url: 'https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg',\n attribution: '© Stadia Maps © Stamen Design © OpenStreetMap contributors',\n maxZoom: 16\n },\n \n // Black and white\n bw: {\n url: 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n \n // Streets with labels\n streets: {\n url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n }\n };\n\n return tileLayers[this.tileLayer] || tileLayers.osm;\n }\n\n async initializeMap() {\n const mapElement = this.element.querySelector(`#map-${this.id}`);\n if (!mapElement || !window.L) return;\n\n // Determine map center\n let mapCenter = this.center;\n if (!mapCenter && this.markers.length > 0) {\n // Use first marker as center\n mapCenter = [this.markers[0].lat, this.markers[0].lng];\n }\n if (!mapCenter) {\n // Default to world view\n mapCenter = [0, 0];\n }\n\n // Create map\n this.map = window.L.map(mapElement, {\n center: mapCenter,\n zoom: this.zoom,\n zoomControl: this.showZoomControl\n });\n\n // Add tile layer\n const tileConfig = this.getTileLayerUrl();\n window.L.tileLayer(tileConfig.url, {\n attribution: tileConfig.attribution,\n maxZoom: tileConfig.maxZoom\n }).addTo(this.map);\n\n // Add markers\n this.addMarkers(this.markers);\n\n // Auto-fit bounds if multiple markers\n if (this.markers.length > 1) {\n this.fitBounds();\n }\n\n // Fix tile rendering issues by invalidating size after a delay\n // This ensures the container has proper dimensions and CSS is applied\n setTimeout(() => {\n if (this.map) {\n this.map.invalidateSize();\n }\n }, 300);\n }\n\n addMarkers(markers) {\n if (!this.map || !Array.isArray(markers)) return;\n\n markers.forEach(markerData => {\n const { lat, lng, popup, icon } = markerData;\n \n if (!lat || !lng) return;\n\n const markerOptions = {};\n \n // Custom icon if provided\n if (icon) {\n markerOptions.icon = window.L.icon(icon);\n }\n\n const marker = window.L.marker([lat, lng], markerOptions).addTo(this.map);\n\n // Add popup if provided\n if (popup) {\n marker.bindPopup(popup);\n }\n\n this.leafletMarkers.push(marker);\n });\n }\n\n fitBounds() {\n if (!this.map || this.leafletMarkers.length === 0) return;\n\n const group = new window.L.featureGroup(this.leafletMarkers);\n this.map.fitBounds(group.getBounds().pad(0.1));\n }\n\n updateMarkers(newMarkers) {\n // Clear existing markers\n this.clearMarkers();\n \n // Add new markers\n this.markers = newMarkers;\n this.addMarkers(newMarkers);\n \n // Fit bounds if multiple markers\n if (newMarkers.length > 1) {\n this.fitBounds();\n } else if (newMarkers.length === 1) {\n this.map.setView([newMarkers[0].lat, newMarkers[0].lng], this.zoom);\n }\n }\n\n clearMarkers() {\n this.leafletMarkers.forEach(marker => {\n this.map.removeLayer(marker);\n });\n this.leafletMarkers = [];\n }\n\n setView(lat, lng, zoom = null) {\n if (!this.map) return;\n this.map.setView([lat, lng], zoom || this.zoom);\n }\n\n setZoom(zoom) {\n if (!this.map) return;\n this.map.setZoom(zoom);\n }\n\n async onBeforeDestroy() {\n if (this.map) {\n this.map.remove();\n this.map = null;\n }\n await super.onBeforeDestroy();\n }\n}\n\nexport default MapView;\n"],"names":["MapView","View","constructor","options","super","className","this","markers","center","zoom","height","showZoomControl","tileLayer","map","leafletMarkers","template","onAfterRender","loadLeaflet","initializeMap","window","L","cssLoaded","Promise","resolve","link","document","createElement","rel","href","onload","onerror","head","appendChild","jsLoaded","reject","script","src","all","getTileLayerUrl","tileLayers","osm","url","attribution","maxZoom","satellite","terrain","dark","light","watercolor","bw","streets","mapElement","element","querySelector","id","mapCenter","length","lat","lng","zoomControl","tileConfig","addTo","addMarkers","fitBounds","setTimeout","invalidateSize","Array","isArray","forEach","markerData","popup","icon","markerOptions","marker","bindPopup","push","group","featureGroup","getBounds","pad","updateMarkers","newMarkers","clearMarkers","setView","removeLayer","setZoom","onBeforeDestroy","remove"],"mappings":"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"}
1
+ {"version":3,"file":"map.cjs.js","sources":["../src/extensions/map/MapView.js"],"sourcesContent":["/**\n * MapView - Interactive map component using Leaflet\n *\n * Features:\n * - Display single or multiple markers\n * - Auto-zoom to fit markers\n * - Customizable marker popups\n * - Support for different tile layers\n *\n * @example\n * const mapView = new MapView({\n * markers: [\n * { lat: 37.422, lng: -122.084, popup: 'Mountain View, CA' }\n * ],\n * zoom: 10,\n * height: 400\n * });\n */\n\nimport View from '@core/View.js';\n\nclass MapView extends View {\n constructor(options = {}) {\n super({\n className: 'map-view',\n ...options\n });\n\n this.markers = options.markers || [];\n this.center = options.center || null;\n this.zoom = options.zoom || 13;\n this.height = options.height || 400;\n this.showZoomControl = options.showZoomControl !== false;\n this.tileLayer = options.tileLayer || 'osm'; // 'osm', 'satellite', 'terrain'\n this.showLeafletBranding = options.showLeafletBranding === true;\n this.showLayerControl = options.showLayerControl === true;\n this.layerOptions = options.layerOptions || {\n osm: 'OSM',\n satellite: 'Satellite',\n terrain: 'Terrain',\n dark: 'Dark',\n light: 'Light',\n watercolor: 'Watercolor',\n bw: 'B/W',\n streets: 'Streets'\n };\n\n this.map = null;\n this.leafletMarkers = [];\n this._tileLayer = null;\n\n this.template = `\n <div class=\"map-container\">\n <div id=\"map-{{id}}\" style=\"height: {{height}}px; width: 100%; border-radius: 0.375rem; border: 1px solid #dee2e6;\"></div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await this.loadLeaflet();\n await this.initializeMap();\n }\n\n async loadLeaflet() {\n // Check if Leaflet is already loaded\n if (window.L) return;\n\n // Load Leaflet CSS and wait for it\n const cssLoaded = new Promise((resolve) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';\n link.onload = resolve;\n link.onerror = resolve; // Continue even if CSS fails\n document.head.appendChild(link);\n });\n\n // Load Leaflet JS\n const jsLoaded = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n\n // Wait for both CSS and JS to load\n await Promise.all([cssLoaded, jsLoaded]);\n }\n\n getTileLayerUrl() {\n const tileLayers = {\n // Standard street maps\n osm: {\n url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',\n attribution: '© OpenStreetMap contributors',\n maxZoom: 19\n },\n\n // Satellite imagery\n satellite: {\n url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n attribution: '© Esri',\n maxZoom: 19\n },\n\n // Terrain and topographic\n terrain: {\n url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',\n attribution: '© OpenTopoMap contributors',\n maxZoom: 17\n },\n\n // Dark mode styles\n dark: {\n url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n\n // Light/minimal styles\n light: {\n url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n\n // Watercolor artistic style\n watercolor: {\n url: 'https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg',\n attribution: '© Stadia Maps © Stamen Design © OpenStreetMap contributors',\n maxZoom: 16\n },\n\n // Black and white\n bw: {\n url: 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n\n // Streets with labels\n streets: {\n url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n }\n };\n\n return tileLayers[this.tileLayer] || tileLayers.osm;\n }\n\n async initializeMap() {\n const mapElement = this.element.querySelector(`#map-${this.id}`);\n if (!mapElement || !window.L) return;\n\n // Determine map center\n let mapCenter = this.center;\n if (!mapCenter && this.markers.length > 0) {\n // Use first marker as center\n mapCenter = [this.markers[0].lat, this.markers[0].lng];\n }\n if (!mapCenter) {\n // Default to world view\n mapCenter = [0, 0];\n }\n\n // Create map\n this.map = window.L.map(mapElement, {\n center: mapCenter,\n zoom: this.zoom,\n zoomControl: this.showZoomControl\n });\n // Optionally hide Leaflet branding/prefix (removes Leaflet link/flag in attribution control)\n if (this.map && this.map.attributionControl && this.showLeafletBranding === false) {\n try { this.map.attributionControl.setPrefix(''); } catch (e) {}\n }\n\n // Add tile layer\n const tileConfig = this.getTileLayerUrl();\n this._tileLayer = window.L.tileLayer(tileConfig.url, {\n attribution: tileConfig.attribution,\n maxZoom: tileConfig.maxZoom\n }).addTo(this.map);\n\n // Optional built-in tile layer selector UI\n if (this.showLayerControl) {\n const container = mapElement.parentElement || this.element.querySelector('.map-container');\n if (container) {\n container.style.position = container.style.position || 'relative';\n const selector = document.createElement('select');\n selector.className = 'form-select form-select-sm';\n selector.style.position = 'absolute';\n selector.style.top = '8px';\n selector.style.right = '8px';\n selector.style.zIndex = '1000';\n selector.style.maxWidth = '180px';\n selector.setAttribute('aria-label', 'Map tile layer');\n\n // Populate options\n Object.entries(this.layerOptions || {}).forEach(([key, label]) => {\n const opt = document.createElement('option');\n opt.value = key;\n opt.textContent = label;\n if (key === this.tileLayer) opt.selected = true;\n selector.appendChild(opt);\n });\n\n selector.addEventListener('change', () => this.setTileLayer(selector.value));\n container.appendChild(selector);\n }\n }\n\n // Add markers\n this.addMarkers(this.markers);\n\n // Auto-fit bounds if multiple markers\n if (this.markers.length > 1) {\n this.fitBounds();\n }\n\n // Fix tile rendering issues by invalidating size after a delay\n // This ensures the container has proper dimensions and CSS is applied\n setTimeout(() => {\n if (this.map) {\n this.map.invalidateSize();\n }\n }, 300);\n }\n\n addMarkers(markers) {\n if (!this.map || !Array.isArray(markers)) return;\n\n markers.forEach(markerData => {\n const { lat, lng, popup, icon } = markerData;\n\n if (!lat || !lng) return;\n\n const markerOptions = {};\n\n // Custom icon if provided\n if (icon) {\n markerOptions.icon = window.L.icon(icon);\n }\n\n const marker = window.L.marker([lat, lng], markerOptions).addTo(this.map);\n\n // Add popup if provided\n if (popup) {\n marker.bindPopup(popup);\n }\n\n this.leafletMarkers.push(marker);\n });\n }\n\n fitBounds() {\n if (!this.map || this.leafletMarkers.length === 0) return;\n\n const group = new window.L.featureGroup(this.leafletMarkers);\n this.map.fitBounds(group.getBounds().pad(0.1));\n }\n\n updateMarkers(newMarkers) {\n // Clear existing markers\n this.clearMarkers();\n\n // Add new markers\n this.markers = newMarkers;\n this.addMarkers(newMarkers);\n\n // Fit bounds if multiple markers\n if (newMarkers.length > 1) {\n this.fitBounds();\n } else if (newMarkers.length === 1) {\n this.map.setView([newMarkers[0].lat, newMarkers[0].lng], this.zoom);\n }\n }\n\n clearMarkers() {\n this.leafletMarkers.forEach(marker => {\n this.map.removeLayer(marker);\n });\n this.leafletMarkers = [];\n }\n\n setView(lat, lng, zoom = null) {\n if (!this.map) return;\n this.map.setView([lat, lng], zoom || this.zoom);\n }\n\n setZoom(zoom) {\n if (!this.map) return;\n this.map.setZoom(zoom);\n }\n\n setTileLayer(key) {\n if (!this.map) return;\n // Resolve tile layer config using the same logic as getTileLayerUrl\n const original = this.tileLayer;\n this.tileLayer = key || this.tileLayer;\n const tileConfig = this.getTileLayerUrl();\n try {\n if (this._tileLayer) {\n this.map.removeLayer(this._tileLayer);\n }\n } catch (e) {\n // ignore if layer already removed\n }\n this._tileLayer = window.L.tileLayer(tileConfig.url, {\n attribution: tileConfig.attribution,\n maxZoom: tileConfig.maxZoom\n }).addTo(this.map);\n // Keep property in sync\n this.tileLayer = key || original;\n\n // Nudge map to ensure proper redraw\n setTimeout(() => {\n try { this.map.invalidateSize(); } catch (e) {}\n }, 150);\n }\n\n async onBeforeDestroy() {\n if (this.map) {\n this.map.remove();\n this.map = null;\n }\n await super.onBeforeDestroy();\n }\n\n static async showAsDialog(options = {}) {\n const view = new MapView(options);\n const dopts = options.dialogOptions || {};\n const dialogOptions = {\n title: \"Map View\",\n header: true,\n body: view,\n size: 'lg',\n centered: false,\n ...dopts\n }\n await view.init();\n await view.getApp().showDialog(dialogOptions);\n }\n}\n\nexport default MapView;\n"],"names":["MapView","View","constructor","options","super","className","this","markers","center","zoom","height","showZoomControl","tileLayer","showLeafletBranding","showLayerControl","layerOptions","osm","satellite","terrain","dark","light","watercolor","bw","streets","map","leafletMarkers","_tileLayer","template","onAfterRender","loadLeaflet","initializeMap","window","L","cssLoaded","Promise","resolve","link","document","createElement","rel","href","onload","onerror","head","appendChild","jsLoaded","reject","script","src","all","getTileLayerUrl","tileLayers","url","attribution","maxZoom","mapElement","element","querySelector","id","mapCenter","length","lat","lng","zoomControl","attributionControl","setPrefix","e","tileConfig","addTo","container","parentElement","style","position","selector","top","right","zIndex","maxWidth","setAttribute","Object","entries","forEach","key","label","opt","value","textContent","selected","addEventListener","setTileLayer","addMarkers","fitBounds","setTimeout","invalidateSize","Array","isArray","markerData","popup","icon","markerOptions","marker","bindPopup","push","group","featureGroup","getBounds","pad","updateMarkers","newMarkers","clearMarkers","setView","removeLayer","setZoom","original","onBeforeDestroy","remove","showAsDialog","view","dialogOptions","title","header","body","size","centered","init","getApp","showDialog"],"mappings":"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"}
package/dist/map.es.js CHANGED
@@ -1,5 +1,5 @@
1
- import { V as View } from "./chunks/Rest-CS4jRCAs.js";
2
- import { C, M } from "./chunks/Collection-DaTm-2LH.js";
1
+ import { V as View } from "./chunks/Rest-DpbPbmra.js";
2
+ import { C, M } from "./chunks/Collection-CsAk0UhA.js";
3
3
  class MapView extends View {
4
4
  constructor(options = {}) {
5
5
  super({
@@ -12,8 +12,21 @@ class MapView extends View {
12
12
  this.height = options.height || 400;
13
13
  this.showZoomControl = options.showZoomControl !== false;
14
14
  this.tileLayer = options.tileLayer || "osm";
15
+ this.showLeafletBranding = options.showLeafletBranding === true;
16
+ this.showLayerControl = options.showLayerControl === true;
17
+ this.layerOptions = options.layerOptions || {
18
+ osm: "OSM",
19
+ satellite: "Satellite",
20
+ terrain: "Terrain",
21
+ dark: "Dark",
22
+ light: "Light",
23
+ watercolor: "Watercolor",
24
+ bw: "B/W",
25
+ streets: "Streets"
26
+ };
15
27
  this.map = null;
16
28
  this.leafletMarkers = [];
29
+ this._tileLayer = null;
17
30
  this.template = `
18
31
  <div class="map-container">
19
32
  <div id="map-{{id}}" style="height: {{height}}px; width: 100%; border-radius: 0.375rem; border: 1px solid #dee2e6;"></div>
@@ -111,11 +124,40 @@ class MapView extends View {
111
124
  zoom: this.zoom,
112
125
  zoomControl: this.showZoomControl
113
126
  });
127
+ if (this.map && this.map.attributionControl && this.showLeafletBranding === false) {
128
+ try {
129
+ this.map.attributionControl.setPrefix("");
130
+ } catch (e) {
131
+ }
132
+ }
114
133
  const tileConfig = this.getTileLayerUrl();
115
- window.L.tileLayer(tileConfig.url, {
134
+ this._tileLayer = window.L.tileLayer(tileConfig.url, {
116
135
  attribution: tileConfig.attribution,
117
136
  maxZoom: tileConfig.maxZoom
118
137
  }).addTo(this.map);
138
+ if (this.showLayerControl) {
139
+ const container = mapElement.parentElement || this.element.querySelector(".map-container");
140
+ if (container) {
141
+ container.style.position = container.style.position || "relative";
142
+ const selector = document.createElement("select");
143
+ selector.className = "form-select form-select-sm";
144
+ selector.style.position = "absolute";
145
+ selector.style.top = "8px";
146
+ selector.style.right = "8px";
147
+ selector.style.zIndex = "1000";
148
+ selector.style.maxWidth = "180px";
149
+ selector.setAttribute("aria-label", "Map tile layer");
150
+ Object.entries(this.layerOptions || {}).forEach(([key, label]) => {
151
+ const opt = document.createElement("option");
152
+ opt.value = key;
153
+ opt.textContent = label;
154
+ if (key === this.tileLayer) opt.selected = true;
155
+ selector.appendChild(opt);
156
+ });
157
+ selector.addEventListener("change", () => this.setTileLayer(selector.value));
158
+ container.appendChild(selector);
159
+ }
160
+ }
119
161
  this.addMarkers(this.markers);
120
162
  if (this.markers.length > 1) {
121
163
  this.fitBounds();
@@ -171,6 +213,29 @@ class MapView extends View {
171
213
  if (!this.map) return;
172
214
  this.map.setZoom(zoom);
173
215
  }
216
+ setTileLayer(key) {
217
+ if (!this.map) return;
218
+ const original = this.tileLayer;
219
+ this.tileLayer = key || this.tileLayer;
220
+ const tileConfig = this.getTileLayerUrl();
221
+ try {
222
+ if (this._tileLayer) {
223
+ this.map.removeLayer(this._tileLayer);
224
+ }
225
+ } catch (e) {
226
+ }
227
+ this._tileLayer = window.L.tileLayer(tileConfig.url, {
228
+ attribution: tileConfig.attribution,
229
+ maxZoom: tileConfig.maxZoom
230
+ }).addTo(this.map);
231
+ this.tileLayer = key || original;
232
+ setTimeout(() => {
233
+ try {
234
+ this.map.invalidateSize();
235
+ } catch (e) {
236
+ }
237
+ }, 150);
238
+ }
174
239
  async onBeforeDestroy() {
175
240
  if (this.map) {
176
241
  this.map.remove();
@@ -178,6 +243,20 @@ class MapView extends View {
178
243
  }
179
244
  await super.onBeforeDestroy();
180
245
  }
246
+ static async showAsDialog(options = {}) {
247
+ const view = new MapView(options);
248
+ const dopts = options.dialogOptions || {};
249
+ const dialogOptions = {
250
+ title: "Map View",
251
+ header: true,
252
+ body: view,
253
+ size: "lg",
254
+ centered: false,
255
+ ...dopts
256
+ };
257
+ await view.init();
258
+ await view.getApp().showDialog(dialogOptions);
259
+ }
181
260
  }
182
261
  export {
183
262
  C as Collection,
@@ -1 +1 @@
1
- {"version":3,"file":"map.es.js","sources":["../src/extensions/map/MapView.js"],"sourcesContent":["/**\n * MapView - Interactive map component using Leaflet\n * \n * Features:\n * - Display single or multiple markers\n * - Auto-zoom to fit markers\n * - Customizable marker popups\n * - Support for different tile layers\n * \n * @example\n * const mapView = new MapView({\n * markers: [\n * { lat: 37.422, lng: -122.084, popup: 'Mountain View, CA' }\n * ],\n * zoom: 10,\n * height: 400\n * });\n */\n\nimport View from '@core/View.js';\n\nclass MapView extends View {\n constructor(options = {}) {\n super({\n className: 'map-view',\n ...options\n });\n\n this.markers = options.markers || [];\n this.center = options.center || null;\n this.zoom = options.zoom || 13;\n this.height = options.height || 400;\n this.showZoomControl = options.showZoomControl !== false;\n this.tileLayer = options.tileLayer || 'osm'; // 'osm', 'satellite', 'terrain'\n \n this.map = null;\n this.leafletMarkers = [];\n\n this.template = `\n <div class=\"map-container\">\n <div id=\"map-{{id}}\" style=\"height: {{height}}px; width: 100%; border-radius: 0.375rem; border: 1px solid #dee2e6;\"></div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await this.loadLeaflet();\n await this.initializeMap();\n }\n\n async loadLeaflet() {\n // Check if Leaflet is already loaded\n if (window.L) return;\n\n // Load Leaflet CSS and wait for it\n const cssLoaded = new Promise((resolve) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';\n link.onload = resolve;\n link.onerror = resolve; // Continue even if CSS fails\n document.head.appendChild(link);\n });\n\n // Load Leaflet JS\n const jsLoaded = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n\n // Wait for both CSS and JS to load\n await Promise.all([cssLoaded, jsLoaded]);\n }\n\n getTileLayerUrl() {\n const tileLayers = {\n // Standard street maps\n osm: {\n url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',\n attribution: '© OpenStreetMap contributors',\n maxZoom: 19\n },\n \n // Satellite imagery\n satellite: {\n url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n attribution: '© Esri',\n maxZoom: 19\n },\n \n // Terrain and topographic\n terrain: {\n url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',\n attribution: '© OpenTopoMap contributors',\n maxZoom: 17\n },\n \n // Dark mode styles\n dark: {\n url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n \n // Light/minimal styles\n light: {\n url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n \n // Watercolor artistic style\n watercolor: {\n url: 'https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg',\n attribution: '© Stadia Maps © Stamen Design © OpenStreetMap contributors',\n maxZoom: 16\n },\n \n // Black and white\n bw: {\n url: 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n \n // Streets with labels\n streets: {\n url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n }\n };\n\n return tileLayers[this.tileLayer] || tileLayers.osm;\n }\n\n async initializeMap() {\n const mapElement = this.element.querySelector(`#map-${this.id}`);\n if (!mapElement || !window.L) return;\n\n // Determine map center\n let mapCenter = this.center;\n if (!mapCenter && this.markers.length > 0) {\n // Use first marker as center\n mapCenter = [this.markers[0].lat, this.markers[0].lng];\n }\n if (!mapCenter) {\n // Default to world view\n mapCenter = [0, 0];\n }\n\n // Create map\n this.map = window.L.map(mapElement, {\n center: mapCenter,\n zoom: this.zoom,\n zoomControl: this.showZoomControl\n });\n\n // Add tile layer\n const tileConfig = this.getTileLayerUrl();\n window.L.tileLayer(tileConfig.url, {\n attribution: tileConfig.attribution,\n maxZoom: tileConfig.maxZoom\n }).addTo(this.map);\n\n // Add markers\n this.addMarkers(this.markers);\n\n // Auto-fit bounds if multiple markers\n if (this.markers.length > 1) {\n this.fitBounds();\n }\n\n // Fix tile rendering issues by invalidating size after a delay\n // This ensures the container has proper dimensions and CSS is applied\n setTimeout(() => {\n if (this.map) {\n this.map.invalidateSize();\n }\n }, 300);\n }\n\n addMarkers(markers) {\n if (!this.map || !Array.isArray(markers)) return;\n\n markers.forEach(markerData => {\n const { lat, lng, popup, icon } = markerData;\n \n if (!lat || !lng) return;\n\n const markerOptions = {};\n \n // Custom icon if provided\n if (icon) {\n markerOptions.icon = window.L.icon(icon);\n }\n\n const marker = window.L.marker([lat, lng], markerOptions).addTo(this.map);\n\n // Add popup if provided\n if (popup) {\n marker.bindPopup(popup);\n }\n\n this.leafletMarkers.push(marker);\n });\n }\n\n fitBounds() {\n if (!this.map || this.leafletMarkers.length === 0) return;\n\n const group = new window.L.featureGroup(this.leafletMarkers);\n this.map.fitBounds(group.getBounds().pad(0.1));\n }\n\n updateMarkers(newMarkers) {\n // Clear existing markers\n this.clearMarkers();\n \n // Add new markers\n this.markers = newMarkers;\n this.addMarkers(newMarkers);\n \n // Fit bounds if multiple markers\n if (newMarkers.length > 1) {\n this.fitBounds();\n } else if (newMarkers.length === 1) {\n this.map.setView([newMarkers[0].lat, newMarkers[0].lng], this.zoom);\n }\n }\n\n clearMarkers() {\n this.leafletMarkers.forEach(marker => {\n this.map.removeLayer(marker);\n });\n this.leafletMarkers = [];\n }\n\n setView(lat, lng, zoom = null) {\n if (!this.map) return;\n this.map.setView([lat, lng], zoom || this.zoom);\n }\n\n setZoom(zoom) {\n if (!this.map) return;\n this.map.setZoom(zoom);\n }\n\n async onBeforeDestroy() {\n if (this.map) {\n this.map.remove();\n this.map = null;\n }\n await super.onBeforeDestroy();\n }\n}\n\nexport default MapView;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"map.es.js","sources":["../src/extensions/map/MapView.js"],"sourcesContent":["/**\n * MapView - Interactive map component using Leaflet\n *\n * Features:\n * - Display single or multiple markers\n * - Auto-zoom to fit markers\n * - Customizable marker popups\n * - Support for different tile layers\n *\n * @example\n * const mapView = new MapView({\n * markers: [\n * { lat: 37.422, lng: -122.084, popup: 'Mountain View, CA' }\n * ],\n * zoom: 10,\n * height: 400\n * });\n */\n\nimport View from '@core/View.js';\n\nclass MapView extends View {\n constructor(options = {}) {\n super({\n className: 'map-view',\n ...options\n });\n\n this.markers = options.markers || [];\n this.center = options.center || null;\n this.zoom = options.zoom || 13;\n this.height = options.height || 400;\n this.showZoomControl = options.showZoomControl !== false;\n this.tileLayer = options.tileLayer || 'osm'; // 'osm', 'satellite', 'terrain'\n this.showLeafletBranding = options.showLeafletBranding === true;\n this.showLayerControl = options.showLayerControl === true;\n this.layerOptions = options.layerOptions || {\n osm: 'OSM',\n satellite: 'Satellite',\n terrain: 'Terrain',\n dark: 'Dark',\n light: 'Light',\n watercolor: 'Watercolor',\n bw: 'B/W',\n streets: 'Streets'\n };\n\n this.map = null;\n this.leafletMarkers = [];\n this._tileLayer = null;\n\n this.template = `\n <div class=\"map-container\">\n <div id=\"map-{{id}}\" style=\"height: {{height}}px; width: 100%; border-radius: 0.375rem; border: 1px solid #dee2e6;\"></div>\n </div>\n `;\n }\n\n async onAfterRender() {\n await this.loadLeaflet();\n await this.initializeMap();\n }\n\n async loadLeaflet() {\n // Check if Leaflet is already loaded\n if (window.L) return;\n\n // Load Leaflet CSS and wait for it\n const cssLoaded = new Promise((resolve) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';\n link.onload = resolve;\n link.onerror = resolve; // Continue even if CSS fails\n document.head.appendChild(link);\n });\n\n // Load Leaflet JS\n const jsLoaded = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';\n script.onload = resolve;\n script.onerror = reject;\n document.head.appendChild(script);\n });\n\n // Wait for both CSS and JS to load\n await Promise.all([cssLoaded, jsLoaded]);\n }\n\n getTileLayerUrl() {\n const tileLayers = {\n // Standard street maps\n osm: {\n url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',\n attribution: '© OpenStreetMap contributors',\n maxZoom: 19\n },\n\n // Satellite imagery\n satellite: {\n url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n attribution: '© Esri',\n maxZoom: 19\n },\n\n // Terrain and topographic\n terrain: {\n url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',\n attribution: '© OpenTopoMap contributors',\n maxZoom: 17\n },\n\n // Dark mode styles\n dark: {\n url: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n\n // Light/minimal styles\n light: {\n url: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n\n // Watercolor artistic style\n watercolor: {\n url: 'https://tiles.stadiamaps.com/tiles/stamen_watercolor/{z}/{x}/{y}.jpg',\n attribution: '© Stadia Maps © Stamen Design © OpenStreetMap contributors',\n maxZoom: 16\n },\n\n // Black and white\n bw: {\n url: 'https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n },\n\n // Streets with labels\n streets: {\n url: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png',\n attribution: '© OpenStreetMap contributors © CARTO',\n maxZoom: 20\n }\n };\n\n return tileLayers[this.tileLayer] || tileLayers.osm;\n }\n\n async initializeMap() {\n const mapElement = this.element.querySelector(`#map-${this.id}`);\n if (!mapElement || !window.L) return;\n\n // Determine map center\n let mapCenter = this.center;\n if (!mapCenter && this.markers.length > 0) {\n // Use first marker as center\n mapCenter = [this.markers[0].lat, this.markers[0].lng];\n }\n if (!mapCenter) {\n // Default to world view\n mapCenter = [0, 0];\n }\n\n // Create map\n this.map = window.L.map(mapElement, {\n center: mapCenter,\n zoom: this.zoom,\n zoomControl: this.showZoomControl\n });\n // Optionally hide Leaflet branding/prefix (removes Leaflet link/flag in attribution control)\n if (this.map && this.map.attributionControl && this.showLeafletBranding === false) {\n try { this.map.attributionControl.setPrefix(''); } catch (e) {}\n }\n\n // Add tile layer\n const tileConfig = this.getTileLayerUrl();\n this._tileLayer = window.L.tileLayer(tileConfig.url, {\n attribution: tileConfig.attribution,\n maxZoom: tileConfig.maxZoom\n }).addTo(this.map);\n\n // Optional built-in tile layer selector UI\n if (this.showLayerControl) {\n const container = mapElement.parentElement || this.element.querySelector('.map-container');\n if (container) {\n container.style.position = container.style.position || 'relative';\n const selector = document.createElement('select');\n selector.className = 'form-select form-select-sm';\n selector.style.position = 'absolute';\n selector.style.top = '8px';\n selector.style.right = '8px';\n selector.style.zIndex = '1000';\n selector.style.maxWidth = '180px';\n selector.setAttribute('aria-label', 'Map tile layer');\n\n // Populate options\n Object.entries(this.layerOptions || {}).forEach(([key, label]) => {\n const opt = document.createElement('option');\n opt.value = key;\n opt.textContent = label;\n if (key === this.tileLayer) opt.selected = true;\n selector.appendChild(opt);\n });\n\n selector.addEventListener('change', () => this.setTileLayer(selector.value));\n container.appendChild(selector);\n }\n }\n\n // Add markers\n this.addMarkers(this.markers);\n\n // Auto-fit bounds if multiple markers\n if (this.markers.length > 1) {\n this.fitBounds();\n }\n\n // Fix tile rendering issues by invalidating size after a delay\n // This ensures the container has proper dimensions and CSS is applied\n setTimeout(() => {\n if (this.map) {\n this.map.invalidateSize();\n }\n }, 300);\n }\n\n addMarkers(markers) {\n if (!this.map || !Array.isArray(markers)) return;\n\n markers.forEach(markerData => {\n const { lat, lng, popup, icon } = markerData;\n\n if (!lat || !lng) return;\n\n const markerOptions = {};\n\n // Custom icon if provided\n if (icon) {\n markerOptions.icon = window.L.icon(icon);\n }\n\n const marker = window.L.marker([lat, lng], markerOptions).addTo(this.map);\n\n // Add popup if provided\n if (popup) {\n marker.bindPopup(popup);\n }\n\n this.leafletMarkers.push(marker);\n });\n }\n\n fitBounds() {\n if (!this.map || this.leafletMarkers.length === 0) return;\n\n const group = new window.L.featureGroup(this.leafletMarkers);\n this.map.fitBounds(group.getBounds().pad(0.1));\n }\n\n updateMarkers(newMarkers) {\n // Clear existing markers\n this.clearMarkers();\n\n // Add new markers\n this.markers = newMarkers;\n this.addMarkers(newMarkers);\n\n // Fit bounds if multiple markers\n if (newMarkers.length > 1) {\n this.fitBounds();\n } else if (newMarkers.length === 1) {\n this.map.setView([newMarkers[0].lat, newMarkers[0].lng], this.zoom);\n }\n }\n\n clearMarkers() {\n this.leafletMarkers.forEach(marker => {\n this.map.removeLayer(marker);\n });\n this.leafletMarkers = [];\n }\n\n setView(lat, lng, zoom = null) {\n if (!this.map) return;\n this.map.setView([lat, lng], zoom || this.zoom);\n }\n\n setZoom(zoom) {\n if (!this.map) return;\n this.map.setZoom(zoom);\n }\n\n setTileLayer(key) {\n if (!this.map) return;\n // Resolve tile layer config using the same logic as getTileLayerUrl\n const original = this.tileLayer;\n this.tileLayer = key || this.tileLayer;\n const tileConfig = this.getTileLayerUrl();\n try {\n if (this._tileLayer) {\n this.map.removeLayer(this._tileLayer);\n }\n } catch (e) {\n // ignore if layer already removed\n }\n this._tileLayer = window.L.tileLayer(tileConfig.url, {\n attribution: tileConfig.attribution,\n maxZoom: tileConfig.maxZoom\n }).addTo(this.map);\n // Keep property in sync\n this.tileLayer = key || original;\n\n // Nudge map to ensure proper redraw\n setTimeout(() => {\n try { this.map.invalidateSize(); } catch (e) {}\n }, 150);\n }\n\n async onBeforeDestroy() {\n if (this.map) {\n this.map.remove();\n this.map = null;\n }\n await super.onBeforeDestroy();\n }\n\n static async showAsDialog(options = {}) {\n const view = new MapView(options);\n const dopts = options.dialogOptions || {};\n const dialogOptions = {\n title: \"Map View\",\n header: true,\n body: view,\n size: 'lg',\n centered: false,\n ...dopts\n }\n await view.init();\n await view.getApp().showDialog(dialogOptions);\n }\n}\n\nexport default MapView;\n"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/ListView-BRGiITfD.js"),e=require("./chunks/Rest-BNYqGlnP.js"),i=require("./chunks/Collection-DD1_31eh.js");class TimelineViewItem extends t.ListViewItem{constructor(t={}){super({className:"timeline-item",...t}),this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.template||(this.template='\n <div class="timeline-marker timeline-marker-{{markerType}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}} text-{{displayColor}}"></i>\n {{/hasIcon}}\n {{^hasIcon}}\n <div class="timeline-dot bg-{{displayColor}}"></div>\n {{/hasIcon}}\n </div>\n \n <div class="timeline-content">\n {{#showDate}}\n <div class="timeline-date text-muted small">\n {{formattedDate}}\n </div>\n {{/showDate}}\n \n <div class="timeline-card">\n {{#model.title}}\n <h6 class="timeline-title mb-1">{{model.title}}</h6>\n {{/model.title}}\n \n {{#model.description}}\n <p class="timeline-description mb-0">{{model.description}}</p>\n {{/model.description}}\n \n {{#model.meta}}\n <div class="timeline-meta mt-2 text-muted small">\n {{model.meta}}\n </div>\n {{/model.meta}}\n </div>\n </div>\n ')}async onInit(){await super.onInit(),this.processItemData()}processItemData(){this.displayColor=this.model?.get?.("color")||this.model?.color||this.theme;const t=!(!this.model?.get?.("icon")&&!this.model?.icon)&&"icon"===this.dotStyle;this.hasIcon=t,this.markerType=t?"icon":this.dotStyle;const e=this.model?.get?.("date")||this.model?.date;this.formattedDate=this.formatDate(e)}formatDate(t){if(!t)return"";switch(this.dateFormat){case"datetime":return e.dataFormatter.pipe(t,"datetime");case"relative":return e.dataFormatter.pipe(t,"timeago");default:return e.dataFormatter.pipe(t,"date")}}async onActionSelect(t,e){t.stopPropagation(),this.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model})}}class TimelineView extends t.ListView{constructor(t={}){super({className:"timeline-view",itemClass:t.itemClass||TimelineViewItem,selectionMode:"none",emptyMessage:t.emptyMessage||"No timeline events to display",template:'\n <div class="timeline-container timeline-{{position}}">\n {{#loading}}\n <div class="timeline-loading text-center py-4">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <span class="ms-2 text-muted">Loading timeline...</span>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="timeline-empty text-center text-muted py-4">\n <i class="bi bi-clock-history fs-1 d-block mb-2"></i>\n <p>{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <div class="timeline" data-container="items"></div>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ',...t}),this.position=t.position||"left",this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.groupBy=t.groupBy||"none"}_createItemView(t,e){if(this.itemViews.has(t.id))return;const i=new this.itemClass({model:t,index:e,listView:this,template:this.itemTemplate,dateFormat:this.dateFormat,dotStyle:this.dotStyle,showDate:this.showDate,theme:this.theme});return this.itemViews.set(t.id,i),i.on("item:click",this._onItemClick.bind(this)),i}_onItemClick(t){this.emit("item:click",t)}setPosition(t){return"left"!==t&&"center"!==t?(console.warn('Invalid position. Use "left" or "center"'),this):(this.position=t,this.isMounted()&&this.render(),this)}setDateFormat(t){return this.dateFormat=t,this.forEachItem(e=>{e.dateFormat=t,e.processItemData(),e.isMounted()&&e.render()}),this}setDotStyle(t){return this.dotStyle=t,this.forEachItem(e=>{e.dotStyle=t,e.processItemData(),e.isMounted()&&e.render()}),this}toggleDates(t=null){return this.showDate=null!==t?t:!this.showDate,this.forEachItem(t=>{t.showDate=this.showDate,t.isMounted()&&t.render()}),this}}exports.ListView=t.ListView,exports.ListViewItem=t.ListViewItem,exports.View=e.View,exports.Collection=i.Collection,exports.Model=i.Model,exports.TimelineView=TimelineView,exports.TimelineViewItem=TimelineViewItem;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/ListView-BpGEatee.js"),e=require("./chunks/Rest-BpDyhFfG.js"),i=require("./chunks/Collection-B64LJ92k.js");class TimelineViewItem extends t.ListViewItem{constructor(t={}){super({className:"timeline-item",...t}),this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.template||(this.template='\n <div class="timeline-marker timeline-marker-{{markerType}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}} text-{{displayColor}}"></i>\n {{/hasIcon}}\n {{^hasIcon}}\n <div class="timeline-dot bg-{{displayColor}}"></div>\n {{/hasIcon}}\n </div>\n \n <div class="timeline-content">\n {{#showDate}}\n <div class="timeline-date text-muted small">\n {{formattedDate}}\n </div>\n {{/showDate}}\n \n <div class="timeline-card">\n {{#model.title}}\n <h6 class="timeline-title mb-1">{{model.title}}</h6>\n {{/model.title}}\n \n {{#model.description}}\n <p class="timeline-description mb-0">{{model.description}}</p>\n {{/model.description}}\n \n {{#model.meta}}\n <div class="timeline-meta mt-2 text-muted small">\n {{model.meta}}\n </div>\n {{/model.meta}}\n </div>\n </div>\n ')}async onInit(){await super.onInit(),this.processItemData()}processItemData(){this.displayColor=this.model?.get?.("color")||this.model?.color||this.theme;const t=!(!this.model?.get?.("icon")&&!this.model?.icon)&&"icon"===this.dotStyle;this.hasIcon=t,this.markerType=t?"icon":this.dotStyle;const e=this.model?.get?.("date")||this.model?.date;this.formattedDate=this.formatDate(e)}formatDate(t){if(!t)return"";switch(this.dateFormat){case"datetime":return e.dataFormatter.pipe(t,"datetime");case"relative":return e.dataFormatter.pipe(t,"timeago");default:return e.dataFormatter.pipe(t,"date")}}async onActionSelect(t,e){t.stopPropagation(),this.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model})}}class TimelineView extends t.ListView{constructor(t={}){super({className:"timeline-view",itemClass:t.itemClass||TimelineViewItem,selectionMode:"none",emptyMessage:t.emptyMessage||"No timeline events to display",template:'\n <div class="timeline-container timeline-{{position}}">\n {{#loading}}\n <div class="timeline-loading text-center py-4">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <span class="ms-2 text-muted">Loading timeline...</span>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="timeline-empty text-center text-muted py-4">\n <i class="bi bi-clock-history fs-1 d-block mb-2"></i>\n <p>{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <div class="timeline" data-container="items"></div>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ',...t}),this.position=t.position||"left",this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.groupBy=t.groupBy||"none"}_createItemView(t,e){if(this.itemViews.has(t.id))return;const i=new this.itemClass({model:t,index:e,listView:this,template:this.itemTemplate,dateFormat:this.dateFormat,dotStyle:this.dotStyle,showDate:this.showDate,theme:this.theme});return this.itemViews.set(t.id,i),i.on("item:click",this._onItemClick.bind(this)),i}_onItemClick(t){this.emit("item:click",t)}setPosition(t){return"left"!==t&&"center"!==t?(console.warn('Invalid position. Use "left" or "center"'),this):(this.position=t,this.isMounted()&&this.render(),this)}setDateFormat(t){return this.dateFormat=t,this.forEachItem(e=>{e.dateFormat=t,e.processItemData(),e.isMounted()&&e.render()}),this}setDotStyle(t){return this.dotStyle=t,this.forEachItem(e=>{e.dotStyle=t,e.processItemData(),e.isMounted()&&e.render()}),this}toggleDates(t=null){return this.showDate=null!==t?t:!this.showDate,this.forEachItem(t=>{t.showDate=this.showDate,t.isMounted()&&t.render()}),this}}exports.ListView=t.ListView,exports.ListViewItem=t.ListViewItem,exports.View=e.View,exports.Collection=i.Collection,exports.Model=i.Model,exports.TimelineView=TimelineView,exports.TimelineViewItem=TimelineViewItem;
2
2
  //# sourceMappingURL=timeline.cjs.js.map
@@ -1,7 +1,7 @@
1
- import { L as ListViewItem, a as ListView } from "./chunks/ListView-BrsQ26R6.js";
2
- import { d as dataFormatter } from "./chunks/Rest-CS4jRCAs.js";
3
- import { V } from "./chunks/Rest-CS4jRCAs.js";
4
- import { C, M } from "./chunks/Collection-DaTm-2LH.js";
1
+ import { L as ListViewItem, a as ListView } from "./chunks/ListView-BGJG4GYH.js";
2
+ import { d as dataFormatter } from "./chunks/Rest-DpbPbmra.js";
3
+ import { V } from "./chunks/Rest-DpbPbmra.js";
4
+ import { C, M } from "./chunks/Collection-CsAk0UhA.js";
5
5
  class TimelineViewItem extends ListViewItem {
6
6
  constructor(options = {}) {
7
7
  super({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-mojo",
3
- "version": "2.1.1044",
3
+ "version": "2.1.1087",
4
4
  "description": "WEB-MOJO - A lightweight JavaScript framework for building data-driven web applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs.js",
@@ -1,2 +0,0 @@
1
- "use strict";const e=require("./Rest-BNYqGlnP.js");class Router{constructor(e={}){this.defaultRoute=e.defaultRoute||"home",this.routes=[],this.currentRoute=null,this.eventEmitter=e.eventEmitter||null,this.boundHandlePopState=this.handlePopState.bind(this)}start(){window.addEventListener("popstate",this.boundHandlePopState),this.handleCurrentLocation()}stop(){window.removeEventListener("popstate",this.boundHandlePopState)}addRoute(e,t){this.routes.push({pattern:this.normalizePattern(e),regex:this.patternToRegex(e),pageName:t,paramNames:this.extractParamNames(e)})}async navigate(e,t={}){const{replace:s=!1,state:i=null,trigger:o=!0}=t,{pageName:n,queryParams:r}=this.parseInput(e);o&&await this.handleRouteChange(n,r)}back(){window.history.back()}forward(){window.history.forward()}getCurrentRoute(){return this.currentRoute}getCurrentPath(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();return this.buildPublicUrl(e,t)}handlePopState(e){this.allowPopState?this.handleCurrentLocation():console.warn("PopStateEvent is not allowed")}async handleCurrentLocation(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();await this.handleRouteChange(e,t)}async handleRouteChange(e,t){const s="/"+e,i=this.matchRoute(s),o=this.buildPublicUrl(e,t);return i?(this.currentRoute=i,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:o,pageName:i.pageName,params:i.params,query:t,route:i}),i):(this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:o}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const i={};return t.paramNames.forEach((e,t)=>{i[e]=s[t+1]}),{...t,params:i,path:e}}}return null}parseInput(e){let t=this.defaultRoute,s={};if(!e)return{pageName:t,queryParams:s};try{if(e.includes("?")){const[i,o]=e.split("?",2),n=new URLSearchParams(o);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[e,t]of n)"page"!==e&&(s[e]=t)}else{t=i.startsWith("/")?i.substring(1)||this.defaultRoute:i||this.defaultRoute;for(const[e,t]of n)s[e]=t}}else t=e.startsWith("/")?e.substring(1)||this.defaultRoute:e}catch(i){console.warn("Failed to parse input:",e,i),t=this.defaultRoute,s={}}return{pageName:t,queryParams:s}}parseCurrentUrl(){const e=new URLSearchParams(window.location.search),t=e.get("page")||this.defaultRoute,s={};for(const[i,o]of e)"page"!==i&&(s[i]=o);return{pageName:t,queryParams:s}}buildPublicUrl(e,t={}){const s=new URLSearchParams;return s.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&s.set(e,String(t))}),"?"+s.toString()}updateBrowserUrl(e,t,s,i){const o=new URL(window.location.origin+window.location.pathname);o.searchParams.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&o.searchParams.set(e,String(t))});const n=o.toString();s?window.history.replaceState(i,"",n):window.history.pushState(i,"",n)}patternToRegex(e){let t=e.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&").replace(/\/:([^/?]+)\?/g,"(?:/([^/]+))?").replace(/:([^/]+)/g,"([^/]+)");return new RegExp(`^${t}$`)}extractParamNames(e){return(e.match(/:([^/?]+)\??/g)||[]).map(e=>e.replace(/[:?]/g,""))}normalizePattern(e){return e.startsWith("/")?e:`/${e}`}updateUrl(e={},t={}){const{replace:s=!1}=t,{pageName:i}=this.parseCurrentUrl();this.updateBrowserUrl(i,e,s)}buildUrl(e,t={}){return this.buildPublicUrl(e,t)}doRoutesMatch(e,t){if(!e||!t)return!1;const{pageName:s}=this.parseInput(e),{pageName:i}=this.parseInput(t);return s===i}}class EventBus{constructor(){this.listeners={},this.onceListeners={},this.maxListeners=100,this.debugMode=!1,this.eventStats={}}on(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.on(e,t)),this):(this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].length>=this.maxListeners&&console.warn(`Max listeners (${this.maxListeners}) exceeded for event: ${e}`),this.listeners[e].push(t),this)}once(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.once(e,t)),this):(this.onceListeners[e]||(this.onceListeners[e]=[]),this.onceListeners[e].push(t),this)}off(e,t){if(Array.isArray(e))return e.forEach(e=>this.off(e,t)),this;if(!t)return delete this.listeners[e],delete this.onceListeners[e],this;if(this.listeners[e]){const s=this.listeners[e].indexOf(t);-1!==s&&(this.listeners[e].splice(s,1),0===this.listeners[e].length&&delete this.listeners[e])}if(this.onceListeners[e]){const s=this.onceListeners[e].indexOf(t);-1!==s&&(this.onceListeners[e].splice(s,1),0===this.onceListeners[e].length&&delete this.onceListeners[e])}return this}emit(e,t){this.updateEventStats(e),this.debugMode;const s=[];return this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]),this.debugMode&&s.length>0&&s.length,s.forEach(s=>{try{s(t,e)&&(e.stopPropagation&&e.stopPropagation(),e.preventDefault&&e.preventDefault())}catch(i){console.error(`Error in event listener for '${e}':`,i),this.emitError(i,e,s)}}),this}async emitAsync(e,t){const s=[];this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]);const i=s.map(s=>new Promise(i=>{try{i(s(t,e))}catch(o){console.error(`Error in async event listener for '${e}':`,o),this.emitError(o,e,s),i()}}));return await Promise.all(i),this}removeAllListeners(){return this.listeners={},this.onceListeners={},this}listenerCount(e){return(this.listeners[e]?this.listeners[e].length:0)+(this.onceListeners[e]?this.onceListeners[e].length:0)}eventNames(){const e=Object.keys(this.listeners),t=Object.keys(this.onceListeners);return[.../* @__PURE__ */new Set([...e,...t])]}setMaxListeners(e){if("number"!=typeof e||e<0)throw new Error("Max listeners must be a non-negative number");return this.maxListeners=e,this}namespace(e){const t=t=>`${e}:${t}`;return{on:(e,s)=>this.on(t(e),s),once:(e,s)=>this.once(t(e),s),off:(e,s)=>this.off(t(e),s),emit:(e,s)=>this.emit(t(e),s),emitAsync:(e,s)=>this.emitAsync(t(e),s)}}use(e){if("function"!=typeof e)throw new Error("Middleware must be a function");const t=this.emit;return this.emit=(s,i)=>{try{const o=e(s,i);if(!1===o)return this;const n=void 0!==o?o:i;return t.call(this,s,n)}catch(o){return console.error("Error in event middleware:",o),t.call(this,s,i)}},this}emitError(e,t,s){"error"!==t&&setTimeout(()=>{this.emit("error",{error:e,originalEvent:t,callback:s.toString()})},0)}waitFor(e,t=null){return new Promise((s,i)=>{let o=null;const n=e=>{o&&clearTimeout(o),s(e)};this.once(e,n),t&&(o=setTimeout(()=>{this.off(e,n),i(new Error(`Timeout waiting for event: ${e}`))},t))})}debug(e=!0){return this.debugMode=e,this}getStats(){const e=this.eventNames(),t={totalEvents:e.length,totalListeners:0,events:{},emissions:{...this.eventStats}};return e.forEach(e=>{const s=this.listenerCount(e);t.events[e]=s,t.totalListeners+=s}),t}updateEventStats(e){this.eventStats[e]||(this.eventStats[e]={count:0,firstEmission:Date.now(),lastEmission:null}),this.eventStats[e].count++,this.eventStats[e].lastEmission=Date.now()}getEventStats(e){const t=this.eventStats[e];return t?{...t,listenerCount:this.listenerCount(e),avgEmissionsPerMinute:this.calculateEmissionRate(t)}:null}calculateEmissionRate(e){if(!e.firstEmission||!e.lastEmission)return 0;const t=e.lastEmission-e.firstEmission;if(0===t)return 0;const s=t/6e4;return Math.round(e.count/s*100)/100}resetStats(){return this.eventStats={},this}getTopEvents(e=10){return Object.entries(this.eventStats).map(([e,t])=>({event:e,count:t.count,rate:this.calculateEmissionRate(t),listeners:this.listenerCount(e)})).sort((e,t)=>t.count-e.count).slice(0,e)}debugInfo(){this.debugMode,this.maxListeners;const e=this.getStats();return e.totalEvents,e.totalListeners,Object.keys(this.eventStats).length>0&&this.getTopEvents(5),this}}class WebApp{constructor(t={}){this.config=t,this.initPluginRegistry(),this.name=t.name||"MOJO App",this.version=t.version||"1.0.0",this.debug=t.debug||!1,this.container=t.container||"#app",this.layoutType=t.layout||"portal",this.layoutConfig=t.layoutConfig||{},t.sidebar&&(this.layoutConfig.sidebarConfig=t.sidebar),t.topbar&&(this.layoutConfig.topbarConfig=t.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=t.pageContainer||"#page-container",this.basePath=t.basePath||"",this.routerMode=t.routerMode||t.router?.mode||"param",this.basePath=t.basePath||t.router?.base||"",this.defaultRoute=t.defaultRoute||"home",this.session=t.session||{},this.router=null,this.navigation=t.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new EventBus,this.rest=e.rest,t.api&&this.rest.configure(t.api),this.router=new Router({mode:"param"===this.routerMode?"params":this.routerMode,basePath:this.basePath,defaultRoute:this.defaultRoute,eventEmitter:this.events}),this.events.on("route:changed",async e=>{const{pageName:t,params:s,query:i}=e;await this.showPage(t,i,s,{fromRouter:!0})}),"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.router=this.router),this.setupFocusTracking(),this.pageCache=/* @__PURE__ */new Map,this.pageClasses=/* @__PURE__ */new Map,this.componentClasses=/* @__PURE__ */new Map,this.modelClasses=/* @__PURE__ */new Map,this.currentPage=null,this.isStarted=!1,window.matchUUID?window[window.matchUUID]=this:window.MOJO?window.MOJO.app=this:window.__app__=this}async start(){if(this.isStarted)console.warn("WebApp already started");else try{this.setupPageContainer(),this.validateDefaultRoute(),await this.setupRouter(),this.isStarted=!0,this.router.allowPopState=!1,this.events.emit("app:ready",{app:this})}catch(e){throw console.error(`Failed to start ${this.name}:`,e),this.showError("Failed to start application"),e}}async setupRouter(){this.router?(this.events.on("route:notfound",async e=>{console.warn(`Route not found: ${e.path}`),this._show404(e.path)}),this.router.start(),this.routerMode):console.error("Router not initialized")}setupPageContainer(){const e="string"==typeof this.container?document.querySelector(this.container):this.container;e&&!e.querySelector("#page-container")&&(e.innerHTML='<div id="page-container"></div>'),this.pageContainer="#page-container"}registerPage(e,t,s={}){if("string"!=typeof e||!e)return console.error("registerPage: pageName must be a non-empty string"),this;if("function"!=typeof t)return console.error("registerPage: PageClass must be a constructor function"),this;if(s.containerId||(s.containerId=this.pageContainer),this.pageClasses.set(e,{PageClass:t,constructorOptions:s}),this.router){let t=s.route||`/${e}`;t.startsWith("/")||(t=`/${t}`),s.route=t,this.router.addRoute(t,e)}return this}getPage(e){return this.pageCache.get(e)}getPagePermissions(e){if(this.pageCache.has(e))return this.pageCache.get(e).permissions;const t=this.pageClasses.get(e);if(!t)return null;const{PageClass:s,constructorOptions:i}=t;return i?i.permissions:null}getOrCreatePage(e){if(this.pageCache.has(e))return this.pageCache.get(e);const t=this.pageClasses.get(e);if(!t)return console.error(`Page not registered: ${e}`),null;const{PageClass:s,constructorOptions:i}=t;try{const t=new s({pageName:e,...i,app:this});return i.route&&(t.route=i.route),this.pageCache.set(e,t),t.route,t}catch(o){return console.error(`Failed to create page ${e}:`,o),null}}async showPage(e,t={},s={},i={}){const{fromRouter:o=!1,replace:n=!1,force:r=!1}=i;try{let i,n;"string"==typeof e?(n=e,i=this.getOrCreatePage(e)):e&&"object"==typeof e&&(i=e,n=e.pageName),this.events.emit("page:showing",{page:i,pageName:i.pageName,params:s,query:t,fromRouter:o});const r=this.currentPage;if(!i)return void this._show404(n,s,t,o);if(!i.canEnter())return void this._showDeniedPage(i,s,t,o);r&&r!==i&&await this._exitOldPage(r),await i.onParams(s,t),r!==i&&await i.onEnter(),i.syncUrl(),this.events.emit("page:show",{page:i,pageName:i.pageName,params:s,query:t,fromRouter:o}),await i.render(),this.currentPage=i,i.pageName}catch(a){console.error("Error in showPage:",a),this.showError(`Failed to load page: ${a.message}`),"error"!==e&&await this.showPage("error",{},{error:a,originalPage:e},{fromRouter:o})}}async _show404(e,t,s,i){const o=this.getOrCreatePage("404");o&&(o.setInfo&&o.setInfo(e),await this._exitOldPage(this.currentPage),await o.render(),this.currentPage=o,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:i}))}async _showDeniedPage(e,t,s,i){const o=this.getOrCreatePage("denied");o.setDeniedPage&&o.setDeniedPage(e),await this._exitOldPage(this.currentPage),await o.render(),this.currentPage=o,this.events.emit("page:denied",{page:e,pageName:e.pageName,params:t,query:s,fromRouter:i})}async _exitOldPage(e){if(e)try{await e.onExit(),await e.unmount(),this.events.emit("page:hide",{page:e})}catch(t){console.error(`Error exiting page ${e.pageName}:`,t)}}async navigate(e,t={},s={}){if(!this.router)return void console.error("Router not initialized");let i=e;if(Object.keys(t).length>0){const s=new URLSearchParams(t).toString();i+=(e.includes("?")?"&":"?")+s}return await this.router.navigate(i,s)}async navigateToDefault(e={}){return await this.showPage(this.defaultRoute,{},{},e)}back(){this.router?this.router.back():console.warn("Router not initialized")}forward(){this.router?this.router.forward():console.warn("Router not initialized")}getCurrentPage(){return this.currentPage}getPageContainer(){return this.layout&&this.layout.getPageContainer?this.layout.getPageContainer():"string"==typeof this.pageContainer?document.querySelector(this.pageContainer):this.pageContainer}async showError(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Error",{size:"md",class:"text-danger"})}catch(s){this.events.emit("notification",{message:e,type:"error"}),"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showError fallback:",s),"undefined"!=typeof window&&alert(`Error: ${e}`)}}async showSuccess(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Success",{size:"md",class:"text-success"})}catch(s){this.events.emit("notification",{message:e,type:"success"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showSuccess fallback:",s),"undefined"!=typeof window&&alert(`Success: ${e}`)}}async showInfo(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Information",{size:"md",class:"text-info"})}catch(s){this.events.emit("notification",{message:e,type:"info"}),"undefined"!=typeof window&&window,"undefined"!=typeof window&&alert(`Info: ${e}`)}}async showWarning(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Warning",{size:"md",class:"text-warning"})}catch(s){this.events.emit("notification",{message:e,type:"warning"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showWarning fallback:",s),"undefined"!=typeof window&&alert(`Warning: ${e}`)}}showNotification(e,t="info"){this.events.emit("notification",{message:e,type:t})}async showLoading(e={}){"string"==typeof e&&(e={message:e});try{(await Promise.resolve().then(()=>t)).default.showBusy(e)}catch(s){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showLoading fallback:",s,e),this.events.emit("notification",{message:e.message||"Loading...",type:"info"})}}async hideLoading(){try{(await Promise.resolve().then(()=>t)).default.hideBusy()}catch(e){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelForm(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showModelForm(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showForm(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showForm(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showForm failed:",s),s}}async confirm(e,s="Confirm",i={}){const o=(await Promise.resolve().then(()=>t)).default;return await o.confirm(e,s,i)}setupFocusTracking(){if("undefined"==typeof window)return;this.isFocused=!document.hidden;const e=()=>{const e=this.isFocused;this.isFocused=!document.hidden,e!==this.isFocused&&(this.isFocused?this.events.emit("browser:focus"):this.events.emit("browser:blur"))},t=()=>{this.isFocused||(this.isFocused=!0,this.events.emit("browser:focus"))},s=()=>{this.isFocused&&(this.isFocused=!1,this.events.emit("browser:blur"))};document.addEventListener("visibilitychange",e),window.addEventListener("focus",t),window.addEventListener("blur",s),this._focusHandlers={visibilitychange:e,focus:t,blur:s}}setupErrorHandling(){window.addEventListener("error",e=>{console.error("Global error:",e.error),this.debug&&this.showError(`Error: ${e.error?.message||"Unknown error"}`)}),window.addEventListener("unhandledrejection",e=>{console.error("Unhandled promise rejection:",e.reason),this.debug&&this.showError(`Promise rejected: ${e.reason?.message||"Unknown error"}`)})}escapeHtml(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}getState(e){return e?this.state[e]:this.state}setState(e){const t={...this.state};Object.assign(this.state,e),this.events.emit("state:changed",{oldState:t,newState:this.state,updates:e})}registerComponent(e,t){this.componentClasses.set(e,t)}getComponent(e){return this.componentClasses.get(e)}registerModel(e,t){this.modelClasses.set(e,t)}getModel(e){return this.modelClasses.get(e)}setupRest(){this.rest=e.rest,e.rest.configure(this.api)}async destroy(){this.router&&this.router.stop(),this._focusHandlers&&"undefined"!=typeof window&&(document.removeEventListener("visibilitychange",this._focusHandlers.visibilitychange),window.removeEventListener("focus",this._focusHandlers.focus),window.removeEventListener("blur",this._focusHandlers.blur));const e=Array.from(this.pageCache.values());if(await Promise.allSettled(e.map(async e=>{try{e.destroy&&await e.destroy()}catch(t){console.error("Error destroying page:",t)}})),this.layout&&this.layout.destroy)try{await this.layout.destroy()}catch(t){console.error("Error destroying layout:",t)}this.pageCache.clear(),this.pageClasses.clear(),this.componentClasses.clear(),this.modelClasses.clear(),"undefined"!=typeof window&&window.MOJO&&delete window.MOJO.router,this.isStarted=!1,this.name}buildPagePath(e,t,s){let i=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(e=>{"string"!=typeof t[e]&&"number"!=typeof t[e]||(i=i.replace(`:${e}`,t[e]))}),s&&Object.keys(s).length>0){const e=new URLSearchParams(s).toString();i+=(i.includes("?")?"&":"?")+e}return i}validateDefaultRoute(){this.pageClasses.has(this.defaultRoute)?this.defaultRoute:(console.warn(`⚠️ Default route '${this.defaultRoute}' is not registered!`),console.warn(` Please register a page: app.registerPage('${this.defaultRoute}', YourPageClass);`),console.warn(" Or change default route: new WebApp({ defaultRoute: 'your-page' });"))}findFallbackPage(){const e=["404","error","denied"];for(const[t]of this.pageClasses.entries())if(!e.includes(t))return t;return null}static create(e={}){return new WebApp(e)}initPluginRegistry(){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.app=this)}static registerPlugin(e,t){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.plugins[e]=t)}}class Dialog extends e.View{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:this._baseZIndex}static _busyIndicator=null;static _busyCounter=0;static _busyTimeout=null;static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=Dialog._openDialogs;if(0===e.length||0===t.length)return;const s=[...t].sort((e,t)=>(e._dialogZIndex||0)-(t._dialogZIndex||0));e.forEach((e,t)=>{if(t<s.length){const i=s[t]._dialogZIndex-5;e.style.zIndex=i;const o=document.querySelector(".table-fullscreen")||document.body;e.parentNode!==o&&o.appendChild(e)}})}static updateAllBackdropStacking(){Dialog.fixAllBackdropStacking()}static showBusy(e={}){const{timeout:t=3e4,message:s="Loading..."}=e;if(this._busyCounter++,1===this._busyCounter){if(this._busyTimeout&&clearTimeout(this._busyTimeout),!this._busyIndicator){const e=this.getFullscreenAwareZIndex().modal+1e3;this._busyIndicator=document.createElement("div"),this._busyIndicator.className="mojo-busy-indicator",this._busyIndicator.innerHTML=`\n <div class="mojo-busy-spinner">\n <div class="spinner-border text-light" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p class="mojo-busy-message mt-3 text-light">${s}</p>\n </div>\n <style>\n .mojo-busy-indicator {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background-color: rgba(0, 0, 0, 0.5); z-index: ${e};\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.15s linear;\n }\n .mojo-busy-indicator.show { opacity: 1; }\n .mojo-busy-spinner .spinner-border { width: 3rem; height: 3rem; }\n </style>\n `,document.body.appendChild(this._busyIndicator)}const e=this._busyIndicator.querySelector(".mojo-busy-message");e&&(e.textContent=s),setTimeout(()=>this._busyIndicator.classList.add("show"),10),this._busyTimeout=setTimeout(()=>{console.error("Busy indicator timed out."),this.hideBusy(!0),this.alert({title:"Operation Timed Out",message:"The operation took too long. Please check your connection and try again.",type:"danger"})},t)}}static hideBusy(e=!1){e?this._busyCounter=0:this._busyCounter--,this._busyCounter<=0&&(this._busyCounter=0,this._busyTimeout&&(clearTimeout(this._busyTimeout),this._busyTimeout=null),this._busyIndicator&&(this._busyIndicator.classList.remove("show"),setTimeout(()=>{this._busyIndicator&&0===this._busyCounter&&(this._busyIndicator.remove(),this._busyIndicator=null)},150)))}constructor(e={}){const t=e.id||`modal-${Date.now()}`;super({...e,id:t,tagName:"div",className:`modal ${!1!==e.fade?"fade":""} ${e.className||""}`,attributes:{tabindex:"-1","aria-hidden":"true","aria-labelledby":e.labelledBy||`${t}-label`,"aria-describedby":e.describedBy||null,...e.attributes}}),this.modalId=t,this.title=e.title||"",this.titleId=`${this.modalId}-label`,this.size=e.size||"",this.centered=void 0!==e.centered&&e.centered,this.scrollable=void 0!==e.scrollable&&e.scrollable,this.autoSize=e.autoSize||"auto"===e.size,this.backdrop=void 0===e.backdrop||e.backdrop,this.keyboard=void 0===e.keyboard||e.keyboard,this.focus=void 0===e.focus||e.focus,this.header=void 0===e.header||e.header,this.headerContent=e.headerContent||null,this.closeButton=void 0===e.closeButton||e.closeButton,this.contextMenu=e.contextMenu||null,this.body=e.body||e.content||"",this.bodyView=null,this.bodyClass=e.bodyClass||"",this.noBodyPadding=e.noBodyPadding||!1,this.minWidth=e.minWidth||300,this.minHeight=e.minHeight||200,this.maxWidthPercent=e.maxWidthPercent||.9,this.maxHeightPercent=e.maxHeightPercent||.8,this._processBodyContent(this.body),this.footer=e.footer||null,this.footerView=null,this.footerClass=e.footerClass||"",this._processFooterContent(this.footer),this.buttons=e.buttons||null,this.onShow=e.onShow||null,this.onShown=e.onShown||null,this.onHide=e.onHide||null,this.onHidden=e.onHidden||null,this.onHidePrevented=e.onHidePrevented||null,this.autoShow=void 0!==e.autoShow&&e.autoShow,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(t){if(t&&t.render)this.bodyView=t,this.body="",this.addChild(this.bodyView);else if("function"==typeof t)try{const s=t();s instanceof e.View?(this.bodyView=s,this.body="",this.addChild(this.bodyView)):s instanceof Promise?(this.bodyPromise=s,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=s}catch(s){console.error("Error processing body function:",s),this.body=t}else this.body=t}_processFooterContent(t){if(t instanceof e.View)this.footerView=t,this.footer=null,this.addChild(this.footerView);else if("function"==typeof t)try{const s=t();s instanceof e.View?(this.footerView=s,this.footer=null,this.addChild(this.footerView)):s instanceof Promise?(this.footerPromise=s,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=s}catch(s){console.error("Error processing footer function:",s),this.footer=t}else this.footer=t}async getTemplate(){const e=["modal-dialog"];return this.size&&"auto"!==this.size&&(this.size.startsWith("fullscreen")||["sm","lg","xl"].includes(this.size))&&e.push(`modal-${this.size}`),this.centered&&e.push("modal-dialog-centered"),this.scrollable&&e.push("modal-dialog-scrollable"),`\n <div class="${e.join(" ")}">\n <div class="modal-content">\n ${await this.buildHeader()}\n ${await this.buildBody()}\n ${await this.buildFooter()}\n </div>\n </div>\n `}async buildHeader(){if(!this.header)return"";if(this.headerContent)return`<div class="modal-header">${this.headerContent}</div>`;let e="";return this.contextMenu&&this.contextMenu.items&&this.contextMenu.items.length>0?e=await this.buildContextMenu():this.closeButton&&(e='<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>'),`\n <div class="modal-header">\n ${this.title?`<h5 class="modal-title" id="${this.titleId}">${this.title}</h5>`:""}\n ${e}\n </div>\n `}async buildContextMenu(){const e=await this.filterContextMenuItems();if(0===e.length)return this.closeButton?'<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>':"";const t=this.contextMenu.icon||"bi-three-dots-vertical";return`\n <div class="dropdown">\n <button class="${this.contextMenu.buttonClass||"btn btn-link p-1 mojo-modal-context-menu-btn"}" type="button" data-bs-toggle="dropdown" aria-expanded="false">\n <i class="${t}"></i>\n </button>\n <ul class="dropdown-menu dropdown-menu-end">\n ${e.map(e=>{if("divider"===e.type)return'<li><hr class="dropdown-divider"></li>';const t=e.icon?`<i class="${e.icon} me-2"></i>`:"",s=e.label||"";if(e.href)return`<li><a class="dropdown-item" href="${e.href}"${e.target?` target="${e.target}"`:""}>${t}${s}</a></li>`;if(e.action){const i=Object.keys(e).filter(e=>e.startsWith("data-")).map(t=>`${t}="${e[t]}"`).join(" ");return`<li><a class="dropdown-item" data-action="${e.action}" ${i}>${t}${s}</a></li>`}return""}).join("")}\n </ul>\n </div>\n `}async filterContextMenuItems(){if(!this.contextMenu||!this.contextMenu.items)return[];const e=[];for(const i of this.contextMenu.items)if("divider"!==i.type){if(i.permissions)try{const e=this.getApp?.();let s=null;if(e&&(s=e.activeUser||e.getState?.("activeUser")),!s&&"undefined"!=typeof window&&window.getApp)try{const e=window.getApp();s=e?.activeUser}catch(t){}if(!s||!s.hasPermission)continue;if(!s.hasPermission(i.permissions))continue}catch(s){console.warn("Error checking permissions for context menu item:",s);continue}e.push(i)}else e.push(i);return e}async buildBody(){return this.bodyView?(this.bodyView.replaceById=!0,`<div class="${this.noBodyPadding?`modal-body p-0 ${this.bodyClass}`:`modal-body ${this.bodyClass}`}" data-view-container="body">\n \x3c!-- View will be mounted here --\x3e\n <div id="${this.bodyView.id}"></div>\n </div>`):this.body||""===this.body?`\n <div class="${this.noBodyPadding?`modal-body p-0 ${this.bodyClass}`:`modal-body ${this.bodyClass}`}">\n ${this.body}\n </div>\n `:""}async buildFooter(){if(this.footerView)return`<div class="modal-footer ${this.footerClass}" data-view-container="footer"></div>`;if(null!==this.footer&&"string"==typeof this.footer)return`<div class="modal-footer ${this.footerClass}">${this.footer}</div>`;if(this.buttons&&this.buttons.length>0){const e=this.buttons.map(e=>{const t=e.dismiss?'data-bs-dismiss="modal"':"",s=e.action?`data-action="${e.action}"`:"",i=e.id?`id="${e.id}"`:"",o=e.disabled?"disabled":"";return`\n <button type="${e.type||"button"}"\n class="btn ${e.class||"btn-secondary"}"\n ${i}\n ${t}\n ${s}\n ${o}>\n ${e.icon?`<i class="bi ${e.icon} me-1"></i>`:""}\n ${e.text||"Button"}\n </button>\n `}).join("");return`<div class="modal-footer ${this.footerClass}">${e}</div>`}return""}async mount(e=null){if(!this.mounted&&!this.destroyed){if(!this.element)throw new Error("Cannot mount dialog without element");return await this.onBeforeMount(),(document.querySelector(".table-fullscreen")||document.body).appendChild(this.element),this.bindEvents(),this.mounted=!0,await this.onAfterMount(),this.emit("mounted",{view:this}),this}}async onAfterRender(){await super.onAfterRender(),window.Prism&&this.element&&this.element.querySelectorAll("pre code").length>0&&window.Prism.highlightAllUnder(this.element),this.autoSize&&this.setupAutoSizing()}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof window&&window.bootstrap&&window.bootstrap.Modal&&("static"===this.backdrop&&this.element.setAttribute("data-bs-backdrop","static"),this.keyboard||this.element.setAttribute("data-bs-keyboard","false"),this.modal=new window.bootstrap.Modal(this.element,{backdrop:this.backdrop,keyboard:this.keyboard,focus:this.focus}),this.bindBootstrapEvents(),this.autoShow&&this.show(this.relatedTarget))}setupAutoSizing(){this.element&&(this.element.addEventListener("shown.bs.modal",()=>{this.applyAutoSizing()},{once:!0}),setTimeout(()=>{this.isShown()&&this.applyAutoSizing()},100))}applyAutoSizing(){if(this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),s=this.element.querySelector(".modal-body");if(!e||!t||!s)return void console.warn("Dialog auto-sizing: Required elements not found");if(this.bodyView&&!this.bodyView.element)return void setTimeout(()=>this.applyAutoSizing(),50);const i={dialogMaxWidth:e.style.maxWidth,dialogWidth:e.style.width,contentWidth:t.style.width,contentMaxHeight:t.style.maxHeight,bodyOverflow:s.style.overflowY};e.style.maxWidth="none",e.style.width="auto",t.style.width="auto",t.style.maxHeight="none",t.offsetHeight;const o=t.getBoundingClientRect(),n=40,r=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-n),a=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-n);let l=Math.max(this.minWidth,Math.ceil(o.width+20)),d=Math.max(this.minHeight,Math.ceil(o.height));l=Math.min(l,r);const c=o.height>a;e.style.maxWidth=`${l}px`,e.style.width=`${l}px`,c&&(t.style.maxHeight=`${a}px`,s.style.overflowY="auto",d=a),this.autoSizedWidth=l,this.autoSizedHeight=d,this._originalStyles=i}catch(e){console.error("Error in dialog auto-sizing:",e),this.element.querySelector(".modal-dialog").style.maxWidth=""}}resetAutoSizing(){if(this.autoSize&&this._originalStyles&&this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),s=this.element.querySelector(".modal-body");e&&t&&s&&(e.style.maxWidth=this._originalStyles.dialogMaxWidth||"",e.style.width=this._originalStyles.dialogWidth||"",t.style.width=this._originalStyles.contentWidth||"",t.style.maxHeight=this._originalStyles.contentMaxHeight||"",s.style.overflowY=this._originalStyles.bodyOverflow||"",delete this.autoSizedWidth,delete this.autoSizedHeight,delete this._originalStyles)}catch(e){console.error("Error resetting dialog auto-sizing:",e)}}bindBootstrapEvents(){this.element.addEventListener("show.bs.modal",e=>{const t=Dialog._openDialogs.length,s=Dialog.getFullscreenAwareZIndex().modal+20*t;this.element.style.zIndex=s,this._dialogZIndex=s,this._backdropZIndex=s-10,Dialog._openDialogs.push(this),this.onShow&&this.onShow(e),this.emit("show",{dialog:this,relatedTarget:e.relatedTarget})}),this.element.addEventListener("shown.bs.modal",e=>{if(setTimeout(()=>{Dialog.fixAllBackdropStacking()},50),this.onShown&&this.onShown(e),this.emit("shown",{dialog:this,relatedTarget:e.relatedTarget}),this.focus){const e=this.element.querySelector('input:not([type="hidden"]), textarea, select');e&&e.focus()}}),this.element.addEventListener("hide.bs.modal",e=>{const t=this.element.querySelector(":focus");t&&t.blur(),this.onHide&&!1===this.onHide(e)?e.preventDefault():this.emit("hide",{dialog:this})}),this.element.addEventListener("hidden.bs.modal",e=>{const t=Dialog._openDialogs.indexOf(this);t>-1&&Dialog._openDialogs.splice(t,1),Dialog._openDialogs.length>0&&(document.body.classList.add("modal-open"),setTimeout(()=>{Dialog.fixAllBackdropStacking()},50)),this.previousFocus&&document.body.contains(this.previousFocus)&&this.previousFocus.focus(),this.onHidden&&this.onHidden(e),this.emit("hidden",{dialog:this})}),this.element.addEventListener("hidePrevented.bs.modal",e=>{this.onHidePrevented&&this.onHidePrevented(e),this.emit("hidePrevented",{dialog:this})})}show(e=null){this.previousFocus=document.activeElement,window.lastDialog=this,this.modal&&this.modal.show(e)}hide(){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal&&this.modal.hide()}toggle(e=null){this.modal&&this.modal.toggle(e)}async destroy(){if(this.modal){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal.dispose(),this.modal=null}this.previousFocus&&document.body.contains(this.previousFocus)&&(this.previousFocus.focus(),this.previousFocus=null),this.autoSize&&this.resetAutoSizing(),await super.destroy()}handleUpdate(){this.modal&&this.modal.handleUpdate()}async setContent(t){if(t instanceof e.View){this.bodyView&&(await this.bodyView.destroy(),this.removeChild(this.bodyView)),this.bodyView=t,this.body="",this.addChild(this.bodyView);const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML="",await this.bodyView.render(e))}else{this.body=t;const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML=t)}this.handleUpdate()}setTitle(e){this.title=e;const t=this.element?.querySelector(".modal-title");t&&(t.textContent=e)}setLoading(e=!0,t="Loading..."){const s=this.element?.querySelector(".modal-body");s&&(e?s.innerHTML=`\n <div class="text-center py-4">\n <div class="spinner-border text-primary mb-3" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p>${t}</p>\n </div>\n `:this.bodyView&&s.replaceChildren(this.bodyView.element))}async onBeforeDestroy(){this.bodyView&&await this.bodyView.destroy(),this.footerView&&await this.footerView.destroy(),await super.onBeforeDestroy(),this.modal&&(this.modal.dispose(),this.modal=null)}static async showCode(e={}){const t=new Dialog({title:e.title||"Source Code",size:e.size||"lg",scrollable:!0,body:Dialog.formatCode(e.code,e.language),buttons:[{text:"Copy to Clipboard",class:"btn-primary",icon:"bi-clipboard",action:"copy"},{text:"Close",class:"btn-secondary",dismiss:!0}]});t.on("action:copy",async()=>{if(navigator.clipboard)try{await navigator.clipboard.writeText(e.code),t.showCopySuccess()}catch(s){console.error("Failed to copy:",s)}});const s=document.querySelector(".table-fullscreen")||document.body;return await t.render(!0,s),window.Prism&&t.element&&window.Prism.highlightAllUnder(t.element),t.show(),t.on("hidden",()=>{t.destroy(),t.element.remove()}),t}static formatCode(e,t="javascript"){let s;s=window.Prism&&window.Prism.languages[t]?window.Prism.highlight(e,window.Prism.languages[t],t):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;");const i=window.Prism?`language-${t}`:"";return`\n <style>\n /* Custom Prism theme overrides for Dialog */\n .dialog-code-block .token.comment { color: #6a9955; }\n .dialog-code-block .token.string { color: #ce9178; }\n .dialog-code-block .token.keyword { color: #569cd6; }\n .dialog-code-block .token.function { color: #dcdcaa; }\n .dialog-code-block .token.number { color: #b5cea8; }\n .dialog-code-block .token.operator { color: #d4d4d4; }\n .dialog-code-block .token.class-name { color: #4ec9b0; }\n .dialog-code-block .token.punctuation { color: #d4d4d4; }\n .dialog-code-block .token.boolean { color: #569cd6; }\n .dialog-code-block .token.property { color: #9cdcfe; }\n .dialog-code-block .token.tag { color: #569cd6; }\n .dialog-code-block .token.attr-name { color: #9cdcfe; }\n .dialog-code-block .token.attr-value { color: #ce9178; }\n .dialog-code-block ::selection { background: #264f78; }\n </style>\n <pre class="${i} dialog-code-block" style="${"\n max-height: 60vh;\n overflow-y: auto;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 1.25rem;\n border-radius: 0.5rem;\n margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Consolas', 'Monaco', monospace;\n font-size: 0.9rem;\n line-height: 1.6;\n border: 1px solid #2d2d30;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);\n ".replace(/\s+/g," ").trim()}">\n <code class="${i}" style="color: inherit; background: transparent; text-shadow: none;">${s}</code>\n </pre>\n `}static highlightCodeBlocks(e=document){window.Prism&&window.Prism.highlightAllUnder&&window.Prism.highlightAllUnder(e)}showCopySuccess(){const e=this.element.querySelector('[data-action="copy"]');if(e){const t=e.innerHTML;e.innerHTML='<i class="bi bi-check me-1"></i>Copied!',e.classList.remove("btn-primary"),e.classList.add("btn-success"),e.disabled=!0,setTimeout(()=>{e.innerHTML=t,e.classList.remove("btn-success"),e.classList.add("btn-primary"),e.disabled=!1},2e3)}}static async showDialog(e={}){"string"==typeof e&&(e={...arguments[2]||{},body:arguments[0],title:arguments[1]||"Alert"});const{title:t="Dialog",content:s,body:i=s||"",size:o="md",centered:n=!0,buttons:r=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:a=!1,...l}=e,d=new Dialog({title:t,body:i,size:o,centered:n,buttons:r,...l}),c=document.querySelector(".table-fullscreen")||document.body;return await d.render(!0,c),new Promise((e,t)=>{let s=!1;d.element.querySelectorAll(".modal-footer button").forEach((t,i)=>{const o=r[i];o&&t.addEventListener("click",async t=>{if(s)return;const n=void 0!==o.value?o.value:o.action??i;if("function"==typeof o.handler)try{const r=await o.handler({dialog:d,button:o,index:i,event:t});if(null===r||!1===r)return;const a=!0===r||void 0===r?n:r;s=!0,o.dismiss||d.hide(),e(a)}catch(r){return void console.error("Dialog button handler error:",r)}else s=!0,o.dismiss||d.hide(),e(n)})}),d.on("hidden",()=>{s||(s=!0,a?t(new Error("Dialog dismissed")):e(null)),setTimeout(()=>{d.destroy(),d.element.remove()},100)}),d.show()})}static async alert(e={}){"string"==typeof e&&(e={message:e,title:"Alert"});const{message:t="",title:s="Alert",type:i="info",...o}=e;let n="",r="";switch(i){case"success":n='<i class="bi bi-check-circle-fill text-success me-2"></i>',r="text-success";break;case"warning":n='<i class="bi bi-exclamation-triangle-fill text-warning me-2"></i>',r="text-warning";break;case"danger":case"error":n='<i class="bi bi-x-circle-fill text-danger me-2"></i>',r="text-danger";break;default:n='<i class="bi bi-info-circle-fill text-info me-2"></i>',r="text-info"}return Dialog.showDialog({title:`<span class="${r}">${n}${s}</span>`,body:`<p>${t}</p>`,size:"sm",centered:!0,buttons:[{text:"OK",class:"btn-primary",value:!0}],...o})}static async confirm(e,t="Confirm",s={}){"object"==typeof e&&(e=(s=e).message,t=s.title||t);const i=new Dialog({title:t,body:`<p>${e}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:[{text:s.cancelText||"Cancel",class:"btn-secondary",dismiss:!0,action:"cancel"},{text:s.confirmText||"Confirm",class:s.confirmClass||"btn-primary",action:"confirm"}],...s}),o=document.querySelector(".table-fullscreen")||document.body;return await i.render(!0,o),i.show(),new Promise(e=>{let t=!1;i.on("action:confirm",()=>{t=!0,i.hide()}),i.on("hidden",()=>{i.destroy(),i.element.remove(),e(t)})})}static async prompt(e,t="Input",s={}){const i=`prompt-input-${Date.now()}`,o=s.defaultValue||"",n=s.inputType||"text",r=s.placeholder||"",a=new Dialog({title:t,body:`\n <p>${e}</p>\n <input type="${n}"\n class="form-control"\n id="${i}"\n value="${o}"\n placeholder="${r}">\n `,size:s.size||"sm",centered:!0,backdrop:"static",buttons:[{text:"Cancel",class:"btn-secondary",dismiss:!0},{text:"OK",class:"btn-primary",action:"ok"}],...s}),l=document.querySelector(".table-fullscreen")||document.body;return await a.render(!0,l),a.show(),a.on("shown",()=>{const e=a.element.querySelector(`#${i}`);e&&(e.focus(),e.select())}),new Promise(e=>{let t=null;a.on("action:ok",()=>{const e=a.element.querySelector(`#${i}`);t=e?e.value:null,a.hide()}),a.on("hidden",()=>{a.destroy(),a.element.remove(),e(t)})})}getModal(){return this.modal}isShown(){return this.element?.classList.contains("show")||!1}static async showForm(e={}){const{title:t="Form",formConfig:s={},size:i="md",centered:o=!0,submitText:n="Submit",cancelText:r="Cancel",...a}=e,l=new(0,(await Promise.resolve().then(()=>require("./FormView-nulck4nL.js")).then(e=>e.FormView$1)).default)({fileHandling:e.fileHandling||"base64",data:e.data,defaults:e.defaults,model:e.model,formConfig:{fields:s.fields||e.fields,...s,submitButton:!1,resetButton:!1}}),d=new Dialog({title:t,body:l,size:i,centered:o,buttons:[{text:r,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],...a}),c=document.querySelector(".table-fullscreen")||document.body;return await d.render(!0,c),d.show(),new Promise(t=>{let s=!1;d.on("action:submit",async()=>{if(!s)if(l.validate()){if(e.autoSave&&e.model){d.setLoading(!0);const e=await l.saveModel();if(!e.success)return d.setLoading(!1),d.render(),void d.getApp().toast.error(e.message);s=!0,d.hide(),t(e)}try{const e=await l.getFormData();s=!0,d.hide(),t(e)}catch(i){console.error("Error collecting form data:",i),l.showError("Error collecting form data")}}else l.focusFirstError()}),d.on("action:cancel",()=>{s||(s=!0,d.hide(),t(null))}),d.on("hidden",()=>{s||(s=!0,t(null)),setTimeout(()=>{l.destroy(),d.destroy()},100)})})}static async showModelForm(e={}){const{title:t="Edit",formConfig:s={},size:i="md",centered:o=!0,submitText:n="Save",cancelText:r="Cancel",model:a,fields:l,...d}=e;if(!a)throw new Error("showModelForm requires a model");const c=new(0,(await Promise.resolve().then(()=>require("./FormView-nulck4nL.js")).then(e=>e.FormView$1)).default)({fileHandling:e.fileHandling||"base64",model:a,data:e.data,defaults:e.defaults,formConfig:{fields:l||s.fields||[],...s,submitButton:!1,resetButton:!1}}),h=new Dialog({title:t,body:c,size:i,centered:o,buttons:[{text:r,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],...d}),u=document.querySelector(".table-fullscreen")||document.body;return await h.render(!0,u),h.show(),new Promise(e=>{let t=!1;h.on("action:submit",async()=>{if(!t){h.setLoading(!0,"Saving...");try{const s=await c.handleSubmit();if(s.success)t=!0,h.hide(),e(s);else{h.setLoading(!1);let e=s.error;s.data&&s.data.error&&(e=s.data.error),h.getApp().toast.error(e)}}catch(s){console.error("Error saving form:",s),await h.setContent(c),c.showError(s.message||"An error occurred while saving")}}}),h.on("action:cancel",()=>{t||(t=!0,h.hide(),e(null))}),h.on("hidden",()=>{t||(t=!0,e(null)),setTimeout(()=>{c.destroy(),h.destroy()},100)})})}static async showData(e={}){const{title:t="Data View",data:s={},model:i=null,fields:o=[],columns:n=2,responsive:r=!0,showEmptyValues:a=!1,emptyValueText:l="—",size:d="lg",centered:c=!0,closeText:h="Close",...u}=e,m=new(0,(await Promise.resolve().then(()=>require("./DataView-D7j4IWyS.js"))).default)({data:s,model:i,fields:o,columns:n,responsive:r,showEmptyValues:a,emptyValueText:l}),g=new Dialog({title:t,body:m,size:d,centered:c,buttons:[{text:h,class:"btn-secondary",value:"close"}],...u}),p=document.querySelector(".table-fullscreen")||document.body;return await g.render(!0,p),g.show(),new Promise(e=>{let t=!1;const s=g.element.querySelector(".modal-footer button");s?.addEventListener("click",()=>{t||(t=!0,g.hide(),e(!0))}),g.on("hidden",()=>{t||(t=!0,e(!0)),setTimeout(()=>{m.destroy(),g.destroy(),g.element.remove()},100)}),m.on("field:click",e=>{g.emit("dataview:field:click",e)}),m.on("error",e=>{g.emit("dataview:error",e)})})}}Dialog.showConfirm=Dialog.confirm,Dialog.showError=Dialog.alert;const t=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,default:Dialog},Symbol.toStringTag,{value:"Module"}));exports.Dialog=Dialog,exports.Dialog$1=t,exports.EventBus=EventBus,exports.Router=Router,exports.WebApp=WebApp;
2
- //# sourceMappingURL=Dialog-7T8ENHYD.js.map