web-mojo 2.1.1043 → 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.
- package/README.md +19 -16
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.cjs.js.map +1 -1
- package/dist/admin.es.js +16 -14
- package/dist/admin.es.js.map +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.cjs.js.map +1 -1
- package/dist/auth.css +305 -266
- package/dist/auth.es.js +537 -2175
- package/dist/auth.es.js.map +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.cjs.js.map +1 -1
- package/dist/charts.css +319 -0
- package/dist/charts.es.js +555 -2
- package/dist/charts.es.js.map +1 -1
- package/dist/chunks/ChatView-BnC15uoD.js +2 -0
- package/dist/chunks/{ChatView-CGBaudUc.js.map → ChatView-BnC15uoD.js.map} +1 -1
- package/dist/chunks/{ChatView-DguKw-gR.js → ChatView-D-5lHZ5H.js} +7 -8
- package/dist/chunks/{ChatView-DguKw-gR.js.map → ChatView-D-5lHZ5H.js.map} +1 -1
- package/dist/chunks/{Collection-DD1_31eh.js → Collection-B64LJ92k.js} +2 -2
- package/dist/chunks/{Collection-DD1_31eh.js.map → Collection-B64LJ92k.js.map} +1 -1
- package/dist/chunks/{Collection-YRfGoT73.js → Collection-CsAk0UhA.js} +2 -2
- package/dist/chunks/{Collection-YRfGoT73.js.map → Collection-CsAk0UhA.js.map} +1 -1
- package/dist/chunks/ContextMenu-CfMAB33c.js +3 -0
- package/dist/chunks/ContextMenu-CfMAB33c.js.map +1 -0
- package/dist/chunks/{ContextMenu-B4_YS0G8.js → ContextMenu-Cvls3QC_.js} +350 -3
- package/dist/chunks/ContextMenu-Cvls3QC_.js.map +1 -0
- package/dist/chunks/DataView-DESqBxT-.js +2 -0
- package/dist/chunks/DataView-DESqBxT-.js.map +1 -0
- package/dist/chunks/{DataView-OUqaLmGB.js → DataView-QXyfcg2M.js} +3 -2
- package/dist/chunks/DataView-QXyfcg2M.js.map +1 -0
- package/dist/chunks/Dialog-BfXN-fFA.js +2 -0
- package/dist/chunks/Dialog-BfXN-fFA.js.map +1 -0
- package/dist/chunks/{Dialog-BiVgKzSK.js → Dialog-DHUsZ92-.js} +1375 -7
- package/dist/chunks/Dialog-DHUsZ92-.js.map +1 -0
- package/dist/chunks/{FormView-BClEkzmE.js → FormView-DGRmcKUG.js} +282 -123
- package/dist/chunks/FormView-DGRmcKUG.js.map +1 -0
- package/dist/chunks/FormView-KGvr68ju.js +3 -0
- package/dist/chunks/FormView-KGvr68ju.js.map +1 -0
- package/dist/chunks/{ListView-BMNhd5-B.js → ListView-BGJG4GYH.js} +3 -3
- package/dist/chunks/{ListView-BMNhd5-B.js.map → ListView-BGJG4GYH.js.map} +1 -1
- package/dist/chunks/{ListView-BRGiITfD.js → ListView-BpGEatee.js} +2 -2
- package/dist/chunks/{ListView-BRGiITfD.js.map → ListView-BpGEatee.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-CCroU6BZ.js → MetricsMiniChartWidget-BKbFGvXG.js} +4 -4
- package/dist/chunks/{MetricsMiniChartWidget-CCroU6BZ.js.map → MetricsMiniChartWidget-BKbFGvXG.js.map} +1 -1
- package/dist/chunks/MetricsMiniChartWidget-BNdGuSZV.js +2 -0
- package/dist/chunks/{MetricsMiniChartWidget-Esvv-lFp.js.map → MetricsMiniChartWidget-BNdGuSZV.js.map} +1 -1
- package/dist/chunks/{PDFViewer-NeL91Gon.js → PDFViewer-BIBNhuWY.js} +3 -3
- package/dist/chunks/{PDFViewer-NeL91Gon.js.map → PDFViewer-BIBNhuWY.js.map} +1 -1
- package/dist/chunks/{PDFViewer-D4uo3oiA.js → PDFViewer-nZAQQScE.js} +2 -2
- package/dist/chunks/{PDFViewer-D4uo3oiA.js.map → PDFViewer-nZAQQScE.js.map} +1 -1
- package/dist/chunks/Rest-BpDyhFfG.js +2 -0
- package/dist/chunks/Rest-BpDyhFfG.js.map +1 -0
- package/dist/chunks/{Rest-CS4jRCAs.js → Rest-DpbPbmra.js} +96 -5
- package/dist/chunks/Rest-DpbPbmra.js.map +1 -0
- package/dist/chunks/TokenManager-BWc_pRpg.js +2 -0
- package/dist/chunks/TokenManager-BWc_pRpg.js.map +1 -0
- package/dist/chunks/{TopNav-DC8oGpHp.js → TokenManager-N3e5wDu1.js} +369 -6
- package/dist/chunks/TokenManager-N3e5wDu1.js.map +1 -0
- package/dist/chunks/{WebSocketClient-D-5DJoMX.js → WebSocketClient-DghNkEyO.js} +2 -2
- package/dist/chunks/{WebSocketClient-D-5DJoMX.js.map → WebSocketClient-DghNkEyO.js.map} +1 -1
- package/dist/chunks/{WebSocketClient-DzcqAmho.js → WebSocketClient-E08hfP5f.js} +2 -2
- package/dist/chunks/{WebSocketClient-DzcqAmho.js.map → WebSocketClient-E08hfP5f.js.map} +1 -1
- package/dist/chunks/version-CKPqwcQJ.js +2 -0
- package/dist/chunks/version-CKPqwcQJ.js.map +1 -0
- package/dist/chunks/version-Dtwh-YkD.js +38 -0
- package/dist/chunks/version-Dtwh-YkD.js.map +1 -0
- package/dist/css/web-mojo.css +1 -17
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.cjs.js.map +1 -1
- package/dist/docit.es.js +6 -8
- package/dist/docit.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +34 -36
- package/dist/index.es.js.map +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.cjs.js.map +1 -1
- package/dist/lightbox.es.js +5 -4
- package/dist/lightbox.es.js.map +1 -1
- package/dist/map.cjs.js +1 -1
- package/dist/map.cjs.js.map +1 -1
- package/dist/map.es.js +82 -3
- package/dist/map.es.js.map +1 -1
- package/dist/timeline.cjs.js +1 -1
- package/dist/timeline.es.js +4 -4
- package/package.json +1 -1
- package/dist/chunks/ChatView-CGBaudUc.js +0 -2
- package/dist/chunks/ContextMenu-B4_YS0G8.js.map +0 -1
- package/dist/chunks/ContextMenu-DcLhcYMp.js +0 -3
- package/dist/chunks/ContextMenu-DcLhcYMp.js.map +0 -1
- package/dist/chunks/DataView-CdDY9ijM.js +0 -2
- package/dist/chunks/DataView-CdDY9ijM.js.map +0 -1
- package/dist/chunks/DataView-OUqaLmGB.js.map +0 -1
- package/dist/chunks/Dialog-BiVgKzSK.js.map +0 -1
- package/dist/chunks/Dialog-DmIPK_Bi.js +0 -2
- package/dist/chunks/Dialog-DmIPK_Bi.js.map +0 -1
- package/dist/chunks/FormView-BClEkzmE.js.map +0 -1
- package/dist/chunks/FormView-nulck4nL.js +0 -3
- package/dist/chunks/FormView-nulck4nL.js.map +0 -1
- package/dist/chunks/MetricsMiniChartWidget-Esvv-lFp.js +0 -2
- package/dist/chunks/Page-CvbwEoLv.js +0 -2
- package/dist/chunks/Page-CvbwEoLv.js.map +0 -1
- package/dist/chunks/Page-Deq4y2Kq.js +0 -351
- package/dist/chunks/Page-Deq4y2Kq.js.map +0 -1
- package/dist/chunks/Rest-BNYqGlnP.js +0 -2
- package/dist/chunks/Rest-BNYqGlnP.js.map +0 -1
- package/dist/chunks/Rest-CS4jRCAs.js.map +0 -1
- package/dist/chunks/TokenManager-CAZNcCMs.js +0 -366
- package/dist/chunks/TokenManager-CAZNcCMs.js.map +0 -1
- package/dist/chunks/TokenManager-CJBYcVqs.js +0 -2
- package/dist/chunks/TokenManager-CJBYcVqs.js.map +0 -1
- package/dist/chunks/TopNav-23B5R-dl.js +0 -2
- package/dist/chunks/TopNav-23B5R-dl.js.map +0 -1
- package/dist/chunks/TopNav-DC8oGpHp.js.map +0 -1
- package/dist/chunks/WebApp-C1vcdSuu.js +0 -1388
- package/dist/chunks/WebApp-C1vcdSuu.js.map +0 -1
- package/dist/chunks/WebApp-CpxtmTk0.js +0 -2
- package/dist/chunks/WebApp-CpxtmTk0.js.map +0 -1
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const t=require("./Dialog-DmIPK_Bi.js"),e=require("./Rest-BNYqGlnP.js"),s=require("./WebSocketClient-DzcqAmho.js");class BaseChart extends e.View{constructor(t={}){super({...t,className:`chart-component ${t.className||""}`,tagName:"div"}),this.chart=null,this.chartType=t.chartType||"line",this.endpoint=t.endpoint||null,this.data=t.data||null,this.dataTransform=t.dataTransform||null,this.refreshInterval=t.refreshInterval||null,this.autoRefresh=!1!==t.autoRefresh,this.refreshTimer=null,this.websocketUrl=t.websocketUrl||null,this.websocket=null,this.websocketReconnect=!1!==t.websocketReconnect,this.width=t.width||null,this.height=t.height||null,this.contentStyle=[this.width?`width: ${this.width}px;`:"",this.height?`height: ${this.height}px;`:""].filter(Boolean).join(" "),void 0===t.maintainAspectRatio&&(t.maintainAspectRatio=!0),this.title=t.title||"",this.chartTitle=t.chartTitle||"",this.chartOptions={responsive:!0,maintainAspectRatio:t.maintainAspectRatio,interaction:{intersect:!1,mode:"index"},plugins:{legend:{display:!1!==t.showLegend,position:t.legendPosition||"top"},title:{display:!!this.chartTitle,text:this.chartTitle},tooltip:{enabled:!1!==t.showTooltips,backgroundColor:"rgba(0,0,0,0.8)",titleColor:"#fff",bodyColor:"#fff",borderColor:"rgba(255,255,255,0.1)",borderWidth:1}},...t.chartOptions},this.xAxis=t.xAxis||null,this.yAxis=t.yAxis||null,this.tooltipFormatters=t.tooltip||{},this.theme=t.theme||"light",this.colorScheme=t.colorScheme||"default",this.animations=!1!==t.animations,this.exportEnabled=!0===t.exportEnabled,this.exportFormats=t.exportFormats||["png","jpg","csv"],this.isLoading=!1,this.hasError=!1,this.lastFetch=null,this.dataPoints=0,this.canvas=null,this.chartJsCdn=t.chartJsCdn||"https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js",this.dataFormatter=e.dataFormatter,this._essentialListeners=[]}get refreshEnabled(){return!(!this.endpoint&&!this.websocketUrl)}buildDefaultHeaderConfig(){return{titleHtml:this.title||"",chartTitle:this.chartTitle||"",showExport:!0===this.exportEnabled,showRefresh:this.refreshEnabled,showTheme:!0,controls:[]}}async getTemplate(){return'\n <div class="chart-container" data-theme="{{theme}}">\n <div class="chart-header mb-3">\n <div data-container="header"></div>\n <div class="chart-header-aux mt-2">\n <div data-container="header-aux"></div>\n </div>\n </div>\n\n <div class="chart-content position-relative" {{#contentStyle}}style="{{contentStyle}}"{{/contentStyle}}>\n <canvas class="chart-canvas" data-container="canvas"></canvas>\n\n \x3c!-- Loading overlay --\x3e\n <div class="chart-overlay d-none" data-loading>\n <div class="d-flex flex-column align-items-center">\n <div class="spinner-border text-primary mb-2" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <small class="text-muted">Loading chart data...</small>\n </div>\n </div>\n\n \x3c!-- Error overlay --\x3e\n <div class="chart-overlay d-none" data-error>\n <div class="alert alert-danger mb-0" role="alert">\n <div class="d-flex align-items-center">\n <i class="bi bi-exclamation-triangle me-2"></i>\n <div class="flex-grow-1">\n <strong>Error:</strong> <span class="error-message">Failed to load chart data</span>\n </div>\n <button class="btn btn-sm btn-outline-danger ms-2" data-action="retry-load">\n <i class="bi bi-arrow-clockwise"></i> Retry\n </button>\n </div>\n </div>\n </div>\n\n \x3c!-- No data overlay --\x3e\n <div class="chart-overlay d-none" data-no-data>\n <div class="text-center text-muted">\n <i class="bi bi-bar-chart display-4 mb-3 opacity-50"></i>\n <p class="mb-0">No data available</p>\n {{#refreshEnabled}}\n <button class="btn btn-sm btn-outline-secondary mt-2" data-action="refresh-chart">\n <i class="bi bi-arrow-clockwise"></i> Refresh\n </button>\n {{/refreshEnabled}}\n </div>\n </div>\n\n \x3c!-- WebSocket status indicator --\x3e\n <div class="position-absolute top-0 end-0 mt-2 me-2">\n <span class="badge bg-success websocket-status" style="display: none;" data-websocket-status>\n <i class="bi bi-wifi"></i> Live\n </span>\n </div>\n </div>\n\n <div class="chart-footer mt-2" style="display: none;">\n <div class="row">\n <div class="col">\n <small class="text-muted">\n <i class="bi bi-graph-up me-1"></i>\n <span class="data-points">0 data points</span>\n </small>\n </div>\n <div class="col text-end">\n <small class="text-muted refresh-info">\n Auto-refresh: <span class="refresh-status">Off</span>\n </small>\n </div>\n </div>\n </div>\n </div>\n '}async onInit(){await this.initializeChartJS();try{const t=this.headerConfig||(this.buildDefaultHeaderConfig?this.buildDefaultHeaderConfig():null);t&&(this.headerView=new ChartHeaderView({...t,containerId:"header"}),this.addChild(this.headerView))}catch(t){}}async onAfterRender(){this.canvas=this.element.querySelector(".chart-canvas"),this.titleElement=this.element.querySelector(".chart-title"),this.contentElement=this.element.querySelector(".chart-content"),this.footerElement=this.element.querySelector(".chart-footer"),this.loadingOverlay=this.element.querySelector("[data-loading]"),this.errorOverlay=this.element.querySelector("[data-error]"),this.noDataOverlay=this.element.querySelector("[data-no-data]"),this.websocketStatus=this.element.querySelector("[data-websocket-status]"),this.refreshBtn=this.element.querySelector(".refresh-btn"),this.themeToggle=this.element.querySelector(".theme-toggle"),this.applyTheme(),this.endpoint?(await this.fetchData(),await this.updateChart(this.data,!0),(this.height||this.width)&&this._updateChartDimensions()):this.data?(await this.updateChart(this.data,!0),(this.height||this.width)&&this._updateChartDimensions()):this.showNoData(),this.autoRefresh&&this.refreshInterval&&this.endpoint&&this.startAutoRefresh(),this.websocketUrl&&await this.connectWebSocket(),this.setupResizeObserver(),this.showFooter()}async initializeChartJS(){try{return void 0===window.Chart&&await this.loadChartJS(),!0}catch(t){return console.error("Failed to initialize Chart.js:",t),this.showError("Failed to initialize charting library"),!1}}async loadChartJS(){return new Promise((t,e)=>{const s=document.createElement("script");s.src=this.chartJsCdn,s.onload=()=>{t()},s.onerror=()=>{e(new Error("Failed to load Chart.js"))},document.head.appendChild(s)})}async handleActionRefreshChart(){await this.fetchData()}async handleActionRetryLoad(){this.hideError(),await this.fetchData()}async handleActionExportChart(t,e){const s=e.getAttribute("data-format")||"png";this.exportChart(s)}async handleActionToggleTheme(){this.toggleTheme()}async handleActionSetChartType(t,e){const s=e.getAttribute("data-type");s&&this.setChartType&&await this.setChartType(s)}async fetchData(){if(this.endpoint){this.showLoading(),this.setRefreshButtonState(!0);try{const t=await fetch(this.endpoint,{method:"GET",headers:{"Content-Type":"application/json",Accept:"application/json"}});if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);let e=await t.json();this.dataTransform&&"function"==typeof this.dataTransform&&(e=this.dataTransform(e)),this.lastFetch=/* @__PURE__ */new Date,this.data=e,this.updateLastUpdatedTime();const s=this.getApp()?.events;s&&s.emit("chart:data-loaded",{chart:this,data:e,source:"http",endpoint:this.endpoint})}catch(t){console.error("Failed to fetch chart data:",t),this.showError(`Failed to load data: ${t.message}`),this.emit("chart:error",{chart:this,error:t,source:"http",endpoint:this.endpoint})}finally{this.hideLoading(),this.setRefreshButtonState(!1)}}}async connectWebSocket(){if(this.websocketUrl)try{this.websocket=new s.WebSocketClient({url:this.websocketUrl,autoReconnect:this.websocketReconnect,dataTransform:this.dataTransform,eventBus:this.getApp()?.events,debug:!1}),this.websocket.on("connected",()=>{this.showWebSocketStatus(!0)}),this.websocket.on("disconnected",()=>{this.showWebSocketStatus(!1)}),this.websocket.on("data",async t=>{await this.updateChart(t),this.updateLastUpdatedTime(),this.emit("chart:data-updated",{chart:this,data:t,source:"websocket"})}),this.websocket.on("error",t=>{console.error("WebSocket error:",t),this.showWebSocketStatus(!1,"error")}),await this.websocket.connect()}catch(t){console.error("Failed to connect WebSocket:",t),this.showWebSocketStatus(!1,"error")}}async updateChart(t,e=!1){if(!t)return void this.showNoData();if(this.data=t,!this.canvas||void 0===window.Chart)return;this.hideAllOverlays();const s=this.processChartData(t);e&&this.chart&&(this.chart.destroy(),this.chart=null),this.chart?(this.chart.data=s,this.chart.update("none")):await this.createChart(s),this.updateDataStats(s),(this.height||this.width)&&this._updateChartDimensions()}processChartData(t){let e={...t};const s=this.normalizeAxis(this.xAxis);return s&&s.formatter&&e.labels&&(e.labels=e.labels.map(t=>this.dataFormatter.pipe(t,s.formatter))),e}async createChart(t){if(!this.canvas||void 0===window.Chart)throw new Error("Chart.js not loaded or canvas not found");const e={type:this.chartType,data:t,options:this.buildChartOptions()};try{this.chart=new window.Chart(this.canvas,e),this.setupChartEventHandlers()}catch(s){throw console.error("Failed to create chart:",s),s}}buildChartOptions(){const t={...this.chartOptions};(this.width||this.height)&&(t.responsive=!0,t.maintainAspectRatio=!1);const e=this.normalizeAxis(this.xAxis),s=this.normalizeAxis(this.yAxis);return t.scales=t.scales||{},t.scales.x={type:this._detectAxisType(this.data,e,"x"),display:!0,title:{display:!!e.label,text:e.label||""},grid:{display:!0},ticks:{}},e.formatter&&(t.scales.x.ticks.callback=this._createFormatterCallback(e.formatter)),t.scales.y={type:this._detectAxisType(this.data,s,"y"),display:!0,beginAtZero:!1!==s.beginAtZero,title:{display:!!s.label,text:s.label||""},grid:{display:!0},ticks:{}},s.formatter&&(t.scales.y.ticks.callback=this._createFormatterCallback(s.formatter)),this.applyThemeToOptions(t),(this.tooltipFormatters.x||this.tooltipFormatters.y)&&(t.plugins=t.plugins||{},t.plugins.tooltip=t.plugins.tooltip||{},t.plugins.tooltip.callbacks=t.plugins.tooltip.callbacks||{},this.tooltipFormatters.x&&(t.plugins.tooltip.callbacks.title=t=>{const e=t[0]?.label;return e?this.dataFormatter.pipe(e,this.tooltipFormatters.x):e}),this.tooltipFormatters.y&&(t.plugins.tooltip.callbacks.label=t=>{const e=t.raw,s=this.dataFormatter.pipe(e,this.tooltipFormatters.y);return`${t.dataset.label}: ${s}`})),"function"==typeof this.applySubclassChartOptions&&this.applySubclassChartOptions(t),t}_createFormatterCallback(t){return t?e=>{try{return this.dataFormatter.pipe(e,t)}catch(s){return console.warn("Chart formatter error:",s),e}}:null}normalizeAxis(t){if(!t)return{};if("string"==typeof t)return{formatter:t};if("object"==typeof t){const{formatter:e,label:s,type:a,beginAtZero:i,...r}=t;return{formatter:e,label:s,type:a,beginAtZero:i,...r}}return{}}_detectAxisType(t,e,s="x"){if(e&&e.type)return e.type;if(e&&e.formatter){const t=e.formatter.toLowerCase();if(t.includes("date")||t.includes("time"))return"time"}if(t){if("x"===s&&t.labels&&t.labels.length>0){const e=t.labels[0];return"string"!=typeof e||/^\d+\.?\d*$/.test(e.trim())?e instanceof Date||"string"==typeof e&&!isNaN(Date.parse(e))?"time":"linear":"category"}if("y"===s&&t.datasets&&t.datasets.length>0){const e=t.datasets[0];if(e.data&&e.data.length>0){const t=e.data[0];return"number"!=typeof t&&isNaN(parseFloat(t))?"category":"linear"}}}return"x"===s?"category":"linear"}setupChartEventHandlers(){this.chart&&(this.chart.options.onClick=(t,e)=>{if(e.length>0){const t=e[0],s=t.datasetIndex,a=t.index,i=this.chart.data.datasets[s].data[a],r=this.chart.data.labels[a];this.emit("chart:point-clicked",{chart:this,datasetIndex:s,index:a,value:i,label:r,dataset:this.chart.data.datasets[s]})}},this.chart.options.onHover=(t,e)=>{this.canvas.style.cursor=e.length>0?"pointer":"default"})}applyTheme(){this.element.setAttribute("data-theme",this.theme),this.chart&&(this.chart.options=this.buildChartOptions(),this.chart.update("none"))}applyThemeToOptions(t){const e="dark"===this.theme;t.scales&&Object.keys(t.scales).forEach(s=>{const a=t.scales[s];a.grid=a.grid||{},a.ticks=a.ticks||{},a.grid.color=e?"rgba(255,255,255,0.1)":"rgba(0,0,0,0.1)",a.ticks.color=e?"#e9ecef":"#495057"}),t.plugins?.legend&&(t.plugins.legend.labels=t.plugins.legend.labels||{},t.plugins.legend.labels.color=e?"#e9ecef":"#495057"),t.plugins?.title&&(t.plugins.title.color=e?"#ffffff":"#212529")}toggleTheme(){this.theme="light"===this.theme?"dark":"light",this.applyTheme(),this.emit("chart:theme-changed",{chart:this,theme:this.theme})}startAutoRefresh(){this.endpoint&&this.refreshInterval&&(this.stopAutoRefresh(),this.refreshTimer=setInterval(()=>{this.fetchData()},this.refreshInterval),this.updateRefreshStatus(!0))}stopAutoRefresh(){this.refreshTimer&&(clearInterval(this.refreshTimer),this.refreshTimer=null),this.updateRefreshStatus(!1)}exportChart(t="png"){if(this.chart)try{if("csv"===t)this.exportCSV();else{const e=this.chart.toBase64Image("image/"+t,1),s=document.createElement("a");s.download=`chart-${Date.now()}.${t}`,s.href=e,s.click(),this.emit("chart:exported",{chart:this,format:t,filename:s.download})}}catch(e){console.error("Failed to export chart:",e),this.showError("Failed to export chart")}}exportCSV(){if(this.chart&&this.chart.data)try{const t=this.generateCSV(),e=new Blob([t],{type:"text/csv;charset=utf-8;"}),s=URL.createObjectURL(e),a=document.createElement("a");a.download=`chart-data-${Date.now()}.csv`,a.href=s,a.click(),URL.revokeObjectURL(s),this.emit("chart:exported",{chart:this,format:"csv",filename:a.download})}catch(t){console.error("Failed to export CSV:",t),this.showError("Failed to export CSV")}}generateCSV(){const t=this.chart.data,e=t.labels||[],s=t.datasets||[];let a="Label";return s.forEach(t=>{a+=","+(t.label||"Data")}),a+="\n",e.forEach((t,e)=>{a+=`"${t}"`,s.forEach(t=>{const s=t.data[e]||"";a+=","+s}),a+="\n"}),a}showLoading(){this.isLoading=!0,this.hideAllOverlays(),this.loadingOverlay?.classList.remove("d-none")}hideLoading(){this.isLoading=!1,this.loadingOverlay?.classList.add("d-none")}showError(t){this.hasError=!0,this.hideAllOverlays();const e=this.errorOverlay?.querySelector(".error-message");e&&(e.textContent=t),this.errorOverlay?.classList.remove("d-none")}hideError(){this.hasError=!1,this.errorOverlay?.classList.add("d-none")}showNoData(){this.hideAllOverlays(),this.noDataOverlay?.classList.remove("d-none")}hideAllOverlays(){this.loadingOverlay?.classList.add("d-none"),this.errorOverlay?.classList.add("d-none"),this.noDataOverlay?.classList.add("d-none")}showWebSocketStatus(t,e="connected"){this.websocketStatus&&(t?(this.websocketStatus.className="badge bg-success",this.websocketStatus.innerHTML='<i class="bi bi-wifi"></i> Live'):(this.websocketStatus.className="error"===e?"badge bg-danger":"badge bg-secondary",this.websocketStatus.innerHTML="error"===e?'<i class="bi bi-wifi-off"></i> Error':'<i class="bi bi-wifi-off"></i> Offline'),this.websocketStatus.style.display="inline-block")}setRefreshButtonState(t){if(!this.refreshBtn)return;const e=this.refreshBtn.querySelector("i");t?(this.refreshBtn.disabled=!0,e?.classList.add("spin")):(this.refreshBtn.disabled=!1,e?.classList.remove("spin"))}updateLastUpdatedTime(){const t=this.element.querySelector(".last-updated"),e=this.element.querySelector(".timestamp");t&&e&&(e.textContent=/* @__PURE__ */(new Date).toLocaleTimeString(),t.style.display="block")}updateRefreshStatus(t){const e=this.element.querySelector(".refresh-status");e&&(e.textContent=t?`Every ${this.refreshInterval/1e3}s`:"Off")}updateDataStats(t){let e=0;t.datasets&&(e=t.datasets.reduce((t,e)=>t+(e.data?e.data.length:0),0)),this.dataPoints=e;const s=this.element.querySelector(".data-points");s&&(s.textContent=`${e} data point${1!==e?"s":""}`)}showFooter(){this.footerElement&&(this.footerElement.style.display="block")}setupResizeObserver(){if(!window.ResizeObserver||!this.contentElement)return;const t=new ResizeObserver(()=>{this.chart&&this.chart.resize()});t.observe(this.contentElement),this._resizeObserver=t}async onBeforeDestroy(){this.stopAutoRefresh(),this.websocket&&(this.websocket.disconnect(),this.websocket=null),this.chart&&(this.chart.destroy(),this.chart=null),this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),this._essentialListeners&&(this._essentialListeners.forEach(({el:t,type:e,fn:s})=>{t&&t.removeEventListener(e,s)}),this._essentialListeners=[]),this.emit("chart:destroyed",{chart:this})}setData(t){return this.data=t,this.updateChart(t)}setEndpoint(t){if(this.endpoint=t,t)return this.fetchData()}setWebSocketUrl(t){if(this.websocket&&this.websocket.disconnect(),this.websocketUrl=t,t)return this.connectWebSocket()}setWidth(t){this.width=t,this.contentStyle=[this.width?`width: ${this.width}px;`:"",this.height?`height: ${this.height}px;`:""].filter(Boolean).join(" "),this.contentElement&&this._updateChartDimensions()}setHeight(t){this.height=t,this.contentStyle=[this.width?`width: ${this.width}px;`:"",this.height?`height: ${this.height}px;`:""].filter(Boolean).join(" "),this.contentElement&&this._updateChartDimensions()}setDimensions(t,e){this.width=t,this.height=e,this.contentStyle=[this.width?`width: ${this.width}px;`:"",this.height?`height: ${this.height}px;`:""].filter(Boolean).join(" "),this.contentElement&&this._updateChartDimensions()}_updateChartDimensions(){this.chart&&(this.width||this.height?(this.chart.options.responsive=!0,this.chart.options.maintainAspectRatio=!1,this.width&&this.contentElement&&(this.contentElement.style.width=this.width?this.width+"px":""),this.height&&this.contentElement&&(this.contentElement.style.height=this.height?this.height+"px":"")):(this.chart.options.responsive=!0,this.chart.options.maintainAspectRatio=this.chartOptions.maintainAspectRatio),this.chart.resize())}resize(){this.chart&&this.chart.resize()}refresh(){return this.fetchData()}export(t="png"){return this.exportChart(t)}setTheme(t){this.theme=t,this.applyTheme()}getStats(){return{isLoading:this.isLoading,hasError:this.hasError,dataPoints:this.dataPoints,lastFetch:this.lastFetch,theme:this.theme,chartType:this.chartType,autoRefresh:!!this.refreshTimer,websocketConnected:this.websocket?.isConnected||!1}}}class ChartHeaderView extends e.View{constructor(t={}){super({...t,className:`mojo-chart-header ${t.className||""}`,tagName:"div"}),this.titleHtml=t.titleHtml||"",this.chartTitle=t.chartTitle||"",this.showExport=!0===t.showExport,this.showRefresh=!!t.showRefresh,this.showTheme=!1,this.showTheme=!0===t.showTheme,this.controls=Array.isArray(t.controls)?t.controls:[],this.controlsHtml=this._buildControlsHtml(this.controls)}async getTemplate(){return'\n <div class="d-flex justify-content-between align-items-center">\n <div class="chart-title-section">\n <h5 class="mb-2 chart-title">{{{titleHtml}}}</h5>\n <small class="text-muted last-updated" style="display: none;">\n Last updated: <span class="timestamp"></span>\n </small>\n </div>\n\n <div class="chart-controls">\n <div class="btn-toolbar" role="toolbar">\n {{{controlsHtml}}}\n\n <div class="btn-group btn-group-sm" role="group">\n\n {{#showTheme}}\n <button type="button" class="btn btn-outline-secondary theme-toggle" data-action="toggle-theme" title="Toggle Theme">\n <i class="bi bi-palette"></i>\n </button>\n {{/showTheme}}\n\n {{#showExport}}\n <div class="btn-group btn-group-sm" role="group">\n <button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" title="Export Chart">\n <i class="bi bi-download"></i>\n </button>\n <ul class="dropdown-menu">\n <li><a class="dropdown-item" href="#" data-action="export-chart" data-format="png">\n <i class="bi bi-image"></i> PNG\n </a></li>\n <li><a class="dropdown-item" href="#" data-action="export-chart" data-format="jpg">\n <i class="bi bi-image"></i> JPEG\n </a></li>\n <li><a class="dropdown-item" href="#" data-action="export-chart" data-format="csv">\n <i class="bi bi-file-earmark-spreadsheet"></i> CSV\n </a></li>\n </ul>\n </div>\n {{/showExport}}\n\n {{#showRefresh}}\n <button type="button" class="btn btn-outline-secondary refresh-btn" data-action="refresh-chart" title="Refresh Data">\n <i class="bi bi-arrow-clockwise"></i>\n </button>\n {{/showRefresh}}\n </div>\n </div>\n </div>\n </div>\n '}_buildControlsHtml(t){if(!Array.isArray(t)||0===t.length)return"";const e=[];return t.forEach(t=>{if(t&&t.type)switch(t.type){case"select":{const s=`form-select${"md"===t.size?"":" form-select-sm"} ${t.className||""}`.trim(),a=(t.options||[]).map(t=>`<option value="${this._escapeAttr(t.value)}"${t.selected?" selected":""}>${this._escapeHtml(t.label)}</option>`).join("");e.push(`\n <div class="btn-group btn-group-sm me-2" role="group">\n <select class="${s}" data-change-action="${this._escapeAttr(t.action||t.name||"select-changed")}" style="width: auto;">\n ${a}\n </select>\n </div>\n `);break}case"button":{const{variant:s="outline-secondary",size:a="sm"}=t,i=`btn btn-${s}${"md"===a?"":" btn-sm"} ${t.className||""}`.trim(),r=t.title?` title="${this._escapeAttr(t.title)}"`:"",h=this._buildDataAttrs(t.data);e.push(`\n <div class="btn-group btn-group-sm me-2" role="group">\n <button type="button" class="${i}" data-action="${this._escapeAttr(t.action||"button-action")}"${r}${h}>\n ${t.labelHtml||""}\n </button>\n </div>\n `);break}case"buttongroup":{const s=t.size||"sm",a=`btn-group btn-group-${s} me-2 ${t.className||""}`.trim(),i=(t.buttons||[]).map(t=>{const e=`btn btn-${t.variant||"outline-secondary"}${"md"===s?"":" btn-sm"} ${t.className||""}`.trim(),a=t.title?` title="${this._escapeAttr(t.title)}"`:"",i=this._buildDataAttrs(t.data);return`<button type="button" class="${e}" data-action="${this._escapeAttr(t.action||"button-action")}"${a}${i}>${t.labelHtml||""}</button>`}).join("");e.push(`\n <div class="${a}" role="group">\n ${i}\n </div>\n `);break}case"divider":e.push('<div class="vr mx-2"></div>');break;case"html":{const s=t.html||"";e.push(`<div class="me-2 d-inline-block">${s}</div>`);break}}}),e.join("\n")}_buildDataAttrs(t){return t&&"object"==typeof t?Object.entries(t).map(([t,e])=>` data-${this._kebabCase(String(t))}="${this._escapeAttr(String(e))}"`).join(""):""}_kebabCase(t){return t.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,"$1-$2").toLowerCase().replace(/[^a-z0-9\-]/g,"-").replace(/--+/g,"-").replace(/^-|-$/g,"")}_escapeAttr(t){return String(t).replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}_escapeHtml(t){return String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}}class SeriesChart extends BaseChart{constructor(t={}){super({...t,chartType:t.chartType||"line"}),this.showTypeSwitch=!0,void 0!==t.showTypeSwitch&&(this.showTypeSwitch=t.showTypeSwitch),this.orientation=t.orientation||"vertical",this.stacked=t.stacked||!1,this.stepped=t.stepped||!1,this.tension=t.tension||.4,this.fill=t.fill||!1,this.showRefreshButton=!1!==t.showRefreshButton,this.headerConfig||(this.headerConfig={titleHtml:this.title||"",chartTitle:this.chartTitle||"",showExport:this.exportEnabled,showRefresh:this.refreshEnabled,showTheme:!0,controls:[]}),this.series=t.series||[],this.xField=t.xField||"x",this.yField=t.yField||"y",this.colors=t.colors||["rgba(54, 162, 235, 0.8)","rgba(255, 99, 132, 0.8)","rgba(75, 192, 192, 0.8)","rgba(255, 206, 86, 0.8)","rgba(153, 102, 255, 0.8)","rgba(255, 159, 64, 0.8)","rgba(199, 199, 199, 0.8)","rgba(83, 102, 255, 0.8)"],this.tooltipFormatters=t.tooltip||{}}async getTemplate(){return await super.getTemplate()}async onInit(){this.showTypeSwitch&&this.headerConfig.controls.push({type:"buttongroup",size:"sm",buttons:[{action:"set-chart-type",labelHtml:'<i class="bi bi-graph-up"></i>',title:"Line",variant:"line"===this.chartType?"primary":"outline-primary",data:{type:"line"}},{action:"set-chart-type",labelHtml:'<i class="bi bi-bar-chart"></i>',title:"Bar",variant:"bar"===this.chartType?"primary":"outline-primary",data:{type:"bar"}}]}),await super.onInit()}async onActionSetChartType(t,e){t.stopPropagation();const s=e.getAttribute("data-type");s&&s!==this.chartType&&await this.setChartType(s)}async rebuildChart(){if(this.chart&&this.data){this.chart.destroy(),this.chart=null;const t=this.processChartData(this.data);await this.createChart(t)}}async setChartType(t){if(!["line","bar"].includes(t))throw new Error(`Unsupported chart type: ${t}`);const e=this.chartType;if(this.chartType=t,this.chart&&this.data){this.chart.destroy(),this.chart=null;const t=this.processChartData(this.data);await this.createChart(t)}this._updateTypeSwitcherButtons();const s=this.getApp()?.events;s&&s.emit("chart:type-changed",{chart:this,oldType:e,newType:this.chartType})}processChartData(t){if(!t)return t;let e;return e=Array.isArray(t)?this.processArrayData(t):t.labels&&t.datasets?this.processChartJSData(t):t.series?this.processSeriesData(t):t,this.applyFormattersToData(e)}processArrayData(t){const e=[],s=[];return t.forEach(t=>{const a=t[this.xField],i=t[this.yField];e.push(a),s.push(i)}),{labels:e,datasets:[{label:this.title||"Data",data:s,backgroundColor:this.colors[0].replace("0.8","0.6"),borderColor:this.colors[0],borderWidth:2,tension:"line"===this.chartType?this.tension:0,fill:"line"===this.chartType&&this.fill,stepped:"line"===this.chartType&&this.stepped}]}}processChartJSData(t){const e={...t};return e.datasets=e.datasets.map((t,e)=>({...t,backgroundColor:t.backgroundColor||this.colors[e%this.colors.length].replace("0.8","0.6"),borderColor:t.borderColor||this.colors[e%this.colors.length],borderWidth:t.borderWidth||2,tension:"line"===this.chartType?t.tension??this.tension:0,fill:"line"===this.chartType&&(t.fill??this.fill),stepped:"line"===this.chartType&&(t.stepped??this.stepped)})),e}processSeriesData(t){const e=t.labels||[],s=[];return t.series.forEach((t,e)=>{s.push({label:t.name||t.label||`Series ${e+1}`,data:t.data||[],backgroundColor:t.backgroundColor||this.colors[e%this.colors.length].replace("0.8","0.6"),borderColor:t.borderColor||this.colors[e%this.colors.length],borderWidth:t.borderWidth||2,tension:"line"===this.chartType?t.tension??this.tension:0,fill:"line"===this.chartType&&(t.fill??this.fill),stepped:"line"===this.chartType&&(t.stepped??this.stepped)})}),{labels:e,datasets:s}}applyFormattersToData(t){if(!t)return t;const e={...t},s=this.normalizeAxis?this.normalizeAxis(this.xAxis):{};return s.formatter&&e.labels&&(e.labels=e.labels.map(t=>this.dataFormatter.pipe(t,s.formatter))),e}applySubclassChartOptions(t){this.stacked&&"bar"===this.chartType&&t.scales&&(t.scales.x&&(t.scales.x.stacked=!0),t.scales.y&&(t.scales.y.stacked=!0)),"bar"===this.chartType&&"horizontal"===this.orientation&&(t.indexAxis="y"),t.interaction=t.interaction||{},t.interaction.intersect=!1,t.interaction.mode="line"===this.chartType?"index":"nearest",t.elements=t.elements||{},t.elements.line={...t.elements.line||{},tension:this.tension,borderWidth:2},t.elements.point={...t.elements.point||{},radius:"line"===this.chartType?4:0,hoverRadius:6,hitRadius:8},t.elements.bar={...t.elements.bar||{},borderWidth:1,borderSkipped:!1}}processAxisConfig(t){return t?"string"==typeof t?{formatter:t}:"object"==typeof t?{formatter:t.formatter,label:t.label,type:t.type,beginAtZero:t.beginAtZero,...t}:{}:{}}_updateTypeSwitcherButtons(){const t=this.element?.querySelectorAll('[data-action="set-chart-type"]');t&&0!==t.length&&t.forEach(t=>{const e=t.getAttribute("data-type")===this.chartType;t.classList.toggle("btn-primary",e),t.classList.toggle("btn-outline-primary",!e),t.classList.toggle("active",e)})}setOrientation(t){if(!["vertical","horizontal"].includes(t))throw new Error(`Invalid orientation: ${t}`);if(this.orientation=t,this.chart&&(this.chart.destroy(),this.chart=null,this.data)){const t=this.processChartData(this.data);this.createChart(t)}}setStacked(t){this.stacked=t,this.chart&&(this.chart.options.scales.x.stacked=t,this.chart.options.scales.y.stacked=t,this.chart.update())}addSeries(t){if(!this.data||!this.data.datasets)return;const e={label:t.label||t.name||`Series ${this.data.datasets.length+1}`,data:t.data||[],backgroundColor:t.backgroundColor||this.colors[this.data.datasets.length%this.colors.length].replace("0.8","0.6"),borderColor:t.borderColor||this.colors[this.data.datasets.length%this.colors.length],borderWidth:t.borderWidth||2,tension:"line"===this.chartType?t.tension??this.tension:0,fill:"line"===this.chartType&&(t.fill??this.fill)};this.data.datasets.push(e),this.chart&&(this.chart.data.datasets.push(e),this.chart.update());const s=this.getApp()?.events;s&&s.emit("chart:series-added",{chart:this,series:e})}removeSeries(t){if(!this.data||!this.data.datasets||t<0||t>=this.data.datasets.length)return;const e=this.data.datasets.splice(t,1)[0];this.chart&&(this.chart.data.datasets.splice(t,1),this.chart.update());const s=this.getApp()?.events;s&&s.emit("chart:series-removed",{chart:this,series:e,index:t})}static async showDialog(e={}){const{title:s="Chart Viewer",size:a="xl",...i}=e,r=new SeriesChart({...i,title:s}),h=new t.default({title:s,body:r,size:a,centered:!0,backdrop:"static",keyboard:!0,buttons:[{text:"Export PNG",action:"export",class:"btn btn-outline-primary"},{text:"Close",action:"close",class:"btn btn-secondary",dismiss:!0}]});return await h.render(),document.body.appendChild(h.element),await h.mount(),h.show(),new Promise(t=>{h.on("hidden",()=>{h.destroy(),t(r)}),h.on("action:export",()=>{r.exportChart("png")}),h.on("action:close",()=>{h.hide()})})}}class PieChart extends BaseChart{constructor(t={}){super({...t,chartType:"pie"}),this.cutout=t.cutout||0,this.rotation=t.rotation||0,this.circumference=t.circumference||360,this.borderWidth=t.borderWidth||2,this.borderColor=t.borderColor||"#ffffff",this.hoverBorderWidth=t.hoverBorderWidth||3,this.showLabels=!1!==t.showLabels,this.labelPosition=t.labelPosition||"outside",this.labelFormatter=t.labelFormatter||null,this.valueFormatter=t.valueFormatter||null,this.labelField=t.labelField||"label",this.valueField=t.valueField||"value",this.colors=t.colors||["#FF6384","#36A2EB","#FFCE56","#4BC0C0","#9966FF","#FF9F40","#C9CBCF","#4BC0C0","#FF6384","#36A2EB"],this.animateRotate=!1!==t.animateRotate,this.animateScale=t.animateScale||!1,this.clickable=!1!==t.clickable,this.hoverable=!1!==t.hoverable,this.selectedSegment=null,this.highlightedSegments=/* @__PURE__ */new Set,this.valueFormatter=t.valueFormatter||null}processChartData(t){if(!t)return t;let e;return e=Array.isArray(t)?this.processArrayData(t):t.labels&&t.datasets?this.processChartJSData(t):"object"!=typeof t||t.labels?t:this.processObjectData(t),this.applyFormattersToData(e)}processArrayData(t){const e=[],s=[];return t.forEach(t=>{const a=t[this.labelField],i=t[this.valueField];void 0!==a&&void 0!==i&&(e.push(a),s.push(i))}),{labels:e,datasets:[{data:s,backgroundColor:this.generateColors(e.length),borderColor:this.borderColor,borderWidth:this.borderWidth,hoverBorderWidth:this.hoverBorderWidth}]}}processChartJSData(t){const e={...t};return e.datasets=e.datasets.map(t=>({...t,backgroundColor:t.backgroundColor||this.generateColors(e.labels.length),borderColor:t.borderColor||this.borderColor,borderWidth:t.borderWidth||this.borderWidth,hoverBorderWidth:t.hoverBorderWidth||this.hoverBorderWidth})),e}processObjectData(t){const e=Object.keys(t);return{labels:e,datasets:[{data:Object.values(t),backgroundColor:this.generateColors(e.length),borderColor:this.borderColor,borderWidth:this.borderWidth,hoverBorderWidth:this.hoverBorderWidth}]}}applyFormattersToData(t){if(!t)return t;const e={...t};return this.labelFormatter&&e.labels&&(e.labels=e.labels.map(t=>this.dataFormatter.pipe(t,this.labelFormatter))),e}generateColors(t){const e=[];for(let s=0;s<t;s++)e.push(this.colors[s%this.colors.length]);return e}buildChartOptions(){const t=super.buildChartOptions();return t.cutout=this.cutout,t.rotation=this.rotation,t.circumference=this.circumference,t.animation={animateRotate:this.animateRotate,animateScale:this.animateScale,duration:this.animations?1e3:0},t.plugins={...t.plugins,legend:{...t.plugins.legend,position:t.plugins.legend.position||"right",labels:{...t.plugins.legend.labels,usePointStyle:!0,padding:20,generateLabels:t=>{const e=t.data;return e.labels.length&&e.datasets.length?e.labels.map((t,s)=>{const a=e.datasets[0],i=a.data[s],r=a.backgroundColor[s];return{text:`${t} (${(i/a.data.reduce((t,e)=>t+e,0)*100).toFixed(1)}%)`,fillStyle:r,strokeStyle:r,lineWidth:0,hidden:!1,index:s}}):[]}}},tooltip:{...t.plugins.tooltip,callbacks:{...t.plugins.tooltip.callbacks,label:t=>{const e=t.label||"",s=t.raw,a=(s/t.dataset.data.reduce((t,e)=>t+e,0)*100).toFixed(1);let i=s;return this.valueFormatter?i=this.dataFormatter.pipe(s,this.valueFormatter):this.tooltipFormatters&&this.tooltipFormatters.y&&(i=this.dataFormatter.pipe(s,this.tooltipFormatters.y)),`${e}: ${i} (${a}%)`}}}},delete t.scales,t}setupChartEventHandlers(){super.setupChartEventHandlers(),this.chart&&this.clickable&&(this.chart.options.onClick=(t,e)=>{if(e.length>0){const t=e[0].index,s=this.chart.data.datasets[0],a=this.chart.data.labels[t],i=s.data[t],r=(i/s.data.reduce((t,e)=>t+e,0)*100).toFixed(1);this.toggleSegmentSelection(t);const h=this.getApp()?.events;h&&h.emit("chart:segment-clicked",{chart:this,index:t,label:a,value:i,percentage:parseFloat(r),isSelected:this.selectedSegment===t})}},this.hoverable&&(this.chart.options.onHover=(t,e)=>{if(this.canvas.style.cursor=e.length>0?"pointer":"default",e.length>0){const t=e[0].index,s=this.getApp()?.events;s&&s.emit("chart:segment-hover",{chart:this,index:t,label:this.chart.data.labels[t],value:this.chart.data.datasets[0].data[t]})}}))}toggleSegmentSelection(t){this.selectedSegment===t?(this.selectedSegment=null,this.resetSegmentStyle(t)):(null!==this.selectedSegment&&this.resetSegmentStyle(this.selectedSegment),this.selectedSegment=t,this.highlightSegment(t))}highlightSegment(t){if(!this.chart)return;const e=this.chart.getDatasetMeta(0).data[t];e&&(e.outerRadius+=10,this.chart.update("none"))}resetSegmentStyle(t){if(!this.chart)return;const e=this.chart.getDatasetMeta(0).data[t];e&&(e.outerRadius-=10,this.chart.update("none"))}highlightSegments(t){Array.isArray(t)||(t=[t]),this.highlightedSegments.clear(),t.forEach(t=>{this.highlightedSegments.add(t),this.highlightSegment(t)})}clearHighlights(){this.highlightedSegments.forEach(t=>{this.resetSegmentStyle(t)}),this.highlightedSegments.clear(),null!==this.selectedSegment&&(this.resetSegmentStyle(this.selectedSegment),this.selectedSegment=null)}selectSegment(t){t>=0&&t<this.chart?.data?.labels?.length&&this.toggleSegmentSelection(t)}getSegmentData(t){if(!this.chart||!this.chart.data)return null;const e=this.chart.data.datasets[0],s=this.chart.data.labels[t],a=e.data[t],i=(a/e.data.reduce((t,e)=>t+e,0)*100).toFixed(1);return{index:t,label:s,value:a,percentage:parseFloat(i),color:e.backgroundColor[t],isSelected:this.selectedSegment===t}}getAllSegments(){return this.chart&&this.chart.data?this.chart.data.labels.map((t,e)=>this.getSegmentData(e)):[]}updateSegmentColor(t,e){if(!this.chart||!this.chart.data.datasets[0])return;this.chart.data.datasets[0].backgroundColor[t]=e,this.chart.update("none");const s=this.getApp()?.events;s&&s.emit("chart:segment-color-changed",{chart:this,index:t,color:e,segment:this.getSegmentData(t)})}addSegment(t,e,s=null){if(!this.chart||!this.chart.data)return;const a=this.chart.data.datasets[0],i=s||this.colors[this.chart.data.labels.length%this.colors.length];this.chart.data.labels.push(t),a.data.push(e),a.backgroundColor.push(i),this.chart.update();const r=this.getApp()?.events;r&&r.emit("chart:segment-added",{chart:this,label:t,value:e,color:i,index:this.chart.data.labels.length-1})}removeSegment(t){if(!this.chart||!this.chart.data||t<0||t>=this.chart.data.labels.length)return;const e=this.chart.data.datasets[0],s=this.chart.data.labels[t],a=e.data[t];this.chart.data.labels.splice(t,1),e.data.splice(t,1),e.backgroundColor.splice(t,1),this.selectedSegment===t?this.selectedSegment=null:this.selectedSegment>t&&this.selectedSegment--,this.chart.update();const i=this.getApp()?.events;i&&i.emit("chart:segment-removed",{chart:this,label:s,value:a,index:t,removedSegment:{label:s,value:a,index:t}})}applyThemeToOptions(t){super.applyThemeToOptions(t);const e="dark"===this.theme;this.borderColor=e?"#404449":"#ffffff"}static async showDialog(e={}){const{title:s="Pie Chart",size:a="lg",...i}=e,r=new PieChart({...i,title:s}),h=new t.default({title:s,body:r,size:a,centered:!0,backdrop:"static",keyboard:!0,buttons:[{text:"Export PNG",action:"export",class:"btn btn-outline-primary"},{text:"Close",action:"close",class:"btn btn-secondary",dismiss:!0}]});return await h.render(),document.body.appendChild(h.element),await h.mount(),h.show(),new Promise(t=>{h.on("hidden",()=>{h.destroy(),t(r)}),h.on("action:export",()=>{r.exportChart("png")}),h.on("action:close",()=>{h.hide()})})}}class MiniChart extends e.View{constructor(t={}){super({className:"mini-chart",...t}),this.chartType=t.chartType||"line",this.data=t.data||[],this.width=t.width||"100%",this.height=t.height||30,this.maintainAspectRatio=t.maintainAspectRatio||!1,this.color=t.color||"rgba(54, 162, 235, 1)",this.fillColor=t.fillColor||"rgba(54, 162, 235, 0.1)",this.strokeWidth=t.strokeWidth||2,this.barGap=t.barGap||2,this.fill=!1!==t.fill,this.smoothing=t.smoothing||.3,this.padding=t.padding||2,this.minValue=t.minValue,this.maxValue=t.maxValue,this.showDots=t.showDots||!1,this.dotRadius=t.dotRadius||2,this.animate=!1!==t.animate,this.animationDuration=t.animationDuration||300,this.showTooltip=!1!==t.showTooltip,this.tooltipFormatter=t.tooltipFormatter||null,this.tooltipTemplate=t.tooltipTemplate||null,this.valueFormat=t.valueFormat||null,this.labelFormat=t.labelFormat||null,this.showCrosshair=!1!==t.showCrosshair,this.crosshairColor=t.crosshairColor||"rgba(0, 0, 0, 0.2)",this.crosshairWidth=t.crosshairWidth||1,this.showXAxis=t.showXAxis||!1,this.xAxisColor=t.xAxisColor||this.color,this.xAxisWidth=t.xAxisWidth||1,this.xAxisDashed=!1!==t.xAxisDashed,this.tooltip=null,this.crosshair=null,this.hoveredIndex=-1,this.dataFormatter=e.dataFormatter,this.labels=t.labels||null}getTemplate(){const t="number"==typeof this.width?`${this.width}px`:this.width,e="number"==typeof this.height?`${this.height}px`:this.height,s=this.maintainAspectRatio?"xMidYMid meet":"none";return`\n <div class="mini-chart-wrapper" style="position: relative; display: block; width: ${t}; height: ${e};">\n <svg\n class="mini-chart-svg"\n width="100%"\n height="100%"\n viewBox="0 0 100 ${this.height}"\n preserveAspectRatio="${s}"\n style="display: block;">\n </svg>\n ${this.showTooltip?'<div class="mini-chart-tooltip" style="display: none;"></div>':""}\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".mini-chart-svg"),this.tooltip=this.element.querySelector(".mini-chart-tooltip"),this.updateDimensions(),this.data&&this.data.length>0&&this.renderChart(),this.showTooltip&&this.svg&&this.setupTooltip(),this.setupResizeObserver()}updateDimensions(){if(!this.svg)return;const t=this.svg.getBoundingClientRect();this.actualWidth=t.width||100,this.actualHeight=t.height||this.height,this.svg.setAttribute("viewBox",`0 0 ${this.actualWidth} ${this.actualHeight}`)}setupResizeObserver(){"undefined"!=typeof ResizeObserver&&(this.resizeObserver=new ResizeObserver(()=>{this.updateDimensions(),this.data&&this.data.length>0&&this.renderChart()}),this.svg&&this.resizeObserver.observe(this.svg))}renderChart(){if(!this.svg||!this.data||0===this.data.length)return;this.svg.innerHTML="";const{min:t,max:e}=this.calculateBounds();if(this.showXAxis&&this.renderXAxis(t,e),"line"===this.chartType?this.renderLine(t,e):"bar"===this.chartType&&this.renderBar(t,e),this.showCrosshair){const t=this.getActualHeight();this.crosshair=this.createSVGElement("line",{x1:0,y1:0,x2:0,y2:t,stroke:this.crosshairColor,"stroke-width":this.crosshairWidth,"stroke-dasharray":"3,3",style:"display: none; pointer-events: none;"}),this.svg.appendChild(this.crosshair)}this.showTooltip&&this.tooltip&&this.setupTooltip(),this.animate&&this.applyAnimation()}renderXAxis(t,e){const s=this.getActualWidth(),a=this.getActualHeight();let i;if(t<=0&&e>=0){const s=e-t,r=(a-2*this.padding)/s;i=a-this.padding-(0-t)*r}else i=a-this.padding;const r=this.createSVGElement("line",{x1:this.padding,y1:i,x2:s-this.padding,y2:i,stroke:this.xAxisColor,"stroke-width":this.xAxisWidth,"stroke-dasharray":this.xAxisDashed?"2,2":"none","stroke-opacity":"0.5"});this.svg.appendChild(r)}calculateBounds(){const t=this.data.map(t=>"object"==typeof t?t.value:t);let e=void 0!==this.minValue?this.minValue:Math.min(...t),s=void 0!==this.maxValue?this.maxValue:Math.max(...t);return 0===s-e&&("bar"===this.chartType&&0===e?(e=0,s=1):(e-=1,s+=1)),{min:e,max:s}}getActualWidth(){return this.actualWidth||this.width||100}getActualHeight(){return this.actualHeight||this.height||30}renderLine(t,e){const s=this.data.map(t=>"object"==typeof t?t.value:t),a=this.calculatePoints(s,t,e);if(this.fill){const t=this.createAreaPath(a),e=this.createSVGElement("path",{d:t,fill:this.fillColor,stroke:"none"});this.svg.appendChild(e)}const i=this.smoothing>0?this.createSmoothPath(a):this.createLinePath(a),r=this.createSVGElement("path",{d:i,fill:"none",stroke:this.color,"stroke-width":this.strokeWidth,"stroke-linecap":"round","stroke-linejoin":"round"});this.svg.appendChild(r),this.showDots&&a.forEach(t=>{const e=this.createSVGElement("circle",{cx:t.x,cy:t.y,r:this.dotRadius,fill:this.color});this.svg.appendChild(e)})}renderBar(t,e){const s=this.data.map(t=>"object"==typeof t?t.value:t),a=this.calculatePoints(s,t,e),i=this.getActualWidth(),r=this.getActualHeight(),h=(i-2*this.padding-this.barGap*(s.length-1))/s.length;a.forEach((t,e)=>{const s=r-2*this.padding-t.y+this.padding,a=t.x-h/2,i=t.y,o=this.createSVGElement("rect",{x:a,y:i,width:h,height:s,fill:this.color,rx:1,"data-bar-index":e,class:"mini-chart-bar"});this.svg.appendChild(o)})}calculatePoints(t,e,s){const a=s-e,i=this.getActualWidth(),r=this.getActualHeight(),h=(i-2*this.padding)/(t.length-1||1),o=(r-2*this.padding)/a;return t.map((t,s)=>({x:this.padding+s*h,y:r-this.padding-(t-e)*o}))}createLinePath(t){if(0===t.length)return"";let e=`M ${t[0].x},${t[0].y}`;for(let s=1;s<t.length;s++)e+=` L ${t[s].x},${t[s].y}`;return e}createSmoothPath(t){if(t.length<2)return this.createLinePath(t);let e=`M ${t[0].x},${t[0].y}`;for(let s=0;s<t.length-1;s++){const a=t[s],i=t[s+1];e+=` C ${a.x+(i.x-a.x)*this.smoothing},${a.y} ${i.x-(i.x-a.x)*this.smoothing},${i.y} ${i.x},${i.y}`}return e}createAreaPath(t){if(0===t.length)return"";const e=this.smoothing>0?this.createSmoothPath(t):this.createLinePath(t),s=t[t.length-1],a=t[0],i=this.getActualHeight();return`${e} L ${s.x},${i-this.padding} L ${a.x},${i-this.padding} Z`}createSVGElement(t,e={}){const s=document.createElementNS("http://www.w3.org/2000/svg",t);return Object.entries(e).forEach(([t,e])=>{s.setAttribute(t,e)}),s}applyAnimation(){this.svg.querySelectorAll("path").forEach(t=>{const e=t.getTotalLength();t.style.strokeDasharray=e,t.style.strokeDashoffset=e,t.style.animation=`mini-chart-draw ${this.animationDuration}ms ease-out forwards`}),this.svg.querySelectorAll("rect").forEach((t,e)=>{t.style.transformOrigin="bottom",t.style.animation=`mini-chart-bar-grow ${this.animationDuration}ms ease-out ${20*e}ms forwards`,t.style.transform="scaleY(0)"})}setupTooltip(){if(!this.svg||!this.tooltip)return;const t=this.data.map(t=>"object"==typeof t?t.value:t),e=this.calculatePoints(t,...Object.values(this.calculateBounds())),s=this.getActualWidth(),a=this.getActualHeight(),i=s/t.length;e.forEach((t,e)=>{const s=this.createSVGElement("rect",{x:e*i,y:0,width:i,height:a,fill:"transparent",style:"cursor: pointer;"});s.addEventListener("mouseenter",t=>{this.showTooltipAtIndex(e,t)}),s.addEventListener("mousemove",t=>{this.updateTooltipPosition(t)}),s.addEventListener("mouseleave",()=>{this.hideTooltip()}),this.svg.appendChild(s)})}showTooltipAtIndex(t,e){if(!this.tooltip)return;this.hoveredIndex=t;const s="object"==typeof this.data[t]?this.data[t].value:this.data[t],a="object"==typeof this.data[t]?this.data[t].label:null,i=this.labels?this.labels[t]:a;let r;if(this.tooltipTemplate&&"function"==typeof this.tooltipTemplate)r=this.tooltipTemplate({value:s,label:i,index:t,data:this.data[t]});else{let e=s;e=this.valueFormat&&this.dataFormatter?this.dataFormatter.pipe(s,this.valueFormat):this.tooltipFormatter&&"function"==typeof this.tooltipFormatter?this.tooltipFormatter(s,t):"number"==typeof s?s.toLocaleString():s;let a=i;i&&this.labelFormat&&this.dataFormatter&&(a=this.dataFormatter.pipe(i,this.labelFormat)),r=`<strong>${e}</strong>`,a&&(r=`<div class="mini-chart-tooltip-label">${a}</div>${r}`)}if(this.tooltip.innerHTML=r,this.tooltip.style.display="block",this.updateTooltipPosition(e),"bar"===this.chartType&&this.highlightBar(t),this.crosshair&&this.showCrosshair){const e=this.getActualWidth()/this.data.length,s=t*e+e/2;this.crosshair.setAttribute("x1",s),this.crosshair.setAttribute("x2",s),this.crosshair.style.display="block"}}updateTooltipPosition(t){if(!this.tooltip||"none"===this.tooltip.style.display)return;const e=this.svg.getBoundingClientRect(),s=t.clientX-e.left,a=t.clientY-e.top;this.tooltip.style.left=`${s}px`,this.tooltip.style.top=a-10+"px",this.tooltip.style.transform="translate(-50%, -100%)"}hideTooltip(){this.tooltip&&(this.tooltip.style.display="none",this.hoveredIndex=-1),"bar"===this.chartType&&this.unhighlightBars(),this.crosshair&&(this.crosshair.style.display="none")}highlightBar(t){if(!this.svg)return;this.unhighlightBars();const e=this.svg.querySelector(`rect.mini-chart-bar[data-bar-index="${t}"]`);e&&(e.style.opacity="0.7")}unhighlightBars(){this.svg&&this.svg.querySelectorAll("rect.mini-chart-bar").forEach(t=>{t.style.opacity="1"})}setData(t){this.data=t,this.svg&&this.renderChart()}setColor(t){this.color=t,this.svg&&this.renderChart()}setType(t){["line","bar"].includes(t)&&(this.chartType=t,this.svg&&this.renderChart())}resize(t,e){this.width=t,this.height=e,this.updateDimensions(),this.svg&&this.renderChart()}async onBeforeDestroy(){this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),await super.onBeforeDestroy()}}class MetricsMiniChart extends MiniChart{constructor(t={}){super(t),this.endpoint=t.endpoint||"/api/metrics/fetch",this.account=t.account||"global",this.granularity=t.granularity||"hours",this.slugs=t.slugs||null,this.category=t.category||null,this.dateStart=t.dateStart||null,this.dateEnd=t.dateEnd||null,this.defaultDateRange=t.defaultDateRange||"24h",this.isLoading=!1,this.lastFetch=null,this.refreshInterval=t.refreshInterval,this.dateStart&&this.dateEnd||this.setQuickRange(this.defaultDateRange),this.slugs&&!Array.isArray(this.slugs)&&(this.slugs=[this.slugs])}async onAfterRender(){await super.onAfterRender(),!this.endpoint||this.data&&0!==this.data.length||await this.fetchData(),this.refreshInterval&&this.endpoint&&this.startAutoRefresh()}buildApiParams(){const t={granularity:this.granularity,account:this.account,with_labels:!0};return this.slugs&&this.slugs.length>0&&this.slugs.forEach(e=>{t["slugs[]"]||(t["slugs[]"]=[]),t["slugs[]"].push(e)}),this.category&&(t.category=this.category),this.dateStart&&(t.dr_start=Math.floor(this.dateStart.getTime()/1e3)),this.dateEnd&&(t.dr_end=Math.floor(this.dateEnd.getTime()/1e3)),t._=Date.now(),t}async fetchData(){if(this.endpoint){this.isLoading=!0;try{const t=this.getApp()?.rest;if(!t)throw new Error("No REST client available");const e=this.buildApiParams(),s=await t.GET(this.endpoint,e);if(!s.success)throw new Error(s.message||"Network error");if(!s.data?.status)throw new Error(s.data?.error||"Server error");const a=s.data.data;this.processMetricsData(a),this.lastFetch=/* @__PURE__ */new Date,await this.render(),this.emit("metrics:loaded",{chart:this,data:a,params:e})}catch(t){console.error("Failed to fetch metrics:",t),this.emit("metrics:error",{chart:this,error:t})}finally{this.isLoading=!1}}}processMetricsData(t){const{data:e,labels:s}=t;if(!e)return;const a=Object.keys(e);if(0===a.length)return;const i=e[a[0]].map(t=>null==t||""===t?0:"number"==typeof t?t:parseFloat(t)||0);this.labels=s||null,this.setData(i)}setQuickRange(t){const e=/* @__PURE__ */new Date;let s;switch(t){case"1h":s=new Date(e.getTime()-36e5);break;case"24h":default:s=new Date(e.getTime()-864e5);break;case"7d":s=new Date(e.getTime()-6048e5);break;case"30d":s=new Date(e.getTime()-2592e6)}this.dateStart=s,this.dateEnd=e}startAutoRefresh(){this.refreshTimer&&clearInterval(this.refreshTimer),this.refreshTimer=setInterval(()=>{this.fetchData()},this.refreshInterval)}stopAutoRefresh(){this.refreshTimer&&(clearInterval(this.refreshTimer),this.refreshTimer=null)}setGranularity(t){return this.granularity=t,this.fetchData()}setDateRange(t,e){return this.dateStart=new Date(t),this.dateEnd=new Date(e),this.fetchData()}setMetrics(t){return this.slugs=Array.isArray(t)?t:[t],this.fetchData()}refresh(){return this.fetchData()}async onBeforeDestroy(){this.stopAutoRefresh(),await super.onBeforeDestroy()}}class MetricsMiniChartWidget extends e.View{constructor(t={}){super({...t,tagName:"div",className:`metrics-mini-chart-widget ${t.className||""}`.trim()}),this.icon=t.icon||null,this.title=t.title||"",this.subtitle=t.subtitle||"",this.background=t.background||null,this.textColor=t.textColor||null,this.showTrending=!!t.showTrending,this.trendRange=t.trendRange??null,this.trendOffset=t.trendOffset??0,this.prevTrendOffset=t.prevTrendOffset??0,this.total=0,this.lastValue=0,this.prevValue=0,this.trendingPercent=0,this.trendingUp=null,this.hasTrending=!1,this.trendingClass="",this.trendingIcon="",this.trendingLabel="",this.chartOptions={endpoint:t.endpoint,account:t.account,granularity:t.granularity,slugs:t.slugs,category:t.category,dateStart:t.dateStart,dateEnd:t.dateEnd,defaultDateRange:t.defaultDateRange,refreshInterval:t.refreshInterval,chartType:t.chartType||"line",showTooltip:void 0===t.showTooltip||t.showTooltip,showXAxis:t.showXAxis||!1,height:t.height||80,width:t.chartWidth||t.width||"100%",color:t.color,fill:void 0===t.fill||t.fill,fillColor:t.fillColor,smoothing:t.smoothing??.3,strokeWidth:t.strokeWidth,barGap:t.barGap,valueFormat:t.valueFormat,labelFormat:t.labelFormat,tooltipFormatter:t.tooltipFormatter,tooltipTemplate:t.tooltipTemplate,showCrosshair:t.showCrosshair,crosshairColor:t.crosshairColor,crosshairWidth:t.crosshairWidth,xAxisColor:t.xAxisColor,xAxisWidth:t.xAxisWidth,xAxisDashed:t.xAxisDashed,padding:t.padding,minValue:t.minValue,maxValue:t.maxValue,showDots:t.showDots,dotRadius:t.dotRadius,animate:t.animate,animationDuration:t.animationDuration}}async onInit(){this.chart=new MetricsMiniChart({...this.chartOptions,containerId:"chart"}),this.addChild(this.chart),this.header=new e.View({containerId:"chart-header",title:this.title,icon:this.icon,template:`\n <div class="d-flex justify-content-between align-items-start mb-2">\n <div class="me-3">\n <h6 class="card-title mb-1" style="${this.textColor?`color: ${this.textColor}`:""}">${this.title}</h6>\n <div class="card-subtitle" style="${this.textColor?`color: ${this.textColor}`:""}">${this.subtitle}</div>\n {{#hasTrending}}\n <div class="small mt-1 fw-semibold {{trendingClass}}" style="${this.textColor?`color: ${this.textColor}`:""}">\n <i class="{{trendingIcon}} me-1"></i>{{trendingLabel}}\n </div>\n {{/hasTrending}}\n </div>\n ${this.icon?`<i class="${this.icon} fs-4 flex-shrink-0" aria-hidden="true" style="${this.textColor?`color: ${this.textColor}`:""}"></i>`:""}\n </div>`}),this.addChild(this.header),this.chart?.on&&this.chart.on("metrics:loaded",this.onChildMetricsLoaded,this),this.updateFromChartData({render:!1})}onChildMetricsLoaded(){this.updateFromChartData({render:!0})}updateFromChartData({render:t=!0}={}){const e=Array.isArray(this.chart?.data)?this.chart.data:null;if(!e||0===e.length)return this.total=0,this.hasTrending=!1,this.header.title=this.title,void(t&&this.render());const s=e.map(t=>{if("number"==typeof t)return t;if(t&&"number"==typeof t.value)return t.value;const e=parseFloat(t);return Number.isNaN(e)?0:e});this.header.title=this.title,this.header.total=s.reduce((t,e)=>t+e,0);const a=Math.max(0,parseInt(this.trendOffset||0,10)||0),i=Math.max(0,s.length-1-a);this.header.now_value=s[i];let r=!1,h=0,o=0;const n=this.trendRange&&this.trendRange>=2?Math.max(1,Math.floor(this.trendRange/2)):1;if(i>=0){const t=i,e=t-(n-1);let a,l;if(this.prevTrendOffset&&this.prevTrendOffset>0?(a=e-this.prevTrendOffset,l=t-this.prevTrendOffset):(l=e-1,a=l-(n-1)),e>=0&&a>=0){const i=(t,e,s)=>{let a=0;for(let i=e;i<=s;i++)a+=t[i]||0;return a};h=i(s,e,t),o=i(s,a,l),r=!0}}if(!r){const t=i-(this.prevTrendOffset&&this.prevTrendOffset>0?this.prevTrendOffset:1);t>=0&&(h=s[i],o=s[t],r=!0)}if(r){this.header.lastValue=h,this.header.prevValue=o;let t=0;t=0===o?h>0?100:0:(h-o)/Math.abs(o)*100,this.header.trendingPercent=t,this.header.trendingUp=t>=0,this.textColor?this.header.trendingClass="":this.header.trendingClass=this.header.trendingUp?"text-success":"text-danger",this.header.trendingIcon=this.header.trendingUp?"bi bi-arrow-up":"bi bi-arrow-down";const e=t>0?"+":"";this.header.trendingLabel=`${e}${t.toFixed(1)}%`,this.header.hasTrending=!0}else this.header.hasTrending=!1;t&&this.header.render()}get cardStyle(){const t=[];return this.background&&t.push(`background: ${this.background}`),this.textColor&&t.push(`color: ${this.textColor}`),t.push("border: 0"),t.join("; ")}async getTemplate(){return`\n <div class="card h-100 shadow-sm" style="${this.cardStyle}">\n <div class="card-body p-3">\n <div data-container="chart-header"></div>\n <div data-container="chart"></div>\n </div>\n </div>\n `}async onBeforeDestroy(){this.chart?.off&&this.chart.off("metrics:loaded",this.onChildMetricsLoaded,this),await super.onBeforeDestroy()}refresh(){this.chart&&(this.chart.account=this.account,this.chart.refresh())}}exports.BaseChart=BaseChart,exports.MetricsChart=class extends SeriesChart{constructor(t={}){super({...t,chartType:t.chartType||"line",title:t.title||"Metrics",colors:t.colors||["rgba(54, 162, 235, 0.8)","rgba(255, 99, 132, 0.8)","rgba(75, 192, 192, 0.8)","rgba(255, 206, 86, 0.8)","rgba(153, 102, 255, 0.8)","rgba(255, 159, 64, 0.8)","rgba(199, 199, 199, 0.8)","rgba(83, 102, 255, 0.8)"],yAxis:t.yAxis||{label:"Count",beginAtZero:!0},tooltip:t.tooltip||{y:"number"},width:t.width,height:t.height}),this.endpoint=t.endpoint||"/api/metrics/fetch",this.account=t.account||"global",this.granularity=t.granularity||"hours",this.slugs=t.slugs||null,this.category=t.category||null,this.dateStart=t.dateStart||null,this.dateEnd=t.dateEnd||null,this.defaultDateRange=t.defaultDateRange||"24h",this.showGranularity=!1!==t.showGranularity,this.showDateRange=!1!==t.showDateRange,this.granularityOptions=t.granularityOptions||[{value:"minutes",label:"Minutes"},{value:"hours",label:"Hours"},{value:"days",label:"Days"},{value:"weeks",label:"Weeks"},{value:"months",label:"Months"}],this.quickRanges=t.quickRanges||[{value:"1h",label:"1H"},{value:"24h",label:"24H"},{value:"7d",label:"7D"},{value:"30d",label:"30D"}],this.availableMetrics=t.availableMetrics||[{value:"api_calls",label:"API Calls"},{value:"api_errors",label:"API Errors"},{value:"incident_evt",label:"System Events"},{value:"incidents",label:"Incidents"}],this.isLoading=!1,this.lastFetch=null,this.dateStart&&this.dateEnd||this.setQuickRange(this.defaultDateRange)}async onInit(){const t=[];this.showGranularity&&t.push({type:"select",name:"granularity",action:"granularity-changed",size:"sm",options:this.granularityOptions.map(t=>({value:t.value,label:t.label,selected:t.value===this.granularity}))}),this.showDateRange&&t.push({type:"button",action:"show-date-range-dialog",labelHtml:`<i class="bi bi-calendar-range me-1"></i>${this.formatDateRangeDisplay()}`,title:"Select Date Range",variant:"outline-secondary",size:"sm"}),this.headerConfig={titleHtml:this.title||"Metrics",chartTitle:this.chartTitle||"",showExport:!0===this.exportEnabled,showRefresh:this.refreshEnabled,showTheme:!1,controls:t},await super.onInit()}async onActionGranularityChanged(t,e){const s=e.value;s&&s!==this.granularity&&(this.granularity=s,await this.fetchData())}async onActionShowDateRangeDialog(){try{const e=await t.default.showForm({title:"Select Date Range",size:"md",fields:[{name:"dateRange",type:"daterange",label:"Date Range",startName:"dt_start",endName:"dt_end",startDate:this.formatDateTimeLocal(this.dateStart),endDate:this.formatDateTimeLocal(this.dateEnd),required:!0}],formConfig:{options:{submitButton:!1,resetButton:!1}}});if(e&&e.startDate&&e.endDate){this.dateStart=new Date(e.startDate),this.dateEnd=new Date(e.endDate);const t=this.element?.querySelector('[data-action="show-date-range-dialog"]');t&&(t.innerHTML=`<i class="bi bi-calendar-range me-1"></i>${this.formatDateRangeDisplay()}`),await this.fetchData()}}catch(e){console.error("Date range dialog error:",e)}}buildApiParams(){const t={granularity:this.granularity,account:this.account,with_labels:!0};return this.slugs&&this.slugs.forEach(e=>{t["slugs[]"]||(t["slugs[]"]=[]),t["slugs[]"].push(e)}),this.category&&(t.category=this.category),this.dateStart&&(t.dr_start=Math.floor(this.dateStart.getTime()/1e3)),this.dateEnd&&(t.dr_end=Math.floor(this.dateEnd.getTime()/1e3)),t._=Date.now(),t}async fetchData(){if(this.endpoint){this.isLoading=!0,this.showLoading();try{const t=this.getApp()?.rest;if(!t)throw new Error("No REST client available");const e=this.buildApiParams(),s=await t.GET(this.endpoint,e);if(!s.success)throw new Error(s.message||"Network error");if(!s.data?.status)throw new Error(s.data?.error||"Server error");const a=s.data.data,i=this.processMetricsData(a);await this.setData(i),this.lastFetch=/* @__PURE__ */new Date,this.emit("metrics:data-loaded",{chart:this,data:a,params:e})}catch(t){console.error("Failed to fetch metrics data:",t),this.showError(`Failed to load metrics: ${t.message}`),this.emit("metrics:error",{chart:this,error:t})}finally{this.isLoading=!1,this.hideLoading()}}}processMetricsData(t){const{data:e,labels:s}=t,a=[];return Object.keys(e).forEach((t,s)=>{const i=e[t].map(t=>null==t||""===t?0:"number"==typeof t?t:parseFloat(t)||0);a.push({label:this.formatMetricLabel(t),data:i,backgroundColor:this.colors[s%this.colors.length].replace("0.8","0.6"),borderColor:this.colors[s%this.colors.length],borderWidth:2,tension:"line"===this.chartType?.4:0,fill:!1,pointRadius:"line"===this.chartType?3:0,pointHoverRadius:5})}),{labels:s,datasets:a}}formatMetricLabel(t){return t.split("_").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}setQuickRange(t){const e=/* @__PURE__ */new Date;let s;switch(t){case"1h":s=new Date(e.getTime()-36e5);break;case"24h":default:s=new Date(e.getTime()-864e5);break;case"7d":s=new Date(e.getTime()-6048e5);break;case"30d":s=new Date(e.getTime()-2592e6)}this.dateStart=s,this.dateEnd=e}formatDateTimeLocal(t){return t?`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}T${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`:""}setGranularity(t){return this.granularity=t,this.fetchData()}setDateRange(t,e){return this.dateStart=new Date(t),this.dateEnd=new Date(e),this.fetchData()}setMetrics(t){return this.slugs=[...t],this.fetchData()}getStats(){return{...super.getStats(),lastFetch:this.lastFetch,granularity:this.granularity,slugs:[...this.slugs],dateRange:{start:this.dateStart,end:this.dateEnd}}}},exports.MetricsMiniChart=MetricsMiniChart,exports.MetricsMiniChartWidget=MetricsMiniChartWidget,exports.MiniChart=MiniChart,exports.PieChart=PieChart,exports.SeriesChart=SeriesChart;
|
|
2
|
-
//# sourceMappingURL=MetricsMiniChartWidget-Esvv-lFp.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const e=require("./Rest-BNYqGlnP.js");class Page extends e.View{constructor(e={}){e.tagName=e.tagName||"main",e.className=e.className||"mojo-page";const t=e.pageName||"";t&&!e.id&&(e.id="page_"+t.toLowerCase().replace(/\s+/g,"_")),super(e),this.pageName=e.pageName||this.constructor.pageName||"",this.route=e.route||this.constructor.route||"",this.title=e.title||this.pageName||"",this.id||!this.constructor.pageName||e.pageName||(this.id="page_"+this.constructor.pageName.toLowerCase().replace(/\s+/g,"_")),this.pageIcon=e.icon||e.pageIcon||this.constructor.pageIcon||"bi bi-file-text",this.displayName=e.displayName||this.constructor.displayName||this.pageName||"",this.pageDescription=e.pageDescription||this.constructor.pageDescription||"",this.params={},this.query={},this.matched=!1,this.isActive=!1,this.pageOptions={title:e.title||this.pageName||"Untitled Page",description:e.description||"",requiresAuth:e.requiresAuth||!1,...e.pageOptions},this.savedState=null,this.pageName,this.route}async onParams(e={},t={}){this.params=e,this.query=t}canEnter(){if(this.options.permissions){const e=this.getApp().activeUser;if(!e||!e.hasPermission(this.options.permissions))return!1}return!(this.options.requiresGroup&&!this.getApp().activeGroup)}async onEnter(){this.isActive=!0,await this.onInitView(),this.savedState&&(this.restoreState(this.savedState),this.savedState=null),this.pageOptions&&this.pageOptions.title&&"undefined"!=typeof document&&(document.title=this.pageOptions.title),this.emit("activated",{page:this.getMetadata()}),this.pageName}async onExit(){this.savedState=this.captureState(),this.isActive=!1,this.emit("deactivated",{page:this.getMetadata()}),this.pageName}getMetadata(){return{name:this.pageName,displayName:this.displayName||this.pageName,icon:this.pageIcon,description:this.pageDescription,route:this.route,isActive:this.isActive}}async onActionDefault(e){this.pageName}async makeActive(){this.getApp().showPage(this)}async onActionNavigate(e,t){e.preventDefault();const s=t.dataset.page;this.getApp().showPage(s)}captureState(){return this.element?{scrollTop:this.element.scrollTop,formData:this.captureFormData(),custom:this.captureCustomState()}:null}restoreState(e){e&&this.element&&(this.element.scrollTop=e.scrollTop||0,this.restoreFormData(e.formData),e.custom&&this.restoreCustomState(e.custom))}captureFormData(){const e={};return this.element?(this.element.querySelectorAll("input, select, textarea").forEach(t=>{t.name&&("checkbox"===t.type?e[t.name]=t.checked:"radio"===t.type?t.checked&&(e[t.name]=t.value):e[t.name]=t.value)}),e):e}restoreFormData(e){e&&this.element&&Object.entries(e).forEach(([e,t])=>{const s=this.element.querySelector(`[name="${e}"]`);if(s)if("checkbox"===s.type)s.checked=t;else if("radio"===s.type){const s=this.element.querySelector(`[name="${e}"][value="${t}"]`);s&&(s.checked=!0)}else s.value=t})}captureCustomState(){return{}}restoreCustomState(e){}setMeta(e={}){if("undefined"!=typeof document){if(e.title&&(document.title=e.title,this.pageOptions.title=e.title),e.description){let t=document.querySelector('meta[name="description"]');t||(t=document.createElement("meta"),t.name="description",document.head.appendChild(t)),t.content=e.description,this.pageOptions.description=e.description}Object.entries(e).forEach(([e,t])=>{if("title"!==e&&"description"!==e){let s=document.querySelector(`meta[name="${e}"]`);s||(s=document.createElement("meta"),s.name=e,document.head.appendChild(s)),s.content=t}})}}showError(e){if(super.showError(e),this.element){const t=document.createElement("div");t.className="alert alert-danger alert-dismissible fade show",t.innerHTML=`\n ${e}\n <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>\n `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},5e3)}}showSuccess(e){if(super.showSuccess(e),this.element){const t=document.createElement("div");t.className="alert alert-success alert-dismissible fade show",t.innerHTML=`\n ${e}\n <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>\n `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},3e3)}}async onBeforeRender(){await super.onBeforeRender(),this.setMeta({title:this.pageOptions.title,description:this.pageOptions.description})}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof document&&this.pageName&&document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}async onBeforeDestroy(){await super.onBeforeDestroy(),"undefined"!=typeof document&&this.pageName&&document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}navigate(e,t={},s={}){return this.app&&this.app.router?this.app.router.navigate(e,s):"undefined"!=typeof window&&window.MOJO?.router?window.MOJO.router.navigate(e,s):void console.error("No router available for navigation")}getRoute(){if(this.route){let e=this.route;return"string"==typeof e&&e.startsWith("/")&&(e=e.substring(1)),e}return this.pageName}syncUrl(e=!0){this.updateBrowserUrl(this.query,!1,!1)}updateBrowserUrl(e=null,t=!1,s=!1){this.getApp(),this.app.router.updateBrowserUrl(this.getRoute(),e,t,s)}static define(e){class DefinedPage extends Page{constructor(t={}){super({...e,...t})}}return DefinedPage.template=e.template,DefinedPage.pageName=e.pageName,DefinedPage.route=e.route,DefinedPage}}exports.Page=Page;
|
|
2
|
-
//# sourceMappingURL=Page-CvbwEoLv.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Page-CvbwEoLv.js","sources":["../../src/core/Page.js"],"sourcesContent":["/**\n * Page - Extends View with routing capabilities for MOJO framework\n * Handles URL routing, parameters, and page-specific actions\n *\n * Event Emitter notes:\n * - Uses EventEmitter via View base class.\n * - Use .emit/.on/.off/.once for all custom events.\n */\n\nimport View from '@core/View.js';\n\nclass Page extends View {\n constructor(options = {}) {\n // Set default tag name for pages\n options.tagName = options.tagName || 'main';\n options.className = options.className || 'mojo-page';\n\n // Set page ID based on page name\n const pageName = options.pageName || '';\n if (pageName && !options.id) {\n options.id = 'page_' + pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n super(options);\n\n // Core page properties from design doc\n this.pageName = options.pageName || this.constructor.pageName || '';\n this.route = options.route || this.constructor.route || '';\n this.title = options.title || this.pageName || '';\n\n // Set page ID if not already set and we have a page_name from constructor\n if (!this.id && this.constructor.pageName && !options.pageName) {\n this.id = 'page_' + this.constructor.pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n // Page metadata for event system\n this.pageIcon = options.icon || options.pageIcon || this.constructor.pageIcon || 'bi bi-file-text';\n this.displayName = options.displayName || this.constructor.displayName || this.pageName || '';\n this.pageDescription = options.pageDescription || this.constructor.pageDescription || '';\n\n // Routing state\n this.params = {};\n this.query = {};\n this.matched = false;\n this.isActive = false;\n\n // Page-specific options\n this.pageOptions = {\n title: options.title || this.pageName || 'Untitled Page',\n description: options.description || '',\n requiresAuth: options.requiresAuth || false,\n ...options.pageOptions\n };\n\n // State preservation\n this.savedState = null;\n\n console.log(`Page ${this.pageName} constructed with route: ${this.route}`);\n }\n\n /**\n * Handle route parameters - from design doc\n * @param {object} params - Route parameters\n * @param {object} query - Query string parameters\n */\n async onParams(params = {}, query = {}) {\n // const paramsChanged = JSON.stringify(params) !== JSON.stringify(this.params);\n // const queryChanged = JSON.stringify(query) !== JSON.stringify(this.query);\n\n this.params = params;\n this.query = query;\n\n // Only re-render if params actually changed and page is active\n // if (this.isActive && (paramsChanged || queryChanged)) {\n // console.log(`Page ${this.pageName} params changed, re-rendering`);\n // await this.render();\n // }\n }\n\n canEnter() {\n if (this.options.permissions) {\n const user = this.getApp().activeUser;\n if (!user || !user.hasPermission(this.options.permissions)) {\n return false;\n }\n }\n if (this.options.requiresGroup && !this.getApp().activeGroup) {\n return false;\n }\n return true;\n }\n\n /**\n * Called when entering this page (before render)\n * Override this method for initialization logic\n */\n async onEnter() {\n this.isActive = true;\n await this.onInitView();\n\n // Restore saved state if exists\n if (this.savedState) {\n this.restoreState(this.savedState);\n this.savedState = null;\n }\n\n // Set page title if provided\n if (this.pageOptions && this.pageOptions.title && typeof document !== 'undefined') {\n document.title = this.pageOptions.title;\n }\n\n // Emit activation event\n this.emit('activated', {\n page: this.getMetadata()\n });\n\n console.log(`Page ${this.pageName} entered`);\n }\n\n /**\n * Called when leaving this page (before cleanup)\n * Override this method for cleanup logic like removing listeners, clearing timers, etc.\n */\n async onExit() {\n // Save state before exit\n this.savedState = this.captureState();\n this.isActive = false;\n\n // Emit deactivation event\n this.emit('deactivated', {\n page: this.getMetadata()\n });\n console.log(`Page ${this.pageName} exiting`);\n }\n\n /**\n * Get page metadata for display and events\n * @returns {object} Page metadata\n */\n getMetadata() {\n return {\n name: this.pageName,\n displayName: this.displayName || this.pageName,\n icon: this.pageIcon,\n description: this.pageDescription,\n route: this.route,\n isActive: this.isActive\n };\n }\n\n /**\n * Handle default action - fallback from design doc\n */\n async onActionDefault(action) {\n console.log(`Default action '${action}' triggered on page: ${this.pageName}`);\n }\n\n async makeActive() {\n this.getApp().showPage(this);\n }\n\n async onActionNavigate(event, element) {\n event.preventDefault();\n const page = element.dataset.page;\n this.getApp().showPage(page);\n }\n\n /**\n * Capture current page state for preservation\n * @returns {object|null} Captured state\n */\n captureState() {\n if (!this.element) return null;\n\n return {\n scrollTop: this.element.scrollTop,\n formData: this.captureFormData(),\n custom: this.captureCustomState()\n };\n }\n\n /**\n * Restore saved state\n * @param {object} state - State to restore\n */\n restoreState(state) {\n if (!state || !this.element) return;\n\n this.element.scrollTop = state.scrollTop || 0;\n this.restoreFormData(state.formData);\n if (state.custom) {\n this.restoreCustomState(state.custom);\n }\n }\n\n /**\n * Capture form data from page\n * @returns {object} Form data\n */\n captureFormData() {\n const data = {};\n if (!this.element) return data;\n\n this.element.querySelectorAll('input, select, textarea').forEach(field => {\n if (field.name) {\n if (field.type === 'checkbox') {\n data[field.name] = field.checked;\n } else if (field.type === 'radio') {\n if (field.checked) {\n data[field.name] = field.value;\n }\n } else {\n data[field.name] = field.value;\n }\n }\n });\n\n return data;\n }\n\n /**\n * Restore form data to page\n * @param {object} formData - Form data to restore\n */\n restoreFormData(formData) {\n if (!formData || !this.element) return;\n\n Object.entries(formData).forEach(([name, value]) => {\n const field = this.element.querySelector(`[name=\"${name}\"]`);\n if (field) {\n if (field.type === 'checkbox') {\n field.checked = value;\n } else if (field.type === 'radio') {\n const radio = this.element.querySelector(`[name=\"${name}\"][value=\"${value}\"]`);\n if (radio) radio.checked = true;\n } else {\n field.value = value;\n }\n }\n });\n }\n\n /**\n * Capture custom state - override in subclasses\n * @returns {object} Custom state\n */\n captureCustomState() {\n return {};\n }\n\n /**\n * Restore custom state - override in subclasses\n * @param {object} state - Custom state to restore\n */\n restoreCustomState(state) {\n // Override in subclasses\n }\n\n\n\n /**\n * Set page metadata\n * @param {object} meta - Metadata object\n */\n setMeta(meta = {}) {\n if (typeof document === 'undefined') {\n return;\n }\n\n // Set title\n if (meta.title) {\n document.title = meta.title;\n this.pageOptions.title = meta.title;\n }\n\n // Set description\n if (meta.description) {\n let descMeta = document.querySelector('meta[name=\"description\"]');\n if (!descMeta) {\n descMeta = document.createElement('meta');\n descMeta.name = 'description';\n document.head.appendChild(descMeta);\n }\n descMeta.content = meta.description;\n this.pageOptions.description = meta.description;\n }\n\n // Set other meta tags\n Object.entries(meta).forEach(([key, value]) => {\n if (key !== 'title' && key !== 'description') {\n let metaEl = document.querySelector(`meta[name=\"${key}\"]`);\n if (!metaEl) {\n metaEl = document.createElement('meta');\n metaEl.name = key;\n document.head.appendChild(metaEl);\n }\n metaEl.content = value;\n }\n });\n }\n\n\n /**\n * Show error message with page context\n * @param {string} message - Error message\n */\n showError(message) {\n super.showError(message);\n\n // Page-specific error display can be implemented here\n if (this.element) {\n // Example: Add error to page\n const errorDiv = document.createElement('div');\n errorDiv.className = 'alert alert-danger alert-dismissible fade show';\n errorDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(errorDiv, this.element.firstChild);\n\n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (errorDiv.parentNode) {\n errorDiv.parentNode.removeChild(errorDiv);\n }\n }, 5000);\n }\n }\n\n /**\n * Show success message with page context\n * @param {string} message - Success message\n */\n showSuccess(message) {\n super.showSuccess(message);\n\n // Page-specific success display\n if (this.element) {\n const successDiv = document.createElement('div');\n successDiv.className = 'alert alert-success alert-dismissible fade show';\n successDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(successDiv, this.element.firstChild);\n\n // Auto-remove after 3 seconds\n setTimeout(() => {\n if (successDiv.parentNode) {\n successDiv.parentNode.removeChild(successDiv);\n }\n }, 3000);\n }\n }\n\n /**\n * Page-specific before render hook\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n // Set page metadata before rendering\n this.setMeta({\n title: this.pageOptions.title,\n description: this.pageOptions.description\n });\n }\n\n /**\n * Page-specific after mount hook\n */\n async onAfterMount() {\n await super.onAfterMount();\n\n // Add page-specific class to body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Page-specific before destroy hook\n */\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove page-specific class from body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Navigate to another page using the app's router\n * @param {string} route - Route to navigate to\n * @param {object} params - Route parameters\n * @param {object} options - Navigation options\n */\n navigate(route, params = {}, options = {}) {\n // Delegate to app's router\n if (this.app && this.app.router) {\n return this.app.router.navigate(route, options);\n }\n\n // Fallback to MOJO global router\n if (typeof window !== 'undefined' && window.MOJO?.router) {\n return window.MOJO.router.navigate(route, options);\n }\n\n console.error('No router available for navigation');\n }\n\n getRoute() {\n if (this.route) {\n let route = this.route;\n if (typeof route === 'string' && route.startsWith('/')) {\n route = route.substring(1);\n }\n return route;\n }\n return this.pageName;\n }\n\n syncUrl(force = true) {\n this.updateBrowserUrl(this.query, false, false);\n }\n\n updateBrowserUrl(query = null, replace = false, trigger = false) {\n this.getApp();\n // we need to do this to normalize the URL\n // const targetPath = this.app.buildPagePath(this, this.params, query);\n // const { pageName, queryParams } = this.app.router.parseInput(targetPath);\n this.app.router.updateBrowserUrl(this.getRoute(), query, replace, trigger);\n }\n\n /**\n * Static method to define a page class with metadata\n * @param {object} definition - Page class definition\n * @returns {class} Page class\n */\n static define(definition) {\n class DefinedPage extends Page {\n constructor(options = {}) {\n super({\n ...definition,\n ...options\n });\n }\n }\n\n // Copy static properties\n DefinedPage.template = definition.template;\n DefinedPage.pageName = definition.pageName;\n DefinedPage.route = definition.route;\n\n return DefinedPage;\n }\n}\n\nexport default Page;\n"],"names":["Page","View","constructor","options","tagName","className","pageName","id","toLowerCase","replace","super","this","route","title","pageIcon","icon","displayName","pageDescription","params","query","matched","isActive","pageOptions","description","requiresAuth","savedState","onParams","canEnter","permissions","user","getApp","activeUser","hasPermission","requiresGroup","activeGroup","onEnter","onInitView","restoreState","document","emit","page","getMetadata","onExit","captureState","name","onActionDefault","action","makeActive","showPage","onActionNavigate","event","element","preventDefault","dataset","scrollTop","formData","captureFormData","custom","captureCustomState","state","restoreFormData","restoreCustomState","data","querySelectorAll","forEach","field","type","checked","value","Object","entries","querySelector","radio","setMeta","meta","descMeta","createElement","head","appendChild","content","key","metaEl","showError","message","errorDiv","innerHTML","insertBefore","firstChild","setTimeout","parentNode","removeChild","showSuccess","successDiv","onBeforeRender","onAfterMount","body","classList","add","onBeforeDestroy","remove","navigate","app","router","window","MOJO","console","error","getRoute","startsWith","substring","syncUrl","force","updateBrowserUrl","trigger","define","definition","DefinedPage","template"],"mappings":"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"}
|
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import { V as View } from "./Rest-CS4jRCAs.js";
|
|
2
|
-
class Page extends View {
|
|
3
|
-
constructor(options = {}) {
|
|
4
|
-
options.tagName = options.tagName || "main";
|
|
5
|
-
options.className = options.className || "mojo-page";
|
|
6
|
-
const pageName = options.pageName || "";
|
|
7
|
-
if (pageName && !options.id) {
|
|
8
|
-
options.id = "page_" + pageName.toLowerCase().replace(/\s+/g, "_");
|
|
9
|
-
}
|
|
10
|
-
super(options);
|
|
11
|
-
this.pageName = options.pageName || this.constructor.pageName || "";
|
|
12
|
-
this.route = options.route || this.constructor.route || "";
|
|
13
|
-
this.title = options.title || this.pageName || "";
|
|
14
|
-
if (!this.id && this.constructor.pageName && !options.pageName) {
|
|
15
|
-
this.id = "page_" + this.constructor.pageName.toLowerCase().replace(/\s+/g, "_");
|
|
16
|
-
}
|
|
17
|
-
this.pageIcon = options.icon || options.pageIcon || this.constructor.pageIcon || "bi bi-file-text";
|
|
18
|
-
this.displayName = options.displayName || this.constructor.displayName || this.pageName || "";
|
|
19
|
-
this.pageDescription = options.pageDescription || this.constructor.pageDescription || "";
|
|
20
|
-
this.params = {};
|
|
21
|
-
this.query = {};
|
|
22
|
-
this.matched = false;
|
|
23
|
-
this.isActive = false;
|
|
24
|
-
this.pageOptions = {
|
|
25
|
-
title: options.title || this.pageName || "Untitled Page",
|
|
26
|
-
description: options.description || "",
|
|
27
|
-
requiresAuth: options.requiresAuth || false,
|
|
28
|
-
...options.pageOptions
|
|
29
|
-
};
|
|
30
|
-
this.savedState = null;
|
|
31
|
-
console.log(`Page ${this.pageName} constructed with route: ${this.route}`);
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Handle route parameters - from design doc
|
|
35
|
-
* @param {object} params - Route parameters
|
|
36
|
-
* @param {object} query - Query string parameters
|
|
37
|
-
*/
|
|
38
|
-
async onParams(params = {}, query = {}) {
|
|
39
|
-
this.params = params;
|
|
40
|
-
this.query = query;
|
|
41
|
-
}
|
|
42
|
-
canEnter() {
|
|
43
|
-
if (this.options.permissions) {
|
|
44
|
-
const user = this.getApp().activeUser;
|
|
45
|
-
if (!user || !user.hasPermission(this.options.permissions)) {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (this.options.requiresGroup && !this.getApp().activeGroup) {
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Called when entering this page (before render)
|
|
56
|
-
* Override this method for initialization logic
|
|
57
|
-
*/
|
|
58
|
-
async onEnter() {
|
|
59
|
-
this.isActive = true;
|
|
60
|
-
await this.onInitView();
|
|
61
|
-
if (this.savedState) {
|
|
62
|
-
this.restoreState(this.savedState);
|
|
63
|
-
this.savedState = null;
|
|
64
|
-
}
|
|
65
|
-
if (this.pageOptions && this.pageOptions.title && typeof document !== "undefined") {
|
|
66
|
-
document.title = this.pageOptions.title;
|
|
67
|
-
}
|
|
68
|
-
this.emit("activated", {
|
|
69
|
-
page: this.getMetadata()
|
|
70
|
-
});
|
|
71
|
-
console.log(`Page ${this.pageName} entered`);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Called when leaving this page (before cleanup)
|
|
75
|
-
* Override this method for cleanup logic like removing listeners, clearing timers, etc.
|
|
76
|
-
*/
|
|
77
|
-
async onExit() {
|
|
78
|
-
this.savedState = this.captureState();
|
|
79
|
-
this.isActive = false;
|
|
80
|
-
this.emit("deactivated", {
|
|
81
|
-
page: this.getMetadata()
|
|
82
|
-
});
|
|
83
|
-
console.log(`Page ${this.pageName} exiting`);
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Get page metadata for display and events
|
|
87
|
-
* @returns {object} Page metadata
|
|
88
|
-
*/
|
|
89
|
-
getMetadata() {
|
|
90
|
-
return {
|
|
91
|
-
name: this.pageName,
|
|
92
|
-
displayName: this.displayName || this.pageName,
|
|
93
|
-
icon: this.pageIcon,
|
|
94
|
-
description: this.pageDescription,
|
|
95
|
-
route: this.route,
|
|
96
|
-
isActive: this.isActive
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Handle default action - fallback from design doc
|
|
101
|
-
*/
|
|
102
|
-
async onActionDefault(action) {
|
|
103
|
-
console.log(`Default action '${action}' triggered on page: ${this.pageName}`);
|
|
104
|
-
}
|
|
105
|
-
async makeActive() {
|
|
106
|
-
this.getApp().showPage(this);
|
|
107
|
-
}
|
|
108
|
-
async onActionNavigate(event, element) {
|
|
109
|
-
event.preventDefault();
|
|
110
|
-
const page = element.dataset.page;
|
|
111
|
-
this.getApp().showPage(page);
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Capture current page state for preservation
|
|
115
|
-
* @returns {object|null} Captured state
|
|
116
|
-
*/
|
|
117
|
-
captureState() {
|
|
118
|
-
if (!this.element) return null;
|
|
119
|
-
return {
|
|
120
|
-
scrollTop: this.element.scrollTop,
|
|
121
|
-
formData: this.captureFormData(),
|
|
122
|
-
custom: this.captureCustomState()
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Restore saved state
|
|
127
|
-
* @param {object} state - State to restore
|
|
128
|
-
*/
|
|
129
|
-
restoreState(state) {
|
|
130
|
-
if (!state || !this.element) return;
|
|
131
|
-
this.element.scrollTop = state.scrollTop || 0;
|
|
132
|
-
this.restoreFormData(state.formData);
|
|
133
|
-
if (state.custom) {
|
|
134
|
-
this.restoreCustomState(state.custom);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Capture form data from page
|
|
139
|
-
* @returns {object} Form data
|
|
140
|
-
*/
|
|
141
|
-
captureFormData() {
|
|
142
|
-
const data = {};
|
|
143
|
-
if (!this.element) return data;
|
|
144
|
-
this.element.querySelectorAll("input, select, textarea").forEach((field) => {
|
|
145
|
-
if (field.name) {
|
|
146
|
-
if (field.type === "checkbox") {
|
|
147
|
-
data[field.name] = field.checked;
|
|
148
|
-
} else if (field.type === "radio") {
|
|
149
|
-
if (field.checked) {
|
|
150
|
-
data[field.name] = field.value;
|
|
151
|
-
}
|
|
152
|
-
} else {
|
|
153
|
-
data[field.name] = field.value;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
return data;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Restore form data to page
|
|
161
|
-
* @param {object} formData - Form data to restore
|
|
162
|
-
*/
|
|
163
|
-
restoreFormData(formData) {
|
|
164
|
-
if (!formData || !this.element) return;
|
|
165
|
-
Object.entries(formData).forEach(([name, value]) => {
|
|
166
|
-
const field = this.element.querySelector(`[name="${name}"]`);
|
|
167
|
-
if (field) {
|
|
168
|
-
if (field.type === "checkbox") {
|
|
169
|
-
field.checked = value;
|
|
170
|
-
} else if (field.type === "radio") {
|
|
171
|
-
const radio = this.element.querySelector(`[name="${name}"][value="${value}"]`);
|
|
172
|
-
if (radio) radio.checked = true;
|
|
173
|
-
} else {
|
|
174
|
-
field.value = value;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Capture custom state - override in subclasses
|
|
181
|
-
* @returns {object} Custom state
|
|
182
|
-
*/
|
|
183
|
-
captureCustomState() {
|
|
184
|
-
return {};
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Restore custom state - override in subclasses
|
|
188
|
-
* @param {object} state - Custom state to restore
|
|
189
|
-
*/
|
|
190
|
-
restoreCustomState(state) {
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Set page metadata
|
|
194
|
-
* @param {object} meta - Metadata object
|
|
195
|
-
*/
|
|
196
|
-
setMeta(meta = {}) {
|
|
197
|
-
if (typeof document === "undefined") {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (meta.title) {
|
|
201
|
-
document.title = meta.title;
|
|
202
|
-
this.pageOptions.title = meta.title;
|
|
203
|
-
}
|
|
204
|
-
if (meta.description) {
|
|
205
|
-
let descMeta = document.querySelector('meta[name="description"]');
|
|
206
|
-
if (!descMeta) {
|
|
207
|
-
descMeta = document.createElement("meta");
|
|
208
|
-
descMeta.name = "description";
|
|
209
|
-
document.head.appendChild(descMeta);
|
|
210
|
-
}
|
|
211
|
-
descMeta.content = meta.description;
|
|
212
|
-
this.pageOptions.description = meta.description;
|
|
213
|
-
}
|
|
214
|
-
Object.entries(meta).forEach(([key, value]) => {
|
|
215
|
-
if (key !== "title" && key !== "description") {
|
|
216
|
-
let metaEl = document.querySelector(`meta[name="${key}"]`);
|
|
217
|
-
if (!metaEl) {
|
|
218
|
-
metaEl = document.createElement("meta");
|
|
219
|
-
metaEl.name = key;
|
|
220
|
-
document.head.appendChild(metaEl);
|
|
221
|
-
}
|
|
222
|
-
metaEl.content = value;
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Show error message with page context
|
|
228
|
-
* @param {string} message - Error message
|
|
229
|
-
*/
|
|
230
|
-
showError(message) {
|
|
231
|
-
super.showError(message);
|
|
232
|
-
if (this.element) {
|
|
233
|
-
const errorDiv = document.createElement("div");
|
|
234
|
-
errorDiv.className = "alert alert-danger alert-dismissible fade show";
|
|
235
|
-
errorDiv.innerHTML = `
|
|
236
|
-
${message}
|
|
237
|
-
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
238
|
-
`;
|
|
239
|
-
this.element.insertBefore(errorDiv, this.element.firstChild);
|
|
240
|
-
setTimeout(() => {
|
|
241
|
-
if (errorDiv.parentNode) {
|
|
242
|
-
errorDiv.parentNode.removeChild(errorDiv);
|
|
243
|
-
}
|
|
244
|
-
}, 5e3);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Show success message with page context
|
|
249
|
-
* @param {string} message - Success message
|
|
250
|
-
*/
|
|
251
|
-
showSuccess(message) {
|
|
252
|
-
super.showSuccess(message);
|
|
253
|
-
if (this.element) {
|
|
254
|
-
const successDiv = document.createElement("div");
|
|
255
|
-
successDiv.className = "alert alert-success alert-dismissible fade show";
|
|
256
|
-
successDiv.innerHTML = `
|
|
257
|
-
${message}
|
|
258
|
-
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
259
|
-
`;
|
|
260
|
-
this.element.insertBefore(successDiv, this.element.firstChild);
|
|
261
|
-
setTimeout(() => {
|
|
262
|
-
if (successDiv.parentNode) {
|
|
263
|
-
successDiv.parentNode.removeChild(successDiv);
|
|
264
|
-
}
|
|
265
|
-
}, 3e3);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Page-specific before render hook
|
|
270
|
-
*/
|
|
271
|
-
async onBeforeRender() {
|
|
272
|
-
await super.onBeforeRender();
|
|
273
|
-
this.setMeta({
|
|
274
|
-
title: this.pageOptions.title,
|
|
275
|
-
description: this.pageOptions.description
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Page-specific after mount hook
|
|
280
|
-
*/
|
|
281
|
-
async onAfterMount() {
|
|
282
|
-
await super.onAfterMount();
|
|
283
|
-
if (typeof document !== "undefined" && this.pageName) {
|
|
284
|
-
document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\s+/g, "-")}`);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Page-specific before destroy hook
|
|
289
|
-
*/
|
|
290
|
-
async onBeforeDestroy() {
|
|
291
|
-
await super.onBeforeDestroy();
|
|
292
|
-
if (typeof document !== "undefined" && this.pageName) {
|
|
293
|
-
document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\s+/g, "-")}`);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Navigate to another page using the app's router
|
|
298
|
-
* @param {string} route - Route to navigate to
|
|
299
|
-
* @param {object} params - Route parameters
|
|
300
|
-
* @param {object} options - Navigation options
|
|
301
|
-
*/
|
|
302
|
-
navigate(route, params = {}, options = {}) {
|
|
303
|
-
if (this.app && this.app.router) {
|
|
304
|
-
return this.app.router.navigate(route, options);
|
|
305
|
-
}
|
|
306
|
-
if (typeof window !== "undefined" && window.MOJO?.router) {
|
|
307
|
-
return window.MOJO.router.navigate(route, options);
|
|
308
|
-
}
|
|
309
|
-
console.error("No router available for navigation");
|
|
310
|
-
}
|
|
311
|
-
getRoute() {
|
|
312
|
-
if (this.route) {
|
|
313
|
-
let route = this.route;
|
|
314
|
-
if (typeof route === "string" && route.startsWith("/")) {
|
|
315
|
-
route = route.substring(1);
|
|
316
|
-
}
|
|
317
|
-
return route;
|
|
318
|
-
}
|
|
319
|
-
return this.pageName;
|
|
320
|
-
}
|
|
321
|
-
syncUrl(force = true) {
|
|
322
|
-
this.updateBrowserUrl(this.query, false, false);
|
|
323
|
-
}
|
|
324
|
-
updateBrowserUrl(query = null, replace = false, trigger = false) {
|
|
325
|
-
this.getApp();
|
|
326
|
-
this.app.router.updateBrowserUrl(this.getRoute(), query, replace, trigger);
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Static method to define a page class with metadata
|
|
330
|
-
* @param {object} definition - Page class definition
|
|
331
|
-
* @returns {class} Page class
|
|
332
|
-
*/
|
|
333
|
-
static define(definition) {
|
|
334
|
-
class DefinedPage extends Page {
|
|
335
|
-
constructor(options = {}) {
|
|
336
|
-
super({
|
|
337
|
-
...definition,
|
|
338
|
-
...options
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
DefinedPage.template = definition.template;
|
|
343
|
-
DefinedPage.pageName = definition.pageName;
|
|
344
|
-
DefinedPage.route = definition.route;
|
|
345
|
-
return DefinedPage;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
export {
|
|
349
|
-
Page as P
|
|
350
|
-
};
|
|
351
|
-
//# sourceMappingURL=Page-Deq4y2Kq.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Page-Deq4y2Kq.js","sources":["../../src/core/Page.js"],"sourcesContent":["/**\n * Page - Extends View with routing capabilities for MOJO framework\n * Handles URL routing, parameters, and page-specific actions\n *\n * Event Emitter notes:\n * - Uses EventEmitter via View base class.\n * - Use .emit/.on/.off/.once for all custom events.\n */\n\nimport View from '@core/View.js';\n\nclass Page extends View {\n constructor(options = {}) {\n // Set default tag name for pages\n options.tagName = options.tagName || 'main';\n options.className = options.className || 'mojo-page';\n\n // Set page ID based on page name\n const pageName = options.pageName || '';\n if (pageName && !options.id) {\n options.id = 'page_' + pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n super(options);\n\n // Core page properties from design doc\n this.pageName = options.pageName || this.constructor.pageName || '';\n this.route = options.route || this.constructor.route || '';\n this.title = options.title || this.pageName || '';\n\n // Set page ID if not already set and we have a page_name from constructor\n if (!this.id && this.constructor.pageName && !options.pageName) {\n this.id = 'page_' + this.constructor.pageName.toLowerCase().replace(/\\s+/g, '_');\n }\n\n // Page metadata for event system\n this.pageIcon = options.icon || options.pageIcon || this.constructor.pageIcon || 'bi bi-file-text';\n this.displayName = options.displayName || this.constructor.displayName || this.pageName || '';\n this.pageDescription = options.pageDescription || this.constructor.pageDescription || '';\n\n // Routing state\n this.params = {};\n this.query = {};\n this.matched = false;\n this.isActive = false;\n\n // Page-specific options\n this.pageOptions = {\n title: options.title || this.pageName || 'Untitled Page',\n description: options.description || '',\n requiresAuth: options.requiresAuth || false,\n ...options.pageOptions\n };\n\n // State preservation\n this.savedState = null;\n\n console.log(`Page ${this.pageName} constructed with route: ${this.route}`);\n }\n\n /**\n * Handle route parameters - from design doc\n * @param {object} params - Route parameters\n * @param {object} query - Query string parameters\n */\n async onParams(params = {}, query = {}) {\n // const paramsChanged = JSON.stringify(params) !== JSON.stringify(this.params);\n // const queryChanged = JSON.stringify(query) !== JSON.stringify(this.query);\n\n this.params = params;\n this.query = query;\n\n // Only re-render if params actually changed and page is active\n // if (this.isActive && (paramsChanged || queryChanged)) {\n // console.log(`Page ${this.pageName} params changed, re-rendering`);\n // await this.render();\n // }\n }\n\n canEnter() {\n if (this.options.permissions) {\n const user = this.getApp().activeUser;\n if (!user || !user.hasPermission(this.options.permissions)) {\n return false;\n }\n }\n if (this.options.requiresGroup && !this.getApp().activeGroup) {\n return false;\n }\n return true;\n }\n\n /**\n * Called when entering this page (before render)\n * Override this method for initialization logic\n */\n async onEnter() {\n this.isActive = true;\n await this.onInitView();\n\n // Restore saved state if exists\n if (this.savedState) {\n this.restoreState(this.savedState);\n this.savedState = null;\n }\n\n // Set page title if provided\n if (this.pageOptions && this.pageOptions.title && typeof document !== 'undefined') {\n document.title = this.pageOptions.title;\n }\n\n // Emit activation event\n this.emit('activated', {\n page: this.getMetadata()\n });\n\n console.log(`Page ${this.pageName} entered`);\n }\n\n /**\n * Called when leaving this page (before cleanup)\n * Override this method for cleanup logic like removing listeners, clearing timers, etc.\n */\n async onExit() {\n // Save state before exit\n this.savedState = this.captureState();\n this.isActive = false;\n\n // Emit deactivation event\n this.emit('deactivated', {\n page: this.getMetadata()\n });\n console.log(`Page ${this.pageName} exiting`);\n }\n\n /**\n * Get page metadata for display and events\n * @returns {object} Page metadata\n */\n getMetadata() {\n return {\n name: this.pageName,\n displayName: this.displayName || this.pageName,\n icon: this.pageIcon,\n description: this.pageDescription,\n route: this.route,\n isActive: this.isActive\n };\n }\n\n /**\n * Handle default action - fallback from design doc\n */\n async onActionDefault(action) {\n console.log(`Default action '${action}' triggered on page: ${this.pageName}`);\n }\n\n async makeActive() {\n this.getApp().showPage(this);\n }\n\n async onActionNavigate(event, element) {\n event.preventDefault();\n const page = element.dataset.page;\n this.getApp().showPage(page);\n }\n\n /**\n * Capture current page state for preservation\n * @returns {object|null} Captured state\n */\n captureState() {\n if (!this.element) return null;\n\n return {\n scrollTop: this.element.scrollTop,\n formData: this.captureFormData(),\n custom: this.captureCustomState()\n };\n }\n\n /**\n * Restore saved state\n * @param {object} state - State to restore\n */\n restoreState(state) {\n if (!state || !this.element) return;\n\n this.element.scrollTop = state.scrollTop || 0;\n this.restoreFormData(state.formData);\n if (state.custom) {\n this.restoreCustomState(state.custom);\n }\n }\n\n /**\n * Capture form data from page\n * @returns {object} Form data\n */\n captureFormData() {\n const data = {};\n if (!this.element) return data;\n\n this.element.querySelectorAll('input, select, textarea').forEach(field => {\n if (field.name) {\n if (field.type === 'checkbox') {\n data[field.name] = field.checked;\n } else if (field.type === 'radio') {\n if (field.checked) {\n data[field.name] = field.value;\n }\n } else {\n data[field.name] = field.value;\n }\n }\n });\n\n return data;\n }\n\n /**\n * Restore form data to page\n * @param {object} formData - Form data to restore\n */\n restoreFormData(formData) {\n if (!formData || !this.element) return;\n\n Object.entries(formData).forEach(([name, value]) => {\n const field = this.element.querySelector(`[name=\"${name}\"]`);\n if (field) {\n if (field.type === 'checkbox') {\n field.checked = value;\n } else if (field.type === 'radio') {\n const radio = this.element.querySelector(`[name=\"${name}\"][value=\"${value}\"]`);\n if (radio) radio.checked = true;\n } else {\n field.value = value;\n }\n }\n });\n }\n\n /**\n * Capture custom state - override in subclasses\n * @returns {object} Custom state\n */\n captureCustomState() {\n return {};\n }\n\n /**\n * Restore custom state - override in subclasses\n * @param {object} state - Custom state to restore\n */\n restoreCustomState(state) {\n // Override in subclasses\n }\n\n\n\n /**\n * Set page metadata\n * @param {object} meta - Metadata object\n */\n setMeta(meta = {}) {\n if (typeof document === 'undefined') {\n return;\n }\n\n // Set title\n if (meta.title) {\n document.title = meta.title;\n this.pageOptions.title = meta.title;\n }\n\n // Set description\n if (meta.description) {\n let descMeta = document.querySelector('meta[name=\"description\"]');\n if (!descMeta) {\n descMeta = document.createElement('meta');\n descMeta.name = 'description';\n document.head.appendChild(descMeta);\n }\n descMeta.content = meta.description;\n this.pageOptions.description = meta.description;\n }\n\n // Set other meta tags\n Object.entries(meta).forEach(([key, value]) => {\n if (key !== 'title' && key !== 'description') {\n let metaEl = document.querySelector(`meta[name=\"${key}\"]`);\n if (!metaEl) {\n metaEl = document.createElement('meta');\n metaEl.name = key;\n document.head.appendChild(metaEl);\n }\n metaEl.content = value;\n }\n });\n }\n\n\n /**\n * Show error message with page context\n * @param {string} message - Error message\n */\n showError(message) {\n super.showError(message);\n\n // Page-specific error display can be implemented here\n if (this.element) {\n // Example: Add error to page\n const errorDiv = document.createElement('div');\n errorDiv.className = 'alert alert-danger alert-dismissible fade show';\n errorDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(errorDiv, this.element.firstChild);\n\n // Auto-remove after 5 seconds\n setTimeout(() => {\n if (errorDiv.parentNode) {\n errorDiv.parentNode.removeChild(errorDiv);\n }\n }, 5000);\n }\n }\n\n /**\n * Show success message with page context\n * @param {string} message - Success message\n */\n showSuccess(message) {\n super.showSuccess(message);\n\n // Page-specific success display\n if (this.element) {\n const successDiv = document.createElement('div');\n successDiv.className = 'alert alert-success alert-dismissible fade show';\n successDiv.innerHTML = `\n ${message}\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" aria-label=\"Close\"></button>\n `;\n\n // Insert at top of page\n this.element.insertBefore(successDiv, this.element.firstChild);\n\n // Auto-remove after 3 seconds\n setTimeout(() => {\n if (successDiv.parentNode) {\n successDiv.parentNode.removeChild(successDiv);\n }\n }, 3000);\n }\n }\n\n /**\n * Page-specific before render hook\n */\n async onBeforeRender() {\n await super.onBeforeRender();\n\n // Set page metadata before rendering\n this.setMeta({\n title: this.pageOptions.title,\n description: this.pageOptions.description\n });\n }\n\n /**\n * Page-specific after mount hook\n */\n async onAfterMount() {\n await super.onAfterMount();\n\n // Add page-specific class to body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Page-specific before destroy hook\n */\n async onBeforeDestroy() {\n await super.onBeforeDestroy();\n\n // Remove page-specific class from body\n if (typeof document !== 'undefined' && this.pageName) {\n document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\\s+/g, '-')}`);\n }\n }\n\n /**\n * Navigate to another page using the app's router\n * @param {string} route - Route to navigate to\n * @param {object} params - Route parameters\n * @param {object} options - Navigation options\n */\n navigate(route, params = {}, options = {}) {\n // Delegate to app's router\n if (this.app && this.app.router) {\n return this.app.router.navigate(route, options);\n }\n\n // Fallback to MOJO global router\n if (typeof window !== 'undefined' && window.MOJO?.router) {\n return window.MOJO.router.navigate(route, options);\n }\n\n console.error('No router available for navigation');\n }\n\n getRoute() {\n if (this.route) {\n let route = this.route;\n if (typeof route === 'string' && route.startsWith('/')) {\n route = route.substring(1);\n }\n return route;\n }\n return this.pageName;\n }\n\n syncUrl(force = true) {\n this.updateBrowserUrl(this.query, false, false);\n }\n\n updateBrowserUrl(query = null, replace = false, trigger = false) {\n this.getApp();\n // we need to do this to normalize the URL\n // const targetPath = this.app.buildPagePath(this, this.params, query);\n // const { pageName, queryParams } = this.app.router.parseInput(targetPath);\n this.app.router.updateBrowserUrl(this.getRoute(), query, replace, trigger);\n }\n\n /**\n * Static method to define a page class with metadata\n * @param {object} definition - Page class definition\n * @returns {class} Page class\n */\n static define(definition) {\n class DefinedPage extends Page {\n constructor(options = {}) {\n super({\n ...definition,\n ...options\n });\n }\n }\n\n // Copy static properties\n DefinedPage.template = definition.template;\n DefinedPage.pageName = definition.pageName;\n DefinedPage.route = definition.route;\n\n return DefinedPage;\n }\n}\n\nexport default Page;\n"],"names":[],"mappings":"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"}
|