web-mojo 2.3.7 → 2.4.1

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 (109) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/dist/admin-models.cjs.js +1 -1
  3. package/dist/admin-models.es.js +1 -1
  4. package/dist/admin.cjs.js +1 -1
  5. package/dist/admin.es.js +1 -1
  6. package/dist/auth.cjs.js +1 -1
  7. package/dist/auth.es.js +1 -1
  8. package/dist/charts.cjs.js +1 -1
  9. package/dist/charts.es.js +1 -1
  10. package/dist/chunks/{AssistantPanelView-B5tMna_t.js → AssistantPanelView-C2UrR8N7.js} +2 -2
  11. package/dist/chunks/{AssistantPanelView-B5tMna_t.js.map → AssistantPanelView-C2UrR8N7.js.map} +1 -1
  12. package/dist/chunks/{AssistantPanelView-BOdIQuqK.js → AssistantPanelView-DVeXmhzx.js} +2 -2
  13. package/dist/chunks/{AssistantPanelView-BOdIQuqK.js.map → AssistantPanelView-DVeXmhzx.js.map} +1 -1
  14. package/dist/chunks/{ChatView-BquP2SP_.js → ChatView-B0xHv7Nq.js} +2 -2
  15. package/dist/chunks/{ChatView-BquP2SP_.js.map → ChatView-B0xHv7Nq.js.map} +1 -1
  16. package/dist/chunks/{ChatView-rWg4ZSJy.js → ChatView-CUmRTKna.js} +2 -2
  17. package/dist/chunks/{ChatView-rWg4ZSJy.js.map → ChatView-CUmRTKna.js.map} +1 -1
  18. package/dist/chunks/{Collection-CtSGTegm.js → Collection-7F3lsq4z.js} +2 -2
  19. package/dist/chunks/{Collection-CtSGTegm.js.map → Collection-7F3lsq4z.js.map} +1 -1
  20. package/dist/chunks/{Collection-BtSHP_BV.js → Collection-Cgxbmj8G.js} +2 -2
  21. package/dist/chunks/{Collection-BtSHP_BV.js.map → Collection-Cgxbmj8G.js.map} +1 -1
  22. package/dist/chunks/{ContextMenu-DvQTJA49.js → ContextMenu-Ba4fjHxg.js} +2 -2
  23. package/dist/chunks/{ContextMenu-DvQTJA49.js.map → ContextMenu-Ba4fjHxg.js.map} +1 -1
  24. package/dist/chunks/{ContextMenu-0KtfqyQm.js → ContextMenu-afYD0lFk.js} +2 -2
  25. package/dist/chunks/{ContextMenu-0KtfqyQm.js.map → ContextMenu-afYD0lFk.js.map} +1 -1
  26. package/dist/chunks/{DataView-jHxX-6Gh.js → DataView-DFGIE3wK.js} +2 -2
  27. package/dist/chunks/{DataView-jHxX-6Gh.js.map → DataView-DFGIE3wK.js.map} +1 -1
  28. package/dist/chunks/{DataView-DJMOmlKN.js → DataView-fA6qQbvN.js} +2 -2
  29. package/dist/chunks/{DataView-DJMOmlKN.js.map → DataView-fA6qQbvN.js.map} +1 -1
  30. package/dist/chunks/FormView-CgnaTPkQ.js +2 -0
  31. package/dist/chunks/FormView-CgnaTPkQ.js.map +1 -0
  32. package/dist/chunks/FormView-LRb8scDI.js +2 -0
  33. package/dist/chunks/FormView-LRb8scDI.js.map +1 -0
  34. package/dist/chunks/{ListView-mr1Kmuj-.js → ListView-Cu6iQ0aG.js} +2 -2
  35. package/dist/chunks/{ListView-mr1Kmuj-.js.map → ListView-Cu6iQ0aG.js.map} +1 -1
  36. package/dist/chunks/{ListView-CjJ-4gD7.js → ListView-Dsezts8J.js} +2 -2
  37. package/dist/chunks/{ListView-CjJ-4gD7.js.map → ListView-Dsezts8J.js.map} +1 -1
  38. package/dist/chunks/{MetricsCountryMapView-D9J4Gwdi.js → MetricsCountryMapView-BkLDonK4.js} +2 -2
  39. package/dist/chunks/{MetricsCountryMapView-D9J4Gwdi.js.map → MetricsCountryMapView-BkLDonK4.js.map} +1 -1
  40. package/dist/chunks/{MetricsCountryMapView-BIsfmvE0.js → MetricsCountryMapView-BsJoEsUE.js} +2 -2
  41. package/dist/chunks/{MetricsCountryMapView-BIsfmvE0.js.map → MetricsCountryMapView-BsJoEsUE.js.map} +1 -1
  42. package/dist/chunks/{Modal-DYJadSN8.js → Modal-BRKy85bz.js} +3 -3
  43. package/dist/chunks/{Modal-DYJadSN8.js.map → Modal-BRKy85bz.js.map} +1 -1
  44. package/dist/chunks/{Modal-DF98u_sN.js → Modal-DKjxtaZI.js} +3 -3
  45. package/dist/chunks/{Modal-DF98u_sN.js.map → Modal-DKjxtaZI.js.map} +1 -1
  46. package/dist/chunks/{Passkeys-Dx5bduZJ.js → Passkeys-CMh9iSax.js} +2 -2
  47. package/dist/chunks/{Passkeys-C1m6avHh.js.map → Passkeys-CMh9iSax.js.map} +1 -1
  48. package/dist/chunks/{Passkeys-C1m6avHh.js → Passkeys-DF7mRGYj.js} +2 -2
  49. package/dist/chunks/{Passkeys-Dx5bduZJ.js.map → Passkeys-DF7mRGYj.js.map} +1 -1
  50. package/dist/chunks/{TokenManager-B-xR8zPl.js → TokenManager-CVR3ENIS.js} +2 -2
  51. package/dist/chunks/{TokenManager-B-xR8zPl.js.map → TokenManager-CVR3ENIS.js.map} +1 -1
  52. package/dist/chunks/{TokenManager-CZTL4OqZ.js → TokenManager-CWRL33UM.js} +2 -2
  53. package/dist/chunks/{TokenManager-CZTL4OqZ.js.map → TokenManager-CWRL33UM.js.map} +1 -1
  54. package/dist/chunks/{User-DRbw-wOB.js → User-BmS8zImI.js} +2 -2
  55. package/dist/chunks/{User-DRbw-wOB.js.map → User-BmS8zImI.js.map} +1 -1
  56. package/dist/chunks/{User-C6Tbn6vZ.js → User-CayBjzMG.js} +2 -2
  57. package/dist/chunks/{User-C6Tbn6vZ.js.map → User-CayBjzMG.js.map} +1 -1
  58. package/dist/chunks/{UserProfileView-CJKQNzSj.js → UserProfileView-B56WeGL1.js} +2 -2
  59. package/dist/chunks/{UserProfileView-CJKQNzSj.js.map → UserProfileView-B56WeGL1.js.map} +1 -1
  60. package/dist/chunks/{UserProfileView-AhUCUowp.js → UserProfileView-CrmACQjJ.js} +2 -2
  61. package/dist/chunks/{UserProfileView-AhUCUowp.js.map → UserProfileView-CrmACQjJ.js.map} +1 -1
  62. package/dist/chunks/{View-BWOE7WJm.js → View-IgBQlwd0.js} +2 -2
  63. package/dist/chunks/{View-BWOE7WJm.js.map → View-IgBQlwd0.js.map} +1 -1
  64. package/dist/chunks/{View-D6Ug7M6k.js → View-gAghvPMN.js} +2 -2
  65. package/dist/chunks/{View-D6Ug7M6k.js.map → View-gAghvPMN.js.map} +1 -1
  66. package/dist/chunks/{WebApp-By80XfTK.js → WebApp-B6wrmIaj.js} +2 -2
  67. package/dist/chunks/{WebApp-By80XfTK.js.map → WebApp-B6wrmIaj.js.map} +1 -1
  68. package/dist/chunks/{WebApp-CLTFSbto.js → WebApp-DeHPnmbD.js} +2 -2
  69. package/dist/chunks/{WebApp-CLTFSbto.js.map → WebApp-DeHPnmbD.js.map} +1 -1
  70. package/dist/chunks/{admin-D2CqCMaa.js → admin-D3DtCOgt.js} +2 -2
  71. package/dist/chunks/{admin-D2CqCMaa.js.map → admin-D3DtCOgt.js.map} +1 -1
  72. package/dist/chunks/{admin-Beq0Eckn.js → admin-oYYbqLlb.js} +2 -2
  73. package/dist/chunks/{admin-Beq0Eckn.js.map → admin-oYYbqLlb.js.map} +1 -1
  74. package/dist/chunks/{exportChart-DqydcfXz.js → exportChart-BK9mLt36.js} +2 -2
  75. package/dist/chunks/{exportChart-DqydcfXz.js.map → exportChart-BK9mLt36.js.map} +1 -1
  76. package/dist/chunks/{exportChart-Cn6owWxP.js → exportChart-mrfTf2Df.js} +2 -2
  77. package/dist/chunks/{exportChart-Cn6owWxP.js.map → exportChart-mrfTf2Df.js.map} +1 -1
  78. package/dist/chunks/{index-BKR6vFMH.js → index-DTXotoXw.js} +2 -2
  79. package/dist/chunks/{index-BKR6vFMH.js.map → index-DTXotoXw.js.map} +1 -1
  80. package/dist/chunks/{index-CMKYMKaH.js → index-NXnA6T-5.js} +2 -2
  81. package/dist/chunks/{index-CMKYMKaH.js.map → index-NXnA6T-5.js.map} +1 -1
  82. package/dist/chunks/{version-DQwtLRjN.js → version-Bpfg5FM3.js} +2 -2
  83. package/dist/chunks/{version-DQwtLRjN.js.map → version-Bpfg5FM3.js.map} +1 -1
  84. package/dist/chunks/{version-CBjwNXEK.js → version-CopJeO_u.js} +2 -2
  85. package/dist/chunks/{version-CBjwNXEK.js.map → version-CopJeO_u.js.map} +1 -1
  86. package/dist/css/web-mojo.css +1 -1
  87. package/dist/docit.cjs.js +1 -1
  88. package/dist/docit.es.js +1 -1
  89. package/dist/index.cjs.js +1 -1
  90. package/dist/index.cjs.js.map +1 -1
  91. package/dist/index.es.js +1 -1
  92. package/dist/index.es.js.map +1 -1
  93. package/dist/lightbox.cjs.js +1 -1
  94. package/dist/lightbox.es.js +1 -1
  95. package/dist/map.cjs.js +1 -1
  96. package/dist/map.es.js +1 -1
  97. package/dist/timeline.cjs.js +1 -1
  98. package/dist/timeline.es.js +1 -1
  99. package/dist/user-profile.cjs.js +1 -1
  100. package/dist/user-profile.es.js +1 -1
  101. package/dist/web-mojo.lite.iife.js +3507 -1562
  102. package/dist/web-mojo.lite.iife.js.map +1 -1
  103. package/dist/web-mojo.lite.iife.min.js +261 -327
  104. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  105. package/package.json +1 -1
  106. package/dist/chunks/FormView-C_7xQuI4.js +0 -3
  107. package/dist/chunks/FormView-C_7xQuI4.js.map +0 -1
  108. package/dist/chunks/FormView-D8YrH2V4.js +0 -3
  109. package/dist/chunks/FormView-D8YrH2V4.js.map +0 -1
@@ -1,2 +1,2 @@
1
- "use strict";const e=require("./Collection-CtSGTegm.js"),t=require("./Modal-DYJadSN8.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:r=null,trigger:i=!0}=t,{pageName:n,queryParams:o}=this.parseInput(e);i&&await this.handleRouteChange(n,o)}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,r=this.matchRoute(s),i=this.buildPublicUrl(e,t);return r?(this.currentRoute=r,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:i,pageName:r.pageName,params:r.params,query:t,route:r}),r):(this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:i}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const r={};return t.paramNames.forEach((e,t)=>{r[e]=s[t+1]}),{...t,params:r,path:e}}}return null}parseInput(e){let t=this.defaultRoute,s={};if(!e)return{pageName:t,queryParams:s};try{if(e.includes("?")){const[r,i]=e.split("?",2),n=new URLSearchParams(i);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[e,t]of n)"page"!==e&&(s[e]=t)}else{t=r.startsWith("/")?r.substring(1)||this.defaultRoute:r||this.defaultRoute;for(const[e,t]of n)s[e]=t}}else t=e.startsWith("/")?e.substring(1)||this.defaultRoute:e}catch(r){console.warn("Failed to parse input:",e,r),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[r,i]of e)"page"!==r&&(s[r]=i);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,r){const i=new URL(window.location.origin+window.location.pathname);i.searchParams.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&i.searchParams.set(e,String(t))});const n=i.toString();s?window.history.replaceState(r,"",n):window.history.pushState(r,"",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:r}=this.parseCurrentUrl();this.updateBrowserUrl(r,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:r}=this.parseInput(t);return s===r}}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(r){console.error(`Error in event listener for '${e}':`,r),this.emitError(r,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 r=s.map(s=>new Promise(r=>{try{r(s(t,e))}catch(i){console.error(`Error in async event listener for '${e}':`,i),this.emitError(i,e,s),r()}}));return await Promise.all(r),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,r)=>{try{const i=e(s,r);if(!1===i)return this;const n=void 0!==i?i:r;return t.call(this,s,n)}catch(i){return console.error("Error in event middleware:",i),t.call(this,s,r)}},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,r)=>{let i=null;const n=e=>{i&&clearTimeout(i),s(e)};this.once(e,n),t&&(i=setTimeout(()=>{this.off(e,n),r(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}}const s=["light","dark","system"];class ThemeManager{constructor({storageKey:e,eventBus:t}={}){this.storageKey=e||"mojo:theme",this.eventBus=t||null,this.preference="system",this.resolved="light",this._mediaQuery=null,this._mediaListener=null}init(){const e=this._readStored();return this.preference=s.includes(e)?e:"system",this._apply(!1),"system"===this.preference&&this._attachSystemListener(),this}getPreference(){return this.preference}getResolved(){return this.resolved}set(e){if(!s.includes(e))return console.warn(`ThemeManager: invalid preference "${e}" — expected 'light' | 'dark' | 'system'`),this;const t="system"===this.preference;return this.preference=e,this._writeStored(e),"system"===e?t||this._attachSystemListener():t&&this._detachSystemListener(),this._apply(!0),this}destroy(){this._detachSystemListener(),this.eventBus=null}_resolve(){return"light"===this.preference||"dark"===this.preference?this.preference:this._systemPrefersDark()?"dark":"light"}_apply(e){const t=this._resolve(),s=t!==this.resolved;this.resolved=t,"undefined"!=typeof document&&document.documentElement&&document.documentElement.setAttribute("data-bs-theme",t),(e&&s&&this.eventBus&&"function"==typeof this.eventBus.emit||e&&this.eventBus&&"function"==typeof this.eventBus.emit)&&this.eventBus.emit("theme:changed",{theme:this.preference,resolved:t})}_systemPrefersDark(){if("undefined"==typeof window||"function"!=typeof window.matchMedia)return!1;try{return window.matchMedia("(prefers-color-scheme: dark)").matches}catch{return!1}}_attachSystemListener(){if(!this._mediaQuery&&"undefined"!=typeof window&&"function"==typeof window.matchMedia){try{this._mediaQuery=window.matchMedia("(prefers-color-scheme: dark)")}catch{return void(this._mediaQuery=null)}this._mediaListener=()=>{"system"===this.preference&&this._apply(!0)},"function"==typeof this._mediaQuery.addEventListener?this._mediaQuery.addEventListener("change",this._mediaListener):"function"==typeof this._mediaQuery.addListener&&this._mediaQuery.addListener(this._mediaListener)}}_detachSystemListener(){if(!this._mediaQuery||!this._mediaListener)return this._mediaQuery=null,void(this._mediaListener=null);"function"==typeof this._mediaQuery.removeEventListener?this._mediaQuery.removeEventListener("change",this._mediaListener):"function"==typeof this._mediaQuery.removeListener&&this._mediaQuery.removeListener(this._mediaListener),this._mediaQuery=null,this._mediaListener=null}_readStored(){try{return"undefined"==typeof localStorage?null:localStorage.getItem(this.storageKey)}catch(e){return console.warn("ThemeManager: failed to read stored theme:",e),null}}_writeStored(e){try{if("undefined"==typeof localStorage)return;localStorage.setItem(this.storageKey,e)}catch(t){console.warn("ThemeManager: failed to persist theme:",t)}}}class WebApp{constructor(s={}){this.config=s,this.initPluginRegistry(),this.name=s.name||"MOJO App",this.version=s.version||"1.0.0",this.debug=s.debug||!1,this.container=s.container||"#app",this.layoutType=s.layout||"portal",this.layoutConfig=s.layoutConfig||{},s.sidebar&&(this.layoutConfig.sidebarConfig=s.sidebar),s.topbar&&(this.layoutConfig.topbarConfig=s.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=s.pageContainer||"#page-container",this.basePath=s.basePath||"",this.routerMode=s.routerMode||s.router?.mode||"param",this.basePath=s.basePath||s.router?.base||"",this.defaultRoute=s.defaultRoute||"home",this.session=s.session||{},this.router=null,this.navigation=s.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new EventBus,this.rest=e.rest,this.modal=t.Modal,s.api&&this.rest.configure(s.api);const r=(this.name||"mojo").replace(/\s+/g,"_").toLowerCase();this.theme=new ThemeManager({storageKey:`${r}:theme`,eventBus:this.events}),this.theme.init(),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:r}=e;await this.showPage(t,r,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:r}=t;return r?r.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:r}=t;try{const t=new s({pageName:e,...r,app:this});return r.route&&(t.route=r.route),this.pageCache.set(e,t),t.route,t}catch(i){return console.error(`Failed to create page ${e}:`,i),null}}async showPage(e,t={},s={},r={}){const{fromRouter:i=!1,replace:n=!1,force:o=!1}=r;try{let r,n;"string"==typeof e?(n=e,r=this.getOrCreatePage(e)):e&&"object"==typeof e&&(r=e,n=e.pageName);const o=this.currentPage;if(!r)return void this._show404(n,s,t,i);if(this.events.emit("page:showing",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),!r.canEnter())return void this._showDeniedPage(r,s,t,i);o&&o!==r&&await this._exitOldPage(o),await r.onParams(s,t),o!==r&&await r.onEnter(),r.syncUrl(),this.events.emit("page:show",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),await r.render(),this.currentPage=r,r.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:i})}}async _show404(e,t,s,r){const i=this.getOrCreatePage("404");i&&(i.setInfo&&i.setInfo(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:r}))}async _showDeniedPage(e,t,s,r){const i=this.getOrCreatePage("denied");i.setDeniedPage&&i.setDeniedPage(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:denied",{page:e,pageName:e.pageName,params:t,query:s,fromRouter:r})}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 r=e;if(Object.keys(t).length>0){const s=new URLSearchParams(t).toString();r+=(e.includes("?")?"&":"?")+s}return await this.router.navigate(r,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 t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Error",{size:"md",type:"error"})}catch(t){this.events.emit("notification",{message:e,type:"error"}),"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showError fallback:",t),"undefined"!=typeof window&&alert(`Error: ${e}`)}}async showSuccess(e){try{const t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Success",{size:"md",type:"success"})}catch(t){this.events.emit("notification",{message:e,type:"success"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showSuccess fallback:",t),"undefined"!=typeof window&&alert(`Success: ${e}`)}}async showInfo(e){try{const t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Information",{size:"md",type:"info"})}catch(t){this.events.emit("notification",{message:e,type:"info"}),"undefined"!=typeof window&&window,"undefined"!=typeof window&&alert(`Info: ${e}`)}}async showWarning(e){try{const t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Warning",{size:"md",type:"warning"})}catch(t){this.events.emit("notification",{message:e,type:"warning"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showWarning fallback:",t),"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(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default.showBusy(e)}catch(t){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showLoading fallback:",t,e),this.events.emit("notification",{message:e.message||"Loading...",type:"info"})}}async hideLoading(){try{(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default.hideBusy()}catch(e){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelView(e,t={}){try{const s=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;return await s.showModelView(e,t)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showModelForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;return await t.modelForm(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",t),t}}async showForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;return await t.form(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showForm failed:",t),t}}async showDialog(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;return await t.dialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async showAlert(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;return await t.dialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async confirm(e,t="Confirm",s={}){const r=(await Promise.resolve().then(()=>require("./Modal-DYJadSN8.js")).then(e=>e.Modal$1)).default;return await r.confirm(e,t,s)}setTheme(e){return this.theme.set(e),this}getTheme(){return this.theme.getPreference()}getResolvedTheme(){return this.theme.getResolved()}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 r=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(e=>{"string"!=typeof t[e]&&"number"!=typeof t[e]||(r=r.replace(`:${e}`,t[e]))}),s&&Object.keys(s).length>0){const e=new URLSearchParams(s).toString();r+=(r.includes("?")?"&":"?")+e}return r}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)}}exports.EventBus=EventBus,exports.Router=Router,exports.WebApp=WebApp;
2
- //# sourceMappingURL=WebApp-By80XfTK.js.map
1
+ "use strict";const e=require("./Collection-7F3lsq4z.js"),t=require("./Modal-BRKy85bz.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:r=null,trigger:i=!0}=t,{pageName:n,queryParams:o}=this.parseInput(e);i&&await this.handleRouteChange(n,o)}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,r=this.matchRoute(s),i=this.buildPublicUrl(e,t);return r?(this.currentRoute=r,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:i,pageName:r.pageName,params:r.params,query:t,route:r}),r):(this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:i}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const r={};return t.paramNames.forEach((e,t)=>{r[e]=s[t+1]}),{...t,params:r,path:e}}}return null}parseInput(e){let t=this.defaultRoute,s={};if(!e)return{pageName:t,queryParams:s};try{if(e.includes("?")){const[r,i]=e.split("?",2),n=new URLSearchParams(i);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[e,t]of n)"page"!==e&&(s[e]=t)}else{t=r.startsWith("/")?r.substring(1)||this.defaultRoute:r||this.defaultRoute;for(const[e,t]of n)s[e]=t}}else t=e.startsWith("/")?e.substring(1)||this.defaultRoute:e}catch(r){console.warn("Failed to parse input:",e,r),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[r,i]of e)"page"!==r&&(s[r]=i);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,r){const i=new URL(window.location.origin+window.location.pathname);i.searchParams.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&i.searchParams.set(e,String(t))});const n=i.toString();s?window.history.replaceState(r,"",n):window.history.pushState(r,"",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:r}=this.parseCurrentUrl();this.updateBrowserUrl(r,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:r}=this.parseInput(t);return s===r}}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(r){console.error(`Error in event listener for '${e}':`,r),this.emitError(r,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 r=s.map(s=>new Promise(r=>{try{r(s(t,e))}catch(i){console.error(`Error in async event listener for '${e}':`,i),this.emitError(i,e,s),r()}}));return await Promise.all(r),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,r)=>{try{const i=e(s,r);if(!1===i)return this;const n=void 0!==i?i:r;return t.call(this,s,n)}catch(i){return console.error("Error in event middleware:",i),t.call(this,s,r)}},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,r)=>{let i=null;const n=e=>{i&&clearTimeout(i),s(e)};this.once(e,n),t&&(i=setTimeout(()=>{this.off(e,n),r(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}}const s=["light","dark","system"];class ThemeManager{constructor({storageKey:e,eventBus:t}={}){this.storageKey=e||"mojo:theme",this.eventBus=t||null,this.preference="system",this.resolved="light",this._mediaQuery=null,this._mediaListener=null}init(){const e=this._readStored();return this.preference=s.includes(e)?e:"system",this._apply(!1),"system"===this.preference&&this._attachSystemListener(),this}getPreference(){return this.preference}getResolved(){return this.resolved}set(e){if(!s.includes(e))return console.warn(`ThemeManager: invalid preference "${e}" — expected 'light' | 'dark' | 'system'`),this;const t="system"===this.preference;return this.preference=e,this._writeStored(e),"system"===e?t||this._attachSystemListener():t&&this._detachSystemListener(),this._apply(!0),this}destroy(){this._detachSystemListener(),this.eventBus=null}_resolve(){return"light"===this.preference||"dark"===this.preference?this.preference:this._systemPrefersDark()?"dark":"light"}_apply(e){const t=this._resolve(),s=t!==this.resolved;this.resolved=t,"undefined"!=typeof document&&document.documentElement&&document.documentElement.setAttribute("data-bs-theme",t),(e&&s&&this.eventBus&&"function"==typeof this.eventBus.emit||e&&this.eventBus&&"function"==typeof this.eventBus.emit)&&this.eventBus.emit("theme:changed",{theme:this.preference,resolved:t})}_systemPrefersDark(){if("undefined"==typeof window||"function"!=typeof window.matchMedia)return!1;try{return window.matchMedia("(prefers-color-scheme: dark)").matches}catch{return!1}}_attachSystemListener(){if(!this._mediaQuery&&"undefined"!=typeof window&&"function"==typeof window.matchMedia){try{this._mediaQuery=window.matchMedia("(prefers-color-scheme: dark)")}catch{return void(this._mediaQuery=null)}this._mediaListener=()=>{"system"===this.preference&&this._apply(!0)},"function"==typeof this._mediaQuery.addEventListener?this._mediaQuery.addEventListener("change",this._mediaListener):"function"==typeof this._mediaQuery.addListener&&this._mediaQuery.addListener(this._mediaListener)}}_detachSystemListener(){if(!this._mediaQuery||!this._mediaListener)return this._mediaQuery=null,void(this._mediaListener=null);"function"==typeof this._mediaQuery.removeEventListener?this._mediaQuery.removeEventListener("change",this._mediaListener):"function"==typeof this._mediaQuery.removeListener&&this._mediaQuery.removeListener(this._mediaListener),this._mediaQuery=null,this._mediaListener=null}_readStored(){try{return"undefined"==typeof localStorage?null:localStorage.getItem(this.storageKey)}catch(e){return console.warn("ThemeManager: failed to read stored theme:",e),null}}_writeStored(e){try{if("undefined"==typeof localStorage)return;localStorage.setItem(this.storageKey,e)}catch(t){console.warn("ThemeManager: failed to persist theme:",t)}}}class WebApp{constructor(s={}){this.config=s,this.initPluginRegistry(),this.name=s.name||"MOJO App",this.version=s.version||"1.0.0",this.debug=s.debug||!1,this.container=s.container||"#app",this.layoutType=s.layout||"portal",this.layoutConfig=s.layoutConfig||{},s.sidebar&&(this.layoutConfig.sidebarConfig=s.sidebar),s.topbar&&(this.layoutConfig.topbarConfig=s.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=s.pageContainer||"#page-container",this.basePath=s.basePath||"",this.routerMode=s.routerMode||s.router?.mode||"param",this.basePath=s.basePath||s.router?.base||"",this.defaultRoute=s.defaultRoute||"home",this.session=s.session||{},this.router=null,this.navigation=s.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new EventBus,this.rest=e.rest,this.modal=t.Modal,s.api&&this.rest.configure(s.api);const r=(this.name||"mojo").replace(/\s+/g,"_").toLowerCase();this.theme=new ThemeManager({storageKey:`${r}:theme`,eventBus:this.events}),this.theme.init(),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:r}=e;await this.showPage(t,r,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:r}=t;return r?r.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:r}=t;try{const t=new s({pageName:e,...r,app:this});return r.route&&(t.route=r.route),this.pageCache.set(e,t),t.route,t}catch(i){return console.error(`Failed to create page ${e}:`,i),null}}async showPage(e,t={},s={},r={}){const{fromRouter:i=!1,replace:n=!1,force:o=!1}=r;try{let r,n;"string"==typeof e?(n=e,r=this.getOrCreatePage(e)):e&&"object"==typeof e&&(r=e,n=e.pageName);const o=this.currentPage;if(!r)return void this._show404(n,s,t,i);if(this.events.emit("page:showing",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),!r.canEnter())return void this._showDeniedPage(r,s,t,i);o&&o!==r&&await this._exitOldPage(o),await r.onParams(s,t),o!==r&&await r.onEnter(),r.syncUrl(),this.events.emit("page:show",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),await r.render(),this.currentPage=r,r.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:i})}}async _show404(e,t,s,r){const i=this.getOrCreatePage("404");i&&(i.setInfo&&i.setInfo(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:r}))}async _showDeniedPage(e,t,s,r){const i=this.getOrCreatePage("denied");i.setDeniedPage&&i.setDeniedPage(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:denied",{page:e,pageName:e.pageName,params:t,query:s,fromRouter:r})}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 r=e;if(Object.keys(t).length>0){const s=new URLSearchParams(t).toString();r+=(e.includes("?")?"&":"?")+s}return await this.router.navigate(r,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 t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Error",{size:"md",type:"error"})}catch(t){this.events.emit("notification",{message:e,type:"error"}),"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showError fallback:",t),"undefined"!=typeof window&&alert(`Error: ${e}`)}}async showSuccess(e){try{const t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Success",{size:"md",type:"success"})}catch(t){this.events.emit("notification",{message:e,type:"success"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showSuccess fallback:",t),"undefined"!=typeof window&&alert(`Success: ${e}`)}}async showInfo(e){try{const t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Information",{size:"md",type:"info"})}catch(t){this.events.emit("notification",{message:e,type:"info"}),"undefined"!=typeof window&&window,"undefined"!=typeof window&&alert(`Info: ${e}`)}}async showWarning(e){try{const t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;await t.alert(e,"Warning",{size:"md",type:"warning"})}catch(t){this.events.emit("notification",{message:e,type:"warning"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showWarning fallback:",t),"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(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default.showBusy(e)}catch(t){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showLoading fallback:",t,e),this.events.emit("notification",{message:e.message||"Loading...",type:"info"})}}async hideLoading(){try{(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default.hideBusy()}catch(e){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelView(e,t={}){try{const s=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;return await s.showModelView(e,t)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showModelForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;return await t.modelForm(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",t),t}}async showForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;return await t.form(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showForm failed:",t),t}}async showDialog(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;return await t.dialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async showAlert(e={}){try{const t=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;return await t.dialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async confirm(e,t="Confirm",s={}){const r=(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default;return await r.confirm(e,t,s)}setTheme(e){return this.theme.set(e),this}getTheme(){return this.theme.getPreference()}getResolvedTheme(){return this.theme.getResolved()}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 r=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(e=>{"string"!=typeof t[e]&&"number"!=typeof t[e]||(r=r.replace(`:${e}`,t[e]))}),s&&Object.keys(s).length>0){const e=new URLSearchParams(s).toString();r+=(r.includes("?")?"&":"?")+e}return r}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)}}exports.EventBus=EventBus,exports.Router=Router,exports.WebApp=WebApp;
2
+ //# sourceMappingURL=WebApp-B6wrmIaj.js.map