web-mojo 2.2.14 → 2.2.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +27 -19
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.es.js +1 -1
  7. package/dist/charts.cjs.js +1 -1
  8. package/dist/charts.es.js +3 -3
  9. package/dist/chunks/ChatView-BqViL7e-.js +2 -0
  10. package/dist/chunks/ChatView-BqViL7e-.js.map +1 -0
  11. package/dist/chunks/{ChatView-eFzjsHBL.js → ChatView-DMC-gH-t.js} +51 -9
  12. package/dist/chunks/ChatView-DMC-gH-t.js.map +1 -0
  13. package/dist/chunks/{Collection-BlP54kxB.js → Collection-BQWznmwY.js} +2 -2
  14. package/dist/chunks/{Collection-BlP54kxB.js.map → Collection-BQWznmwY.js.map} +1 -1
  15. package/dist/chunks/{Collection-CTkDG1NZ.js → Collection-sSP1JF8d.js} +26 -2
  16. package/dist/chunks/{Collection-CTkDG1NZ.js.map → Collection-sSP1JF8d.js.map} +1 -1
  17. package/dist/chunks/{ContextMenu-Capwv7d-.js → ContextMenu-C9qnhdFg.js} +2 -2
  18. package/dist/chunks/{ContextMenu-Capwv7d-.js.map → ContextMenu-C9qnhdFg.js.map} +1 -1
  19. package/dist/chunks/{ContextMenu-BH5SaDXX.js → ContextMenu-NNHmt1iq.js} +2 -2
  20. package/dist/chunks/{ContextMenu-BH5SaDXX.js.map → ContextMenu-NNHmt1iq.js.map} +1 -1
  21. package/dist/chunks/{Dialog-RzLLLfJD.js → Dialog-DgYEebtR.js} +3 -3
  22. package/dist/chunks/{Dialog-RzLLLfJD.js.map → Dialog-DgYEebtR.js.map} +1 -1
  23. package/dist/chunks/{Dialog--hl_Uh6X.js → Dialog-VyLukswR.js} +2 -2
  24. package/dist/chunks/{Dialog--hl_Uh6X.js.map → Dialog-VyLukswR.js.map} +1 -1
  25. package/dist/chunks/{FormView-C1emfj3B.js → FormView-DCI29KlM.js} +3 -3
  26. package/dist/chunks/FormView-DCI29KlM.js.map +1 -0
  27. package/dist/chunks/{FormView--WuITh01.js → FormView-GO8yahxE.js} +39 -5
  28. package/dist/chunks/FormView-GO8yahxE.js.map +1 -0
  29. package/dist/chunks/{ListView-CNkYumcc.js → ListView-0fx1T87y.js} +2 -2
  30. package/dist/chunks/{ListView-CNkYumcc.js.map → ListView-0fx1T87y.js.map} +1 -1
  31. package/dist/chunks/{ListView-O9AO02Rf.js → ListView-DHQyUB3V.js} +2 -2
  32. package/dist/chunks/{ListView-O9AO02Rf.js.map → ListView-DHQyUB3V.js.map} +1 -1
  33. package/dist/chunks/{MetricsMiniChartWidget-DoxqoF1X.js → MetricsMiniChartWidget-JLmDm3sm.js} +2 -2
  34. package/dist/chunks/{MetricsMiniChartWidget-DoxqoF1X.js.map → MetricsMiniChartWidget-JLmDm3sm.js.map} +1 -1
  35. package/dist/chunks/{MetricsMiniChartWidget-DyVs4Wt0.js → MetricsMiniChartWidget-XTU45k_e.js} +2 -2
  36. package/dist/chunks/{MetricsMiniChartWidget-DyVs4Wt0.js.map → MetricsMiniChartWidget-XTU45k_e.js.map} +1 -1
  37. package/dist/chunks/{PDFViewer-CHX2NLkG.js → PDFViewer-DMpN-d6N.js} +2 -2
  38. package/dist/chunks/{PDFViewer-CHX2NLkG.js.map → PDFViewer-DMpN-d6N.js.map} +1 -1
  39. package/dist/chunks/{PDFViewer-BxFcG82d.js → PDFViewer-DbPamhVj.js} +2 -2
  40. package/dist/chunks/{PDFViewer-BxFcG82d.js.map → PDFViewer-DbPamhVj.js.map} +1 -1
  41. package/dist/chunks/{TokenManager-CBXqj6Iw.js → TokenManager-A0zSdQ6i.js} +4 -4
  42. package/dist/chunks/{TokenManager-CBXqj6Iw.js.map → TokenManager-A0zSdQ6i.js.map} +1 -1
  43. package/dist/chunks/{TokenManager-CCfcK4aA.js → TokenManager-DH4-kElJ.js} +2 -2
  44. package/dist/chunks/{TokenManager-CCfcK4aA.js.map → TokenManager-DH4-kElJ.js.map} +1 -1
  45. package/dist/chunks/{version-DnlcM3tJ.js → version-BpfLBsbA.js} +2 -2
  46. package/dist/chunks/{version-DnlcM3tJ.js.map → version-BpfLBsbA.js.map} +1 -1
  47. package/dist/chunks/{version-DCTYSNWj.js → version-iQsUQBiz.js} +4 -4
  48. package/dist/chunks/{version-DCTYSNWj.js.map → version-iQsUQBiz.js.map} +1 -1
  49. package/dist/docit.cjs.js +1 -1
  50. package/dist/docit.es.js +5 -5
  51. package/dist/index.cjs.js +1 -1
  52. package/dist/index.es.js +11 -11
  53. package/dist/lightbox.cjs.js +1 -1
  54. package/dist/lightbox.es.js +4 -4
  55. package/dist/map.cjs.js +1 -1
  56. package/dist/map.es.js +1 -1
  57. package/dist/timeline.cjs.js +1 -1
  58. package/dist/timeline.es.js +2 -2
  59. package/package.json +1 -1
  60. package/dist/chunks/ChatView-DGulpthL.js +0 -2
  61. package/dist/chunks/ChatView-DGulpthL.js.map +0 -1
  62. package/dist/chunks/ChatView-eFzjsHBL.js.map +0 -1
  63. package/dist/chunks/FormView--WuITh01.js.map +0 -1
  64. package/dist/chunks/FormView-C1emfj3B.js.map +0 -1
@@ -1,2 +1,2 @@
1
- "use strict";const e=require("./Rest-P-KCJpjB.js");class Router{constructor(e={}){this.defaultRoute=e.defaultRoute||"home",this.routes=[],this.currentRoute=null,this.eventEmitter=e.eventEmitter||null,this.boundHandlePopState=this.handlePopState.bind(this)}start(){window.addEventListener("popstate",this.boundHandlePopState),this.handleCurrentLocation()}stop(){window.removeEventListener("popstate",this.boundHandlePopState)}addRoute(e,t){this.routes.push({pattern:this.normalizePattern(e),regex:this.patternToRegex(e),pageName:t,paramNames:this.extractParamNames(e)})}async navigate(e,t={}){const{replace:s=!1,state:i=null,trigger:o=!0}=t,{pageName:n,queryParams:r}=this.parseInput(e);o&&await this.handleRouteChange(n,r)}back(){window.history.back()}forward(){window.history.forward()}getCurrentRoute(){return this.currentRoute}getCurrentPath(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();return this.buildPublicUrl(e,t)}handlePopState(e){this.allowPopState?this.handleCurrentLocation():console.warn("PopStateEvent is not allowed")}async handleCurrentLocation(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();await this.handleRouteChange(e,t)}async handleRouteChange(e,t){const s="/"+e,i=this.matchRoute(s),o=this.buildPublicUrl(e,t);return i?(this.currentRoute=i,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:o,pageName:i.pageName,params:i.params,query:t,route:i}),i):(this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:o}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const i={};return t.paramNames.forEach((e,t)=>{i[e]=s[t+1]}),{...t,params:i,path:e}}}return null}parseInput(e){let t=this.defaultRoute,s={};if(!e)return{pageName:t,queryParams:s};try{if(e.includes("?")){const[i,o]=e.split("?",2),n=new URLSearchParams(o);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[e,t]of n)"page"!==e&&(s[e]=t)}else{t=i.startsWith("/")?i.substring(1)||this.defaultRoute:i||this.defaultRoute;for(const[e,t]of n)s[e]=t}}else t=e.startsWith("/")?e.substring(1)||this.defaultRoute:e}catch(i){console.warn("Failed to parse input:",e,i),t=this.defaultRoute,s={}}return{pageName:t,queryParams:s}}parseCurrentUrl(){const e=new URLSearchParams(window.location.search),t=e.get("page")||this.defaultRoute,s={};for(const[i,o]of e)"page"!==i&&(s[i]=o);return{pageName:t,queryParams:s}}buildPublicUrl(e,t={}){const s=new URLSearchParams;return s.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&s.set(e,String(t))}),"?"+s.toString()}updateBrowserUrl(e,t,s,i){const o=new URL(window.location.origin+window.location.pathname);o.searchParams.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&o.searchParams.set(e,String(t))});const n=o.toString();s?window.history.replaceState(i,"",n):window.history.pushState(i,"",n)}patternToRegex(e){let t=e.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&").replace(/\/:([^/?]+)\?/g,"(?:/([^/]+))?").replace(/:([^/]+)/g,"([^/]+)");return new RegExp(`^${t}$`)}extractParamNames(e){return(e.match(/:([^/?]+)\??/g)||[]).map(e=>e.replace(/[:?]/g,""))}normalizePattern(e){return e.startsWith("/")?e:`/${e}`}updateUrl(e={},t={}){const{replace:s=!1}=t,{pageName:i}=this.parseCurrentUrl();this.updateBrowserUrl(i,e,s)}buildUrl(e,t={}){return this.buildPublicUrl(e,t)}doRoutesMatch(e,t){if(!e||!t)return!1;const{pageName:s}=this.parseInput(e),{pageName:i}=this.parseInput(t);return s===i}}class EventBus{constructor(){this.listeners={},this.onceListeners={},this.maxListeners=100,this.debugMode=!1,this.eventStats={}}on(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.on(e,t)),this):(this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].length>=this.maxListeners&&console.warn(`Max listeners (${this.maxListeners}) exceeded for event: ${e}`),this.listeners[e].push(t),this)}once(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.once(e,t)),this):(this.onceListeners[e]||(this.onceListeners[e]=[]),this.onceListeners[e].push(t),this)}off(e,t){if(Array.isArray(e))return e.forEach(e=>this.off(e,t)),this;if(!t)return delete this.listeners[e],delete this.onceListeners[e],this;if(this.listeners[e]){const s=this.listeners[e].indexOf(t);-1!==s&&(this.listeners[e].splice(s,1),0===this.listeners[e].length&&delete this.listeners[e])}if(this.onceListeners[e]){const s=this.onceListeners[e].indexOf(t);-1!==s&&(this.onceListeners[e].splice(s,1),0===this.onceListeners[e].length&&delete this.onceListeners[e])}return this}emit(e,t){this.updateEventStats(e),this.debugMode;const s=[];return this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]),this.debugMode&&s.length>0&&s.length,s.forEach(s=>{try{s(t,e)&&(e.stopPropagation&&e.stopPropagation(),e.preventDefault&&e.preventDefault())}catch(i){console.error(`Error in event listener for '${e}':`,i),this.emitError(i,e,s)}}),this}async emitAsync(e,t){const s=[];this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]);const i=s.map(s=>new Promise(i=>{try{i(s(t,e))}catch(o){console.error(`Error in async event listener for '${e}':`,o),this.emitError(o,e,s),i()}}));return await Promise.all(i),this}removeAllListeners(){return this.listeners={},this.onceListeners={},this}listenerCount(e){return(this.listeners[e]?this.listeners[e].length:0)+(this.onceListeners[e]?this.onceListeners[e].length:0)}eventNames(){const e=Object.keys(this.listeners),t=Object.keys(this.onceListeners);return[.../* @__PURE__ */new Set([...e,...t])]}setMaxListeners(e){if("number"!=typeof e||e<0)throw new Error("Max listeners must be a non-negative number");return this.maxListeners=e,this}namespace(e){const t=t=>`${e}:${t}`;return{on:(e,s)=>this.on(t(e),s),once:(e,s)=>this.once(t(e),s),off:(e,s)=>this.off(t(e),s),emit:(e,s)=>this.emit(t(e),s),emitAsync:(e,s)=>this.emitAsync(t(e),s)}}use(e){if("function"!=typeof e)throw new Error("Middleware must be a function");const t=this.emit;return this.emit=(s,i)=>{try{const o=e(s,i);if(!1===o)return this;const n=void 0!==o?o:i;return t.call(this,s,n)}catch(o){return console.error("Error in event middleware:",o),t.call(this,s,i)}},this}emitError(e,t,s){"error"!==t&&setTimeout(()=>{this.emit("error",{error:e,originalEvent:t,callback:s.toString()})},0)}waitFor(e,t=null){return new Promise((s,i)=>{let o=null;const n=e=>{o&&clearTimeout(o),s(e)};this.once(e,n),t&&(o=setTimeout(()=>{this.off(e,n),i(new Error(`Timeout waiting for event: ${e}`))},t))})}debug(e=!0){return this.debugMode=e,this}getStats(){const e=this.eventNames(),t={totalEvents:e.length,totalListeners:0,events:{},emissions:{...this.eventStats}};return e.forEach(e=>{const s=this.listenerCount(e);t.events[e]=s,t.totalListeners+=s}),t}updateEventStats(e){this.eventStats[e]||(this.eventStats[e]={count:0,firstEmission:Date.now(),lastEmission:null}),this.eventStats[e].count++,this.eventStats[e].lastEmission=Date.now()}getEventStats(e){const t=this.eventStats[e];return t?{...t,listenerCount:this.listenerCount(e),avgEmissionsPerMinute:this.calculateEmissionRate(t)}:null}calculateEmissionRate(e){if(!e.firstEmission||!e.lastEmission)return 0;const t=e.lastEmission-e.firstEmission;if(0===t)return 0;const s=t/6e4;return Math.round(e.count/s*100)/100}resetStats(){return this.eventStats={},this}getTopEvents(e=10){return Object.entries(this.eventStats).map(([e,t])=>({event:e,count:t.count,rate:this.calculateEmissionRate(t),listeners:this.listenerCount(e)})).sort((e,t)=>t.count-e.count).slice(0,e)}debugInfo(){this.debugMode,this.maxListeners;const e=this.getStats();return e.totalEvents,e.totalListeners,Object.keys(this.eventStats).length>0&&this.getTopEvents(5),this}}class WebApp{constructor(t={}){this.config=t,this.initPluginRegistry(),this.name=t.name||"MOJO App",this.version=t.version||"1.0.0",this.debug=t.debug||!1,this.container=t.container||"#app",this.layoutType=t.layout||"portal",this.layoutConfig=t.layoutConfig||{},t.sidebar&&(this.layoutConfig.sidebarConfig=t.sidebar),t.topbar&&(this.layoutConfig.topbarConfig=t.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=t.pageContainer||"#page-container",this.basePath=t.basePath||"",this.routerMode=t.routerMode||t.router?.mode||"param",this.basePath=t.basePath||t.router?.base||"",this.defaultRoute=t.defaultRoute||"home",this.session=t.session||{},this.router=null,this.navigation=t.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new EventBus,this.rest=e.rest,t.api&&this.rest.configure(t.api),this.router=new Router({mode:"param"===this.routerMode?"params":this.routerMode,basePath:this.basePath,defaultRoute:this.defaultRoute,eventEmitter:this.events}),this.events.on("route:changed",async e=>{const{pageName:t,params:s,query:i}=e;await this.showPage(t,i,s,{fromRouter:!0})}),"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.router=this.router),this.setupFocusTracking(),this.pageCache=/* @__PURE__ */new Map,this.pageClasses=/* @__PURE__ */new Map,this.componentClasses=/* @__PURE__ */new Map,this.modelClasses=/* @__PURE__ */new Map,this.currentPage=null,this.isStarted=!1,window.matchUUID?window[window.matchUUID]=this:window.MOJO?window.MOJO.app=this:window.__app__=this}async start(){if(this.isStarted)console.warn("WebApp already started");else try{this.setupPageContainer(),this.validateDefaultRoute(),await this.setupRouter(),this.isStarted=!0,this.router.allowPopState=!1,this.events.emit("app:ready",{app:this})}catch(e){throw console.error(`Failed to start ${this.name}:`,e),this.showError("Failed to start application"),e}}async setupRouter(){this.router?(this.events.on("route:notfound",async e=>{console.warn(`Route not found: ${e.path}`),this._show404(e.path)}),this.router.start(),this.routerMode):console.error("Router not initialized")}setupPageContainer(){const e="string"==typeof this.container?document.querySelector(this.container):this.container;e&&!e.querySelector("#page-container")&&(e.innerHTML='<div id="page-container"></div>'),this.pageContainer="#page-container"}registerPage(e,t,s={}){if("string"!=typeof e||!e)return console.error("registerPage: pageName must be a non-empty string"),this;if("function"!=typeof t)return console.error("registerPage: PageClass must be a constructor function"),this;if(s.containerId||(s.containerId=this.pageContainer),this.pageClasses.set(e,{PageClass:t,constructorOptions:s}),this.router){let t=s.route||`/${e}`;t.startsWith("/")||(t=`/${t}`),s.route=t,this.router.addRoute(t,e)}return this}getPage(e){return this.pageCache.get(e)}getPagePermissions(e){if(this.pageCache.has(e))return this.pageCache.get(e).permissions;const t=this.pageClasses.get(e);if(!t)return null;const{PageClass:s,constructorOptions:i}=t;return i?i.permissions:null}getOrCreatePage(e){if(this.pageCache.has(e))return this.pageCache.get(e);const t=this.pageClasses.get(e);if(!t)return console.error(`Page not registered: ${e}`),null;const{PageClass:s,constructorOptions:i}=t;try{const t=new s({pageName:e,...i,app:this});return i.route&&(t.route=i.route),this.pageCache.set(e,t),t.route,t}catch(o){return console.error(`Failed to create page ${e}:`,o),null}}async showPage(e,t={},s={},i={}){const{fromRouter:o=!1,replace:n=!1,force:r=!1}=i;try{let i,n;"string"==typeof e?(n=e,i=this.getOrCreatePage(e)):e&&"object"==typeof e&&(i=e,n=e.pageName),this.events.emit("page:showing",{page:i,pageName:i.pageName,params:s,query:t,fromRouter:o});const r=this.currentPage;if(!i)return void this._show404(n,s,t,o);if(!i.canEnter())return void this._showDeniedPage(i,s,t,o);r&&r!==i&&await this._exitOldPage(r),await i.onParams(s,t),r!==i&&await i.onEnter(),i.syncUrl(),this.events.emit("page:show",{page:i,pageName:i.pageName,params:s,query:t,fromRouter:o}),await i.render(),this.currentPage=i,i.pageName}catch(a){console.error("Error in showPage:",a),this.showError(`Failed to load page: ${a.message}`),"error"!==e&&await this.showPage("error",{},{error:a,originalPage:e},{fromRouter:o})}}async _show404(e,t,s,i){const o=this.getOrCreatePage("404");o&&(o.setInfo&&o.setInfo(e),await this._exitOldPage(this.currentPage),await o.render(),this.currentPage=o,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:i}))}async _showDeniedPage(e,t,s,i){const o=this.getOrCreatePage("denied");o.setDeniedPage&&o.setDeniedPage(e),await this._exitOldPage(this.currentPage),await o.render(),this.currentPage=o,this.events.emit("page:denied",{page:e,pageName:e.pageName,params:t,query:s,fromRouter:i})}async _exitOldPage(e){if(e)try{await e.onExit(),await e.unmount(),this.events.emit("page:hide",{page:e})}catch(t){console.error(`Error exiting page ${e.pageName}:`,t)}}async navigate(e,t={},s={}){if(!this.router)return void console.error("Router not initialized");let i=e;if(Object.keys(t).length>0){const s=new URLSearchParams(t).toString();i+=(e.includes("?")?"&":"?")+s}return await this.router.navigate(i,s)}async navigateToDefault(e={}){return await this.showPage(this.defaultRoute,{},{},e)}back(){this.router?this.router.back():console.warn("Router not initialized")}forward(){this.router?this.router.forward():console.warn("Router not initialized")}getCurrentPage(){return this.currentPage}getPageContainer(){return this.layout&&this.layout.getPageContainer?this.layout.getPageContainer():"string"==typeof this.pageContainer?document.querySelector(this.pageContainer):this.pageContainer}async showError(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Error",{size:"md",class:"text-danger"})}catch(s){this.events.emit("notification",{message:e,type:"error"}),"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showError fallback:",s),"undefined"!=typeof window&&alert(`Error: ${e}`)}}async showSuccess(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Success",{size:"md",class:"text-success"})}catch(s){this.events.emit("notification",{message:e,type:"success"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showSuccess fallback:",s),"undefined"!=typeof window&&alert(`Success: ${e}`)}}async showInfo(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Information",{size:"md",class:"text-info"})}catch(s){this.events.emit("notification",{message:e,type:"info"}),"undefined"!=typeof window&&window,"undefined"!=typeof window&&alert(`Info: ${e}`)}}async showWarning(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Warning",{size:"md",class:"text-warning"})}catch(s){this.events.emit("notification",{message:e,type:"warning"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showWarning fallback:",s),"undefined"!=typeof window&&alert(`Warning: ${e}`)}}showNotification(e,t="info"){this.events.emit("notification",{message:e,type:t})}async showLoading(e={}){"string"==typeof e&&(e={message:e});try{(await Promise.resolve().then(()=>t)).default.showBusy(e)}catch(s){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showLoading fallback:",s,e),this.events.emit("notification",{message:e.message||"Loading...",type:"info"})}}async hideLoading(){try{(await Promise.resolve().then(()=>t)).default.hideBusy()}catch(e){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelForm(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showModelForm(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showForm(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showForm(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showForm failed:",s),s}}async showDialog(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showDialog(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",s),s}}async confirm(e,s="Confirm",i={}){const o=(await Promise.resolve().then(()=>t)).default;return await o.confirm(e,s,i)}setupFocusTracking(){if("undefined"==typeof window)return;this.isFocused=!document.hidden;const e=()=>{const e=this.isFocused;this.isFocused=!document.hidden,e!==this.isFocused&&(this.isFocused?this.events.emit("browser:focus"):this.events.emit("browser:blur"))},t=()=>{this.isFocused||(this.isFocused=!0,this.events.emit("browser:focus"))},s=()=>{this.isFocused&&(this.isFocused=!1,this.events.emit("browser:blur"))};document.addEventListener("visibilitychange",e),window.addEventListener("focus",t),window.addEventListener("blur",s),this._focusHandlers={visibilitychange:e,focus:t,blur:s}}setupErrorHandling(){window.addEventListener("error",e=>{console.error("Global error:",e.error),this.debug&&this.showError(`Error: ${e.error?.message||"Unknown error"}`)}),window.addEventListener("unhandledrejection",e=>{console.error("Unhandled promise rejection:",e.reason),this.debug&&this.showError(`Promise rejected: ${e.reason?.message||"Unknown error"}`)})}escapeHtml(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}getState(e){return e?this.state[e]:this.state}setState(e){const t={...this.state};Object.assign(this.state,e),this.events.emit("state:changed",{oldState:t,newState:this.state,updates:e})}registerComponent(e,t){this.componentClasses.set(e,t)}getComponent(e){return this.componentClasses.get(e)}registerModel(e,t){this.modelClasses.set(e,t)}getModel(e){return this.modelClasses.get(e)}setupRest(){this.rest=e.rest,e.rest.configure(this.api)}async destroy(){this.router&&this.router.stop(),this._focusHandlers&&"undefined"!=typeof window&&(document.removeEventListener("visibilitychange",this._focusHandlers.visibilitychange),window.removeEventListener("focus",this._focusHandlers.focus),window.removeEventListener("blur",this._focusHandlers.blur));const e=Array.from(this.pageCache.values());if(await Promise.allSettled(e.map(async e=>{try{e.destroy&&await e.destroy()}catch(t){console.error("Error destroying page:",t)}})),this.layout&&this.layout.destroy)try{await this.layout.destroy()}catch(t){console.error("Error destroying layout:",t)}this.pageCache.clear(),this.pageClasses.clear(),this.componentClasses.clear(),this.modelClasses.clear(),"undefined"!=typeof window&&window.MOJO&&delete window.MOJO.router,this.isStarted=!1,this.name}buildPagePath(e,t,s){let i=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(e=>{"string"!=typeof t[e]&&"number"!=typeof t[e]||(i=i.replace(`:${e}`,t[e]))}),s&&Object.keys(s).length>0){const e=new URLSearchParams(s).toString();i+=(i.includes("?")?"&":"?")+e}return i}validateDefaultRoute(){this.pageClasses.has(this.defaultRoute)?this.defaultRoute:(console.warn(`⚠️ Default route '${this.defaultRoute}' is not registered!`),console.warn(` Please register a page: app.registerPage('${this.defaultRoute}', YourPageClass);`),console.warn(" Or change default route: new WebApp({ defaultRoute: 'your-page' });"))}findFallbackPage(){const e=["404","error","denied"];for(const[t]of this.pageClasses.entries())if(!e.includes(t))return t;return null}static create(e={}){return new WebApp(e)}initPluginRegistry(){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.app=this)}static registerPlugin(e,t){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.plugins[e]=t)}}class Dialog extends e.View{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:this._baseZIndex}static _busyIndicator=null;static _busyCounter=0;static _busyTimeout=null;static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=Dialog._openDialogs;if(0===e.length||0===t.length)return;const s=[...t].sort((e,t)=>(e._dialogZIndex||0)-(t._dialogZIndex||0));e.forEach((e,t)=>{if(t<s.length){const i=s[t]._dialogZIndex-5;e.style.zIndex=i;const o=document.querySelector(".table-fullscreen")||document.body;e.parentNode!==o&&o.appendChild(e)}})}static updateAllBackdropStacking(){Dialog.fixAllBackdropStacking()}static showBusy(e={}){const{timeout:t=3e4,message:s="Loading..."}=e;if(this._busyCounter++,1===this._busyCounter){if(this._busyTimeout&&clearTimeout(this._busyTimeout),!this._busyIndicator){const e=this.getFullscreenAwareZIndex().modal+1e3;this._busyIndicator=document.createElement("div"),this._busyIndicator.className="mojo-busy-indicator",this._busyIndicator.innerHTML=`\n <div class="mojo-busy-spinner">\n <div class="spinner-border text-light" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p class="mojo-busy-message mt-3 text-light">${s}</p>\n </div>\n <style>\n .mojo-busy-indicator {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background-color: rgba(0, 0, 0, 0.5); z-index: ${e};\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.15s linear;\n }\n .mojo-busy-indicator.show { opacity: 1; }\n .mojo-busy-spinner .spinner-border { width: 3rem; height: 3rem; }\n </style>\n `,document.body.appendChild(this._busyIndicator)}const e=this._busyIndicator.querySelector(".mojo-busy-message");e&&(e.textContent=s),setTimeout(()=>this._busyIndicator.classList.add("show"),10),this._busyTimeout=setTimeout(()=>{console.error("Busy indicator timed out."),this.hideBusy(!0),this.alert({title:"Operation Timed Out",message:"The operation took too long. Please check your connection and try again.",type:"danger"})},t)}}static hideBusy(e=!1){e?this._busyCounter=0:this._busyCounter--,this._busyCounter<=0&&(this._busyCounter=0,this._busyTimeout&&(clearTimeout(this._busyTimeout),this._busyTimeout=null),this._busyIndicator&&(this._busyIndicator.classList.remove("show"),setTimeout(()=>{this._busyIndicator&&0===this._busyCounter&&(this._busyIndicator.remove(),this._busyIndicator=null)},150)))}constructor(e={}){const t=e.id||`modal-${Date.now()}`;super({...e,id:t,tagName:"div",className:`modal ${!1!==e.fade?"fade":""} ${e.className||""}`,attributes:{tabindex:"-1","aria-hidden":"true","aria-labelledby":e.labelledBy||`${t}-label`,"aria-describedby":e.describedBy||null,...e.attributes}}),this.modalId=t,this.title=e.title||"",this.titleId=`${this.modalId}-label`,this.size=e.size||"",this.centered=void 0!==e.centered&&e.centered,this.scrollable=void 0!==e.scrollable&&e.scrollable,this.autoSize=e.autoSize||"auto"===e.size,this.backdrop=void 0===e.backdrop||e.backdrop,this.keyboard=void 0===e.keyboard||e.keyboard,this.focus=void 0===e.focus||e.focus,this.header=void 0===e.header||e.header,this.headerContent=e.headerContent||null,this.closeButton=void 0===e.closeButton||e.closeButton,this.contextMenu=e.contextMenu||null,this.body=e.body||e.content||"",this.bodyView=null,this.bodyClass=e.bodyClass||"",this.noBodyPadding=e.noBodyPadding||!1,this.minWidth=e.minWidth||300,this.minHeight=e.minHeight||200,e.maxHeight&&(this.maxHeight=e.maxHeight),this.maxWidthPercent=e.maxWidthPercent||.9,this.maxHeightPercent=e.maxHeightPercent||.8,this._processBodyContent(this.body),this.footer=e.footer||null,this.footerView=null,this.footerClass=e.footerClass||"",this._processFooterContent(this.footer),this.buttons=e.buttons||null,this.onShow=e.onShow||null,this.onShown=e.onShown||null,this.onHide=e.onHide||null,this.onHidden=e.onHidden||null,this.onHidePrevented=e.onHidePrevented||null,this.autoShow=void 0!==e.autoShow&&e.autoShow,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(t){if(t&&t.render)this.bodyView=t,this.body="",this.addChild(this.bodyView);else if("function"==typeof t)try{const s=t();s instanceof e.View?(this.bodyView=s,this.body="",this.addChild(this.bodyView)):s instanceof Promise?(this.bodyPromise=s,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=s}catch(s){console.error("Error processing body function:",s),this.body=t}else this.body=t}_processFooterContent(t){if(t instanceof e.View)this.footerView=t,this.footer=null,this.addChild(this.footerView);else if("function"==typeof t)try{const s=t();s instanceof e.View?(this.footerView=s,this.footer=null,this.addChild(this.footerView)):s instanceof Promise?(this.footerPromise=s,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=s}catch(s){console.error("Error processing footer function:",s),this.footer=t}else this.footer=t}async getTemplate(){const e=["modal-dialog"];return this.size&&"auto"!==this.size&&(this.size.startsWith("fullscreen")?e.push(`modal-${this.size}`):["sm","lg","xl","xxl"].includes(this.size)&&(e.push(`modal-${this.size}`),["lg","xl","xxl"].includes(this.size)&&e.push("modal-fullscreen-sm-down"))),this.centered&&e.push("modal-dialog-centered"),this.scrollable&&(this.maxHeight?e.push("overflow-hidden"):e.push("modal-dialog-scrollable")),`\n <div class="${e.join(" ")}">\n <div class="modal-content">\n ${await this.buildHeader()}\n ${await this.buildBody()}\n ${await this.buildFooter()}\n </div>\n </div>\n `}async buildHeader(){if(!this.header)return"";if(this.headerContent)return`<div class="modal-header">${this.headerContent}</div>`;let e="";return this.contextMenu&&this.contextMenu.items&&this.contextMenu.items.length>0?e=await this.buildContextMenu():this.closeButton&&(e='<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>'),`\n <div class="modal-header">\n ${this.title?`<h5 class="modal-title" id="${this.titleId}">${this.title}</h5>`:""}\n ${e}\n </div>\n `}async buildContextMenu(){const e=await this.filterContextMenuItems();if(0===e.length)return this.closeButton?'<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>':"";const t=this.contextMenu.icon||"bi-three-dots-vertical";return`\n <div class="dropdown">\n <button class="${this.contextMenu.buttonClass||"btn btn-link p-1 mojo-modal-context-menu-btn"}" type="button" data-bs-toggle="dropdown" aria-expanded="false">\n <i class="${t}"></i>\n </button>\n <ul class="dropdown-menu dropdown-menu-end">\n ${e.map(e=>{if("divider"===e.type)return'<li><hr class="dropdown-divider"></li>';const t=e.icon?`<i class="${e.icon} me-2"></i>`:"",s=e.label||"";if(e.href)return`<li><a class="dropdown-item" href="${e.href}"${e.target?` target="${e.target}"`:""}>${t}${s}</a></li>`;if(e.action){const i=Object.keys(e).filter(e=>e.startsWith("data-")).map(t=>`${t}="${e[t]}"`).join(" ");return`<li><a class="dropdown-item" data-action="${e.action}" ${i}>${t}${s}</a></li>`}return""}).join("")}\n </ul>\n </div>\n `}async filterContextMenuItems(){if(!this.contextMenu||!this.contextMenu.items)return[];const e=[];for(const i of this.contextMenu.items)if("divider"!==i.type){if(i.permissions)try{const e=this.getApp?.();let s=null;if(e&&(s=e.activeUser||e.getState?.("activeUser")),!s&&"undefined"!=typeof window&&window.getApp)try{const e=window.getApp();s=e?.activeUser}catch(t){}if(!s||!s.hasPermission)continue;if(!s.hasPermission(i.permissions))continue}catch(s){console.warn("Error checking permissions for context menu item:",s);continue}e.push(i)}else e.push(i);return e}async buildBody(){return this.bodyView?(this.bodyView.replaceById=!0,`<div class="${this.noBodyPadding?`modal-body p-0 ${this.bodyClass}`:`modal-body ${this.bodyClass}`}" data-view-container="body">\n \x3c!-- View will be mounted here --\x3e\n <div id="${this.bodyView.id}"></div>\n </div>`):this.body||""===this.body?`\n <div class="${this.noBodyPadding?`modal-body p-0 ${this.bodyClass}`:`modal-body ${this.bodyClass}`}">\n ${this.body}\n </div>\n `:""}async buildFooter(){if(this.footerView)return`<div class="modal-footer ${this.footerClass}" data-view-container="footer"></div>`;if(null!==this.footer&&"string"==typeof this.footer)return`<div class="modal-footer ${this.footerClass}">${this.footer}</div>`;if(this.buttons&&this.buttons.length>0){const e=this.buttons.map(e=>{const t=e.dismiss?'data-bs-dismiss="modal"':"",s=e.action?`data-action="${e.action}"`:"",i=e.id?`id="${e.id}"`:"",o=e.disabled?"disabled":"";return`\n <button type="${e.type||"button"}"\n class="btn ${e.class||"btn-secondary"}"\n ${i}\n ${t}\n ${s}\n ${o}>\n ${e.icon?`<i class="bi ${e.icon} me-1"></i>`:""}\n ${e.text||"Button"}\n </button>\n `}).join("");return`<div class="modal-footer ${this.footerClass}">${e}</div>`}return""}async mount(e=null){if(!this.mounted&&!this.destroyed){if(!this.element)throw new Error("Cannot mount dialog without element");return await this.onBeforeMount(),(document.querySelector(".table-fullscreen")||document.body).appendChild(this.element),this.bindEvents(),this.mounted=!0,await this.onAfterMount(),this.emit("mounted",{view:this}),this}}async onAfterRender(){if(await super.onAfterRender(),window.Prism&&this.element&&this.element.querySelectorAll("pre code").length>0&&window.Prism.highlightAllUnder(this.element),this.autoSize)this.setupAutoSizing();else if(this.maxHeight){const e=this.element.querySelector(".modal-body");e&&(e.style.maxHeight=`${this.maxHeight}px`)}}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof window&&window.bootstrap&&window.bootstrap.Modal&&("static"===this.backdrop&&this.element.setAttribute("data-bs-backdrop","static"),this.keyboard||this.element.setAttribute("data-bs-keyboard","false"),this.modal=new window.bootstrap.Modal(this.element,{backdrop:this.backdrop,keyboard:this.keyboard,focus:this.focus}),this.bindBootstrapEvents(),this.autoShow&&this.show(this.relatedTarget))}setupAutoSizing(){this.element&&(this.element.addEventListener("shown.bs.modal",()=>{this.applyAutoSizing()},{once:!0}),setTimeout(()=>{this.isShown()&&this.applyAutoSizing()},100))}applyAutoSizing(){if(this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),s=this.element.querySelector(".modal-body");if(!e||!t||!s)return void console.warn("Dialog auto-sizing: Required elements not found");if(this.bodyView&&!this.bodyView.element)return void setTimeout(()=>this.applyAutoSizing(),50);const i={dialogMaxWidth:e.style.maxWidth,dialogWidth:e.style.width,contentWidth:t.style.width,contentMaxHeight:t.style.maxHeight,hadScrollableClass:e.classList.contains("modal-dialog-scrollable")};e.style.maxWidth="none",e.style.width="auto",t.style.width="auto",t.style.maxHeight="none",t.offsetHeight;const o=t.getBoundingClientRect(),n=40,r=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-n);let a=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-n),l=Math.max(this.minWidth,Math.ceil(o.width+20)),d=Math.max(this.minHeight,Math.ceil(o.height));this.maxHeight&&(a=Math.min(this.maxHeight,a),e.style.maxHeight=`${a}px`),l=Math.min(l,r);const c=o.height>a;e.style.maxWidth=`${l}px`,e.style.width=`${l}px`,c&&(e.classList.contains("modal-dialog-scrollable")||e.classList.add("modal-dialog-scrollable"),t.style.maxHeight=`${a}px`,d=a),this.autoSizedWidth=l,this.autoSizedHeight=d,this._originalStyles=i}catch(e){console.error("Error in dialog auto-sizing:",e),this.element.querySelector(".modal-dialog").style.maxWidth=""}}resetAutoSizing(){if(this.autoSize&&this._originalStyles&&this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),s=this.element.querySelector(".modal-body");e&&t&&s&&(e.style.maxWidth=this._originalStyles.dialogMaxWidth||"",e.style.width=this._originalStyles.dialogWidth||"",t.style.width=this._originalStyles.contentWidth||"",t.style.maxHeight=this._originalStyles.contentMaxHeight||"",!this._originalStyles.hadScrollableClass&&e.classList.contains("modal-dialog-scrollable")&&e.classList.remove("modal-dialog-scrollable"),delete this.autoSizedWidth,delete this.autoSizedHeight,delete this._originalStyles)}catch(e){console.error("Error resetting dialog auto-sizing:",e)}}bindBootstrapEvents(){this.element.addEventListener("show.bs.modal",e=>{const t=Dialog._openDialogs.length,s=Dialog.getFullscreenAwareZIndex().modal+20*t;this.element.style.zIndex=s,this._dialogZIndex=s,this._backdropZIndex=s-10,Dialog._openDialogs.push(this),this.onShow&&this.onShow(e),this.emit("show",{dialog:this,relatedTarget:e.relatedTarget})}),this.element.addEventListener("shown.bs.modal",e=>{if(setTimeout(()=>{Dialog.fixAllBackdropStacking()},50),this.onShown&&this.onShown(e),this.emit("shown",{dialog:this,relatedTarget:e.relatedTarget}),this.focus){const e=this.element.querySelector('input:not([type="hidden"]), textarea, select');e&&e.focus()}}),this.element.addEventListener("hide.bs.modal",e=>{const t=this.element.querySelector(":focus");t&&t.blur(),this.onHide&&!1===this.onHide(e)?e.preventDefault():this.emit("hide",{dialog:this})}),this.element.addEventListener("hidden.bs.modal",e=>{const t=Dialog._openDialogs.indexOf(this);t>-1&&Dialog._openDialogs.splice(t,1),Dialog._openDialogs.length>0&&(document.body.classList.add("modal-open"),setTimeout(()=>{Dialog.fixAllBackdropStacking()},50)),this.previousFocus&&document.body.contains(this.previousFocus)&&this.previousFocus.focus(),this.onHidden&&this.onHidden(e),this.emit("hidden",{dialog:this})}),this.element.addEventListener("hidePrevented.bs.modal",e=>{this.onHidePrevented&&this.onHidePrevented(e),this.emit("hidePrevented",{dialog:this})})}show(e=null){this.previousFocus=document.activeElement,window.lastDialog=this,this.modal&&this.modal.show(e)}hide(){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal&&this.modal.hide()}toggle(e=null){this.modal&&this.modal.toggle(e)}async destroy(){if(this.modal){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal.dispose(),this.modal=null}this.previousFocus&&document.body.contains(this.previousFocus)&&(this.previousFocus.focus(),this.previousFocus=null),this.autoSize&&this.resetAutoSizing(),await super.destroy()}handleUpdate(){this.modal&&this.modal.handleUpdate()}async setContent(t){if(t instanceof e.View){this.bodyView&&(await this.bodyView.destroy(),this.removeChild(this.bodyView)),this.bodyView=t,this.body="",this.addChild(this.bodyView);const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML="",await this.bodyView.render(e))}else{this.body=t;const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML=t)}this.handleUpdate()}setTitle(e){this.title=e;const t=this.element?.querySelector(".modal-title");t&&(t.textContent=e)}setLoading(e=!0,t="Loading..."){const s=this.element?.querySelector(".modal-body");s&&(e?s.innerHTML=`\n <div class="text-center py-4">\n <div class="spinner-border text-primary mb-3" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p>${t}</p>\n </div>\n `:this.bodyView&&s.replaceChildren(this.bodyView.element))}async onBeforeDestroy(){this.bodyView&&await this.bodyView.destroy(),this.footerView&&await this.footerView.destroy(),await super.onBeforeDestroy(),this.modal&&(this.modal.dispose(),this.modal=null)}static async showCode(e={}){const t=new Dialog({title:e.title||"Source Code",size:e.size||"lg",scrollable:!0,body:Dialog.formatCode(e.code,e.language),buttons:[{text:"Copy to Clipboard",class:"btn-primary",icon:"bi-clipboard",action:"copy"},{text:"Close",class:"btn-secondary",dismiss:!0}]});t.on("action:copy",async()=>{if(navigator.clipboard)try{await navigator.clipboard.writeText(e.code),t.showCopySuccess()}catch(s){console.error("Failed to copy:",s)}});const s=document.querySelector(".table-fullscreen")||document.body;return await t.render(!0,s),window.Prism&&t.element&&window.Prism.highlightAllUnder(t.element),t.show(),t.on("hidden",()=>{t.destroy(),t.element.remove()}),t}static formatCode(e,t="javascript"){let s;s=window.Prism&&window.Prism.languages[t]?window.Prism.highlight(e,window.Prism.languages[t],t):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;");const i=window.Prism?`language-${t}`:"";return`\n <style>\n /* Custom Prism theme overrides for Dialog */\n .dialog-code-block .token.comment { color: #6a9955; }\n .dialog-code-block .token.string { color: #ce9178; }\n .dialog-code-block .token.keyword { color: #569cd6; }\n .dialog-code-block .token.function { color: #dcdcaa; }\n .dialog-code-block .token.number { color: #b5cea8; }\n .dialog-code-block .token.operator { color: #d4d4d4; }\n .dialog-code-block .token.class-name { color: #4ec9b0; }\n .dialog-code-block .token.punctuation { color: #d4d4d4; }\n .dialog-code-block .token.boolean { color: #569cd6; }\n .dialog-code-block .token.property { color: #9cdcfe; }\n .dialog-code-block .token.tag { color: #569cd6; }\n .dialog-code-block .token.attr-name { color: #9cdcfe; }\n .dialog-code-block .token.attr-value { color: #ce9178; }\n .dialog-code-block ::selection { background: #264f78; }\n </style>\n <pre class="${i} dialog-code-block" style="${"\n max-height: 60vh;\n overflow-y: auto;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 1.25rem;\n border-radius: 0.5rem;\n margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Consolas', 'Monaco', monospace;\n font-size: 0.9rem;\n line-height: 1.6;\n border: 1px solid #2d2d30;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);\n ".replace(/\s+/g," ").trim()}">\n <code class="${i}" style="color: inherit; background: transparent; text-shadow: none;">${s}</code>\n </pre>\n `}static highlightCodeBlocks(e=document){window.Prism&&window.Prism.highlightAllUnder&&window.Prism.highlightAllUnder(e)}showCopySuccess(){const e=this.element.querySelector('[data-action="copy"]');if(e){const t=e.innerHTML;e.innerHTML='<i class="bi bi-check me-1"></i>Copied!',e.classList.remove("btn-primary"),e.classList.add("btn-success"),e.disabled=!0,setTimeout(()=>{e.innerHTML=t,e.classList.remove("btn-success"),e.classList.add("btn-primary"),e.disabled=!1},2e3)}}static async showDialog(e={}){"string"==typeof e&&(e={...arguments[2]||{},body:arguments[0],title:arguments[1]||"Alert"});const{title:t="Dialog",content:s,body:i=s||"",size:o="md",centered:n=!0,buttons:r=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:a=!1,...l}=e,d=new Dialog({title:t,body:i,size:o,centered:n,buttons:r,...l}),c=document.querySelector(".table-fullscreen")||document.body;return await d.render(!0,c),new Promise((e,t)=>{let s=!1;d.element.querySelectorAll(".modal-footer button").forEach((t,i)=>{const o=r[i];o&&t.addEventListener("click",async t=>{if(s)return;const n=void 0!==o.value?o.value:o.action??i;if("function"==typeof o.handler)try{const r=await o.handler({dialog:d,button:o,index:i,event:t});if(null===r||!1===r)return;const a=!0===r||void 0===r?n:r;s=!0,o.dismiss||d.hide(),e(a)}catch(r){return void console.error("Dialog button handler error:",r)}else s=!0,o.dismiss||d.hide(),e(n)})}),d.on("hidden",()=>{s||(s=!0,a?t(new Error("Dialog dismissed")):e(null)),setTimeout(()=>{d.destroy(),d.element.remove()},100)}),d.show()})}static async alert(e={}){"string"==typeof e&&(e={message:e,title:"Alert"});const{message:t="",title:s="Alert",type:i="info",...o}=e;let n="",r="";switch(i){case"success":n='<i class="bi bi-check-circle-fill text-success me-2"></i>',r="text-success";break;case"warning":n='<i class="bi bi-exclamation-triangle-fill text-warning me-2"></i>',r="text-warning";break;case"danger":case"error":n='<i class="bi bi-x-circle-fill text-danger me-2"></i>',r="text-danger";break;default:n='<i class="bi bi-info-circle-fill text-info me-2"></i>',r="text-info"}return Dialog.showDialog({title:`<span class="${r}">${n}${s}</span>`,body:`<p>${t}</p>`,size:"sm",centered:!0,buttons:[{text:"OK",class:"btn-primary",value:!0}],...o})}static async confirm(e,t="Confirm",s={}){"object"==typeof e&&(e=(s=e).message,t=s.title||t);const i=new Dialog({title:t,body:`<p>${e}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:[{text:s.cancelText||"Cancel",class:"btn-secondary",dismiss:!0,action:"cancel"},{text:s.confirmText||"Confirm",class:s.confirmClass||"btn-primary",action:"confirm"}],...s}),o=document.querySelector(".table-fullscreen")||document.body;return await i.render(!0,o),i.show(),new Promise(e=>{let t=!1;i.on("action:confirm",()=>{t=!0,i.hide()}),i.on("hidden",()=>{i.destroy(),i.element.remove(),e(t)})})}static async prompt(e,t="Input",s={}){const i=`prompt-input-${Date.now()}`,o=s.defaultValue||"",n=s.inputType||"text",r=s.placeholder||"",a=new Dialog({title:t,body:`\n <p>${e}</p>\n <input type="${n}"\n class="form-control"\n id="${i}"\n value="${o}"\n placeholder="${r}">\n `,size:s.size||"sm",centered:!0,backdrop:"static",buttons:[{text:"Cancel",class:"btn-secondary",dismiss:!0},{text:"OK",class:"btn-primary",action:"ok"}],...s}),l=document.querySelector(".table-fullscreen")||document.body;return await a.render(!0,l),a.show(),a.on("shown",()=>{const e=a.element.querySelector(`#${i}`);e&&(e.focus(),e.select())}),new Promise(e=>{let t=null;a.on("action:ok",()=>{const e=a.element.querySelector(`#${i}`);t=e?e.value:null,a.hide()}),a.on("hidden",()=>{a.destroy(),a.element.remove(),e(t)})})}getModal(){return this.modal}isShown(){return this.element?.classList.contains("show")||!1}static async showForm(e={}){const{title:t="Form",formConfig:s={},size:i="md",centered:o=!0,submitText:n="Submit",cancelText:r="Cancel",...a}=e,l=new(0,(await Promise.resolve().then(()=>require("./FormView-C1emfj3B.js")).then(e=>e.FormView$1)).default)({fileHandling:e.fileHandling||"base64",data:e.data,defaults:e.defaults,model:e.model,formConfig:{fields:s.fields||e.fields,...s,submitButton:!1,resetButton:!1}}),d=new Dialog({title:t,body:l,size:i,centered:o,buttons:[{text:r,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],...a}),c=document.querySelector(".table-fullscreen")||document.body;return await d.render(!0,c),d.show(),new Promise(t=>{let s=!1;d.on("action:submit",async()=>{if(!s)if(l.validate()){if(e.autoSave&&e.model){d.setLoading(!0);const e=await l.saveModel();if(!e.success)return d.setLoading(!1),d.render(),void d.getApp().toast.error(e.message);s=!0,d.hide(),t(e)}try{const e=await l.getFormData();s=!0,d.hide(),t(e)}catch(i){console.error("Error collecting form data:",i),l.showError("Error collecting form data")}}else l.focusFirstError()}),d.on("action:cancel",()=>{s||(s=!0,d.hide(),t(null))}),d.on("hidden",()=>{s||(s=!0,t(null)),setTimeout(()=>{l.destroy(),d.destroy()},100)})})}static async showModelForm(e={}){const{title:t="Edit",formConfig:s={},size:i="md",centered:o=!0,submitText:n="Save",cancelText:r="Cancel",model:a,fields:l,...d}=e;if(!a)throw new Error("showModelForm requires a model");const c=new(0,(await Promise.resolve().then(()=>require("./FormView-C1emfj3B.js")).then(e=>e.FormView$1)).default)({fileHandling:e.fileHandling||"base64",model:a,data:e.data,defaults:e.defaults,formConfig:{fields:l||s.fields||[],...s,submitButton:!1,resetButton:!1}}),h=new Dialog({title:t,body:c,size:i,centered:o,buttons:[{text:r,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],...d}),u=document.querySelector(".table-fullscreen")||document.body;return await h.render(!0,u),h.show(),new Promise(e=>{let t=!1;h.on("action:submit",async()=>{if(!t){h.setLoading(!0,"Saving...");try{const s=await c.handleSubmit();if(s.success)t=!0,h.hide(),e(s);else{h.setLoading(!1);let e=s.error;s.data&&s.data.error&&(e=s.data.error),h.getApp().toast.error(e)}}catch(s){console.error("Error saving form:",s),await h.setContent(c),c.showError(s.message||"An error occurred while saving")}}}),h.on("action:cancel",()=>{t||(t=!0,h.hide(),e(null))}),h.on("hidden",()=>{t||(t=!0,e(null)),setTimeout(()=>{c.destroy(),h.destroy()},100)})})}static async showData(e={}){const{title:t="Data View",data:s={},model:i=null,fields:o=[],columns:n=2,responsive:r=!0,showEmptyValues:a=!1,emptyValueText:l="—",size:d="lg",centered:c=!0,closeText:h="Close",...u}=e,m=new(0,(await Promise.resolve().then(()=>require("./DataView-R_LkYBAw.js"))).default)({data:s,model:i,fields:o,columns:n,responsive:r,showEmptyValues:a,emptyValueText:l}),g=new Dialog({title:t,body:m,size:d,centered:c,buttons:[{text:h,class:"btn-secondary",value:"close"}],...u}),p=document.querySelector(".table-fullscreen")||document.body;return await g.render(!0,p),g.show(),new Promise(e=>{let t=!1;const s=g.element.querySelector(".modal-footer button");s?.addEventListener("click",()=>{t||(t=!0,g.hide(),e(!0))}),g.on("hidden",()=>{t||(t=!0,e(!0)),setTimeout(()=>{m.destroy(),g.destroy(),g.element.remove()},100)}),m.on("field:click",e=>{g.emit("dataview:field:click",e)}),m.on("error",e=>{g.emit("dataview:error",e)})})}}Dialog.showConfirm=Dialog.confirm,Dialog.showError=Dialog.alert;const t=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,default:Dialog},Symbol.toStringTag,{value:"Module"}));exports.Dialog=Dialog,exports.EventBus=EventBus,exports.Router=Router,exports.WebApp=WebApp;
2
- //# sourceMappingURL=Dialog--hl_Uh6X.js.map
1
+ "use strict";const e=require("./Rest-P-KCJpjB.js");class Router{constructor(e={}){this.defaultRoute=e.defaultRoute||"home",this.routes=[],this.currentRoute=null,this.eventEmitter=e.eventEmitter||null,this.boundHandlePopState=this.handlePopState.bind(this)}start(){window.addEventListener("popstate",this.boundHandlePopState),this.handleCurrentLocation()}stop(){window.removeEventListener("popstate",this.boundHandlePopState)}addRoute(e,t){this.routes.push({pattern:this.normalizePattern(e),regex:this.patternToRegex(e),pageName:t,paramNames:this.extractParamNames(e)})}async navigate(e,t={}){const{replace:s=!1,state:i=null,trigger:o=!0}=t,{pageName:n,queryParams:r}=this.parseInput(e);o&&await this.handleRouteChange(n,r)}back(){window.history.back()}forward(){window.history.forward()}getCurrentRoute(){return this.currentRoute}getCurrentPath(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();return this.buildPublicUrl(e,t)}handlePopState(e){this.allowPopState?this.handleCurrentLocation():console.warn("PopStateEvent is not allowed")}async handleCurrentLocation(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();await this.handleRouteChange(e,t)}async handleRouteChange(e,t){const s="/"+e,i=this.matchRoute(s),o=this.buildPublicUrl(e,t);return i?(this.currentRoute=i,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:o,pageName:i.pageName,params:i.params,query:t,route:i}),i):(this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:o}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const i={};return t.paramNames.forEach((e,t)=>{i[e]=s[t+1]}),{...t,params:i,path:e}}}return null}parseInput(e){let t=this.defaultRoute,s={};if(!e)return{pageName:t,queryParams:s};try{if(e.includes("?")){const[i,o]=e.split("?",2),n=new URLSearchParams(o);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[e,t]of n)"page"!==e&&(s[e]=t)}else{t=i.startsWith("/")?i.substring(1)||this.defaultRoute:i||this.defaultRoute;for(const[e,t]of n)s[e]=t}}else t=e.startsWith("/")?e.substring(1)||this.defaultRoute:e}catch(i){console.warn("Failed to parse input:",e,i),t=this.defaultRoute,s={}}return{pageName:t,queryParams:s}}parseCurrentUrl(){const e=new URLSearchParams(window.location.search),t=e.get("page")||this.defaultRoute,s={};for(const[i,o]of e)"page"!==i&&(s[i]=o);return{pageName:t,queryParams:s}}buildPublicUrl(e,t={}){const s=new URLSearchParams;return s.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&s.set(e,String(t))}),"?"+s.toString()}updateBrowserUrl(e,t,s,i){const o=new URL(window.location.origin+window.location.pathname);o.searchParams.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&o.searchParams.set(e,String(t))});const n=o.toString();s?window.history.replaceState(i,"",n):window.history.pushState(i,"",n)}patternToRegex(e){let t=e.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&").replace(/\/:([^/?]+)\?/g,"(?:/([^/]+))?").replace(/:([^/]+)/g,"([^/]+)");return new RegExp(`^${t}$`)}extractParamNames(e){return(e.match(/:([^/?]+)\??/g)||[]).map(e=>e.replace(/[:?]/g,""))}normalizePattern(e){return e.startsWith("/")?e:`/${e}`}updateUrl(e={},t={}){const{replace:s=!1}=t,{pageName:i}=this.parseCurrentUrl();this.updateBrowserUrl(i,e,s)}buildUrl(e,t={}){return this.buildPublicUrl(e,t)}doRoutesMatch(e,t){if(!e||!t)return!1;const{pageName:s}=this.parseInput(e),{pageName:i}=this.parseInput(t);return s===i}}class EventBus{constructor(){this.listeners={},this.onceListeners={},this.maxListeners=100,this.debugMode=!1,this.eventStats={}}on(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.on(e,t)),this):(this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].length>=this.maxListeners&&console.warn(`Max listeners (${this.maxListeners}) exceeded for event: ${e}`),this.listeners[e].push(t),this)}once(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.once(e,t)),this):(this.onceListeners[e]||(this.onceListeners[e]=[]),this.onceListeners[e].push(t),this)}off(e,t){if(Array.isArray(e))return e.forEach(e=>this.off(e,t)),this;if(!t)return delete this.listeners[e],delete this.onceListeners[e],this;if(this.listeners[e]){const s=this.listeners[e].indexOf(t);-1!==s&&(this.listeners[e].splice(s,1),0===this.listeners[e].length&&delete this.listeners[e])}if(this.onceListeners[e]){const s=this.onceListeners[e].indexOf(t);-1!==s&&(this.onceListeners[e].splice(s,1),0===this.onceListeners[e].length&&delete this.onceListeners[e])}return this}emit(e,t){this.updateEventStats(e),this.debugMode;const s=[];return this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]),this.debugMode&&s.length>0&&s.length,s.forEach(s=>{try{s(t,e)&&(e.stopPropagation&&e.stopPropagation(),e.preventDefault&&e.preventDefault())}catch(i){console.error(`Error in event listener for '${e}':`,i),this.emitError(i,e,s)}}),this}async emitAsync(e,t){const s=[];this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]);const i=s.map(s=>new Promise(i=>{try{i(s(t,e))}catch(o){console.error(`Error in async event listener for '${e}':`,o),this.emitError(o,e,s),i()}}));return await Promise.all(i),this}removeAllListeners(){return this.listeners={},this.onceListeners={},this}listenerCount(e){return(this.listeners[e]?this.listeners[e].length:0)+(this.onceListeners[e]?this.onceListeners[e].length:0)}eventNames(){const e=Object.keys(this.listeners),t=Object.keys(this.onceListeners);return[.../* @__PURE__ */new Set([...e,...t])]}setMaxListeners(e){if("number"!=typeof e||e<0)throw new Error("Max listeners must be a non-negative number");return this.maxListeners=e,this}namespace(e){const t=t=>`${e}:${t}`;return{on:(e,s)=>this.on(t(e),s),once:(e,s)=>this.once(t(e),s),off:(e,s)=>this.off(t(e),s),emit:(e,s)=>this.emit(t(e),s),emitAsync:(e,s)=>this.emitAsync(t(e),s)}}use(e){if("function"!=typeof e)throw new Error("Middleware must be a function");const t=this.emit;return this.emit=(s,i)=>{try{const o=e(s,i);if(!1===o)return this;const n=void 0!==o?o:i;return t.call(this,s,n)}catch(o){return console.error("Error in event middleware:",o),t.call(this,s,i)}},this}emitError(e,t,s){"error"!==t&&setTimeout(()=>{this.emit("error",{error:e,originalEvent:t,callback:s.toString()})},0)}waitFor(e,t=null){return new Promise((s,i)=>{let o=null;const n=e=>{o&&clearTimeout(o),s(e)};this.once(e,n),t&&(o=setTimeout(()=>{this.off(e,n),i(new Error(`Timeout waiting for event: ${e}`))},t))})}debug(e=!0){return this.debugMode=e,this}getStats(){const e=this.eventNames(),t={totalEvents:e.length,totalListeners:0,events:{},emissions:{...this.eventStats}};return e.forEach(e=>{const s=this.listenerCount(e);t.events[e]=s,t.totalListeners+=s}),t}updateEventStats(e){this.eventStats[e]||(this.eventStats[e]={count:0,firstEmission:Date.now(),lastEmission:null}),this.eventStats[e].count++,this.eventStats[e].lastEmission=Date.now()}getEventStats(e){const t=this.eventStats[e];return t?{...t,listenerCount:this.listenerCount(e),avgEmissionsPerMinute:this.calculateEmissionRate(t)}:null}calculateEmissionRate(e){if(!e.firstEmission||!e.lastEmission)return 0;const t=e.lastEmission-e.firstEmission;if(0===t)return 0;const s=t/6e4;return Math.round(e.count/s*100)/100}resetStats(){return this.eventStats={},this}getTopEvents(e=10){return Object.entries(this.eventStats).map(([e,t])=>({event:e,count:t.count,rate:this.calculateEmissionRate(t),listeners:this.listenerCount(e)})).sort((e,t)=>t.count-e.count).slice(0,e)}debugInfo(){this.debugMode,this.maxListeners;const e=this.getStats();return e.totalEvents,e.totalListeners,Object.keys(this.eventStats).length>0&&this.getTopEvents(5),this}}class WebApp{constructor(t={}){this.config=t,this.initPluginRegistry(),this.name=t.name||"MOJO App",this.version=t.version||"1.0.0",this.debug=t.debug||!1,this.container=t.container||"#app",this.layoutType=t.layout||"portal",this.layoutConfig=t.layoutConfig||{},t.sidebar&&(this.layoutConfig.sidebarConfig=t.sidebar),t.topbar&&(this.layoutConfig.topbarConfig=t.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=t.pageContainer||"#page-container",this.basePath=t.basePath||"",this.routerMode=t.routerMode||t.router?.mode||"param",this.basePath=t.basePath||t.router?.base||"",this.defaultRoute=t.defaultRoute||"home",this.session=t.session||{},this.router=null,this.navigation=t.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new EventBus,this.rest=e.rest,t.api&&this.rest.configure(t.api),this.router=new Router({mode:"param"===this.routerMode?"params":this.routerMode,basePath:this.basePath,defaultRoute:this.defaultRoute,eventEmitter:this.events}),this.events.on("route:changed",async e=>{const{pageName:t,params:s,query:i}=e;await this.showPage(t,i,s,{fromRouter:!0})}),"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.router=this.router),this.setupFocusTracking(),this.pageCache=/* @__PURE__ */new Map,this.pageClasses=/* @__PURE__ */new Map,this.componentClasses=/* @__PURE__ */new Map,this.modelClasses=/* @__PURE__ */new Map,this.currentPage=null,this.isStarted=!1,window.matchUUID?window[window.matchUUID]=this:window.MOJO?window.MOJO.app=this:window.__app__=this}async start(){if(this.isStarted)console.warn("WebApp already started");else try{this.setupPageContainer(),this.validateDefaultRoute(),await this.setupRouter(),this.isStarted=!0,this.router.allowPopState=!1,this.events.emit("app:ready",{app:this})}catch(e){throw console.error(`Failed to start ${this.name}:`,e),this.showError("Failed to start application"),e}}async setupRouter(){this.router?(this.events.on("route:notfound",async e=>{console.warn(`Route not found: ${e.path}`),this._show404(e.path)}),this.router.start(),this.routerMode):console.error("Router not initialized")}setupPageContainer(){const e="string"==typeof this.container?document.querySelector(this.container):this.container;e&&!e.querySelector("#page-container")&&(e.innerHTML='<div id="page-container"></div>'),this.pageContainer="#page-container"}registerPage(e,t,s={}){if("string"!=typeof e||!e)return console.error("registerPage: pageName must be a non-empty string"),this;if("function"!=typeof t)return console.error("registerPage: PageClass must be a constructor function"),this;if(s.containerId||(s.containerId=this.pageContainer),this.pageClasses.set(e,{PageClass:t,constructorOptions:s}),this.router){let t=s.route||`/${e}`;t.startsWith("/")||(t=`/${t}`),s.route=t,this.router.addRoute(t,e)}return this}getPage(e){return this.pageCache.get(e)}getPagePermissions(e){if(this.pageCache.has(e))return this.pageCache.get(e).permissions;const t=this.pageClasses.get(e);if(!t)return null;const{PageClass:s,constructorOptions:i}=t;return i?i.permissions:null}getOrCreatePage(e){if(this.pageCache.has(e))return this.pageCache.get(e);const t=this.pageClasses.get(e);if(!t)return console.error(`Page not registered: ${e}`),null;const{PageClass:s,constructorOptions:i}=t;try{const t=new s({pageName:e,...i,app:this});return i.route&&(t.route=i.route),this.pageCache.set(e,t),t.route,t}catch(o){return console.error(`Failed to create page ${e}:`,o),null}}async showPage(e,t={},s={},i={}){const{fromRouter:o=!1,replace:n=!1,force:r=!1}=i;try{let i,n;"string"==typeof e?(n=e,i=this.getOrCreatePage(e)):e&&"object"==typeof e&&(i=e,n=e.pageName),this.events.emit("page:showing",{page:i,pageName:i.pageName,params:s,query:t,fromRouter:o});const r=this.currentPage;if(!i)return void this._show404(n,s,t,o);if(!i.canEnter())return void this._showDeniedPage(i,s,t,o);r&&r!==i&&await this._exitOldPage(r),await i.onParams(s,t),r!==i&&await i.onEnter(),i.syncUrl(),this.events.emit("page:show",{page:i,pageName:i.pageName,params:s,query:t,fromRouter:o}),await i.render(),this.currentPage=i,i.pageName}catch(a){console.error("Error in showPage:",a),this.showError(`Failed to load page: ${a.message}`),"error"!==e&&await this.showPage("error",{},{error:a,originalPage:e},{fromRouter:o})}}async _show404(e,t,s,i){const o=this.getOrCreatePage("404");o&&(o.setInfo&&o.setInfo(e),await this._exitOldPage(this.currentPage),await o.render(),this.currentPage=o,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:i}))}async _showDeniedPage(e,t,s,i){const o=this.getOrCreatePage("denied");o.setDeniedPage&&o.setDeniedPage(e),await this._exitOldPage(this.currentPage),await o.render(),this.currentPage=o,this.events.emit("page:denied",{page:e,pageName:e.pageName,params:t,query:s,fromRouter:i})}async _exitOldPage(e){if(e)try{await e.onExit(),await e.unmount(),this.events.emit("page:hide",{page:e})}catch(t){console.error(`Error exiting page ${e.pageName}:`,t)}}async navigate(e,t={},s={}){if(!this.router)return void console.error("Router not initialized");let i=e;if(Object.keys(t).length>0){const s=new URLSearchParams(t).toString();i+=(e.includes("?")?"&":"?")+s}return await this.router.navigate(i,s)}async navigateToDefault(e={}){return await this.showPage(this.defaultRoute,{},{},e)}back(){this.router?this.router.back():console.warn("Router not initialized")}forward(){this.router?this.router.forward():console.warn("Router not initialized")}getCurrentPage(){return this.currentPage}getPageContainer(){return this.layout&&this.layout.getPageContainer?this.layout.getPageContainer():"string"==typeof this.pageContainer?document.querySelector(this.pageContainer):this.pageContainer}async showError(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Error",{size:"md",class:"text-danger"})}catch(s){this.events.emit("notification",{message:e,type:"error"}),"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showError fallback:",s),"undefined"!=typeof window&&alert(`Error: ${e}`)}}async showSuccess(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Success",{size:"md",class:"text-success"})}catch(s){this.events.emit("notification",{message:e,type:"success"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showSuccess fallback:",s),"undefined"!=typeof window&&alert(`Success: ${e}`)}}async showInfo(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Information",{size:"md",class:"text-info"})}catch(s){this.events.emit("notification",{message:e,type:"info"}),"undefined"!=typeof window&&window,"undefined"!=typeof window&&alert(`Info: ${e}`)}}async showWarning(e){try{const s=(await Promise.resolve().then(()=>t)).default;await s.alert(e,"Warning",{size:"md",class:"text-warning"})}catch(s){this.events.emit("notification",{message:e,type:"warning"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showWarning fallback:",s),"undefined"!=typeof window&&alert(`Warning: ${e}`)}}showNotification(e,t="info"){this.events.emit("notification",{message:e,type:t})}async showLoading(e={}){"string"==typeof e&&(e={message:e});try{(await Promise.resolve().then(()=>t)).default.showBusy(e)}catch(s){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showLoading fallback:",s,e),this.events.emit("notification",{message:e.message||"Loading...",type:"info"})}}async hideLoading(){try{(await Promise.resolve().then(()=>t)).default.hideBusy()}catch(e){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelForm(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showModelForm(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showForm(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showForm(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showForm failed:",s),s}}async showDialog(e={}){try{const s=(await Promise.resolve().then(()=>t)).default;return await s.showDialog(e)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",s),s}}async confirm(e,s="Confirm",i={}){const o=(await Promise.resolve().then(()=>t)).default;return await o.confirm(e,s,i)}setupFocusTracking(){if("undefined"==typeof window)return;this.isFocused=!document.hidden;const e=()=>{const e=this.isFocused;this.isFocused=!document.hidden,e!==this.isFocused&&(this.isFocused?this.events.emit("browser:focus"):this.events.emit("browser:blur"))},t=()=>{this.isFocused||(this.isFocused=!0,this.events.emit("browser:focus"))},s=()=>{this.isFocused&&(this.isFocused=!1,this.events.emit("browser:blur"))};document.addEventListener("visibilitychange",e),window.addEventListener("focus",t),window.addEventListener("blur",s),this._focusHandlers={visibilitychange:e,focus:t,blur:s}}setupErrorHandling(){window.addEventListener("error",e=>{console.error("Global error:",e.error),this.debug&&this.showError(`Error: ${e.error?.message||"Unknown error"}`)}),window.addEventListener("unhandledrejection",e=>{console.error("Unhandled promise rejection:",e.reason),this.debug&&this.showError(`Promise rejected: ${e.reason?.message||"Unknown error"}`)})}escapeHtml(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}getState(e){return e?this.state[e]:this.state}setState(e){const t={...this.state};Object.assign(this.state,e),this.events.emit("state:changed",{oldState:t,newState:this.state,updates:e})}registerComponent(e,t){this.componentClasses.set(e,t)}getComponent(e){return this.componentClasses.get(e)}registerModel(e,t){this.modelClasses.set(e,t)}getModel(e){return this.modelClasses.get(e)}setupRest(){this.rest=e.rest,e.rest.configure(this.api)}async destroy(){this.router&&this.router.stop(),this._focusHandlers&&"undefined"!=typeof window&&(document.removeEventListener("visibilitychange",this._focusHandlers.visibilitychange),window.removeEventListener("focus",this._focusHandlers.focus),window.removeEventListener("blur",this._focusHandlers.blur));const e=Array.from(this.pageCache.values());if(await Promise.allSettled(e.map(async e=>{try{e.destroy&&await e.destroy()}catch(t){console.error("Error destroying page:",t)}})),this.layout&&this.layout.destroy)try{await this.layout.destroy()}catch(t){console.error("Error destroying layout:",t)}this.pageCache.clear(),this.pageClasses.clear(),this.componentClasses.clear(),this.modelClasses.clear(),"undefined"!=typeof window&&window.MOJO&&delete window.MOJO.router,this.isStarted=!1,this.name}buildPagePath(e,t,s){let i=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(e=>{"string"!=typeof t[e]&&"number"!=typeof t[e]||(i=i.replace(`:${e}`,t[e]))}),s&&Object.keys(s).length>0){const e=new URLSearchParams(s).toString();i+=(i.includes("?")?"&":"?")+e}return i}validateDefaultRoute(){this.pageClasses.has(this.defaultRoute)?this.defaultRoute:(console.warn(`⚠️ Default route '${this.defaultRoute}' is not registered!`),console.warn(` Please register a page: app.registerPage('${this.defaultRoute}', YourPageClass);`),console.warn(" Or change default route: new WebApp({ defaultRoute: 'your-page' });"))}findFallbackPage(){const e=["404","error","denied"];for(const[t]of this.pageClasses.entries())if(!e.includes(t))return t;return null}static create(e={}){return new WebApp(e)}initPluginRegistry(){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.app=this)}static registerPlugin(e,t){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.plugins[e]=t)}}class Dialog extends e.View{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:this._baseZIndex}static _busyIndicator=null;static _busyCounter=0;static _busyTimeout=null;static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=Dialog._openDialogs;if(0===e.length||0===t.length)return;const s=[...t].sort((e,t)=>(e._dialogZIndex||0)-(t._dialogZIndex||0));e.forEach((e,t)=>{if(t<s.length){const i=s[t]._dialogZIndex-5;e.style.zIndex=i;const o=document.querySelector(".table-fullscreen")||document.body;e.parentNode!==o&&o.appendChild(e)}})}static updateAllBackdropStacking(){Dialog.fixAllBackdropStacking()}static showBusy(e={}){const{timeout:t=3e4,message:s="Loading..."}=e;if(this._busyCounter++,1===this._busyCounter){if(this._busyTimeout&&clearTimeout(this._busyTimeout),!this._busyIndicator){const e=this.getFullscreenAwareZIndex().modal+1e3;this._busyIndicator=document.createElement("div"),this._busyIndicator.className="mojo-busy-indicator",this._busyIndicator.innerHTML=`\n <div class="mojo-busy-spinner">\n <div class="spinner-border text-light" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p class="mojo-busy-message mt-3 text-light">${s}</p>\n </div>\n <style>\n .mojo-busy-indicator {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background-color: rgba(0, 0, 0, 0.5); z-index: ${e};\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.15s linear;\n }\n .mojo-busy-indicator.show { opacity: 1; }\n .mojo-busy-spinner .spinner-border { width: 3rem; height: 3rem; }\n </style>\n `,document.body.appendChild(this._busyIndicator)}const e=this._busyIndicator.querySelector(".mojo-busy-message");e&&(e.textContent=s),setTimeout(()=>this._busyIndicator.classList.add("show"),10),this._busyTimeout=setTimeout(()=>{console.error("Busy indicator timed out."),this.hideBusy(!0),this.alert({title:"Operation Timed Out",message:"The operation took too long. Please check your connection and try again.",type:"danger"})},t)}}static hideBusy(e=!1){e?this._busyCounter=0:this._busyCounter--,this._busyCounter<=0&&(this._busyCounter=0,this._busyTimeout&&(clearTimeout(this._busyTimeout),this._busyTimeout=null),this._busyIndicator&&(this._busyIndicator.classList.remove("show"),setTimeout(()=>{this._busyIndicator&&0===this._busyCounter&&(this._busyIndicator.remove(),this._busyIndicator=null)},150)))}constructor(e={}){const t=e.id||`modal-${Date.now()}`;super({...e,id:t,tagName:"div",className:`modal ${!1!==e.fade?"fade":""} ${e.className||""}`,attributes:{tabindex:"-1","aria-hidden":"true","aria-labelledby":e.labelledBy||`${t}-label`,"aria-describedby":e.describedBy||null,...e.attributes}}),this.modalId=t,this.title=e.title||"",this.titleId=`${this.modalId}-label`,this.size=e.size||"",this.centered=void 0!==e.centered&&e.centered,this.scrollable=void 0!==e.scrollable&&e.scrollable,this.autoSize=e.autoSize||"auto"===e.size,this.backdrop=void 0===e.backdrop||e.backdrop,this.keyboard=void 0===e.keyboard||e.keyboard,this.focus=void 0===e.focus||e.focus,this.header=void 0===e.header||e.header,this.headerContent=e.headerContent||null,this.closeButton=void 0===e.closeButton||e.closeButton,this.contextMenu=e.contextMenu||null,this.body=e.body||e.content||"",this.bodyView=null,this.bodyClass=e.bodyClass||"",this.noBodyPadding=e.noBodyPadding||!1,this.minWidth=e.minWidth||300,this.minHeight=e.minHeight||200,e.maxHeight&&(this.maxHeight=e.maxHeight),this.maxWidthPercent=e.maxWidthPercent||.9,this.maxHeightPercent=e.maxHeightPercent||.8,this._processBodyContent(this.body),this.footer=e.footer||null,this.footerView=null,this.footerClass=e.footerClass||"",this._processFooterContent(this.footer),this.buttons=e.buttons||null,this.onShow=e.onShow||null,this.onShown=e.onShown||null,this.onHide=e.onHide||null,this.onHidden=e.onHidden||null,this.onHidePrevented=e.onHidePrevented||null,this.autoShow=void 0!==e.autoShow&&e.autoShow,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(t){if(t&&t.render)this.bodyView=t,this.body="",this.addChild(this.bodyView);else if("function"==typeof t)try{const s=t();s instanceof e.View?(this.bodyView=s,this.body="",this.addChild(this.bodyView)):s instanceof Promise?(this.bodyPromise=s,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=s}catch(s){console.error("Error processing body function:",s),this.body=t}else this.body=t}_processFooterContent(t){if(t instanceof e.View)this.footerView=t,this.footer=null,this.addChild(this.footerView);else if("function"==typeof t)try{const s=t();s instanceof e.View?(this.footerView=s,this.footer=null,this.addChild(this.footerView)):s instanceof Promise?(this.footerPromise=s,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=s}catch(s){console.error("Error processing footer function:",s),this.footer=t}else this.footer=t}async getTemplate(){const e=["modal-dialog"];return this.size&&"auto"!==this.size&&(this.size.startsWith("fullscreen")?e.push(`modal-${this.size}`):["sm","lg","xl","xxl"].includes(this.size)&&(e.push(`modal-${this.size}`),["lg","xl","xxl"].includes(this.size)&&e.push("modal-fullscreen-sm-down"))),this.centered&&e.push("modal-dialog-centered"),this.scrollable&&(this.maxHeight?e.push("overflow-hidden"):e.push("modal-dialog-scrollable")),`\n <div class="${e.join(" ")}">\n <div class="modal-content">\n ${await this.buildHeader()}\n ${await this.buildBody()}\n ${await this.buildFooter()}\n </div>\n </div>\n `}async buildHeader(){if(!this.header)return"";if(this.headerContent)return`<div class="modal-header">${this.headerContent}</div>`;let e="";return this.contextMenu&&this.contextMenu.items&&this.contextMenu.items.length>0?e=await this.buildContextMenu():this.closeButton&&(e='<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>'),`\n <div class="modal-header">\n ${this.title?`<h5 class="modal-title" id="${this.titleId}">${this.title}</h5>`:""}\n ${e}\n </div>\n `}async buildContextMenu(){const e=await this.filterContextMenuItems();if(0===e.length)return this.closeButton?'<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>':"";const t=this.contextMenu.icon||"bi-three-dots-vertical";return`\n <div class="dropdown">\n <button class="${this.contextMenu.buttonClass||"btn btn-link p-1 mojo-modal-context-menu-btn"}" type="button" data-bs-toggle="dropdown" aria-expanded="false">\n <i class="${t}"></i>\n </button>\n <ul class="dropdown-menu dropdown-menu-end">\n ${e.map(e=>{if("divider"===e.type)return'<li><hr class="dropdown-divider"></li>';const t=e.icon?`<i class="${e.icon} me-2"></i>`:"",s=e.label||"";if(e.href)return`<li><a class="dropdown-item" href="${e.href}"${e.target?` target="${e.target}"`:""}>${t}${s}</a></li>`;if(e.action){const i=Object.keys(e).filter(e=>e.startsWith("data-")).map(t=>`${t}="${e[t]}"`).join(" ");return`<li><a class="dropdown-item" data-action="${e.action}" ${i}>${t}${s}</a></li>`}return""}).join("")}\n </ul>\n </div>\n `}async filterContextMenuItems(){if(!this.contextMenu||!this.contextMenu.items)return[];const e=[];for(const i of this.contextMenu.items)if("divider"!==i.type){if(i.permissions)try{const e=this.getApp?.();let s=null;if(e&&(s=e.activeUser||e.getState?.("activeUser")),!s&&"undefined"!=typeof window&&window.getApp)try{const e=window.getApp();s=e?.activeUser}catch(t){}if(!s||!s.hasPermission)continue;if(!s.hasPermission(i.permissions))continue}catch(s){console.warn("Error checking permissions for context menu item:",s);continue}e.push(i)}else e.push(i);return e}async buildBody(){return this.bodyView?(this.bodyView.replaceById=!0,`<div class="${this.noBodyPadding?`modal-body p-0 ${this.bodyClass}`:`modal-body ${this.bodyClass}`}" data-view-container="body">\n \x3c!-- View will be mounted here --\x3e\n <div id="${this.bodyView.id}"></div>\n </div>`):this.body||""===this.body?`\n <div class="${this.noBodyPadding?`modal-body p-0 ${this.bodyClass}`:`modal-body ${this.bodyClass}`}">\n ${this.body}\n </div>\n `:""}async buildFooter(){if(this.footerView)return`<div class="modal-footer ${this.footerClass}" data-view-container="footer"></div>`;if(null!==this.footer&&"string"==typeof this.footer)return`<div class="modal-footer ${this.footerClass}">${this.footer}</div>`;if(this.buttons&&this.buttons.length>0){const e=this.buttons.map(e=>{const t=e.dismiss?'data-bs-dismiss="modal"':"",s=e.action?`data-action="${e.action}"`:"",i=e.id?`id="${e.id}"`:"",o=e.disabled?"disabled":"";return`\n <button type="${e.type||"button"}"\n class="btn ${e.class||"btn-secondary"}"\n ${i}\n ${t}\n ${s}\n ${o}>\n ${e.icon?`<i class="bi ${e.icon} me-1"></i>`:""}\n ${e.text||"Button"}\n </button>\n `}).join("");return`<div class="modal-footer ${this.footerClass}">${e}</div>`}return""}async mount(e=null){if(!this.mounted&&!this.destroyed){if(!this.element)throw new Error("Cannot mount dialog without element");return await this.onBeforeMount(),(document.querySelector(".table-fullscreen")||document.body).appendChild(this.element),this.bindEvents(),this.mounted=!0,await this.onAfterMount(),this.emit("mounted",{view:this}),this}}async onAfterRender(){if(await super.onAfterRender(),window.Prism&&this.element&&this.element.querySelectorAll("pre code").length>0&&window.Prism.highlightAllUnder(this.element),this.autoSize)this.setupAutoSizing();else if(this.maxHeight){const e=this.element.querySelector(".modal-body");e&&(e.style.maxHeight=`${this.maxHeight}px`)}}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof window&&window.bootstrap&&window.bootstrap.Modal&&("static"===this.backdrop&&this.element.setAttribute("data-bs-backdrop","static"),this.keyboard||this.element.setAttribute("data-bs-keyboard","false"),this.modal=new window.bootstrap.Modal(this.element,{backdrop:this.backdrop,keyboard:this.keyboard,focus:this.focus}),this.bindBootstrapEvents(),this.autoShow&&this.show(this.relatedTarget))}setupAutoSizing(){this.element&&(this.element.addEventListener("shown.bs.modal",()=>{this.applyAutoSizing()},{once:!0}),setTimeout(()=>{this.isShown()&&this.applyAutoSizing()},100))}applyAutoSizing(){if(this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),s=this.element.querySelector(".modal-body");if(!e||!t||!s)return void console.warn("Dialog auto-sizing: Required elements not found");if(this.bodyView&&!this.bodyView.element)return void setTimeout(()=>this.applyAutoSizing(),50);const i={dialogMaxWidth:e.style.maxWidth,dialogWidth:e.style.width,contentWidth:t.style.width,contentMaxHeight:t.style.maxHeight,hadScrollableClass:e.classList.contains("modal-dialog-scrollable")};e.style.maxWidth="none",e.style.width="auto",t.style.width="auto",t.style.maxHeight="none",t.offsetHeight;const o=t.getBoundingClientRect(),n=40,r=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-n);let a=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-n),l=Math.max(this.minWidth,Math.ceil(o.width+20)),d=Math.max(this.minHeight,Math.ceil(o.height));this.maxHeight&&(a=Math.min(this.maxHeight,a),e.style.maxHeight=`${a}px`),l=Math.min(l,r);const c=o.height>a;e.style.maxWidth=`${l}px`,e.style.width=`${l}px`,c&&(e.classList.contains("modal-dialog-scrollable")||e.classList.add("modal-dialog-scrollable"),t.style.maxHeight=`${a}px`,d=a),this.autoSizedWidth=l,this.autoSizedHeight=d,this._originalStyles=i}catch(e){console.error("Error in dialog auto-sizing:",e),this.element.querySelector(".modal-dialog").style.maxWidth=""}}resetAutoSizing(){if(this.autoSize&&this._originalStyles&&this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),s=this.element.querySelector(".modal-body");e&&t&&s&&(e.style.maxWidth=this._originalStyles.dialogMaxWidth||"",e.style.width=this._originalStyles.dialogWidth||"",t.style.width=this._originalStyles.contentWidth||"",t.style.maxHeight=this._originalStyles.contentMaxHeight||"",!this._originalStyles.hadScrollableClass&&e.classList.contains("modal-dialog-scrollable")&&e.classList.remove("modal-dialog-scrollable"),delete this.autoSizedWidth,delete this.autoSizedHeight,delete this._originalStyles)}catch(e){console.error("Error resetting dialog auto-sizing:",e)}}bindBootstrapEvents(){this.element.addEventListener("show.bs.modal",e=>{const t=Dialog._openDialogs.length,s=Dialog.getFullscreenAwareZIndex().modal+20*t;this.element.style.zIndex=s,this._dialogZIndex=s,this._backdropZIndex=s-10,Dialog._openDialogs.push(this),this.onShow&&this.onShow(e),this.emit("show",{dialog:this,relatedTarget:e.relatedTarget})}),this.element.addEventListener("shown.bs.modal",e=>{if(setTimeout(()=>{Dialog.fixAllBackdropStacking()},50),this.onShown&&this.onShown(e),this.emit("shown",{dialog:this,relatedTarget:e.relatedTarget}),this.focus){const e=this.element.querySelector('input:not([type="hidden"]), textarea, select');e&&e.focus()}}),this.element.addEventListener("hide.bs.modal",e=>{const t=this.element.querySelector(":focus");t&&t.blur(),this.onHide&&!1===this.onHide(e)?e.preventDefault():this.emit("hide",{dialog:this})}),this.element.addEventListener("hidden.bs.modal",e=>{const t=Dialog._openDialogs.indexOf(this);t>-1&&Dialog._openDialogs.splice(t,1),Dialog._openDialogs.length>0&&(document.body.classList.add("modal-open"),setTimeout(()=>{Dialog.fixAllBackdropStacking()},50)),this.previousFocus&&document.body.contains(this.previousFocus)&&this.previousFocus.focus(),this.onHidden&&this.onHidden(e),this.emit("hidden",{dialog:this})}),this.element.addEventListener("hidePrevented.bs.modal",e=>{this.onHidePrevented&&this.onHidePrevented(e),this.emit("hidePrevented",{dialog:this})})}show(e=null){this.previousFocus=document.activeElement,window.lastDialog=this,this.modal&&this.modal.show(e)}hide(){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal&&this.modal.hide()}toggle(e=null){this.modal&&this.modal.toggle(e)}async destroy(){if(this.modal){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal.dispose(),this.modal=null}this.previousFocus&&document.body.contains(this.previousFocus)&&(this.previousFocus.focus(),this.previousFocus=null),this.autoSize&&this.resetAutoSizing(),await super.destroy()}handleUpdate(){this.modal&&this.modal.handleUpdate()}async setContent(t){if(t instanceof e.View){this.bodyView&&(await this.bodyView.destroy(),this.removeChild(this.bodyView)),this.bodyView=t,this.body="",this.addChild(this.bodyView);const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML="",await this.bodyView.render(e))}else{this.body=t;const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML=t)}this.handleUpdate()}setTitle(e){this.title=e;const t=this.element?.querySelector(".modal-title");t&&(t.textContent=e)}setLoading(e=!0,t="Loading..."){const s=this.element?.querySelector(".modal-body");s&&(e?s.innerHTML=`\n <div class="text-center py-4">\n <div class="spinner-border text-primary mb-3" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p>${t}</p>\n </div>\n `:this.bodyView&&s.replaceChildren(this.bodyView.element))}async onBeforeDestroy(){this.bodyView&&await this.bodyView.destroy(),this.footerView&&await this.footerView.destroy(),await super.onBeforeDestroy(),this.modal&&(this.modal.dispose(),this.modal=null)}static async showCode(e={}){const t=new Dialog({title:e.title||"Source Code",size:e.size||"lg",scrollable:!0,body:Dialog.formatCode(e.code,e.language),buttons:[{text:"Copy to Clipboard",class:"btn-primary",icon:"bi-clipboard",action:"copy"},{text:"Close",class:"btn-secondary",dismiss:!0}]});t.on("action:copy",async()=>{if(navigator.clipboard)try{await navigator.clipboard.writeText(e.code),t.showCopySuccess()}catch(s){console.error("Failed to copy:",s)}});const s=document.querySelector(".table-fullscreen")||document.body;return await t.render(!0,s),window.Prism&&t.element&&window.Prism.highlightAllUnder(t.element),t.show(),t.on("hidden",()=>{t.destroy(),t.element.remove()}),t}static formatCode(e,t="javascript"){let s;s=window.Prism&&window.Prism.languages[t]?window.Prism.highlight(e,window.Prism.languages[t],t):e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;");const i=window.Prism?`language-${t}`:"";return`\n <style>\n /* Custom Prism theme overrides for Dialog */\n .dialog-code-block .token.comment { color: #6a9955; }\n .dialog-code-block .token.string { color: #ce9178; }\n .dialog-code-block .token.keyword { color: #569cd6; }\n .dialog-code-block .token.function { color: #dcdcaa; }\n .dialog-code-block .token.number { color: #b5cea8; }\n .dialog-code-block .token.operator { color: #d4d4d4; }\n .dialog-code-block .token.class-name { color: #4ec9b0; }\n .dialog-code-block .token.punctuation { color: #d4d4d4; }\n .dialog-code-block .token.boolean { color: #569cd6; }\n .dialog-code-block .token.property { color: #9cdcfe; }\n .dialog-code-block .token.tag { color: #569cd6; }\n .dialog-code-block .token.attr-name { color: #9cdcfe; }\n .dialog-code-block .token.attr-value { color: #ce9178; }\n .dialog-code-block ::selection { background: #264f78; }\n </style>\n <pre class="${i} dialog-code-block" style="${"\n max-height: 60vh;\n overflow-y: auto;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 1.25rem;\n border-radius: 0.5rem;\n margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Consolas', 'Monaco', monospace;\n font-size: 0.9rem;\n line-height: 1.6;\n border: 1px solid #2d2d30;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);\n ".replace(/\s+/g," ").trim()}">\n <code class="${i}" style="color: inherit; background: transparent; text-shadow: none;">${s}</code>\n </pre>\n `}static highlightCodeBlocks(e=document){window.Prism&&window.Prism.highlightAllUnder&&window.Prism.highlightAllUnder(e)}showCopySuccess(){const e=this.element.querySelector('[data-action="copy"]');if(e){const t=e.innerHTML;e.innerHTML='<i class="bi bi-check me-1"></i>Copied!',e.classList.remove("btn-primary"),e.classList.add("btn-success"),e.disabled=!0,setTimeout(()=>{e.innerHTML=t,e.classList.remove("btn-success"),e.classList.add("btn-primary"),e.disabled=!1},2e3)}}static async showDialog(e={}){"string"==typeof e&&(e={...arguments[2]||{},body:arguments[0],title:arguments[1]||"Alert"});const{title:t="Dialog",content:s,body:i=s||"",size:o="md",centered:n=!0,buttons:r=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:a=!1,...l}=e,d=new Dialog({title:t,body:i,size:o,centered:n,buttons:r,...l}),c=document.querySelector(".table-fullscreen")||document.body;return await d.render(!0,c),new Promise((e,t)=>{let s=!1;d.element.querySelectorAll(".modal-footer button").forEach((t,i)=>{const o=r[i];o&&t.addEventListener("click",async t=>{if(s)return;const n=void 0!==o.value?o.value:o.action??i;if("function"==typeof o.handler)try{const r=await o.handler({dialog:d,button:o,index:i,event:t});if(null===r||!1===r)return;const a=!0===r||void 0===r?n:r;s=!0,o.dismiss||d.hide(),e(a)}catch(r){return void console.error("Dialog button handler error:",r)}else s=!0,o.dismiss||d.hide(),e(n)})}),d.on("hidden",()=>{s||(s=!0,a?t(new Error("Dialog dismissed")):e(null)),setTimeout(()=>{d.destroy(),d.element.remove()},100)}),d.show()})}static async alert(e={}){"string"==typeof e&&(e={message:e,title:"Alert"});const{message:t="",title:s="Alert",type:i="info",...o}=e;let n="",r="";switch(i){case"success":n='<i class="bi bi-check-circle-fill text-success me-2"></i>',r="text-success";break;case"warning":n='<i class="bi bi-exclamation-triangle-fill text-warning me-2"></i>',r="text-warning";break;case"danger":case"error":n='<i class="bi bi-x-circle-fill text-danger me-2"></i>',r="text-danger";break;default:n='<i class="bi bi-info-circle-fill text-info me-2"></i>',r="text-info"}return Dialog.showDialog({title:`<span class="${r}">${n}${s}</span>`,body:`<p>${t}</p>`,size:"sm",centered:!0,buttons:[{text:"OK",class:"btn-primary",value:!0}],...o})}static async confirm(e,t="Confirm",s={}){"object"==typeof e&&(e=(s=e).message,t=s.title||t);const i=new Dialog({title:t,body:`<p>${e}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:[{text:s.cancelText||"Cancel",class:"btn-secondary",dismiss:!0,action:"cancel"},{text:s.confirmText||"Confirm",class:s.confirmClass||"btn-primary",action:"confirm"}],...s}),o=document.querySelector(".table-fullscreen")||document.body;return await i.render(!0,o),i.show(),new Promise(e=>{let t=!1;i.on("action:confirm",()=>{t=!0,i.hide()}),i.on("hidden",()=>{i.destroy(),i.element.remove(),e(t)})})}static async prompt(e,t="Input",s={}){const i=`prompt-input-${Date.now()}`,o=s.defaultValue||"",n=s.inputType||"text",r=s.placeholder||"",a=new Dialog({title:t,body:`\n <p>${e}</p>\n <input type="${n}"\n class="form-control"\n id="${i}"\n value="${o}"\n placeholder="${r}">\n `,size:s.size||"sm",centered:!0,backdrop:"static",buttons:[{text:"Cancel",class:"btn-secondary",dismiss:!0},{text:"OK",class:"btn-primary",action:"ok"}],...s}),l=document.querySelector(".table-fullscreen")||document.body;return await a.render(!0,l),a.show(),a.on("shown",()=>{const e=a.element.querySelector(`#${i}`);e&&(e.focus(),e.select())}),new Promise(e=>{let t=null;a.on("action:ok",()=>{const e=a.element.querySelector(`#${i}`);t=e?e.value:null,a.hide()}),a.on("hidden",()=>{a.destroy(),a.element.remove(),e(t)})})}getModal(){return this.modal}isShown(){return this.element?.classList.contains("show")||!1}static async showForm(e={}){const{title:t="Form",formConfig:s={},size:i="md",centered:o=!0,submitText:n="Submit",cancelText:r="Cancel",...a}=e,l=new(0,(await Promise.resolve().then(()=>require("./FormView-DCI29KlM.js")).then(e=>e.FormView$1)).default)({fileHandling:e.fileHandling||"base64",data:e.data,defaults:e.defaults,model:e.model,formConfig:{fields:s.fields||e.fields,...s,submitButton:!1,resetButton:!1}}),d=new Dialog({title:t,body:l,size:i,centered:o,buttons:[{text:r,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],...a}),c=document.querySelector(".table-fullscreen")||document.body;return await d.render(!0,c),d.show(),new Promise(t=>{let s=!1;d.on("action:submit",async()=>{if(!s)if(l.validate()){if(e.autoSave&&e.model){d.setLoading(!0);const e=await l.saveModel();if(!e.success)return d.setLoading(!1),d.render(),void d.getApp().toast.error(e.message);s=!0,d.hide(),t(e)}try{const e=await l.getFormData();s=!0,d.hide(),t(e)}catch(i){console.error("Error collecting form data:",i),l.showError("Error collecting form data")}}else l.focusFirstError()}),d.on("action:cancel",()=>{s||(s=!0,d.hide(),t(null))}),d.on("hidden",()=>{s||(s=!0,t(null)),setTimeout(()=>{l.destroy(),d.destroy()},100)})})}static async showModelForm(e={}){const{title:t="Edit",formConfig:s={},size:i="md",centered:o=!0,submitText:n="Save",cancelText:r="Cancel",model:a,fields:l,...d}=e;if(!a)throw new Error("showModelForm requires a model");const c=new(0,(await Promise.resolve().then(()=>require("./FormView-DCI29KlM.js")).then(e=>e.FormView$1)).default)({fileHandling:e.fileHandling||"base64",model:a,data:e.data,defaults:e.defaults,formConfig:{fields:l||s.fields||[],...s,submitButton:!1,resetButton:!1}}),h=new Dialog({title:t,body:c,size:i,centered:o,buttons:[{text:r,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],...d}),u=document.querySelector(".table-fullscreen")||document.body;return await h.render(!0,u),h.show(),new Promise(e=>{let t=!1;h.on("action:submit",async()=>{if(!t){h.setLoading(!0,"Saving...");try{const s=await c.handleSubmit();if(s.success)t=!0,h.hide(),e(s);else{h.setLoading(!1);let e=s.error;s.data&&s.data.error&&(e=s.data.error),h.getApp().toast.error(e)}}catch(s){console.error("Error saving form:",s),await h.setContent(c),c.showError(s.message||"An error occurred while saving")}}}),h.on("action:cancel",()=>{t||(t=!0,h.hide(),e(null))}),h.on("hidden",()=>{t||(t=!0,e(null)),setTimeout(()=>{c.destroy(),h.destroy()},100)})})}static async showData(e={}){const{title:t="Data View",data:s={},model:i=null,fields:o=[],columns:n=2,responsive:r=!0,showEmptyValues:a=!1,emptyValueText:l="—",size:d="lg",centered:c=!0,closeText:h="Close",...u}=e,m=new(0,(await Promise.resolve().then(()=>require("./DataView-R_LkYBAw.js"))).default)({data:s,model:i,fields:o,columns:n,responsive:r,showEmptyValues:a,emptyValueText:l}),g=new Dialog({title:t,body:m,size:d,centered:c,buttons:[{text:h,class:"btn-secondary",value:"close"}],...u}),p=document.querySelector(".table-fullscreen")||document.body;return await g.render(!0,p),g.show(),new Promise(e=>{let t=!1;const s=g.element.querySelector(".modal-footer button");s?.addEventListener("click",()=>{t||(t=!0,g.hide(),e(!0))}),g.on("hidden",()=>{t||(t=!0,e(!0)),setTimeout(()=>{m.destroy(),g.destroy(),g.element.remove()},100)}),m.on("field:click",e=>{g.emit("dataview:field:click",e)}),m.on("error",e=>{g.emit("dataview:error",e)})})}}Dialog.showConfirm=Dialog.confirm,Dialog.showError=Dialog.alert;const t=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,default:Dialog},Symbol.toStringTag,{value:"Module"}));exports.Dialog=Dialog,exports.EventBus=EventBus,exports.Router=Router,exports.WebApp=WebApp;
2
+ //# sourceMappingURL=Dialog-VyLukswR.js.map