web-mojo 2.6.4 → 2.7.0

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 (114) hide show
  1. package/CHANGELOG.md +26 -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/ChatView-B76p_4u8.js +2 -0
  11. package/dist/chunks/ChatView-B76p_4u8.js.map +1 -0
  12. package/dist/chunks/ChatView-CC4SaAGA.js +2 -0
  13. package/dist/chunks/ChatView-CC4SaAGA.js.map +1 -0
  14. package/dist/chunks/{ContextMenu-3_bOvSwa.js → ContextMenu-B6u-y5X8.js} +2 -2
  15. package/dist/chunks/ContextMenu-B6u-y5X8.js.map +1 -0
  16. package/dist/chunks/{ContextMenu-xjj8Quls.js → ContextMenu-DkIc9twn.js} +2 -2
  17. package/dist/chunks/ContextMenu-DkIc9twn.js.map +1 -0
  18. package/dist/chunks/{DataView-CdyrhKrD.js → DataView-CnbbvE5S.js} +2 -2
  19. package/dist/chunks/{DataView-CdyrhKrD.js.map → DataView-CnbbvE5S.js.map} +1 -1
  20. package/dist/chunks/{DataView-B7XoPBZd.js → DataView-CvXW1Ewe.js} +2 -2
  21. package/dist/chunks/{DataView-B7XoPBZd.js.map → DataView-CvXW1Ewe.js.map} +1 -1
  22. package/dist/chunks/FormView-BMjKplJy.js +2 -0
  23. package/dist/chunks/FormView-BMjKplJy.js.map +1 -0
  24. package/dist/chunks/FormView-geCsNsn1.js +2 -0
  25. package/dist/chunks/FormView-geCsNsn1.js.map +1 -0
  26. package/dist/chunks/ListView-B6cE3WKB.js +2 -0
  27. package/dist/chunks/ListView-B6cE3WKB.js.map +1 -0
  28. package/dist/chunks/ListView-DXfD53sU.js +2 -0
  29. package/dist/chunks/ListView-DXfD53sU.js.map +1 -0
  30. package/dist/chunks/{MetricsCountryMapView-9e2t5sfH.js → MetricsCountryMapView-BuFNN1Ey.js} +2 -2
  31. package/dist/chunks/{MetricsCountryMapView-9e2t5sfH.js.map → MetricsCountryMapView-BuFNN1Ey.js.map} +1 -1
  32. package/dist/chunks/{MetricsCountryMapView-ki6auFBe.js → MetricsCountryMapView-Dse3HsUv.js} +2 -2
  33. package/dist/chunks/{MetricsCountryMapView-ki6auFBe.js.map → MetricsCountryMapView-Dse3HsUv.js.map} +1 -1
  34. package/dist/chunks/{Modal-Bbn-54-6.js → Modal-BmXvplWi.js} +3 -3
  35. package/dist/chunks/Modal-BmXvplWi.js.map +1 -0
  36. package/dist/chunks/{Modal-BRmaTaWa.js → Modal-DRrfsnNP.js} +3 -3
  37. package/dist/chunks/Modal-DRrfsnNP.js.map +1 -0
  38. package/dist/chunks/Passkeys-D2LFSJpQ.js +2 -0
  39. package/dist/chunks/Passkeys-D2LFSJpQ.js.map +1 -0
  40. package/dist/chunks/Passkeys-vneS9ywK.js +2 -0
  41. package/dist/chunks/Passkeys-vneS9ywK.js.map +1 -0
  42. package/dist/chunks/{TokenManager-qlmZ7eW3.js → TokenManager-DBwv-cF4.js} +2 -2
  43. package/dist/chunks/{TokenManager-qlmZ7eW3.js.map → TokenManager-DBwv-cF4.js.map} +1 -1
  44. package/dist/chunks/{TokenManager-BkW1MQ1m.js → TokenManager-DXtiygmr.js} +2 -2
  45. package/dist/chunks/{TokenManager-BkW1MQ1m.js.map → TokenManager-DXtiygmr.js.map} +1 -1
  46. package/dist/chunks/User-DJHaSCL9.js +2 -0
  47. package/dist/chunks/User-DJHaSCL9.js.map +1 -0
  48. package/dist/chunks/User-ao-iRfPc.js +2 -0
  49. package/dist/chunks/User-ao-iRfPc.js.map +1 -0
  50. package/dist/chunks/{UserProfileView-Dbei45vn.js → UserProfileView-DRpHVJtE.js} +2 -2
  51. package/dist/chunks/{UserProfileView-Dbei45vn.js.map → UserProfileView-DRpHVJtE.js.map} +1 -1
  52. package/dist/chunks/{UserProfileView-OcqSynHt.js → UserProfileView-DtIBSw3O.js} +2 -2
  53. package/dist/chunks/{UserProfileView-OcqSynHt.js.map → UserProfileView-DtIBSw3O.js.map} +1 -1
  54. package/dist/chunks/{WebApp-CIhrSvuV.js → WebApp-7COAyECf.js} +2 -2
  55. package/dist/chunks/{WebApp-CIhrSvuV.js.map → WebApp-7COAyECf.js.map} +1 -1
  56. package/dist/chunks/{WebApp-DAviV-_c.js → WebApp-CSvy-GUm.js} +2 -2
  57. package/dist/chunks/{WebApp-DAviV-_c.js.map → WebApp-CSvy-GUm.js.map} +1 -1
  58. package/dist/chunks/{admin-models-BBmATRhV.js → admin-models-DHXtrq87.js} +2 -2
  59. package/dist/chunks/{admin-models-BBmATRhV.js.map → admin-models-DHXtrq87.js.map} +1 -1
  60. package/dist/chunks/{admin-models-C-SHgZGn.js → admin-models-vhiH86Tq.js} +2 -2
  61. package/dist/chunks/{admin-models-C-SHgZGn.js.map → admin-models-vhiH86Tq.js.map} +1 -1
  62. package/dist/chunks/{exportChart-2I2hxr7t.js → exportChart-B1pjkCdm.js} +2 -2
  63. package/dist/chunks/{exportChart-2I2hxr7t.js.map → exportChart-B1pjkCdm.js.map} +1 -1
  64. package/dist/chunks/{exportChart-B5optjiT.js → exportChart-Vq4_f06o.js} +2 -2
  65. package/dist/chunks/{exportChart-B5optjiT.js.map → exportChart-Vq4_f06o.js.map} +1 -1
  66. package/dist/chunks/{index-B543iMCu.js → index-Bj5AxsEG.js} +2 -2
  67. package/dist/chunks/{index-B543iMCu.js.map → index-Bj5AxsEG.js.map} +1 -1
  68. package/dist/chunks/{index-C6reyIyu.js → index-DrmdnYWO.js} +2 -2
  69. package/dist/chunks/{index-C6reyIyu.js.map → index-DrmdnYWO.js.map} +1 -1
  70. package/dist/chunks/{version-D_d_sDRM.js → version-CSb8B3nS.js} +2 -2
  71. package/dist/chunks/{version-D_d_sDRM.js.map → version-CSb8B3nS.js.map} +1 -1
  72. package/dist/chunks/{version-DWWDfVB9.js → version-_kAV0pF7.js} +2 -2
  73. package/dist/chunks/{version-DWWDfVB9.js.map → version-_kAV0pF7.js.map} +1 -1
  74. package/dist/docit.cjs.js +1 -1
  75. package/dist/docit.es.js +1 -1
  76. package/dist/index.cjs.js +1 -1
  77. package/dist/index.es.js +1 -1
  78. package/dist/lightbox.cjs.js +1 -1
  79. package/dist/lightbox.es.js +1 -1
  80. package/dist/map.cjs.js +1 -1
  81. package/dist/map.es.js +1 -1
  82. package/dist/timeline.cjs.js +1 -1
  83. package/dist/timeline.es.js +1 -1
  84. package/dist/user-profile.cjs.js +1 -1
  85. package/dist/user-profile.es.js +1 -1
  86. package/dist/web-mojo.lite.iife.js +1406 -43
  87. package/dist/web-mojo.lite.iife.js.map +1 -1
  88. package/dist/web-mojo.lite.iife.min.js +336 -95
  89. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  90. package/package.json +1 -1
  91. package/dist/chunks/ChatView-C1Vc-P_O.js +0 -2
  92. package/dist/chunks/ChatView-C1Vc-P_O.js.map +0 -1
  93. package/dist/chunks/ChatView-Cv6kH3MO.js +0 -2
  94. package/dist/chunks/ChatView-Cv6kH3MO.js.map +0 -1
  95. package/dist/chunks/ContextMenu-3_bOvSwa.js.map +0 -1
  96. package/dist/chunks/ContextMenu-xjj8Quls.js.map +0 -1
  97. package/dist/chunks/FormView-BE4qZvNA.js +0 -2
  98. package/dist/chunks/FormView-BE4qZvNA.js.map +0 -1
  99. package/dist/chunks/FormView-BqR4x5nz.js +0 -2
  100. package/dist/chunks/FormView-BqR4x5nz.js.map +0 -1
  101. package/dist/chunks/ListView-BF442PdR.js +0 -2
  102. package/dist/chunks/ListView-BF442PdR.js.map +0 -1
  103. package/dist/chunks/ListView-DqfZmgXS.js +0 -2
  104. package/dist/chunks/ListView-DqfZmgXS.js.map +0 -1
  105. package/dist/chunks/Modal-BRmaTaWa.js.map +0 -1
  106. package/dist/chunks/Modal-Bbn-54-6.js.map +0 -1
  107. package/dist/chunks/Passkeys-B_bxdIVa.js +0 -2
  108. package/dist/chunks/Passkeys-B_bxdIVa.js.map +0 -1
  109. package/dist/chunks/Passkeys-LRaiCx3H.js +0 -2
  110. package/dist/chunks/Passkeys-LRaiCx3H.js.map +0 -1
  111. package/dist/chunks/User-B7jwnBx2.js +0 -2
  112. package/dist/chunks/User-B7jwnBx2.js.map +0 -1
  113. package/dist/chunks/User-Dbw_wZAz.js +0 -2
  114. package/dist/chunks/User-Dbw_wZAz.js.map +0 -1
@@ -1,4 +1,4 @@
1
- var MOJO=(function(T){"use strict";class Te{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:r=!0}=t,{pageName:n,queryParams:a}=this.parseInput(e);r&&await this.handleRouteChange(n,a)}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),r=this.buildPublicUrl(e,t);return i?(this.currentRoute=i,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:r,pageName:i.pageName,params:i.params,query:t,route:i}),i):(console.log("No route matched for page:",e),this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:r}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const i={};return t.paramNames.forEach((r,n)=>{i[r]=s[n+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,r]=e.split("?",2),n=new URLSearchParams(r);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[a,o]of n)a!=="page"&&(s[a]=o)}else{i.startsWith("/")?t=i.substring(1)||this.defaultRoute:t=i||this.defaultRoute;for(const[a,o]of n)s[a]=o}}else e.startsWith("/")?t=e.substring(1)||this.defaultRoute:t=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,r]of e)i!=="page"&&(s[i]=r);return{pageName:t,queryParams:s}}buildPublicUrl(e,t={}){const s=new URLSearchParams;return s.set("page",e),Object.entries(t).forEach(([i,r])=>{r!=null&&r!==""&&s.set(i,String(r))}),"?"+s.toString()}updateBrowserUrl(e,t,s,i){const r=new URL(window.location.origin+window.location.pathname);r.searchParams.set("page",e),Object.entries(t).forEach(([a,o])=>{o!=null&&o!==""&&r.searchParams.set(a,String(o))});const n=r.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(s=>s.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 Vt{constructor(){this.listeners={},this.onceListeners={},this.maxListeners=100,this.debugMode=!1,this.eventStats={}}on(e,t){if(typeof t!="function")throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(s=>this.on(s,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(typeof t!="function")throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(s=>this.once(s,t)),this):(this.onceListeners[e]||(this.onceListeners[e]=[]),this.onceListeners[e].push(t),this)}off(e,t){if(Array.isArray(e))return e.forEach(s=>this.off(s,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);s!==-1&&(this.listeners[e].splice(s,1),this.listeners[e].length===0&&delete this.listeners[e])}if(this.onceListeners[e]){const s=this.onceListeners[e].indexOf(t);s!==-1&&(this.onceListeners[e].splice(s,1),this.onceListeners[e].length===0&&delete this.onceListeners[e])}return this}emit(e,t){this.updateEventStats(e),this.debugMode&&console.log(`[EventBus] Emitting: ${e}`,t);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&&console.log(`[EventBus] ${s.length} listener(s) for '${e}'`),s.forEach(i=>{try{i(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,i)}}),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(r=>new Promise(n=>{try{const a=r(t,e);n(a)}catch(a){console.error(`Error in async event listener for '${e}':`,a),this.emitError(a,e,r),n()}}));return await Promise.all(i),this}removeAllListeners(){return this.listeners={},this.onceListeners={},this}listenerCount(e){const t=this.listeners[e]?this.listeners[e].length:0,s=this.onceListeners[e]?this.onceListeners[e].length:0;return t+s}eventNames(){const e=Object.keys(this.listeners),t=Object.keys(this.onceListeners);return[...new Set([...e,...t])]}setMaxListeners(e){if(typeof e!="number"||e<0)throw new Error("Max listeners must be a non-negative number");return this.maxListeners=e,this}namespace(e){const t=s=>`${e}:${s}`;return{on:(s,i)=>this.on(t(s),i),once:(s,i)=>this.once(t(s),i),off:(s,i)=>this.off(t(s),i),emit:(s,i)=>this.emit(t(s),i),emitAsync:(s,i)=>this.emitAsync(t(s),i)}}use(e){if(typeof e!="function")throw new Error("Middleware must be a function");const t=this.emit;return this.emit=(s,i)=>{try{const r=e(s,i);if(r===!1)return this;const n=r!==void 0?r:i;return t.call(this,s,n)}catch(r){return console.error("Error in event middleware:",r),t.call(this,s,i)}},this}emitError(e,t,s){t!=="error"&&setTimeout(()=>{this.emit("error",{error:e,originalEvent:t,callback:s.toString()})},0)}waitFor(e,t=null){return new Promise((s,i)=>{let r=null;const n=()=>{r&&clearTimeout(r)},a=o=>{n(),s(o)};this.once(e,a),t&&(r=setTimeout(()=>{this.off(e,a),i(new Error(`Timeout waiting for event: ${e}`))},t))})}debug(e=!0){return this.debugMode=e,console.log(e?"[EventBus] Debug mode enabled":"[EventBus] Debug mode disabled"),this}getStats(){const e=this.eventNames(),t={totalEvents:e.length,totalListeners:0,events:{},emissions:{...this.eventStats}};return e.forEach(s=>{const i=this.listenerCount(s);t.events[s]=i,t.totalListeners+=i}),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(t===0)return 0;const s=t/(1e3*60);return Math.round(e.count/s*100)/100}resetStats(){return this.eventStats={},this}getTopEvents(e=10){return Object.entries(this.eventStats).map(([t,s])=>({event:t,count:s.count,rate:this.calculateEmissionRate(s),listeners:this.listenerCount(t)})).sort((t,s)=>s.count-t.count).slice(0,e)}debugInfo(){console.group("[EventBus] Debug Information"),console.log("Debug Mode:",this.debugMode),console.log("Max Listeners:",this.maxListeners);const e=this.getStats();return console.log("Total Events:",e.totalEvents),console.log("Total Listeners:",e.totalListeners),Object.keys(this.eventStats).length>0&&console.log("Top Events:",this.getTopEvents(5)),console.groupEnd(),this}}const Ke=["light","dark","system"];class Nt{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=Ke.includes(e)?e:"system",this._apply(!1),this.preference==="system"&&this._attachSystemListener(),this}getPreference(){return this.preference}getResolved(){return this.resolved}set(e){if(!Ke.includes(e))return console.warn(`ThemeManager: invalid preference "${e}" — expected 'light' | 'dark' | 'system'`),this;const t=this.preference==="system";return this.preference=e,this._writeStored(e),e==="system"?t||this._attachSystemListener():t&&this._detachSystemListener(),this._apply(!0),this}destroy(){this._detachSystemListener(),this.eventBus=null}_resolve(){return this.preference==="light"||this.preference==="dark"?this.preference:this._systemPrefersDark()?"dark":"light"}_apply(e){const t=this._resolve(),s=t!==this.resolved;this.resolved=t,typeof document<"u"&&document.documentElement&&document.documentElement.setAttribute("data-bs-theme",t),e&&s&&this.eventBus&&typeof this.eventBus.emit=="function"?this.eventBus.emit("theme:changed",{theme:this.preference,resolved:t}):e&&this.eventBus&&typeof this.eventBus.emit=="function"&&this.eventBus.emit("theme:changed",{theme:this.preference,resolved:t})}_systemPrefersDark(){if(typeof window>"u"||typeof window.matchMedia!="function")return!1;try{return window.matchMedia("(prefers-color-scheme: dark)").matches}catch{return!1}}_attachSystemListener(){if(!(this._mediaQuery||typeof window>"u"||typeof window.matchMedia!="function")){try{this._mediaQuery=window.matchMedia("(prefers-color-scheme: dark)")}catch{this._mediaQuery=null;return}this._mediaListener=()=>{this.preference==="system"&&this._apply(!0)},typeof this._mediaQuery.addEventListener=="function"?this._mediaQuery.addEventListener("change",this._mediaListener):typeof this._mediaQuery.addListener=="function"&&this._mediaQuery.addListener(this._mediaListener)}}_detachSystemListener(){if(!this._mediaQuery||!this._mediaListener){this._mediaQuery=null,this._mediaListener=null;return}typeof this._mediaQuery.removeEventListener=="function"?this._mediaQuery.removeEventListener("change",this._mediaListener):typeof this._mediaQuery.removeListener=="function"&&this._mediaQuery.removeListener(this._mediaListener),this._mediaQuery=null,this._mediaListener=null}_readStored(){try{return typeof localStorage>"u"?null:localStorage.getItem(this.storageKey)}catch(e){return console.warn("ThemeManager: failed to read stored theme:",e),null}}_writeStored(e){try{if(typeof localStorage>"u")return;localStorage.setItem(this.storageKey,e)}catch(t){console.warn("ThemeManager: failed to persist theme:",t)}}}class Ot{constructor(){this.config={baseURL:"",timeout:3e4,headers:{"Content-Type":"application/json",Accept:"application/json"},trackDevice:!0,duidHeader:"X-Mojo-UID",duidTransport:"header"},this.interceptors={request:[],response:[]},this.duid=null,this.config.trackDevice&&this._initializeDuid()}_initializeDuid(){const e="mojo_device_uid";try{let t=localStorage.getItem(e);t?this.duid=t:(this.duid=this._generateDuid(),localStorage.setItem(e,this.duid))}catch(t){console.error("Could not access localStorage to get/set DUID.",t),this.duid=this._generateDuid()}}_generateDuid(){return crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}configure(e){e.baseUrl&&(e.baseURL=e.baseUrl);const t=this.config.trackDevice;this.config={...this.config,...e,headers:{...this.config.headers,...e.headers}},this.config.trackDevice&&!t&&this._initializeDuid()}addInterceptor(e,t){this.interceptors[e]&&this.interceptors[e].push(t)}buildUrl(e){if(e.startsWith("http://")||e.startsWith("https://"))return e;const t=this.config.baseURL.endsWith("/")?this.config.baseURL.slice(0,-1):this.config.baseURL,s=e.startsWith("/")?e:`/${e}`;return`${t}${s}`}categorizeError(e,t=0){if(e.name==="TypeError"&&e.message.includes("fetch"))return{reason:"not_reachable",message:"Service is not reachable - please check your connection"};if(e.name==="AbortError")return{reason:"cancelled",message:"Request was cancelled"};if(e.name==="TimeoutError"||e.message.includes("timeout"))return{reason:"timed_out",message:"Request timed out - please try again"};if(t>=400){if(t===400)return{reason:"bad_request",message:"Invalid request data"};if(t===401)return{reason:"unauthorized",message:"Authentication required"};if(t===403)return{reason:"forbidden",message:"Access denied"};if(t===404)return{reason:"not_found",message:"Resource not found"};if(t===409)return{reason:"conflict",message:"Resource conflict"};if(t===422)return{reason:"validation_error",message:"Validation failed"};if(t===429)return{reason:"rate_limited",message:"Too many requests - please wait"};if(t>=500)return{reason:"server_error",message:"Server error - please try again later"};if(t>=400)return{reason:"client_error",message:"Request error"}}return e.message.includes("CORS")?{reason:"cors_error",message:"Cross-origin request blocked"}:e.message.includes("DNS")||e.message.includes("ENOTFOUND")?{reason:"dns_error",message:"Unable to resolve server address"}:{reason:"unknown_error",message:`Network error: ${e.message}`}}buildQueryString(e={}){const t=new URLSearchParams;Object.entries(e).forEach(([i,r])=>{r!=null&&(Array.isArray(r)?r.forEach(n=>t.append(`${i}[]`,n)):t.append(i,r))});const s=t.toString();return s?`?${s}`:""}async processRequestInterceptors(e){let t={...e};for(const s of this.interceptors.request)try{t=await s(t)}catch(i){throw console.error("Request interceptor error:",i),i}return t}async processResponseInterceptors(e,t){let s={success:e.ok,status:e.status,statusText:e.statusText,headers:Object.fromEntries(e.headers.entries()),data:null,errors:null,message:null,reason:null};try{const i=e.headers.get("content-type");if(i&&i.includes("application/json")){const r=await e.json();if(s.data=r,!e.ok){const n=this.categorizeError(new Error("HTTP Error"),e.status);s.errors=r.errors||{},s.message=r.message||n.message,s.reason=n.reason}}else if(s.data=await e.text(),!e.ok){const r=this.categorizeError(new Error("HTTP Error"),e.status);s.message=r.message,s.reason=r.reason}}catch{s.errors={parse:"Failed to parse response"},s.message="Invalid response format"}for(const i of this.interceptors.response)try{s=await i(s,t)}catch(r){console.error("Response interceptor error:",r)}return s}async request(e,t,s=null,i={},r={}){let n={method:e.toUpperCase(),url:this.buildUrl(t)+this.buildQueryString(i),headers:{...this.config.headers,...r.headers},data:s,options:{timeout:this.config.timeout,...r}};try{n=await this.processRequestInterceptors(n)}catch(l){if(l.name==="AuthRequiredError")return{success:!1,status:401,statusText:"Unauthorized",headers:{},data:null,errors:{auth:l.message},message:"Authentication required",reason:"unauthorized"};throw l}if(this.config.trackDevice&&this.duid)if(this.config.duidTransport==="header")n.headers[this.config.duidHeader]=this.duid;else if(n.method==="GET"){const l=new URL(n.url);l.searchParams.append("duid",this.duid),n.url=l.toString()}else n.data&&typeof n.data=="object"&&!(n.data instanceof FormData)&&(n.data.duid=this.duid);const a={method:n.method,headers:n.headers},o=[];n.options.timeout&&o.push(AbortSignal.timeout(n.options.timeout)),n.options.signal&&o.push(n.options.signal),o.length>1?a.signal=AbortSignal.any?AbortSignal.any(o):o[0]:o.length===1&&(a.signal=o[0]),n.data&&["POST","PUT","PATCH"].includes(n.method)&&(n.data instanceof FormData?(a.body=n.data,delete a.headers["Content-Type"]):typeof n.data=="object"?a.body=JSON.stringify(n.data):a.body=n.data);try{const l=await fetch(n.url,a),d=await this.processResponseInterceptors(l,n);return r.dataOnly&&d.data&&typeof d.data=="object"&&"data"in d.data&&(d.message=d.message||d.data.message,d.data=d.data.data),d}catch(l){if(l.name==="AbortError")throw l;const d=this.categorizeError(l),h={success:!1,status:0,statusText:"Network Error",headers:{},data:null,errors:{network:l.message},message:d.message,reason:d.reason},u={ok:!1,status:0,statusText:"Network Error",headers:new Headers,json:async()=>({}),text:async()=>""};return await this.processResponseInterceptors(u,n),h}}async GET(e,t={},s={}){return this.request("GET",e,null,t,s)}async POST(e,t={},s={},i={}){return this.request("POST",e,t,s,i)}async PUT(e,t={},s={},i={}){return this.request("PUT",e,t,s,i)}async PATCH(e,t={},s={},i={}){return this.request("PATCH",e,t,s,i)}async DELETE(e,t={},s={}){return this.request("DELETE",e,null,t,s)}get(...e){return this.GET(...e)}post(...e){return this.POST(...e)}put(...e){return this.PUT(...e)}patch(...e){return this.PATCH(...e)}delete(...e){return this.DELETE(...e)}async download(e,t={},s={}){const r={method:"GET",url:this.buildUrl(e)+this.buildQueryString(t),headers:{...this.config.headers,Accept:"*/*",...s.headers},options:{...s}};delete r.headers["Content-Type"];try{const n=await fetch(r.url,{method:r.method,headers:r.headers,signal:r.options.signal});if(!n.ok)throw new Error(`Download failed: ${n.status} ${n.statusText}`);const a=n.headers.get("content-disposition");let o=s.filename||"download";if(a){const p=a.match(/filename="?(.+)"?/);p&&p.length>1&&(o=p[1])}const l=n.body.getReader(),d=new ReadableStream({start(p){function f(){return l.read().then(({done:g,value:b})=>{if(g){p.close();return}return p.enqueue(b),f()})}return f()}}),h=await new Response(d).blob(),u=window.URL.createObjectURL(h),m=document.createElement("a");return m.style.display="none",m.href=u,m.download=o,document.body.appendChild(m),m.click(),window.URL.revokeObjectURL(u),m.remove(),{success:!0,message:"Download initiated"}}catch(n){return console.error("Download error:",n),{success:!1,message:n.message}}}async downloadBlob(e,t={},s={}){const r={method:"GET",url:this.buildUrl(e)+this.buildQueryString(t),headers:{...this.config.headers,Accept:"*/*",...s.headers},options:{...s}};delete r.headers["Content-Type"];try{const n=await fetch(r.url,{method:r.method,headers:r.headers,signal:r.options.signal});if(!n.ok)throw new Error(`Download failed: ${n.status} ${n.statusText}`);const a=await n.blob(),o=n.headers.get("content-disposition");let l=s.filename||"download";if(o){const u=o.match(/filename="?(.+)"?/);u&&u.length>1&&(l=u[1])}const d=window.URL.createObjectURL(a),h=document.createElement("a");return h.style.display="none",h.href=d,h.download=l,document.body.appendChild(h),h.click(),window.URL.revokeObjectURL(d),h.remove(),{success:!0,message:"Download initiated"}}catch(n){return console.error("Download error:",n),{success:!1,message:n.message}}}async upload(e,t,s={}){return new Promise((i,r)=>{if(!(t instanceof File)){r(new Error("Only single File objects are supported for legacy backend compatibility"));return}const n=new XMLHttpRequest;s.onProgress&&typeof s.onProgress=="function"&&(n.upload.onprogress=s.onProgress),n.onload=function(){n.status>=200&&n.status<300?i({data:n.response,status:n.status,statusText:n.statusText,xhr:n}):r(new Error(`Upload failed: ${n.status} ${n.statusText}`))},n.onerror=function(){r(new Error("Upload failed: Network error"))},n.ontimeout=function(){r(new Error("Upload failed: Timeout"))},n.open("PUT",e),n.setRequestHeader("Content-Type",t.type),s.timeout&&(n.timeout=s.timeout),n.send(t)})}async uploadMultipart(e,t,s={},i={}){const r=new FormData;if(t instanceof FileList)Array.from(t).forEach((n,a)=>{r.append(`file_${a}`,n)});else if(t instanceof File)r.append("file",t);else if(t instanceof FormData)return this.POST(e,t,{},i);return Object.entries(s).forEach(([n,a])=>{r.append(n,a)}),this.POST(e,r,{},i)}setAuthToken(e,t="Bearer"){e?this.config.headers.Authorization=`${t} ${e}`:delete this.config.headers.Authorization}clearAuth(){delete this.config.headers.Authorization}isRetryableError(e){return["not_reachable","timed_out","server_error","dns_error"].includes(e.reason)}requiresAuth(e){return e.reason==="unauthorized"}isNetworkError(e){return["not_reachable","timed_out","cancelled","cors_error","dns_error"].includes(e.reason)}getUserMessage(e){return e.message?e.message:{not_reachable:"Unable to connect to the server. Please check your internet connection.",timed_out:"The request took too long. Please try again.",cancelled:"The request was cancelled.",unauthorized:"Please log in to continue.",forbidden:"You don't have permission to perform this action.",not_found:"The requested resource was not found.",validation_error:"Please check your input and try again.",rate_limited:"Too many requests. Please wait a moment before trying again.",server_error:"Server error. Please try again later.",cors_error:"Access blocked by security policy.",dns_error:"Unable to reach the server.",unknown_error:"An unexpected error occurred."}[e.reason]||"An error occurred. Please try again."}}const ne=new Ot,Rt="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2NlZDRkYSI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg==";class jt{constructor(){this.formatters=new Map,this.registerBuiltInFormatters()}escapeHtml(e){if(e==null)return"";const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return String(e).replace(/[&<>"']/g,s=>t[s])}registerBuiltInFormatters(){this.register("date",this.date.bind(this)),this.register("time",this.time.bind(this)),this.register("datetime",this.datetime.bind(this)),this.register("datetime_tz",this.datetime_tz.bind(this)),this.register("datatime_tz",this.datetime_tz.bind(this)),this.register("date_range",this.date_range.bind(this)),this.register("datetime_range",this.datetime_range.bind(this)),this.register("relative",this.relative.bind(this)),this.register("fromNow",this.relative.bind(this)),this.register("timeago",this.relative.bind(this)),this.register("relative_short",this.relative_short.bind(this)),this.register("iso",this.iso.bind(this)),this.register("epoch",e=>{if(e==null||e===""||e instanceof Date||typeof e=="string"&&!/^\s*[+-]?\d+(\.\d+)?\s*$/.test(e))return e;const t=Number(e);return Number.isFinite(t)?t*1e3:e}),this.register("number",this.number.bind(this)),this.register("currency",this.currency.bind(this)),this.register("percent",this.percent.bind(this)),this.register("filesize",this.filesize.bind(this)),this.register("ordinal",this.ordinal.bind(this)),this.register("compact",this.compact.bind(this)),this.register("add",this.add.bind(this)),this.register("subtract",this.subtract.bind(this)),this.register("multiply",this.multiply.bind(this)),this.register("divide",this.divide.bind(this)),this.register("sub",this.subtract.bind(this)),this.register("mult",this.multiply.bind(this)),this.register("div",this.divide.bind(this)),this.register("uppercase",e=>String(e).toUpperCase()),this.register("lowercase",e=>String(e).toLowerCase()),this.register("upper",e=>String(e).toUpperCase()),this.register("lower",e=>String(e).toLowerCase()),this.register("capitalize",this.capitalize.bind(this)),this.register("caps",this.capitalize.bind(this)),this.register("replace",this.replace.bind(this)),this.register("truncate",this.truncate.bind(this)),this.register("truncate_middle",this.truncate_middle.bind(this)),this.register("truncate_front",this.truncate_front.bind(this)),this.register("slug",this.slug.bind(this)),this.register("initials",this.initials.bind(this)),this.register("mask",this.mask.bind(this)),this.register("hex",this.hex.bind(this)),this.register("tohex",this.hex.bind(this)),this.register("unhex",this.unhex.bind(this)),this.register("fromhex",this.unhex.bind(this)),this.register("email",this.email.bind(this)),this.register("phone",this.phone.bind(this)),this.register("url",this.url.bind(this)),this.register("badge",this.badge.bind(this)),this.register("badgeClass",this.badgeClass.bind(this)),this.register("status",this.status.bind(this)),this.register("status_text",this.status_text.bind(this)),this.register("status_icon",this.status_icon.bind(this)),this.register("boolean",this.boolean.bind(this)),this.register("bool",this.bool.bind(this)),this.register("yesno",e=>this.boolean(e,"Yes","No")),this.register("yesnoicon",this.yesnoicon.bind(this)),this.register("icon",this.icon.bind(this)),this.register("avatar",this.avatar.bind(this)),this.register("image",this.image.bind(this)),this.register("tooltip",this.tooltip.bind(this)),this.register("linkify",this.linkify.bind(this)),this.register("clipboard",this.clipboard.bind(this)),this.register("default",this.default.bind(this)),this.register("equals",this.equals.bind(this)),this.register("json",this.json.bind(this)),this.register("raw",e=>e),this.register("custom",(e,t)=>typeof t=="function"?t(e):e),this.register("iter",this.iter.bind(this)),this.register("keys",e=>e&&typeof e=="object"&&!Array.isArray(e)?Object.keys(e):null),this.register("values",e=>e&&typeof e=="object"&&!Array.isArray(e)?Object.values(e):null),this.register("plural",this.plural.bind(this)),this.register("list",this.formatList.bind(this)),this.register("duration",this.duration.bind(this)),this.register("hash",this.hash.bind(this)),this.register("stripHtml",this.stripHtml.bind(this)),this.register("highlight",this.highlight.bind(this)),this.register("nl2br",this.nl2br.bind(this)),this.register("code",this.code.bind(this)),this.register("pre",e=>`<pre class="bg-light p-2 rounded border">${this.escapeHtml(String(e))}</pre>`)}relative_short(e){return this.relative(e,!0)}linkify(e,t={}){if(e==null)return"";const s=String(e),i=this.escapeHtml(s),r={urls:!0,emails:!0,target:"_blank",rel:"noopener noreferrer"},n=t&&typeof t=="object"?{...r,...t}:r;let a=i;if(n.urls!==!1){const o=/(^|\s)((?:https?:\/\/|www\.)[^\s<]+)/gi;a=a.replace(o,(l,d,h)=>{const u=h.startsWith("www.")?`https://${h}`:h;return`${d}<a href="${u}" target="${n.target}" rel="${n.rel}">${h}</a>`})}if(n.emails!==!1){const o=/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;a=a.replace(o,l=>`<a href="mailto:${l}">${l}</a>`)}return a}clipboard(e,t="text"){if(e==null)return"";const s=String(e),i=this.escapeHtml(s),r=t!=="icon-only",n=`
1
+ var MOJO=(function(T){"use strict";class Te{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:r=!0}=t,{pageName:n,queryParams:a}=this.parseInput(e);r&&await this.handleRouteChange(n,a)}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),r=this.buildPublicUrl(e,t);return i?(this.currentRoute=i,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:r,pageName:i.pageName,params:i.params,query:t,route:i}),i):(console.log("No route matched for page:",e),this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:r}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const i={};return t.paramNames.forEach((r,n)=>{i[r]=s[n+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,r]=e.split("?",2),n=new URLSearchParams(r);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[a,o]of n)a!=="page"&&(s[a]=o)}else{i.startsWith("/")?t=i.substring(1)||this.defaultRoute:t=i||this.defaultRoute;for(const[a,o]of n)s[a]=o}}else e.startsWith("/")?t=e.substring(1)||this.defaultRoute:t=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,r]of e)i!=="page"&&(s[i]=r);return{pageName:t,queryParams:s}}buildPublicUrl(e,t={}){const s=new URLSearchParams;return s.set("page",e),Object.entries(t).forEach(([i,r])=>{r!=null&&r!==""&&s.set(i,String(r))}),"?"+s.toString()}updateBrowserUrl(e,t,s,i){const r=new URL(window.location.origin+window.location.pathname);r.searchParams.set("page",e),Object.entries(t).forEach(([a,o])=>{o!=null&&o!==""&&r.searchParams.set(a,String(o))});const n=r.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(s=>s.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 Vt{constructor(){this.listeners={},this.onceListeners={},this.maxListeners=100,this.debugMode=!1,this.eventStats={}}on(e,t){if(typeof t!="function")throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(s=>this.on(s,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(typeof t!="function")throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(s=>this.once(s,t)),this):(this.onceListeners[e]||(this.onceListeners[e]=[]),this.onceListeners[e].push(t),this)}off(e,t){if(Array.isArray(e))return e.forEach(s=>this.off(s,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);s!==-1&&(this.listeners[e].splice(s,1),this.listeners[e].length===0&&delete this.listeners[e])}if(this.onceListeners[e]){const s=this.onceListeners[e].indexOf(t);s!==-1&&(this.onceListeners[e].splice(s,1),this.onceListeners[e].length===0&&delete this.onceListeners[e])}return this}emit(e,t){this.updateEventStats(e),this.debugMode&&console.log(`[EventBus] Emitting: ${e}`,t);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&&console.log(`[EventBus] ${s.length} listener(s) for '${e}'`),s.forEach(i=>{try{i(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,i)}}),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(r=>new Promise(n=>{try{const a=r(t,e);n(a)}catch(a){console.error(`Error in async event listener for '${e}':`,a),this.emitError(a,e,r),n()}}));return await Promise.all(i),this}removeAllListeners(){return this.listeners={},this.onceListeners={},this}listenerCount(e){const t=this.listeners[e]?this.listeners[e].length:0,s=this.onceListeners[e]?this.onceListeners[e].length:0;return t+s}eventNames(){const e=Object.keys(this.listeners),t=Object.keys(this.onceListeners);return[...new Set([...e,...t])]}setMaxListeners(e){if(typeof e!="number"||e<0)throw new Error("Max listeners must be a non-negative number");return this.maxListeners=e,this}namespace(e){const t=s=>`${e}:${s}`;return{on:(s,i)=>this.on(t(s),i),once:(s,i)=>this.once(t(s),i),off:(s,i)=>this.off(t(s),i),emit:(s,i)=>this.emit(t(s),i),emitAsync:(s,i)=>this.emitAsync(t(s),i)}}use(e){if(typeof e!="function")throw new Error("Middleware must be a function");const t=this.emit;return this.emit=(s,i)=>{try{const r=e(s,i);if(r===!1)return this;const n=r!==void 0?r:i;return t.call(this,s,n)}catch(r){return console.error("Error in event middleware:",r),t.call(this,s,i)}},this}emitError(e,t,s){t!=="error"&&setTimeout(()=>{this.emit("error",{error:e,originalEvent:t,callback:s.toString()})},0)}waitFor(e,t=null){return new Promise((s,i)=>{let r=null;const n=()=>{r&&clearTimeout(r)},a=o=>{n(),s(o)};this.once(e,a),t&&(r=setTimeout(()=>{this.off(e,a),i(new Error(`Timeout waiting for event: ${e}`))},t))})}debug(e=!0){return this.debugMode=e,console.log(e?"[EventBus] Debug mode enabled":"[EventBus] Debug mode disabled"),this}getStats(){const e=this.eventNames(),t={totalEvents:e.length,totalListeners:0,events:{},emissions:{...this.eventStats}};return e.forEach(s=>{const i=this.listenerCount(s);t.events[s]=i,t.totalListeners+=i}),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(t===0)return 0;const s=t/(1e3*60);return Math.round(e.count/s*100)/100}resetStats(){return this.eventStats={},this}getTopEvents(e=10){return Object.entries(this.eventStats).map(([t,s])=>({event:t,count:s.count,rate:this.calculateEmissionRate(s),listeners:this.listenerCount(t)})).sort((t,s)=>s.count-t.count).slice(0,e)}debugInfo(){console.group("[EventBus] Debug Information"),console.log("Debug Mode:",this.debugMode),console.log("Max Listeners:",this.maxListeners);const e=this.getStats();return console.log("Total Events:",e.totalEvents),console.log("Total Listeners:",e.totalListeners),Object.keys(this.eventStats).length>0&&console.log("Top Events:",this.getTopEvents(5)),console.groupEnd(),this}}const Ze=["light","dark","system"];class Rt{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=Ze.includes(e)?e:"system",this._apply(!1),this.preference==="system"&&this._attachSystemListener(),this}getPreference(){return this.preference}getResolved(){return this.resolved}set(e){if(!Ze.includes(e))return console.warn(`ThemeManager: invalid preference "${e}" — expected 'light' | 'dark' | 'system'`),this;const t=this.preference==="system";return this.preference=e,this._writeStored(e),e==="system"?t||this._attachSystemListener():t&&this._detachSystemListener(),this._apply(!0),this}destroy(){this._detachSystemListener(),this.eventBus=null}_resolve(){return this.preference==="light"||this.preference==="dark"?this.preference:this._systemPrefersDark()?"dark":"light"}_apply(e){const t=this._resolve(),s=t!==this.resolved;this.resolved=t,typeof document<"u"&&document.documentElement&&document.documentElement.setAttribute("data-bs-theme",t),e&&s&&this.eventBus&&typeof this.eventBus.emit=="function"?this.eventBus.emit("theme:changed",{theme:this.preference,resolved:t}):e&&this.eventBus&&typeof this.eventBus.emit=="function"&&this.eventBus.emit("theme:changed",{theme:this.preference,resolved:t})}_systemPrefersDark(){if(typeof window>"u"||typeof window.matchMedia!="function")return!1;try{return window.matchMedia("(prefers-color-scheme: dark)").matches}catch{return!1}}_attachSystemListener(){if(!(this._mediaQuery||typeof window>"u"||typeof window.matchMedia!="function")){try{this._mediaQuery=window.matchMedia("(prefers-color-scheme: dark)")}catch{this._mediaQuery=null;return}this._mediaListener=()=>{this.preference==="system"&&this._apply(!0)},typeof this._mediaQuery.addEventListener=="function"?this._mediaQuery.addEventListener("change",this._mediaListener):typeof this._mediaQuery.addListener=="function"&&this._mediaQuery.addListener(this._mediaListener)}}_detachSystemListener(){if(!this._mediaQuery||!this._mediaListener){this._mediaQuery=null,this._mediaListener=null;return}typeof this._mediaQuery.removeEventListener=="function"?this._mediaQuery.removeEventListener("change",this._mediaListener):typeof this._mediaQuery.removeListener=="function"&&this._mediaQuery.removeListener(this._mediaListener),this._mediaQuery=null,this._mediaListener=null}_readStored(){try{return typeof localStorage>"u"?null:localStorage.getItem(this.storageKey)}catch(e){return console.warn("ThemeManager: failed to read stored theme:",e),null}}_writeStored(e){try{if(typeof localStorage>"u")return;localStorage.setItem(this.storageKey,e)}catch(t){console.warn("ThemeManager: failed to persist theme:",t)}}}class Nt{constructor(){this.config={baseURL:"",timeout:3e4,headers:{"Content-Type":"application/json",Accept:"application/json"},trackDevice:!0,duidHeader:"X-Mojo-UID",duidTransport:"header"},this.interceptors={request:[],response:[]},this.duid=null,this.config.trackDevice&&this._initializeDuid()}_initializeDuid(){const e="mojo_device_uid";try{let t=localStorage.getItem(e);t?this.duid=t:(this.duid=this._generateDuid(),localStorage.setItem(e,this.duid))}catch(t){console.error("Could not access localStorage to get/set DUID.",t),this.duid=this._generateDuid()}}_generateDuid(){return crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){const t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}configure(e){e.baseUrl&&(e.baseURL=e.baseUrl);const t=this.config.trackDevice;this.config={...this.config,...e,headers:{...this.config.headers,...e.headers}},this.config.trackDevice&&!t&&this._initializeDuid()}addInterceptor(e,t){this.interceptors[e]&&this.interceptors[e].push(t)}buildUrl(e){if(e.startsWith("http://")||e.startsWith("https://"))return e;const t=this.config.baseURL.endsWith("/")?this.config.baseURL.slice(0,-1):this.config.baseURL,s=e.startsWith("/")?e:`/${e}`;return`${t}${s}`}categorizeError(e,t=0){if(e.name==="TypeError"&&e.message.includes("fetch"))return{reason:"not_reachable",message:"Service is not reachable - please check your connection"};if(e.name==="AbortError")return{reason:"cancelled",message:"Request was cancelled"};if(e.name==="TimeoutError"||e.message.includes("timeout"))return{reason:"timed_out",message:"Request timed out - please try again"};if(t>=400){if(t===400)return{reason:"bad_request",message:"Invalid request data"};if(t===401)return{reason:"unauthorized",message:"Authentication required"};if(t===403)return{reason:"forbidden",message:"Access denied"};if(t===404)return{reason:"not_found",message:"Resource not found"};if(t===409)return{reason:"conflict",message:"Resource conflict"};if(t===422)return{reason:"validation_error",message:"Validation failed"};if(t===429)return{reason:"rate_limited",message:"Too many requests - please wait"};if(t>=500)return{reason:"server_error",message:"Server error - please try again later"};if(t>=400)return{reason:"client_error",message:"Request error"}}return e.message.includes("CORS")?{reason:"cors_error",message:"Cross-origin request blocked"}:e.message.includes("DNS")||e.message.includes("ENOTFOUND")?{reason:"dns_error",message:"Unable to resolve server address"}:{reason:"unknown_error",message:`Network error: ${e.message}`}}buildQueryString(e={}){const t=new URLSearchParams;Object.entries(e).forEach(([i,r])=>{r!=null&&(Array.isArray(r)?r.forEach(n=>t.append(`${i}[]`,n)):t.append(i,r))});const s=t.toString();return s?`?${s}`:""}async processRequestInterceptors(e){let t={...e};for(const s of this.interceptors.request)try{t=await s(t)}catch(i){throw console.error("Request interceptor error:",i),i}return t}async processResponseInterceptors(e,t){let s={success:e.ok,status:e.status,statusText:e.statusText,headers:Object.fromEntries(e.headers.entries()),data:null,errors:null,message:null,reason:null};try{const i=e.headers.get("content-type");if(i&&i.includes("application/json")){const r=await e.json();if(s.data=r,!e.ok){const n=this.categorizeError(new Error("HTTP Error"),e.status);s.errors=r.errors||{},s.message=r.message||n.message,s.reason=n.reason}}else if(s.data=await e.text(),!e.ok){const r=this.categorizeError(new Error("HTTP Error"),e.status);s.message=r.message,s.reason=r.reason}}catch{s.errors={parse:"Failed to parse response"},s.message="Invalid response format"}for(const i of this.interceptors.response)try{s=await i(s,t)}catch(r){console.error("Response interceptor error:",r)}return s}async request(e,t,s=null,i={},r={}){let n={method:e.toUpperCase(),url:this.buildUrl(t)+this.buildQueryString(i),headers:{...this.config.headers,...r.headers},data:s,options:{timeout:this.config.timeout,...r}};try{n=await this.processRequestInterceptors(n)}catch(l){if(l.name==="AuthRequiredError")return{success:!1,status:401,statusText:"Unauthorized",headers:{},data:null,errors:{auth:l.message},message:"Authentication required",reason:"unauthorized"};throw l}if(this.config.trackDevice&&this.duid)if(this.config.duidTransport==="header")n.headers[this.config.duidHeader]=this.duid;else if(n.method==="GET"){const l=new URL(n.url);l.searchParams.append("duid",this.duid),n.url=l.toString()}else n.data&&typeof n.data=="object"&&!(n.data instanceof FormData)&&(n.data.duid=this.duid);const a={method:n.method,headers:n.headers},o=[];n.options.timeout&&o.push(AbortSignal.timeout(n.options.timeout)),n.options.signal&&o.push(n.options.signal),o.length>1?a.signal=AbortSignal.any?AbortSignal.any(o):o[0]:o.length===1&&(a.signal=o[0]),n.data&&["POST","PUT","PATCH"].includes(n.method)&&(n.data instanceof FormData?(a.body=n.data,delete a.headers["Content-Type"]):typeof n.data=="object"?a.body=JSON.stringify(n.data):a.body=n.data);try{const l=await fetch(n.url,a),d=await this.processResponseInterceptors(l,n);return r.dataOnly&&d.data&&typeof d.data=="object"&&"data"in d.data&&(d.message=d.message||d.data.message,d.data=d.data.data),d}catch(l){if(l.name==="AbortError")throw l;const d=this.categorizeError(l),h={success:!1,status:0,statusText:"Network Error",headers:{},data:null,errors:{network:l.message},message:d.message,reason:d.reason},u={ok:!1,status:0,statusText:"Network Error",headers:new Headers,json:async()=>({}),text:async()=>""};return await this.processResponseInterceptors(u,n),h}}async GET(e,t={},s={}){return this.request("GET",e,null,t,s)}async POST(e,t={},s={},i={}){return this.request("POST",e,t,s,i)}async PUT(e,t={},s={},i={}){return this.request("PUT",e,t,s,i)}async PATCH(e,t={},s={},i={}){return this.request("PATCH",e,t,s,i)}async DELETE(e,t={},s={}){return this.request("DELETE",e,null,t,s)}get(...e){return this.GET(...e)}post(...e){return this.POST(...e)}put(...e){return this.PUT(...e)}patch(...e){return this.PATCH(...e)}delete(...e){return this.DELETE(...e)}async download(e,t={},s={}){const r={method:"GET",url:this.buildUrl(e)+this.buildQueryString(t),headers:{...this.config.headers,Accept:"*/*",...s.headers},options:{...s}};delete r.headers["Content-Type"];try{const n=await fetch(r.url,{method:r.method,headers:r.headers,signal:r.options.signal});if(!n.ok)throw new Error(`Download failed: ${n.status} ${n.statusText}`);const a=n.headers.get("content-disposition");let o=s.filename||"download";if(a){const p=a.match(/filename="?(.+)"?/);p&&p.length>1&&(o=p[1])}const l=n.body.getReader(),d=new ReadableStream({start(p){function f(){return l.read().then(({done:g,value:b})=>{if(g){p.close();return}return p.enqueue(b),f()})}return f()}}),h=await new Response(d).blob(),u=window.URL.createObjectURL(h),m=document.createElement("a");return m.style.display="none",m.href=u,m.download=o,document.body.appendChild(m),m.click(),window.URL.revokeObjectURL(u),m.remove(),{success:!0,message:"Download initiated"}}catch(n){return console.error("Download error:",n),{success:!1,message:n.message}}}async downloadBlob(e,t={},s={}){const r={method:"GET",url:this.buildUrl(e)+this.buildQueryString(t),headers:{...this.config.headers,Accept:"*/*",...s.headers},options:{...s}};delete r.headers["Content-Type"];try{const n=await fetch(r.url,{method:r.method,headers:r.headers,signal:r.options.signal});if(!n.ok)throw new Error(`Download failed: ${n.status} ${n.statusText}`);const a=await n.blob(),o=n.headers.get("content-disposition");let l=s.filename||"download";if(o){const u=o.match(/filename="?(.+)"?/);u&&u.length>1&&(l=u[1])}const d=window.URL.createObjectURL(a),h=document.createElement("a");return h.style.display="none",h.href=d,h.download=l,document.body.appendChild(h),h.click(),window.URL.revokeObjectURL(d),h.remove(),{success:!0,message:"Download initiated"}}catch(n){return console.error("Download error:",n),{success:!1,message:n.message}}}async upload(e,t,s={}){return new Promise((i,r)=>{if(!(t instanceof File)){r(new Error("Only single File objects are supported for legacy backend compatibility"));return}const n=new XMLHttpRequest;s.onProgress&&typeof s.onProgress=="function"&&(n.upload.onprogress=s.onProgress),n.onload=function(){n.status>=200&&n.status<300?i({data:n.response,status:n.status,statusText:n.statusText,xhr:n}):r(new Error(`Upload failed: ${n.status} ${n.statusText}`))},n.onerror=function(){r(new Error("Upload failed: Network error"))},n.ontimeout=function(){r(new Error("Upload failed: Timeout"))},n.open("PUT",e),n.setRequestHeader("Content-Type",t.type),s.timeout&&(n.timeout=s.timeout),n.send(t)})}async uploadMultipart(e,t,s={},i={}){const r=new FormData;if(t instanceof FileList)Array.from(t).forEach((n,a)=>{r.append(`file_${a}`,n)});else if(t instanceof File)r.append("file",t);else if(t instanceof FormData)return this.POST(e,t,{},i);return Object.entries(s).forEach(([n,a])=>{r.append(n,a)}),this.POST(e,r,{},i)}setAuthToken(e,t="Bearer"){e?this.config.headers.Authorization=`${t} ${e}`:delete this.config.headers.Authorization}clearAuth(){delete this.config.headers.Authorization}isRetryableError(e){return["not_reachable","timed_out","server_error","dns_error"].includes(e.reason)}requiresAuth(e){return e.reason==="unauthorized"}isNetworkError(e){return["not_reachable","timed_out","cancelled","cors_error","dns_error"].includes(e.reason)}getUserMessage(e){return e.message?e.message:{not_reachable:"Unable to connect to the server. Please check your internet connection.",timed_out:"The request took too long. Please try again.",cancelled:"The request was cancelled.",unauthorized:"Please log in to continue.",forbidden:"You don't have permission to perform this action.",not_found:"The requested resource was not found.",validation_error:"Please check your input and try again.",rate_limited:"Too many requests. Please wait a moment before trying again.",server_error:"Server error. Please try again later.",cors_error:"Access blocked by security policy.",dns_error:"Unable to reach the server.",unknown_error:"An unexpected error occurred."}[e.reason]||"An error occurred. Please try again."}}const ne=new Nt,Ot="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2NlZDRkYSI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg==";class jt{constructor(){this.formatters=new Map,this.registerBuiltInFormatters()}escapeHtml(e){if(e==null)return"";const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#039;"};return String(e).replace(/[&<>"']/g,s=>t[s])}registerBuiltInFormatters(){this.register("date",this.date.bind(this)),this.register("time",this.time.bind(this)),this.register("datetime",this.datetime.bind(this)),this.register("datetime_tz",this.datetime_tz.bind(this)),this.register("datatime_tz",this.datetime_tz.bind(this)),this.register("date_range",this.date_range.bind(this)),this.register("datetime_range",this.datetime_range.bind(this)),this.register("relative",this.relative.bind(this)),this.register("fromNow",this.relative.bind(this)),this.register("timeago",this.relative.bind(this)),this.register("relative_short",this.relative_short.bind(this)),this.register("iso",this.iso.bind(this)),this.register("epoch",e=>{if(e==null||e===""||e instanceof Date||typeof e=="string"&&!/^\s*[+-]?\d+(\.\d+)?\s*$/.test(e))return e;const t=Number(e);return Number.isFinite(t)?t*1e3:e}),this.register("number",this.number.bind(this)),this.register("currency",this.currency.bind(this)),this.register("percent",this.percent.bind(this)),this.register("filesize",this.filesize.bind(this)),this.register("ordinal",this.ordinal.bind(this)),this.register("compact",this.compact.bind(this)),this.register("add",this.add.bind(this)),this.register("subtract",this.subtract.bind(this)),this.register("multiply",this.multiply.bind(this)),this.register("divide",this.divide.bind(this)),this.register("sub",this.subtract.bind(this)),this.register("mult",this.multiply.bind(this)),this.register("div",this.divide.bind(this)),this.register("uppercase",e=>String(e).toUpperCase()),this.register("lowercase",e=>String(e).toLowerCase()),this.register("upper",e=>String(e).toUpperCase()),this.register("lower",e=>String(e).toLowerCase()),this.register("capitalize",this.capitalize.bind(this)),this.register("caps",this.capitalize.bind(this)),this.register("replace",this.replace.bind(this)),this.register("truncate",this.truncate.bind(this)),this.register("truncate_middle",this.truncate_middle.bind(this)),this.register("truncate_front",this.truncate_front.bind(this)),this.register("slug",this.slug.bind(this)),this.register("initials",this.initials.bind(this)),this.register("mask",this.mask.bind(this)),this.register("hex",this.hex.bind(this)),this.register("tohex",this.hex.bind(this)),this.register("unhex",this.unhex.bind(this)),this.register("fromhex",this.unhex.bind(this)),this.register("email",this.email.bind(this)),this.register("phone",this.phone.bind(this)),this.register("url",this.url.bind(this)),this.register("badge",this.badge.bind(this)),this.register("badgeClass",this.badgeClass.bind(this)),this.register("status",this.status.bind(this)),this.register("status_text",this.status_text.bind(this)),this.register("status_icon",this.status_icon.bind(this)),this.register("boolean",this.boolean.bind(this)),this.register("bool",this.bool.bind(this)),this.register("yesno",e=>this.boolean(e,"Yes","No")),this.register("yesnoicon",this.yesnoicon.bind(this)),this.register("icon",this.icon.bind(this)),this.register("avatar",this.avatar.bind(this)),this.register("image",this.image.bind(this)),this.register("tooltip",this.tooltip.bind(this)),this.register("linkify",this.linkify.bind(this)),this.register("clipboard",this.clipboard.bind(this)),this.register("default",this.default.bind(this)),this.register("equals",this.equals.bind(this)),this.register("json",this.json.bind(this)),this.register("raw",e=>e),this.register("custom",(e,t)=>typeof t=="function"?t(e):e),this.register("iter",this.iter.bind(this)),this.register("keys",e=>e&&typeof e=="object"&&!Array.isArray(e)?Object.keys(e):null),this.register("values",e=>e&&typeof e=="object"&&!Array.isArray(e)?Object.values(e):null),this.register("plural",this.plural.bind(this)),this.register("list",this.formatList.bind(this)),this.register("duration",this.duration.bind(this)),this.register("hash",this.hash.bind(this)),this.register("stripHtml",this.stripHtml.bind(this)),this.register("highlight",this.highlight.bind(this)),this.register("nl2br",this.nl2br.bind(this)),this.register("code",this.code.bind(this)),this.register("pre",e=>`<pre class="bg-light p-2 rounded border">${this.escapeHtml(String(e))}</pre>`)}relative_short(e){return this.relative(e,!0)}linkify(e,t={}){if(e==null)return"";const s=String(e),i=this.escapeHtml(s),r={urls:!0,emails:!0,target:"_blank",rel:"noopener noreferrer"},n=t&&typeof t=="object"?{...r,...t}:r;let a=i;if(n.urls!==!1){const o=/(^|\s)((?:https?:\/\/|www\.)[^\s<]+)/gi;a=a.replace(o,(l,d,h)=>{const u=h.startsWith("www.")?`https://${h}`:h;return`${d}<a href="${u}" target="${n.target}" rel="${n.rel}">${h}</a>`})}if(n.emails!==!1){const o=/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;a=a.replace(o,l=>`<a href="mailto:${l}">${l}</a>`)}return a}clipboard(e,t="text"){if(e==null)return"";const s=String(e),i=this.escapeHtml(s),r=t!=="icon-only",n=`
2
2
  <button type="button"
3
3
  class="btn btn-sm btn-outline-secondary ms-1 p-0 border-0 bg-transparent"
4
4
  title="Copy"
@@ -11,8 +11,8 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
11
11
  ${r?`<span class="font-monospace">${i}</span>`:""}
12
12
  ${n}
13
13
  </span>
14
- `}nl2br(e){return e==null?"":this.escapeHtml(String(e)).replace(/\r\n|\r|\n/g,"<br>")}code(e,t=""){if(e==null)return"";const s=t?`language-${this.escapeHtml(String(t))}`:"",i=this.escapeHtml(String(e));return`<pre class="bg-light p-2 rounded border"><code class="${s}">${i}</code></pre>`}register(e,t){if(typeof t!="function")throw new Error(`Formatter must be a function, got ${typeof t}`);return this.formatters.set(e.toLowerCase(),t),this}apply(e,t,...s){if(Array.isArray(t)&&t.length>0&&t.every(i=>typeof i=="string"))return t.reduce((i,r)=>this.apply(r,i,...s),e);try{const i=this.formatters.get(e.toLowerCase());return i?i(t,...s):(console.warn(`Formatter '${e}' not found`),t)}catch(i){return console.error(`Error in formatter '${e}':`,i),t}}pipe(e,t,s=null){return t?this.parsePipeString(t,s).reduce((r,n)=>this.apply(n.name,r,...n.args),e):e}parsePipeString(e,t=null){const s=[],i=e.split("|").map(r=>r.trim());for(const r of i){const n=this.parseFormatter(r,t);n&&s.push(n)}return s}parseFormatter(e,t=null){const s=e.match(/^([a-zA-Z_]\w*)\s*\((.*)\)$/);if(s){const[,r,n]=s,a=n?this.parseArguments(n,t):[];return{name:r,args:a}}const i=e.match(/^([a-zA-Z_]\w*)(?::(.+))?$/);if(i){const[,r,n]=i,a=n?this.parseColonArguments(n,t):[];return{name:r,args:a}}return null}parseArguments(e,t=null){const s=[];let i="",r=!1,n=null,a=0;for(let o=0;o<e.length;o++){const l=e[o];!r&&(l==='"'||l==="'")?(r=!0,n=l,i+=l):r&&l===n&&e[o-1]!=="\\"?(r=!1,n=null,i+=l):!r&&l==="{"?(a++,i+=l):!r&&l==="}"?(a--,i+=l):!r&&a===0&&l===","?(s.push(this.parseValue(i.trim(),t)),i=""):i+=l}return i.trim()&&s.push(this.parseValue(i.trim(),t)),s}parseColonArguments(e,t=null){const s=[];let i="",r=!1,n=null;for(let a=0;a<e.length;a++){const o=e[a];!r&&(o==='"'||o==="'")?(r=!0,n=o,i+=o):r&&o===n&&e[a-1]!=="\\"?(r=!1,n=null,i+=o):!r&&o===":"?(s.push(this.parseValue(i.trim(),t)),i=""):i+=o}return i.trim()&&s.push(this.parseValue(i.trim(),t)),s}parseValue(e,t=null){if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;if(e!=="undefined"){if(!isNaN(e)&&e!=="")return Number(e);if(e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{}if(t&&this.isIdentifier(e)){if(!e.includes(".")&&Object.prototype.hasOwnProperty.call(t,e))return t[e];if(t.get&&typeof t.get=="function"){const s=t.get(e);if(s!==void 0)return s}if(t.getContextValue&&typeof t.getContextValue=="function"){const s=t.getContextValue(e);if(s!==void 0)return s}if(e.includes(".")){const s=window.MOJOUtils||(typeof require<"u"?require("./MOJOUtils.js").default:null);if(s){const i=s.getNestedValue(t,e);if(i!==void 0)return i}}}return e}}isIdentifier(e){return/^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/.test(e)}date(e,t="MM/DD/YYYY"){if(!e)return"";e=this.normalizeEpoch(e);let s;if(e instanceof Date)s=e;else if(typeof e=="string")if(/^\d{4}-\d{2}-\d{2}$/.test(e)){const[a,o,l]=e.split("-").map(Number);s=new Date(a,o-1,l)}else s=new Date(e);else s=new Date(e);if(isNaN(s.getTime()))return String(e);const i={YYYY:s.getFullYear(),YY:String(s.getFullYear()).slice(-2),MMMM:s.toLocaleDateString("en-US",{month:"long"}),MMM:s.toLocaleDateString("en-US",{month:"short"}),MM:String(s.getMonth()+1).padStart(2,"0"),M:s.getMonth()+1,dddd:s.toLocaleDateString("en-US",{weekday:"long"}),ddd:s.toLocaleDateString("en-US",{weekday:"short"}),DD:String(s.getDate()).padStart(2,"0"),D:s.getDate()};let r=t;const n=new RegExp(`(${Object.keys(i).join("|")})`,"g");return r=r.replace(n,a=>i[a]||a),r}time(e,t="HH:mm:ss"){if(!e)return"";e=this.normalizeEpoch(e);const s=e instanceof Date?e:new Date(e);if(isNaN(s.getTime()))return String(e);const i=s.getHours(),r={HH:String(i).padStart(2,"0"),H:i,hh:String(i%12||12).padStart(2,"0"),h:i%12||12,mm:String(s.getMinutes()).padStart(2,"0"),m:s.getMinutes(),ss:String(s.getSeconds()).padStart(2,"0"),s:s.getSeconds(),A:i>=12?"PM":"AM",a:i>=12?"pm":"am"};let n=t;const a=Object.keys(r).sort((o,l)=>l.length-o.length);for(const o of a)n=n.replace(new RegExp(o,"g"),r[o]);return n}datetime(e,t="MM/DD/YYYY",s="HH:mm:ss"){e=this.normalizeEpoch(e);const i=this.date(e,t),r=this.time(e,s);return i&&r?`${i} ${r}`:""}datetime_tz(e,t="MM/DD/YYYY",s="HH:mm:ss",i={}){if(!e)return"";e=this.normalizeEpoch(e);const r=e instanceof Date?e:new Date(e);if(isNaN(r.getTime()))return String(e);const n=i&&i.locale||"en-US",a=i&&i.timeZone?i.timeZone:void 0,o=()=>{let k="";try{const ie=new Intl.DateTimeFormat(n,{hour:"2-digit",minute:"2-digit",timeZoneName:"short",...a?{timeZone:a}:{}}).formatToParts(r).find(H=>H.type==="timeZoneName");if(k=ie?ie.value:"",k&&/^GMT[+-]/i.test(k))try{const re=new Intl.DateTimeFormat(n,{timeStyle:"short",timeZoneName:"short",...a?{timeZone:a}:{}}).formatToParts(r).find(Ms=>Ms.type==="timeZoneName");re&&re.value&&!/^GMT[+-]/i.test(re.value)&&(k=re.value)}catch{}if(k&&/\s/.test(k)){const H=k.split(/\s+/).map(re=>re[0]).join("").toUpperCase();H.length>=2&&H.length<=4&&(k=H)}}catch{k=""}return k};if(!a){const k=this.date(r,t),Y=this.time(r,s),ie=o();return k&&Y?`${k} ${Y} ${ie}`.trim():""}const l=new Intl.DateTimeFormat(n,{timeZone:a,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"}).formatToParts(r),d=k=>{const Y=l.find(ie=>ie.type===k);return Y?Y.value:""},h=d("year"),u=d("month"),m=d("day"),p=d("hour"),f=d("minute"),g=d("second"),b=u?String(parseInt(u,10)):"",y=m?String(parseInt(m,10)):"",C=p?String(parseInt(p,10)):"",_=p?parseInt(p,10)%12||12:"",A=p?parseInt(p,10)>=12?"PM":"AM":"",F=A?A.toLowerCase():"",j=new Intl.DateTimeFormat(n,{timeZone:a,month:"long"}).format(r),I=new Intl.DateTimeFormat(n,{timeZone:a,month:"short"}).format(r),R=new Intl.DateTimeFormat(n,{timeZone:a,weekday:"long"}).format(r),oe=new Intl.DateTimeFormat(n,{timeZone:a,weekday:"short"}).format(r),be={YYYY:h,YY:h?h.slice(-2):"",MMMM:j,MMM:I,MM:u,M:b,dddd:R,ddd:oe,DD:m,D:y},ye={HH:p,H:C,hh:_!==""?String(_).padStart(2,"0"):"",h:_!==""?String(_):"",mm:f,m:f?String(parseInt(f,10)):"",ss:g,s:g?String(parseInt(g,10)):"",A,a:F},M=(k,Y)=>{if(!k)return"";const ie=new RegExp(`(${Object.keys(Y).sort((H,re)=>re.length-H.length).join("|")})`,"g");return k.replace(ie,H=>Y[H]??H)},z=M(t,be),Pt=M(s,ye),Ds=o();return z&&Pt?`${z} ${Pt} ${Ds}`.trim():""}normalizeEpoch(e){if(e instanceof Date)return e;if(typeof e=="string"){const t=Number(e);if(Number.isFinite(t))e=t;else{const s=Date.parse(e);return Number.isFinite(s)?s:""}}else typeof e!="number"&&(e=Number(e));if(isNaN(e))return"";if(e<1e11)return e*1e3;if(e>1e12&&e<1e13)return e;throw new Error("Value doesn't look like epoch seconds or ms")}date_range(e,t=null,s="MM/DD/YYYY"){if(!e)return"";const i=t||new Date,r=this.date(e,s),n=this.date(i,s);return!r||!n?"":`${r} - ${n}`}datetime_range(e,t=null,s="MM/DD/YYYY",i="HH:mm"){if(!e)return"";const r=t||new Date,n=this.datetime(e,s,i),a=this.datetime(r,s,i);return!n||!a?"":`${n} - ${a}`}relative(e,t=!1){if(!e)return"";e=this.normalizeEpoch(e);const s=e instanceof Date?e:new Date(e);if(isNaN(s.getTime()))return String(e);const r=s-new Date,n=Math.abs(r),a=Math.floor(n/1e3),o=Math.floor(a/60),l=Math.floor(o/60),d=Math.floor(l/24),h=r>0;if(t)return d>365?Math.floor(d/365)+"y":d>30?Math.floor(d/30)+"mo":d>7?Math.floor(d/7)+"w":d>0?d+"d":l>0?l+"h":o>0?o+"m":"now";if(d>365){const u=Math.floor(d/365),m=h?"in ":"",p=h?"":" ago";return m+u+" year"+(u>1?"s":"")+p}if(d>30){const u=Math.floor(d/30),m=h?"in ":"",p=h?"":" ago";return m+u+" month"+(u>1?"s":"")+p}if(d>7){const u=Math.floor(d/7),m=h?"in ":"",p=h?"":" ago";return m+u+" week"+(u>1?"s":"")+p}if(d===1)return h?"tomorrow":"yesterday";if(d>0){const u=h?"in ":"",m=h?"":" ago";return u+d+" days"+m}if(l>0){const u=h?"in ":"",m=h?"":" ago";return u+l+" hour"+(l>1?"s":"")+m}if(o>0){const u=h?"in ":"",m=h?"":" ago";return u+o+" minute"+(o>1?"s":"")+m}if(a>30){const u=h?"in ":"",m=h?"":" ago";return u+a+" seconds"+m}return"just now"}iso(e,t=!1){if(!e)return"";e=this.normalizeEpoch(e);const s=e instanceof Date?e:new Date(e);return isNaN(s.getTime())?String(e):t?s.toISOString().split("T")[0]:s.toISOString()}number(e,t=2,s="en-US"){const i=parseFloat(e);return isNaN(i)?String(e):i.toLocaleString(s,{minimumFractionDigits:t,maximumFractionDigits:t})}currency(e,t="$",s=2){const i=parseInt(e);if(isNaN(i))return String(e);const r=Math.abs(i).toString(),n=i<0?"-":"";let a,o;r.length<=2?(a="0",o=r.padStart(2,"0")):(a=r.slice(0,-2),o=r.slice(-2)),a=a.replace(/\B(?=(\d{3})+(?!\d))/g,",");let l;if(s===0)parseInt(o)>=50&&(a=(parseInt(a.replace(/,/g,""))+1).toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")),l=a;else if(s===2)l=`${a}.${o}`;else{const d=o.slice(0,s).padEnd(s,"0");l=`${a}.${d}`}return n+t+l}percent(e,t=0,s=!0){const i=parseFloat(e);if(isNaN(i))return String(e);const r=s?i*100:i;return this.number(r,t)+"%"}filesize(e,t=!1,s=1){const i=parseInt(e);if(isNaN(i))return String(e);const r=t?["B","KiB","MiB","GiB","TiB"]:["B","KB","MB","GB","TB"],n=t?1024:1e3;let a=i,o=0;for(;a>=n&&o<r.length-1;)a/=n,o++;const l=o===0?0:s;return`${a.toFixed(l)} ${r[o]}`}ordinal(e,t=!1){const s=parseInt(e);if(isNaN(s))return String(e);const i=s%10,r=s%100;let n="th";return i===1&&r!==11?n="st":i===2&&r!==12?n="nd":i===3&&r!==13&&(n="rd"),t?n:s+n}compact(e,t=1){const s=parseFloat(e);if(isNaN(s))return String(e);const i=Math.abs(s),r=s<0?"-":"";return i>=1e9?r+(i/1e9).toFixed(t)+"B":i>=1e6?r+(i/1e6).toFixed(t)+"M":i>=1e3?r+(i/1e3).toFixed(t)+"K":String(s)}add(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)?e:s+i}subtract(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)?e:s-i}multiply(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)?e:s*i}divide(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)||i===0?e:s/i}capitalize(e,t=!0){const s=String(e);return s?t?s.replace(/\b\w/g,i=>i.toUpperCase()):s.charAt(0).toUpperCase()+s.slice(1):""}replace(e,t,s="",i="g"){if(e==null)return"";const r=String(e);if(t==null||t==="")return r;if(t instanceof RegExp)return r.replace(t,String(s));const n=String(t),a=n.match(/^\/(.+)\/([a-z]*)$/i);if(a){const[,o,l]=a;try{return r.replace(new RegExp(o,l),String(s))}catch{}}return String(i).includes("g")?r.split(n).join(String(s)):r.replace(n,String(s))}truncate(e,t=50,s="..."){const i=String(e);return i.length<=t?i:i.substring(0,t)+s}truncate_front(e,t=8,s="..."){const i=String(e);return i.length<=t?i:`${s}${i.slice(-t)}`}truncate_middle(e,t=8,s="***"){const i=String(e);if(i.length<=t)return i;const r=Math.floor(t/2),n=i.substring(0,r),a=i.substring(i.length-r);return`${n}${s}${a}`}slug(e,t="-"){return String(e).toLowerCase().replace(/[^\w\s-]/g,"").replace(/\s+/g,t).replace(new RegExp(`${t}+`,"g"),t).replace(new RegExp(`^${t}|${t}$`,"g"),"")}initials(e,t=2){return String(e).split(/\s+/).filter(r=>r.length>0).slice(0,t).map(r=>r.charAt(0).toUpperCase()).join("")}mask(e,t="*",s=4){const i=String(e);if(i.length<=s)return i;const r=t.repeat(Math.max(0,i.length-s)),n=i.slice(-s);return r+n}email(e,t={}){const s=String(e).trim();if(!s)return"";if(t.link===!1)return s;const i=t.subject?`?subject=${encodeURIComponent(t.subject)}`:"",r=t.body?`&body=${encodeURIComponent(t.body)}`:"",n=t.class?` class="${t.class}"`:"";return`<a href="mailto:${s}${i}${r}"${n}>${s}</a>`}phone(e,t="US",s=!0){let i=String(e).replace(/\D/g,""),r=i;return t==="US"&&(i.length===10?r=`(${i.slice(0,3)}) ${i.slice(3,6)}-${i.slice(6)}`:i.length===11&&i[0]==="1"&&(r=`+1 (${i.slice(1,4)}) ${i.slice(4,7)}-${i.slice(7)}`)),s?`<a href="tel:${i}">${r}</a>`:r}url(e,t=null,s=!0){let i=String(e).trim();return i?(/^https?:\/\//.test(i)||(i="https://"+i),`<a href="${i}"${s?' target="_blank"':""}${s?' rel="noopener noreferrer"':""}>${t||i}</a>`):""}badge(e,t="auto"){if(Array.isArray(e))return e.map(n=>this.badge(n,t)).join(" ");const s=String(e);if(typeof t=="string"&&t.includes("=")){const n=Object.fromEntries(t.split(",").map(l=>l.split("=").map(d=>d.trim()))),a=n[s]||n[s.toLowerCase()]||this.inferBadgeType(s);return`<span class="badge ${a?`bg-${a}`:"bg-secondary"}">${s}</span>`}const i=t==="auto"?this.inferBadgeType(s):t;return`<span class="badge ${i?`bg-${i}`:"bg-secondary"}">${s}</span>`}badgeClass(e,t="auto"){const s=String(e),i=t==="auto"?this.inferBadgeType(s):t;return i?`bg-${i}`:"bg-secondary"}inferBadgeType(e){const t=e.toLowerCase();return["active","pass","success","complete","completed","approved","done","true","on","yes"].includes(t)?"success":["error","failed","fail","rejected","deleted","cancelled","false","off","no","declined"].includes(t)?"danger":["warning","pending","review","processing","uploading"].includes(t)?"warning":["info","new","draft"].includes(t)?"info":(["inactive","disabled","archived","suspended"].includes(t),"secondary")}status(e){return this._status(e)}status_icon(e){return this._status(e,{},{},!1,!0)}status_text(e){return this._status(e,{},{},!0,!1)}_status(e,t={},s={},i=!1,r=!1){const n=String(e).toLowerCase(),a={active:"bi bi-check-circle-fill",approved:"bi bi-check-circle-fill",declined:"bi bi-x-circle-fill",inactive:"bi bi-pause-circle-fill",pending:"bi bi-clock-fill",success:"bi bi-check-circle-fill",error:"bi bi-exclamation-triangle-fill",warning:"bi bi-exclamation-triangle-fill"},o={active:"success",approved:"success",declined:"danger",inactive:"secondary",pending:"warning",success:"success",error:"danger",warning:"warning"},l=t[n]||a[n]||"",d=s[n]||o[n]||"secondary";let h="";!i&&l&&(h=`<i class="${l}"></i>`);let u="";return r||(u=e),`<span class="text-${d}">${h}${h?" ":""}${u}</span>`}boolean(e,t="True",s="False",i=!1){const r=e?t:s;return i?`<span class="text-${e?"success":"danger"}">${r}</span>`:r}bool(e){return e==null||e===0||e===""||e===!1||e==="false"?!1:e===!0||e==="true"?!0:!(Array.isArray(e)&&e.length===0||e&&typeof e=="object"&&e.constructor===Object&&Object.keys(e).length===0)}icon(e,t={}){const s=String(e).toLowerCase(),i=t[s]||"";return i?`<i class="${i}"></i>`:""}yesnoicon(e,t="bi bi-check-circle-fill text-success",s="bi bi-x-circle-fill text-danger"){return e?`<i class="${t}"></i>`:`<i class="${s}"></i>`}image(e,t="thumbnail",s="img-fluid",i=""){const r=this._extractImageUrl(e,t);return r?`<img src="${r}" class="${s}" alt="${i}" />`:""}avatar(e,t="md",s="rounded-circle",i=""){const r=this._extractImageUrl(e,"square_sm")||Rt,n={xs:"width: 1.5rem; height: 1.5rem;",sm:"width: 2rem; height: 2rem;",md:"width: 3rem; height: 3rem;",lg:"width: 4rem; height: 4rem;",xl:"width: 5rem; height: 5rem;"},a=n[t]||n.md,l=`object-fit-cover ${s}`.trim();return`<img src="${r}" class="${l}" style="${a}" alt="${i}" />`}tooltip(e,t="",s="top",i=""){if(e==null)return"";const r=String(e),n=i==="html"?t:this.escapeHtml(t);return`<span data-bs-toggle="tooltip" data-bs-placement="${s}" ${i==="html"?'data-bs-html="true"':""} data-bs-title="${n}">${r}</span>`}_extractImageUrl(e,t="thumbnail"){if(!e)return null;if(typeof e=="string")return e;if(typeof e=="object"){if(e.attributes&&(e=e.attributes),t==="thumbnail"&&e.thumbnail&&typeof e.thumbnail=="string")return e.thumbnail;if(e.renditions&&typeof e.renditions=="object"){const s=e.renditions[t];if(s&&s.url)return s.url;const i=Object.values(e.renditions);if(i.length>0&&i[0].url)return i[0].url}if(e.url)return e.url}return null}default(e,t=""){return e==null||e===""?t:e}equals(e,t,s,i=""){return e==t?s:i}plural(e,t,s=null,i=!0){if(e==null||t===null||t===void 0)return i?`${e} ${t}`:t||"";const r=parseInt(e);if(isNaN(r))return i?`${e} ${t}`:t||"";const n=Math.abs(r)===1?t:s||t+"s";return i?`${r} ${n}`:n}formatList(e,t={}){if(!Array.isArray(e))return String(e);const{conjunction:s="and",limit:i=null,moreText:r="others"}=t;if(e.length===0)return"";if(e.length===1)return String(e[0]);let n=e.slice(),a=!1;if(i&&e.length>i&&(n=e.slice(0,i),a=!0),a){const o=e.length-i;return`${n.join(", ")}, ${s} ${o} ${r}`}return n.length===2?`${n[0]} ${s} ${n[1]}`:`${n.slice(0,-1).join(", ")}, ${s} ${n[n.length-1]}`}duration(e,t="ms",s=!1,i=2){if(e==null)return"";const r=parseFloat(e);if(isNaN(r))return String(e);let n;switch(t){case"s":case"sec":case"seconds":n=r*1e3;break;case"m":case"min":case"minutes":n=r*6e4;break;case"h":case"hr":case"hours":n=r*36e5;break;case"d":case"day":case"days":n=r*864e5;break;default:n=r}const a=[{name:"day",short:"d",value:864e5},{name:"hour",short:"h",value:36e5},{name:"minute",short:"m",value:6e4},{name:"second",short:"s",value:1e3}];if(n===0)return s?"0s":"0 seconds";const o=Math.abs(n),l=n<0?"-":"",d=[];let h=o;for(const u of a)if(h>=u.value){const m=Math.floor(h/u.value);h=h%u.value;const p=s?u.short:m===1?u.name:u.name+"s";if(d.push(s?`${m}${p}`:`${m} ${p}`),d.length>=i)break}return d.length===0?s?`${Math.round(o)}ms`:`${Math.round(o)} milliseconds`:l+(s?d.join(""):d.join(" "))}hash(e,t=8,s="",i="..."){if(e==null)return"";const r=String(e);return r.length<=t?s+r:s+r.substring(0,t)+i}stripHtml(e){return e==null?"":String(e).replace(/<[^>]*>/g,"")}highlight(e,t,s="highlight"){if(e==null||!t)return String(e||"");const i=String(t).replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=new RegExp(`(${i})`,"gi");return String(e).replace(r,`<mark class="${s}">$1</mark>`)}hex(e,t=!1,s=!1){if(e==null)return"";let i="";const r=n=>Array.from(n).map(a=>a.toString(16).padStart(2,"0")).join("");if(typeof e=="number"){let n=Math.abs(Math.trunc(e)).toString(16);n.length%2&&(n="0"+n),i=n}else if(e instanceof Uint8Array)i=r(e);else if(e instanceof ArrayBuffer)i=r(new Uint8Array(e));else if(Array.isArray(e)&&e.every(n=>typeof n=="number"))i=r(Uint8Array.from(e.map(n=>n&255)));else{const a=new TextEncoder().encode(String(e));i=r(a)}return t&&(i=i.toUpperCase()),(s?"0x":"")+i}unhex(e){if(e==null)return"";let t=String(e).trim();if((t.startsWith("0x")||t.startsWith("0X"))&&(t=t.slice(2)),t=t.replace(/\s+/g,""),t.length===0)return"";t.length%2!==0&&(t="0"+t);const s=new Uint8Array(t.length/2);for(let i=0;i<t.length;i+=2){const r=parseInt(t.slice(i,i+2),16);if(Number.isNaN(r))return String(e);s[i/2]=r}try{return new TextDecoder().decode(s)}catch{let r="";for(const n of s)r+=String.fromCharCode(n);return r}}json(e,t=2){try{return JSON.stringify(e,null,t)}catch{return String(e)}}has(e){return this.formatters.has(e.toLowerCase())}unregister(e){return this.formatters.delete(e.toLowerCase())}listFormatters(){return Array.from(this.formatters.keys()).sort()}iter(e){return e==null?[]:Array.isArray(e)?e:typeof e=="object"?Object.entries(e).map(([t,s])=>({key:t,value:s})):[{key:"0",value:e}]}}const V=new jt;window.dataFormatter=V;const Qe=new Set(["__proto__","constructor","prototype"]),Xe=(c,e)=>c!=null&&Object.prototype.hasOwnProperty.call(c,e);class ${static getContextData(e,t){if(!t||e==null)return;let s=t,i="",r=0,n=-1;for(let o=0;o<t.length;o++){const l=t[o];if(l==="(")r++;else if(l===")")r--;else if(l==="|"&&r===0){n=o;break}}n>-1&&(s=t.substring(0,n).trim(),i=t.substring(n+1).trim());const a=this.getNestedValue(e,s);return i?V.pipe(a,i,e):a}static getNestedValue(e,t){if(!t||e==null||t.split(".").some(r=>Qe.has(r)))return;if(!t.includes(".")){if(t in e){const r=e[t];return typeof r=="function"?r===Object.prototype[t]?void 0:r.call(e):r}return}const s=t.split(".");let i=e;for(let r=0;r<s.length;r++){const n=s[r];if(i==null)return;if(r===0)if(Xe(i,n)){const a=i[n];typeof a=="function"?i=a.call(e):i=a}else return;else{if(i&&typeof i.getContextValue=="function"){const a=s.slice(r).join(".");return i.getContextValue(a)}if(Array.isArray(i)&&!isNaN(n))i=i[parseInt(n)];else if(Xe(i,n))i=i[n];else return}}return i}static isNullOrUndefined(e){return e==null}static deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(e instanceof Array)return e.map(t=>this.deepClone(t));if(e instanceof Object){const t={};for(const s in e)e.hasOwnProperty(s)&&(t[s]=this.deepClone(e[s]));return t}}static deepMerge(e,...t){if(!t.length)return e;const s=t.shift();if(this.isObject(e)&&this.isObject(s))for(const i in s)this.isObject(s[i])?(e[i]||Object.assign(e,{[i]:{}}),this.deepMerge(e[i],s[i])):Object.assign(e,{[i]:s[i]});return this.deepMerge(e,...t)}static isObject(e){return e&&typeof e=="object"&&!Array.isArray(e)}static debounce(e,t){let s;return function(...r){const n=()=>{clearTimeout(s),e(...r)};clearTimeout(s),s=setTimeout(n,t)}}static throttle(e,t){let s;return function(...i){s||(e.apply(this,i),s=!0,setTimeout(()=>s=!1,t))}}static generateId(e=""){const t=Date.now().toString(36),s=Math.random().toString(36).substr(2,9);return e?`${e}_${t}_${s}`:`${t}_${s}`}static escapeHtml(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(e).replace(/[&<>"'`=\/]/g,s=>t[s])}static checkPasswordStrength(e){if(!e||typeof e!="string")return{score:0,strength:"invalid",feedback:["Password must be a non-empty string"],details:{length:0,hasLowercase:!1,hasUppercase:!1,hasNumbers:!1,hasSpecialChars:!1,hasCommonPatterns:!1,isCommonPassword:!1}};const t=[],s={length:e.length,hasLowercase:/[a-z]/.test(e),hasUppercase:/[A-Z]/.test(e),hasNumbers:/[0-9]/.test(e),hasSpecialChars:/[^a-zA-Z0-9]/.test(e),hasCommonPatterns:!1,isCommonPassword:!1};let i=0;e.length<6?t.push("Password should be at least 6 characters long"):e.length<8?(i+=1,t.push("Consider using at least 8 characters for better security")):e.length<12?i+=3:i+=4,s.hasLowercase?i+=1:t.push("Include lowercase letters"),s.hasUppercase?i+=1:t.push("Include uppercase letters"),s.hasNumbers?i+=1:t.push("Include numbers"),s.hasSpecialChars?i+=2:t.push("Include special characters (!@#$%^&* etc.)");const r=[/123/,/abc/i,/qwerty/i,/asdf/i,/(.)\1{2,}/,/password/i,/admin/i,/user/i,/login/i];for(const o of r)if(o.test(e)){s.hasCommonPatterns=!0,i-=1,t.push("Avoid common patterns and dictionary words");break}["123456","password","123456789","12345678","12345","1234567","1234567890","qwerty","abc123","111111","123123","admin","letmein","welcome","monkey","password123","123qwe","qwerty123","000000","dragon","sunshine","princess","azerty","1234","iloveyou","trustno1","superman","shadow","master","jennifer"].includes(e.toLowerCase())&&(s.isCommonPassword=!0,i=Math.max(0,i-3),t.push("This password is too common and easily guessed"));let a;return i<2?a="very-weak":i<4?a="weak":i<6?a="fair":i<8?a="good":a="strong",i>=7&&t.length===0?t.push("Strong password! Consider using a password manager."):i>=5&&t.length<=1&&t.push("Good password strength. Consider adding more variety."),{score:Math.max(0,i),strength:a,feedback:t,details:s}}static generatePassword(e={}){const s={...{length:12,includeLowercase:!0,includeUppercase:!0,includeNumbers:!0,includeSpecialChars:!0,customChars:"",excludeAmbiguous:!1},...e};if(s.length<4)throw new Error("Password length must be at least 4 characters");let i="abcdefghijklmnopqrstuvwxyz",r="ABCDEFGHIJKLMNOPQRSTUVWXYZ",n="0123456789",a="!@#$%^&*()_+-=[]{}|;:,.<>?";s.excludeAmbiguous&&(i=i.replace(/[il]/g,""),r=r.replace(/[IOL]/g,""),n=n.replace(/[01]/g,""),a=a.replace(/[|]/g,""));let o="";const l=[];if(s.customChars?o=s.customChars:(s.includeLowercase&&(o+=i,l.push(i[Math.floor(Math.random()*i.length)])),s.includeUppercase&&(o+=r,l.push(r[Math.floor(Math.random()*r.length)])),s.includeNumbers&&(o+=n,l.push(n[Math.floor(Math.random()*n.length)])),s.includeSpecialChars&&(o+=a,l.push(a[Math.floor(Math.random()*a.length)]))),!o)throw new Error("No character types selected for password generation");let d="";for(const h of l)d+=h;for(let h=d.length;h<s.length;h++)d+=o[Math.floor(Math.random()*o.length)];return d.split("").sort(()=>Math.random()-.5).join("")}static parseQueryString(e){const t={},s=new URLSearchParams(e);for(const[i,r]of s.entries())t[i]=r;return t}static toQueryString(e){return new URLSearchParams(e).toString()}static wrapData(e,t=null,s=3){return!e||typeof e!="object"||e instanceof Date||e instanceof RegExp||e instanceof Error||s<=0||typeof e.getContextValue=="function"?e:Array.isArray(e)?e.map(i=>i&&typeof i=="object"&&!i.getContextValue?new Ee(i,t):i):new Ee(e,t)}}class Ee{constructor(e,t=null){if(Object.defineProperty(this,"_data",{value:e,writable:!1,enumerable:!1,configurable:!1}),Object.defineProperty(this,"_rootContext",{value:t,writable:!1,enumerable:!1,configurable:!1}),e&&typeof e=="object"){for(const s in e)if(e.hasOwnProperty(s)){const i=e[s];this[s]=$.wrapData(i,t)}}}getContextValue(e){let t=e,s="",i=0,r=-1;for(let a=0;a<e.length;a++){const o=e[a];if(o==="(")i++;else if(o===")")i--;else if(o==="|"&&i===0){r=a;break}}r>-1&&(t=e.substring(0,r).trim(),s=e.substring(r+1).trim());let n;return t in this&&!Qe.has(t)&&t!=="_data"&&t!=="_rootContext"?n=this[t]:n=$.getNestedValue(this._data,t),s&&n!==void 0?V.pipe(n,s,this._rootContext||this._data):n}has(e){return this._data&&this._data.hasOwnProperty(e)}toJSON(){return this._data}}$.DataWrapper=Ee,typeof window<"u"&&(window.utils=$);const zt=new Set(["__proto__","constructor","prototype"]),Ht=Object.prototype.toString,le=Array.isArray||function(c){return Ht.call(c)==="[object Array]"},ue=function(c){return typeof c=="function"},et=function(c){return c!==null&&typeof c=="object"};function qt(){return typeof window>"u"?null:window.MOJO?.dataFormatter?window.MOJO.dataFormatter:window.dataFormatter?window.dataFormatter:null}const tt=function(c){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(c).replace(/[&<>"'`=\/]/g,function(t){return e[t]})};class st{constructor(e){this.string=e,this.tail=e,this.pos=0}eos(){return this.tail===""}scan(e){const t=this.tail.match(e);if(!t||t.index!==0)return"";const s=t[0];return this.tail=this.tail.substring(s.length),this.pos+=s.length,s}scanUntil(e){const t=this.tail.search(e);let s;switch(t){case-1:s=this.tail,this.tail="";break;case 0:s="";break;default:s=this.tail.substring(0,t),this.tail=this.tail.substring(t)}return this.pos+=s.length,s}}class we{constructor(e,t){this.view=e,this.cache={".":this.view},this.parent=t,this.view?._cacheId||this.view&&typeof this.view=="object"&&(this.view._cacheId=Math.random().toString(36).substring(2))}push(e){return new we(e,this)}lookup(e){if(this.renderCache&&this.view?._cacheId){const i=`${this.view._cacheId}:${e}`;if(this.renderCache.has(i))return this.renderCache.get(i)}if(e===".")return this.view;if(e&&(e.startsWith(".")?e.slice(1):e).split("|")[0].split(".").some(r=>zt.has(r)))return;if(e&&e.startsWith(".")){let i=e.substring(1),r=!1,n=null;const a=i.indexOf("|");if(a!==-1&&(n=i.substring(a+1).trim(),i=i.substring(0,a).trim()),i.endsWith("|iter")&&(i=i.substring(0,i.length-5),r=!0),this.view&&typeof this.view=="object"){let o;if(typeof this.view.getContextValue=="function")try{o=this.view.getContextValue(i),o!==void 0&&ue(o)&&(o=o.call(this.view))}catch{o=void 0}if(o===void 0&&(i.indexOf(".")>0?o=$.getNestedValue(this.view,i):i in this.view&&(o=this.view[i],ue(o)&&(o===Object.prototype[i]?o=void 0:o=o.call(this.view)))),n&&o!==void 0)try{const l=qt();l&&typeof l.pipe=="function"&&(o=l.pipe(o,n,this))}catch{}return le(o)?r?o:o.length>0:et(o)?r?Object.entries(o).map(([l,d])=>({key:l,value:d})):Object.keys(o).length>0:o}return}const t=this.cache;let s;if(t.hasOwnProperty(e))s=t[e];else{let i=this,r,n,a,o=!1;for(;i;){if(i.view&&typeof i.view.getContextValue=="function")try{r=i.view.getContextValue(e),r!==void 0&&(o=!0)}catch{o=!1}if(!o)if(e.indexOf(".")>0)for(r=i.view,n=e.split("."),a=0;r!=null&&a<n.length;)if(r&&typeof r.getContextValue=="function"&&a<n.length)try{const l=n.slice(a).join(".");r=r.getContextValue(l),a=n.length,r!==void 0&&(o=!0)}catch{a===n.length-1&&(o=Fe(r,n[a])||it(r,n[a])),r=r[n[a++]]}else a===n.length-1&&(o=Fe(r,n[a])||it(r,n[a])),r=r[n[a++]];else r=i.view[e],o=Fe(i.view,e);if(o){s=r;break}i=i.parent}t[e]=s}if(ue(s)){const i=e.split("|")[0].split(".").pop();if(s===Object.prototype[i])s=void 0;else try{s=s.call(this.view)}catch(r){if(r instanceof TypeError&&/^Class constructor /.test(r.message))s=void 0;else throw r}}if(this.renderCache&&this.view?._cacheId){const i=`${this.view._cacheId}:${e}`;this.renderCache.set(i,s)}return s}}function Fe(c,e){return c!=null&&typeof c=="object"&&e in c}function it(c,e){return c!=null&&typeof c!="object"&&c.hasOwnProperty&&c.hasOwnProperty(e)}class rt{constructor(){this.templateCache=new Map}clearCache(){this.templateCache.clear()}parse(e,t){t=t||["{{","}}"];const s=e+":"+t.join(":");let i=this.templateCache.get(s);return i==null&&(i=this.parseTemplate(e,t),this.templateCache.set(s,i)),i}parseTemplate(e,t){if(!e)return[];const s=t[0],i=t[1],r=new st(e),n=[];let a,o,l,d,h;const u=new RegExp(De(s)+"\\s*"),m=new RegExp("\\s*"+De(i)),p=new RegExp("\\s*"+De("}"+i));for(;!r.eos();){if(a=r.pos,l=r.scanUntil(u),l)for(let f=0;f<l.length;++f)d=l.charAt(f),d===`
15
- `?n.push(["text",d]):n.push(["text",d]);if(!r.scan(u))break;if(o=r.scan(/[#^\/>{&=!]/),o||(o="name"),r.scan(/\s*/),o==="="?(l=r.scanUntil(/\s*=/),r.scan(/\s*=/),r.scanUntil(m)):o==="{"?(l=r.scanUntil(p),r.scan(p),o="&"):l=r.scanUntil(m),r.scan(m),o==="#"||o==="^")h=[o,l,a,r.pos],n.push(h);else if(o==="/"){let f;for(let g=n.length-1;g>=0;--g)if((n[g][0]==="#"||n[g][0]==="^")&&n[g][1]===l){f=n[g];break}f&&f.length===4&&f.push(r.pos),n.push([o,l,a,r.pos])}else n.push([o,l,a,r.pos])}return this.nestSections(this.squashTokens(n))}squashTokens(e){const t=[];let s,i;for(let r=0;r<e.length;++r)s=e[r],s&&(s[0]==="text"&&i&&i[0]==="text"?(i[1]+=s[1],i[3]=s[3]):(t.push(s),i=s));return t}nestSections(e){const t=[];let s=t;const i=[];for(let r=0;r<e.length;++r){const n=e[r];switch(n[0]){case"#":case"^":const a=[n[0],n[1],n[2],n[3],[],n[4]||null];s.push(a),i.push(a),s=a[4];break;case"/":const o=i.pop();o&&(o[5]=n[2],s=i.length>0?i[i.length-1][4]:t);break;default:s.push(n)}}return t}render(e,t,s,i){const r=this.getConfigTags(i)||["{{","}}"],n=this.parse(e,r),a=new Map;return this.renderTokens(n,new we(t),s,e,i,a)}renderTokens(e,t,s,i,r,n){n&&!t.renderCache&&(t.renderCache=n);let a="";for(let o=0;o<e.length;++o){const l=e[o];let d;switch(l[0]){case"#":if(d=t.lookup(l[1]),!d)continue;const h=l[4];if(!h||!le(h)){console.warn(`MUSTACHE WARNING - Section ${l[1]} has no child tokens:`,l);continue}if(le(d))for(let u=0;u<d.length;++u){const m=t.push(d[u]);t.renderCache&&(m.renderCache=t.renderCache);const p=this.renderTokens(h,m,s,i,r,n);a+=p}else if(typeof d=="object"||typeof d=="string"||typeof d=="number"){const u=t.push(d);t.renderCache&&(u.renderCache=t.renderCache),a+=this.renderTokens(h,u,s,i,r,n)}else if(ue(d)){const u=i==null?null:i.slice(l[3],l[5]);d=d.call(t.view,u,m=>this.render(m,t.view,s,r)),d!=null&&(a+=d)}else d&&(a+=this.renderTokens(h,t,s,i,r,n));break;case"^":if(d=t.lookup(l[1]),!d||le(d)&&d.length===0){const u=l[4];u&&le(u)&&(a+=this.renderTokens(u,t,s,i,r,n))}break;case">":if(!s)continue;d=ue(s)?s(l[1]):s[l[1]],d!=null&&(a+=this.render(d,t.view,s,r));break;case"&":d=t.lookup(l[1]),d!=null&&(a+=d);break;case"name":d=t.lookup(l[1]),d!=null&&(a+=tt(d));break;case"text":a+=l[1];break}}return a}getConfigTags(e){return et(e)&&le(e.tags)?e.tags:null}}function De(c){return c.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}const Me=new rt,D={name:"MOJO Mustache",version:"1.0.0",tags:["{{","}}"],Scanner:st,Context:we,Writer:rt,escape:tt,clearCache(){return Me.clearCache()},parse(c,e){return Me.parse(c,e)},render(c,e,t,s){if(typeof c!="string")throw new TypeError('Invalid template! Template should be a "string"');return e&&typeof e=="object"&&!e.getContextValue&&typeof e.toJSON!="function"&&(e=$.wrapData(e)),Me.render(c,e,t,s)}};class Bt{constructor(e){this.view=e,this.domListeners=[],this.debounceTimers=new Map}_enterDispatchChain(e){const t=e._mojoDispatch;let s;return e._mojoDispatch=new Promise(i=>{s=i}),{prior:t,done:s}}bind(e){if(this.unbind(),!e)return;const t=async a=>{const{prior:o,done:l}=this._enterDispatchChain(a);try{o&&await o;const d=a.target.closest("[data-action]");if(d&&this.shouldHandle(d,a)){const u=d.getAttribute("data-action");if(d.tagName==="A"&&a.preventDefault(),this.hideTooltip(d),await this.dispatch(u,a,d)){a.preventDefault(),a.stopPropagation(),a.handledByChild=!0;return}}const h=a.target.closest("a[href], [data-page]");if(h&&!h.hasAttribute("data-action")&&this.shouldHandle(h,a)){if(a.ctrlKey||a.metaKey||a.shiftKey||a.button===1)return;if(h.tagName==="A"){const u=h.getAttribute("href");if(u&&u!=="#"&&!u.startsWith("#")&&(this.view.isExternalLink(u)||h.hasAttribute("data-external")))return}this.hideTooltip(h),a.preventDefault(),a.stopPropagation(),a.handledByChild=!0,h.hasAttribute("data-page")?await this.view.handlePageNavigation(h):await this.view.handleHrefNavigation(h)}}finally{l()}},s=async a=>{const{prior:o,done:l}=this._enterDispatchChain(a);try{o&&await o;const d=a.target.closest("[data-change-action]");if(d&&this.shouldHandle(d,a)){const u=d.getAttribute("data-change-action");await this.dispatchChange(u,a,d)&&(a.stopPropagation(),a.handledByChild=!0);return}const h=a.target.closest("[data-action]");if(h&&this.isFormControl(h)&&this.shouldHandle(h,a)){const u=h.getAttribute("data-action");await this.dispatch(u,a,h)&&(a.stopPropagation(),a.handledByChild=!0)}}finally{l()}},i=a=>{const o=a.target.closest("[data-change-action]");if(o&&this.shouldHandle(o,a)&&a.target.matches('[data-filter="live-search"]')){const m=o.getAttribute("data-change-action"),p=parseInt(o.getAttribute("data-filter-debounce"))||300,f=`change-${m}-${o.getAttribute("data-container")||"default"}`;this.debounceTimers.has(f)&&clearTimeout(this.debounceTimers.get(f));const g=setTimeout(()=>{this.debounceTimers.delete(f),this.dispatchChange(m,a,o).then(b=>{b&&(a.stopPropagation(),a.handledByChild=!0)})},p);this.debounceTimers.set(f,g);return}const l=a.target.closest("[data-action]");if(!l||!this.isFormControl(l)||l.hasAttribute("data-change-action")||!this.shouldHandle(l,a))return;const d=l.getAttribute("data-action"),h=l.getAttribute("data-action-debounce"),u=h!=null&&parseInt(h)||0;if(u>0){const m=`action-${d}-${l.getAttribute("data-container")||"default"}`;this.debounceTimers.has(m)&&clearTimeout(this.debounceTimers.get(m));const p=setTimeout(()=>{this.debounceTimers.delete(m),this.dispatch(d,a,l).then(f=>{f&&(a.stopPropagation(),a.handledByChild=!0)})},u);this.debounceTimers.set(m,p);return}this.dispatch(d,a,l).then(m=>{m&&(a.stopPropagation(),a.handledByChild=!0)})},r=async a=>{if(a.target.matches('[data-filter="search"]'))return;const o=a.target.closest("[data-keydown-action]")||a.target.closest("[data-change-action]");if(!o)return;const{prior:l,done:d}=this._enterDispatchChain(a);try{if(l&&await l,!this.shouldHandle(o,a))return;let h=["Enter"];if(o.getAttribute("data-change-keys")&&(h=o.getAttribute("data-change-keys").split(",").map(u=>u.trim())),h.includes("*")||h.includes(a.key)){const u=o.getAttribute("data-keydown-action")||o.getAttribute("data-change-action");await this.dispatch(u,a,o)&&(a.preventDefault(),a.stopPropagation(),a.handledByChild=!0)}}finally{d()}},n=a=>{const o=a.target.closest("form[data-action]");if(!o||!this.shouldHandle(o,a))return;a.preventDefault();const l=o.getAttribute("data-action");this.dispatch(l,a,o)};e.addEventListener("click",t),e.addEventListener("change",s),e.addEventListener("input",i),e.addEventListener("keydown",r),e.addEventListener("submit",n),this.domListeners.push({el:e,type:"click",fn:t},{el:e,type:"change",fn:s},{el:e,type:"input",fn:i},{el:e,type:"keydown",fn:r},{el:e,type:"submit",fn:n})}unbind(){for(const{el:e,type:t,fn:s}of this.domListeners)e.removeEventListener(t,s);this.domListeners=[];for(const e of this.debounceTimers.values())clearTimeout(e);this.debounceTimers.clear()}hideDropdown(e){const s=e.closest(".dropdown-menu").closest(".dropdown");if(!s)return;const i=s.querySelector('[data-bs-toggle="dropdown"]');i&&window.bootstrap?.Dropdown&&window.bootstrap.Dropdown.getInstance(i)?.hide()}hideTooltip(e){if(e&&window.bootstrap?.Tooltip){const t=window.bootstrap.Tooltip.getInstance(e);t&&t.dispose()}}hideAllTooltips(){window.bootstrap?.Tooltip&&document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(t=>{const s=window.bootstrap.Tooltip.getInstance(t);s&&s.hide()})}async dispatch(e,t,s){const i=this.view,r=l=>l.includes("-")?l.split("-").map(d=>d[0].toUpperCase()+d.slice(1)).join(""):l[0].toUpperCase()+l.slice(1),n=`handleAction${r(e)}`;if(typeof i[n]=="function")try{return t.preventDefault(),await i[n](t,s),!0}catch(l){return console.error(`Error in action ${e}:`,l),i.handleActionError(e,l,t,s),!0}const a=`onAction${r(e)}`;if(typeof i[a]=="function")try{return await i[a](t,s)?(s.closest(".dropdown-menu")&&this.hideDropdown(s),t.preventDefault(),t.stopPropagation(),!0):!1}catch(l){return console.error(`Error in action ${e}:`,l),i.handleActionError(e,l,t,s),!0}const o=`onPassThruAction${r(e)}`;if(typeof i[o]=="function")try{return await i[o](t,s),!1}catch(l){return console.error(`Error in action ${e}:`,l),i.handleActionError(e,l,t,s),!0}if(typeof i.onActionDefault=="function")try{return await i.onActionDefault(e,t,s)}catch(l){return console.error(`Error in default action handler for ${e}:`,l),i.handleActionError(e,l,t,s),!0}return i.emit?.(`action:${e}`,{action:e,event:t,element:s}),!1}async dispatchChange(e,t,s){const i=this.view,n=`onChange${(a=>a.includes("-")?a.split("-").map(o=>o[0].toUpperCase()+o.slice(1)).join(""):a[0].toUpperCase()+a.slice(1))(e)}`;if(typeof i[n]=="function")try{return await i[n](t,s),!0}catch(a){return console.error(`Error in onChange ${e}:`,a),i.handleActionError?.(e,a,t,s),!0}return await this.dispatch(e,t,s)}isFormControl(e){if(!e||!e.tagName)return!1;const t=e.tagName;return t==="INPUT"||t==="TEXTAREA"||t==="SELECT"}shouldHandle(e,t){return!!(this.owns(e)||this.contains(e)&&!t.handledByChild)}owns(e){const t=this.view.element;if(!t||!t.contains(e))return!1;for(const s of Object.values(this.view.children))if(s.element&&s.element.contains(e))return!1;return!0}contains(e){return!!this.view.element&&this.view.element.contains(e)}}const Ie={on(c,e,t){this._listeners||(this._listeners={}),this._listeners[c]||(this._listeners[c]=[]);const s={callback:e,context:t,fn:t?e.bind(t):e};return this._listeners[c].push(s),this},off(c,e,t){return!this._listeners||!this._listeners[c]?this:(e?(this._listeners[c]=this._listeners[c].filter(s=>s.callback!==e||arguments.length===3&&s.context!==t),this._listeners[c].length===0&&delete this._listeners[c]):delete this._listeners[c],this)},once(c,e,t){const s=(...i)=>{this.off(c,s),(t?e.bind(t):e).apply(t||this,i)};return this.on(c,s),this},emit(c,...e){if(!this._listeners||!this._listeners[c])return this;const t=this._listeners[c].slice();for(const s of t)try{s.fn.apply(s.context||this,e)}catch(i){console&&console.error&&console.error(`Error in ${c} event handler:`,i)}return this}};typeof window<"u"&&(window.Mustache=D);class S{constructor(e={}){this.tagName=e.tagName??"div",this.className=e.className??"mojo-view",this.style=e.style??null,this.id=e.id??S._genId(),this.containerId=e.containerId??null,this.container=e.container??null,typeof this.container=="string"&&(this.containerId=this.container,this.container=null),this.parent=e.parent??null,this.children=e.children??{},this.template=e.template||e.templateUrl||"",this.data=e.data??{},this.isRendering=!1,this.lastRenderTime=0,this.mounted=!1,this.debug=e.debug??!1,this.app=e.app??null,this.cacheTemplate=e.cacheTemplate??!0,this.enableTooltips=e.enableTooltips??!1,this.options={...e},this.element=this._ensureElement(),this.events=new Bt(this),e.model&&this.setModel(e.model)}async onInit(){}async onInitView(){this.initialized||(this.initialized=!0,await this.onInit())}async onBeforeRender(){}async onAfterRender(){}async onBeforeMount(){}async onAfterMount(){}async onBeforeUnmount(){}async onAfterUnmount(){}async onBeforeDestroy(){}async onAfterDestroy(){}setModel(e={}){let t=e!==this.model;if(!t)return this;this.model&&this.model.off&&this.model.off("change",this._onModelChange,this),this.model=e,this.model&&this.model.on&&this.model.on("change",this._onModelChange,this);for(const s in this.children){const i=this.children[s];i&&typeof i.setModel=="function"&&i.setModel(e)}return t&&this._onModelChange(),this}_onModelChange(e,t){t&&t.skipRender||this.isMounted()&&this.render()}setTemplate(e){return this.template=e??"",this}addChild(e,t){try{if(!e||typeof e!="object")return this;t&&((t.containerId||t.container)&&(e.containerId=t.containerId||t.container),t.id&&(e.id=t.id),t.lazyMount===!0&&(e._lazyMount=!0)),e.parent=this,this.getApp()&&(e.app=this.app),this.children[e.id]=e}catch(s){S._warn("addChild error",s)}return e}removeChild(e){try{const t=typeof e=="string"?e:e&&e.id;if(!t)return this;const s=this.children[t];s&&(Promise.resolve(s.destroy()).catch(i=>S._warn("removeChild destroy error",i)),delete this.children[t])}catch(t){S._warn("removeChild error",t)}return this}getChild(e){return this.children[e]}async updateData(e,t=!1){return Object.assign(this.data,e),t&&this.isMounted()&&await this.render(),this}toggleClass(e,t){return t===void 0&&(t=!this.element.classList.contains(e)),this.element.classList.toggle(e,t),this}addClass(e){return this.element.classList.add(e),this}setClass(e){return this.element.className=e,this}removeClass(e){return this.element.classList.remove(e),this}canRender(){if(this.isRendering)return!1;const e=Date.now();if(this.options.renderCooldown>0&&e-this.lastRenderTime<this.options.renderCooldown)return S._warn(`View ${this.id}: Render called too quickly, cooldown active`),!1;if(this.options.noAppend&&this.parent)if(this.parent.contains(this.containerId||this.container)){if(this.containerId&&!document.getElementById(this.containerId))return!1;if(this.container&&!document.contains(this.container))return!1}else return!1;return!0}async render(e=!0,t=null){const s=Date.now();if(!this.canRender())return this;this.isRendering=!0,this.lastRenderTime=s;try{this.initialized||await this.onInitView(),this.unbindEvents(),await this.onBeforeRender(),this.getViewData&&(this.data=await this.getViewData());const i=await this.renderTemplate();this.element.innerHTML=i,e&&!this.isMounted()&&await this.mount(t),await this._renderChildren(),await this.onAfterRender(),this.bindEvents()}catch(i){S._warn(`Render error in ${this.id}`,i)}finally{this.isRendering=!1}return this}async _renderChildren(){const e=[];for(const t in this.children){const s=this.children[t];if(s){if(s.parent=this,s._lazyMount&&!s._lazyTriggered){e.push(s);continue}await Promise.resolve(s.render()).catch(i=>S._warn(`Child render error (${t})`,i))}}e.length&&this._setupLazyMountObserver(e)}_setupLazyMountObserver(e){if(typeof IntersectionObserver>"u"){e.forEach(t=>{t._lazyTriggered=!0,Promise.resolve(t.render()).catch(s=>S._warn(`Lazy child render error (${t.id})`,s))});return}this._lazyObserver||(this._lazyObserver=new IntersectionObserver((t,s)=>{for(const i of t){if(!i.isIntersecting)continue;const r=i.target.__mojoLazyChild;s.unobserve(i.target),!(!r||r._lazyTriggered)&&(r._lazyTriggered=!0,Promise.resolve(r.render()).catch(n=>S._warn(`Lazy child render error (${r.id})`,n)))}},{rootMargin:"120px 0px",threshold:.01}));for(const t of e){const s=this.getChildElement(t.containerId);s&&(s.__mojoLazyChild=t,s.style.minHeight||(s.classList.add("mojo-lazy-placeholder"),s.style.minHeight="1px"),this._lazyObserver.observe(s),requestAnimationFrame(()=>{if(t._lazyTriggered)return;const i=s.getBoundingClientRect(),r=typeof window<"u"?window.innerHeight:0,n=typeof window<"u"?window.innerWidth:0;i.top<r+120&&i.bottom>-120&&i.left<n&&i.right>0&&(t._lazyTriggered=!0,this._lazyObserver?.unobserve(s),Promise.resolve(t.render()).catch(o=>S._warn(`Lazy child render error (${t.id})`,o)))}))}}async _unmountChildren(){for(const e in this.children){const t=this.children[e];t&&t.unbindEvents()}}isMounted(){return this.element?.isConnected}getChildElementById(e,t=null){const s=e.startsWith("#")?e.substring(1):e;return t?t.querySelector(`#${s}`):this.element.querySelector(`#${s}`)}getChildElement(e){if(e.startsWith("#"))return this.getChildElementById(e);let t=this.element?.querySelector(`[data-container="${e}"]`);return t||this.getChildElementById(e)}getContainer(){return this.replaceById?this.parent?this.parent.getChildElementById(this.id):null:this.containerId?this.parent?this.parent.getChildElement(this.containerId):this.getChildElementById(this.containerId,document.body):null}async mount(e=null){if(await this.onBeforeMount(),e||(e=this.getContainer()),this.containerId&&!e){console.error(`Container not found for ${this.containerId}`);return}e&&this.replaceById?e.replaceWith(this.element):e?e.replaceChildren(this.element):!this.containerId&&this.parent?this.parent.element.appendChild(this.element):!this.containerId&&!this.parent&&this.options.allowAppendToBody?(console.log("APPENDING TO BODY!!!!"),document.body.appendChild(this.element)):console.error(`Container not found for ${this.containerId}`),await this.onAfterMount(),this.mounted=!0}async unmount(){!this.element||!this.element.parentNode||(await this.onBeforeUnmount(),await this._unmountChildren(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),this.events.unbind(),await this.onAfterUnmount(),this.mounted=!1)}async destroy(){try{this.events.unbind(),this._lazyObserver&&(this._lazyObserver.disconnect(),this._lazyObserver=null);for(const e in this.children){const t=this.children[e];t&&await Promise.resolve(t.destroy()).catch(s=>S._warn(`Child destroy error (${e})`,s))}this.mounted=!1,this.element&&this.element.parentNode&&(await this.onBeforeDestroy(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),await this.onAfterDestroy())}catch(e){S._warn(`Destroy error in ${this.id}`,e)}}_ensureElement(){try{if(this.element&&this.element.tagName?.toLowerCase()===this.tagName)return this._syncAttrs(),this.element;const e=document.createElement(this.tagName);return this.element=e,this.el=e,this._syncAttrs(),e}catch(e){S._warn("ensureElement error",e);const t=document.createElement("div");return t.id=this.id||S._genId(),t}}_syncAttrs(){try{if(!this.element)return;this.id&&(this.element.id=this.id),this.element.className=this.className||"",this.style==null?this.element.removeAttribute("style"):this.element.style.cssText=String(this.style)}catch(e){S._warn("_syncAttrs error",e)}}bindEvents(){this.events.bind(this.element),this.enableTooltips&&this.initializeTooltips()}unbindEvents(){this.events.unbind(),this.enableTooltips&&this.disposeTooltips()}async renderTemplate(){const e=await this.getTemplate();if(!e)return"";const t=this.getPartials();return D.render(e,this,t)}renderTemplateString(e,t,s){return D.render(e,t,s)}getPartials(){return{}}async getTemplate(){if(this._templateCache&&this.cacheTemplate)return this._templateCache;const e=this.template||this.templateUrl;if(!e)throw new Error("Template not found");let t="";if(typeof e=="string")if(e.includes("<")||e.includes("{"))t=e;else try{let s=e;this.app||(this.app=this.getApp()),this.app&&this.app.basePath&&!s.startsWith("/")&&!s.startsWith("http://")&&!s.startsWith("https://")&&(s=`${this.app.basePath.endsWith("/")?this.app.basePath.slice(0,-1):this.app.basePath}/${s}`);const i=await fetch(s);if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);t=await i.text()}catch(s){S._warn(`Failed to load template from ${e}: ${s}`),this.showError?.(`Failed to load template from ${e}: ${s.message}`)}else typeof e=="function"&&(t=await this.template(this.data,this.state));return this.cacheTemplate&&t&&typeof e!="function"&&(this._templateCache=t),t}getContextValue(e){const t=$.getContextData(this,e);return e&&e.startsWith("data.")&&t&&typeof t=="object"?$.wrapData(t,this):e&&e.startsWith("model.")&&e!=="model"&&t&&typeof t=="object"&&typeof t.getContextValue!="function"?$.wrapData(t,null):t}async handlePageNavigation(e){const t=e.getAttribute("data-page"),s=e.getAttribute("data-params");let i={};if(s)try{i=JSON.parse(s)}catch{console.warn("Invalid JSON in data-params:",s)}const r=this.getApp();if(r){r.showPage(t,i);return}const n=this.findRouter();n&&typeof n.navigateToPage=="function"?await n.navigateToPage(t,i):console.error(`No router found for page navigation to '${t}'`)}async handleHrefNavigation(e){const t=e.getAttribute("href");if(this.isExternalLink(t)||e.hasAttribute("data-external"))return;const s=this.findRouter();if(s){if(s.options&&s.options.mode==="param"&&t.startsWith("?")){const r="/"+t;await s.navigate(r);return}if(s.options&&s.options.mode==="hash"&&t.startsWith("#")){await s.navigate(t);return}const i=this.hrefToRoutePath(t);await s.navigate(i)}else console.warn("No router found for navigation, using default behavior"),window.location.href=t}isExternalLink(e){return e?e.startsWith("/")&&this.getApp()?!e.startsWith(this.findRouter().basePath):e.startsWith("#")||e.startsWith("mailto:")||e.startsWith("tel:")||e.startsWith("http://")||e.startsWith("https://")||e.startsWith("//"):!0}hrefToRoutePath(e){if(e.startsWith("/")){const t=this.findRouter();if(t&&t.options&&t.options.base){const s=t.options.base;if(e.startsWith(s))return e.substring(s.length)||"/"}return e}return e.startsWith("./")?e.substring(2):e}findRouter(){return this.getApp(),this.app?.router||null}getApp(){if(this.app)return this.app;const e=[window.__app__,window.MOJO?.app,window.APP,window.app,window.WebApp,window.matchUUID?window[window.matchUUID]():window[window.matchUUID]];return this.app=e.find(t=>t&&typeof t.showPage=="function")||null,this.app}checkPermissions(e){if(!e)return!0;const t=this.getApp()?.activeUser;return!!(t&&typeof t.hasPermission=="function"&&t.hasPermission(e))}handleActionError(e,t,s,i){this.showError(`Action '${e}' failed: ${t}`,s,i)}escapeHtml(e){if(typeof e!="string")return e;const t=document.createElement("div");return t.textContent=e,t.innerHTML}contains(e){if(typeof e=="string"){if(!this.element)return!1;e=document.getElementById(e)}return e?this.element.contains(e):!1}initializeTooltips(){if(!this.element||!window.bootstrap?.Tooltip)return;this.disposeTooltips(),[...this.element.querySelectorAll('[data-bs-toggle="tooltip"]')].map(t=>{const s=t.getAttribute("data-tooltip-theme"),i=t.getAttribute("data-tooltip-size");let r="";s&&(r+=`tooltip-${s} `),i&&(r+=`tooltip-${i}`);const n={},a=r.trim();return a&&(n.customClass=a),new window.bootstrap.Tooltip(t,n)})}disposeTooltips(){if(!this.element||!window.bootstrap?.Tooltip)return;this.element.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(t=>{const s=window.bootstrap.Tooltip.getInstance(t);s&&s.dispose()})}async showError(e){console.error(`View ${this.id} error:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showError=="function"){await t.showError(e);return}alert(`Error: ${e}`)}async showSuccess(e){this.debug&&console.log(`View ${this.id} success:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showSuccess=="function"){await t.showSuccess(e);return}alert(`Success: ${e}`)}async showInfo(e){console.info(`View ${this.id} info:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showInfo=="function"){await t.showInfo(e);return}alert(`Info: ${e}`)}async showWarning(e){console.warn(`View ${this.id} warning:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showWarning=="function"){await t.showWarning(e);return}alert(`Warning: ${e}`)}async onActionCopyToClipboard(e,t){try{const i=(t?.closest("[data-clipboard]")||t)?.getAttribute("data-clipboard")||"";if(!i)return!0;if(navigator.clipboard&&window.isSecureContext)await navigator.clipboard.writeText(i);else{const a=document.createElement("textarea");a.value=i,document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a)}const r=t.querySelector("i"),n=r&&r.className;return r&&(r.className="bi bi-check",setTimeout(()=>{r.className=n},1e3)),!0}catch(s){return console.warn("Copy to clipboard failed:",s),!0}}static _genId(){return`view_${Math.random().toString(36).substr(2,9)}`}static _warn(e,t){try{t?console.warn(`[View] ${e}:`,t):console.warn(`[View] ${e}`)}catch{}}}Object.assign(S.prototype,Ie);class x extends S{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:x._baseZIndex}static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=x._openDialogs;if(e.length===0||t.length===0)return;const s=[...t].sort((n,a)=>(n._dialogZIndex||0)-(a._dialogZIndex||0)),r=document.querySelector(".table-fullscreen")||document.body;e.forEach((n,a)=>{if(a>=s.length)return;const o=s[a];n.style.zIndex=o._dialogZIndex-5,n.parentNode!==r&&r.appendChild(n)})}static updateAllBackdropStacking(){x.fixAllBackdropStacking()}static getMountTarget(){return document.querySelector(".table-fullscreen")||document.body}constructor(e={}){const t=e.id||`modal-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;super({...e,id:t,tagName:"div",className:`modal ${e.fade!==!1?"fade":""} ${e.className||""}`.trim().replace(/\s+/g," "),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=e.centered!==void 0?e.centered:!1,this.scrollable=e.scrollable!==void 0?e.scrollable:!1,this.autoSize=e.autoSize||e.size==="auto",this.backdrop=e.backdrop!==void 0?e.backdrop:!0,this.keyboard=e.keyboard!==void 0?e.keyboard:!0,this.focus=e.focus!==void 0?e.focus:!0,this.header=e.header!==void 0?e.header:!0,this.headerContent=e.headerContent||null,this.headerView=null,this.closeButton=e.closeButton!==void 0?e.closeButton:!0,this.contextMenu=e.contextMenu||null,this._processHeaderContent(this.headerContent),this.body=e.body??e.view??e.message??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=e.autoShow!==void 0?e.autoShow:!1,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(e){if(e instanceof S||e&&typeof e=="object"&&typeof e.render=="function")this.bodyView=e,this.body="",this.addChild(this.bodyView);else if(typeof e=="function")try{const t=e();t instanceof S?(this.bodyView=t,this.body="",this.addChild(this.bodyView)):t instanceof Promise?(this.bodyPromise=t,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=t}catch(t){console.error("ModalView: error processing body function:",t),this.body=e}else this.body=e}_processHeaderContent(e){if(e instanceof S)this.headerView=e,this.headerContent=null,this.addChild(this.headerView);else if(typeof e=="function")try{const t=e();t instanceof S?(this.headerView=t,this.headerContent=null,this.addChild(this.headerView)):t instanceof Promise?(this.headerPromise=t,this.headerContent='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.headerContent=t}catch(t){console.error("ModalView: error processing headerContent function:",t),this.headerContent=e}else this.headerContent=e}_processFooterContent(e){if(e instanceof S)this.footerView=e,this.footer=null,this.addChild(this.footerView);else if(typeof e=="function")try{const t=e();t instanceof S?(this.footerView=t,this.footer=null,this.addChild(this.footerView)):t instanceof Promise?(this.footerPromise=t,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=t}catch(t){console.error("ModalView: error processing footer function:",t),this.footer=e}else this.footer=e}async getTemplate(){const e=["modal-dialog"];return this.size&&this.size!=="auto"&&(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")),`
14
+ `}nl2br(e){return e==null?"":this.escapeHtml(String(e)).replace(/\r\n|\r|\n/g,"<br>")}code(e,t=""){if(e==null)return"";const s=t?`language-${this.escapeHtml(String(t))}`:"",i=this.escapeHtml(String(e));return`<pre class="bg-light p-2 rounded border"><code class="${s}">${i}</code></pre>`}register(e,t){if(typeof t!="function")throw new Error(`Formatter must be a function, got ${typeof t}`);return this.formatters.set(e.toLowerCase(),t),this}apply(e,t,...s){if(Array.isArray(t)&&t.length>0&&t.every(i=>typeof i=="string"))return t.reduce((i,r)=>this.apply(r,i,...s),e);try{const i=this.formatters.get(e.toLowerCase());return i?i(t,...s):(console.warn(`Formatter '${e}' not found`),t)}catch(i){return console.error(`Error in formatter '${e}':`,i),t}}pipe(e,t,s=null){return t?this.parsePipeString(t,s).reduce((r,n)=>this.apply(n.name,r,...n.args),e):e}parsePipeString(e,t=null){const s=[],i=e.split("|").map(r=>r.trim());for(const r of i){const n=this.parseFormatter(r,t);n&&s.push(n)}return s}parseFormatter(e,t=null){const s=e.match(/^([a-zA-Z_]\w*)\s*\((.*)\)$/);if(s){const[,r,n]=s,a=n?this.parseArguments(n,t):[];return{name:r,args:a}}const i=e.match(/^([a-zA-Z_]\w*)(?::(.+))?$/);if(i){const[,r,n]=i,a=n?this.parseColonArguments(n,t):[];return{name:r,args:a}}return null}parseArguments(e,t=null){const s=[];let i="",r=!1,n=null,a=0;for(let o=0;o<e.length;o++){const l=e[o];!r&&(l==='"'||l==="'")?(r=!0,n=l,i+=l):r&&l===n&&e[o-1]!=="\\"?(r=!1,n=null,i+=l):!r&&l==="{"?(a++,i+=l):!r&&l==="}"?(a--,i+=l):!r&&a===0&&l===","?(s.push(this.parseValue(i.trim(),t)),i=""):i+=l}return i.trim()&&s.push(this.parseValue(i.trim(),t)),s}parseColonArguments(e,t=null){const s=[];let i="",r=!1,n=null;for(let a=0;a<e.length;a++){const o=e[a];!r&&(o==='"'||o==="'")?(r=!0,n=o,i+=o):r&&o===n&&e[a-1]!=="\\"?(r=!1,n=null,i+=o):!r&&o===":"?(s.push(this.parseValue(i.trim(),t)),i=""):i+=o}return i.trim()&&s.push(this.parseValue(i.trim(),t)),s}parseValue(e,t=null){if(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))return e.slice(1,-1);if(e==="true")return!0;if(e==="false")return!1;if(e==="null")return null;if(e!=="undefined"){if(!isNaN(e)&&e!=="")return Number(e);if(e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{}if(t&&this.isIdentifier(e)){if(!e.includes(".")&&Object.prototype.hasOwnProperty.call(t,e))return t[e];if(t.get&&typeof t.get=="function"){const s=t.get(e);if(s!==void 0)return s}if(t.getContextValue&&typeof t.getContextValue=="function"){const s=t.getContextValue(e);if(s!==void 0)return s}if(e.includes(".")){const s=window.MOJOUtils||(typeof require<"u"?require("./MOJOUtils.js").default:null);if(s){const i=s.getNestedValue(t,e);if(i!==void 0)return i}}}return e}}isIdentifier(e){return/^[a-zA-Z_$][a-zA-Z0-9_$]*(\.[a-zA-Z_$][a-zA-Z0-9_$]*)*$/.test(e)}date(e,t="MM/DD/YYYY"){if(!e)return"";e=this.normalizeEpoch(e);let s;if(e instanceof Date)s=e;else if(typeof e=="string")if(/^\d{4}-\d{2}-\d{2}$/.test(e)){const[a,o,l]=e.split("-").map(Number);s=new Date(a,o-1,l)}else s=new Date(e);else s=new Date(e);if(isNaN(s.getTime()))return String(e);const i={YYYY:s.getFullYear(),YY:String(s.getFullYear()).slice(-2),MMMM:s.toLocaleDateString("en-US",{month:"long"}),MMM:s.toLocaleDateString("en-US",{month:"short"}),MM:String(s.getMonth()+1).padStart(2,"0"),M:s.getMonth()+1,dddd:s.toLocaleDateString("en-US",{weekday:"long"}),ddd:s.toLocaleDateString("en-US",{weekday:"short"}),DD:String(s.getDate()).padStart(2,"0"),D:s.getDate()};let r=t;const n=new RegExp(`(${Object.keys(i).join("|")})`,"g");return r=r.replace(n,a=>i[a]||a),r}time(e,t="HH:mm:ss"){if(!e)return"";e=this.normalizeEpoch(e);const s=e instanceof Date?e:new Date(e);if(isNaN(s.getTime()))return String(e);const i=s.getHours(),r={HH:String(i).padStart(2,"0"),H:i,hh:String(i%12||12).padStart(2,"0"),h:i%12||12,mm:String(s.getMinutes()).padStart(2,"0"),m:s.getMinutes(),ss:String(s.getSeconds()).padStart(2,"0"),s:s.getSeconds(),A:i>=12?"PM":"AM",a:i>=12?"pm":"am"};let n=t;const a=Object.keys(r).sort((o,l)=>l.length-o.length);for(const o of a)n=n.replace(new RegExp(o,"g"),r[o]);return n}datetime(e,t="MM/DD/YYYY",s="HH:mm:ss"){e=this.normalizeEpoch(e);const i=this.date(e,t),r=this.time(e,s);return i&&r?`${i} ${r}`:""}datetime_tz(e,t="MM/DD/YYYY",s="HH:mm:ss",i={}){if(!e)return"";e=this.normalizeEpoch(e);const r=e instanceof Date?e:new Date(e);if(isNaN(r.getTime()))return String(e);const n=i&&i.locale||"en-US",a=i&&i.timeZone?i.timeZone:void 0,o=()=>{let M="";try{const ie=new Intl.DateTimeFormat(n,{hour:"2-digit",minute:"2-digit",timeZoneName:"short",...a?{timeZone:a}:{}}).formatToParts(r).find(z=>z.type==="timeZoneName");if(M=ie?ie.value:"",M&&/^GMT[+-]/i.test(M))try{const re=new Intl.DateTimeFormat(n,{timeStyle:"short",timeZoneName:"short",...a?{timeZone:a}:{}}).formatToParts(r).find(ks=>ks.type==="timeZoneName");re&&re.value&&!/^GMT[+-]/i.test(re.value)&&(M=re.value)}catch{}if(M&&/\s/.test(M)){const z=M.split(/\s+/).map(re=>re[0]).join("").toUpperCase();z.length>=2&&z.length<=4&&(M=z)}}catch{M=""}return M};if(!a){const M=this.date(r,t),Y=this.time(r,s),ie=o();return M&&Y?`${M} ${Y} ${ie}`.trim():""}const l=new Intl.DateTimeFormat(n,{timeZone:a,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hourCycle:"h23"}).formatToParts(r),d=M=>{const Y=l.find(ie=>ie.type===M);return Y?Y.value:""},h=d("year"),u=d("month"),m=d("day"),p=d("hour"),f=d("minute"),g=d("second"),b=u?String(parseInt(u,10)):"",y=m?String(parseInt(m,10)):"",_=p?String(parseInt(p,10)):"",S=p?parseInt(p,10)%12||12:"",A=p?parseInt(p,10)>=12?"PM":"AM":"",F=A?A.toLowerCase():"",j=new Intl.DateTimeFormat(n,{timeZone:a,month:"long"}).format(r),I=new Intl.DateTimeFormat(n,{timeZone:a,month:"short"}).format(r),O=new Intl.DateTimeFormat(n,{timeZone:a,weekday:"long"}).format(r),oe=new Intl.DateTimeFormat(n,{timeZone:a,weekday:"short"}).format(r),be={YYYY:h,YY:h?h.slice(-2):"",MMMM:j,MMM:I,MM:u,M:b,dddd:O,ddd:oe,DD:m,D:y},ye={HH:p,H:_,hh:S!==""?String(S).padStart(2,"0"):"",h:S!==""?String(S):"",mm:f,m:f?String(parseInt(f,10)):"",ss:g,s:g?String(parseInt(g,10)):"",A,a:F},k=(M,Y)=>{if(!M)return"";const ie=new RegExp(`(${Object.keys(Y).sort((z,re)=>re.length-z.length).join("|")})`,"g");return M.replace(ie,z=>Y[z]??z)},H=k(t,be),Lt=k(s,ye),Ds=o();return H&&Lt?`${H} ${Lt} ${Ds}`.trim():""}normalizeEpoch(e){if(e instanceof Date)return e;if(typeof e=="string"){const t=Number(e);if(Number.isFinite(t))e=t;else{const s=Date.parse(e);return Number.isFinite(s)?s:""}}else typeof e!="number"&&(e=Number(e));if(isNaN(e))return"";if(e<1e11)return e*1e3;if(e>1e12&&e<1e13)return e;throw new Error("Value doesn't look like epoch seconds or ms")}date_range(e,t=null,s="MM/DD/YYYY"){if(!e)return"";const i=t||new Date,r=this.date(e,s),n=this.date(i,s);return!r||!n?"":`${r} - ${n}`}datetime_range(e,t=null,s="MM/DD/YYYY",i="HH:mm"){if(!e)return"";const r=t||new Date,n=this.datetime(e,s,i),a=this.datetime(r,s,i);return!n||!a?"":`${n} - ${a}`}relative(e,t=!1){if(!e)return"";e=this.normalizeEpoch(e);const s=e instanceof Date?e:new Date(e);if(isNaN(s.getTime()))return String(e);const r=s-new Date,n=Math.abs(r),a=Math.floor(n/1e3),o=Math.floor(a/60),l=Math.floor(o/60),d=Math.floor(l/24),h=r>0;if(t)return d>365?Math.floor(d/365)+"y":d>30?Math.floor(d/30)+"mo":d>7?Math.floor(d/7)+"w":d>0?d+"d":l>0?l+"h":o>0?o+"m":"now";if(d>365){const u=Math.floor(d/365),m=h?"in ":"",p=h?"":" ago";return m+u+" year"+(u>1?"s":"")+p}if(d>30){const u=Math.floor(d/30),m=h?"in ":"",p=h?"":" ago";return m+u+" month"+(u>1?"s":"")+p}if(d>7){const u=Math.floor(d/7),m=h?"in ":"",p=h?"":" ago";return m+u+" week"+(u>1?"s":"")+p}if(d===1)return h?"tomorrow":"yesterday";if(d>0){const u=h?"in ":"",m=h?"":" ago";return u+d+" days"+m}if(l>0){const u=h?"in ":"",m=h?"":" ago";return u+l+" hour"+(l>1?"s":"")+m}if(o>0){const u=h?"in ":"",m=h?"":" ago";return u+o+" minute"+(o>1?"s":"")+m}if(a>30){const u=h?"in ":"",m=h?"":" ago";return u+a+" seconds"+m}return"just now"}iso(e,t=!1){if(!e)return"";e=this.normalizeEpoch(e);const s=e instanceof Date?e:new Date(e);return isNaN(s.getTime())?String(e):t?s.toISOString().split("T")[0]:s.toISOString()}number(e,t=2,s="en-US"){const i=parseFloat(e);return isNaN(i)?String(e):i.toLocaleString(s,{minimumFractionDigits:t,maximumFractionDigits:t})}currency(e,t="$",s=2){const i=parseInt(e);if(isNaN(i))return String(e);const r=Math.abs(i).toString(),n=i<0?"-":"";let a,o;r.length<=2?(a="0",o=r.padStart(2,"0")):(a=r.slice(0,-2),o=r.slice(-2)),a=a.replace(/\B(?=(\d{3})+(?!\d))/g,",");let l;if(s===0)parseInt(o)>=50&&(a=(parseInt(a.replace(/,/g,""))+1).toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")),l=a;else if(s===2)l=`${a}.${o}`;else{const d=o.slice(0,s).padEnd(s,"0");l=`${a}.${d}`}return n+t+l}percent(e,t=0,s=!0){const i=parseFloat(e);if(isNaN(i))return String(e);const r=s?i*100:i;return this.number(r,t)+"%"}filesize(e,t=!1,s=1){const i=parseInt(e);if(isNaN(i))return String(e);const r=t?["B","KiB","MiB","GiB","TiB"]:["B","KB","MB","GB","TB"],n=t?1024:1e3;let a=i,o=0;for(;a>=n&&o<r.length-1;)a/=n,o++;const l=o===0?0:s;return`${a.toFixed(l)} ${r[o]}`}ordinal(e,t=!1){const s=parseInt(e);if(isNaN(s))return String(e);const i=s%10,r=s%100;let n="th";return i===1&&r!==11?n="st":i===2&&r!==12?n="nd":i===3&&r!==13&&(n="rd"),t?n:s+n}compact(e,t=1){const s=parseFloat(e);if(isNaN(s))return String(e);const i=Math.abs(s),r=s<0?"-":"";return i>=1e9?r+(i/1e9).toFixed(t)+"B":i>=1e6?r+(i/1e6).toFixed(t)+"M":i>=1e3?r+(i/1e3).toFixed(t)+"K":String(s)}add(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)?e:s+i}subtract(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)?e:s-i}multiply(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)?e:s*i}divide(e,t){const s=parseFloat(e),i=parseFloat(t);return isNaN(s)||isNaN(i)||i===0?e:s/i}capitalize(e,t=!0){const s=String(e);return s?t?s.replace(/\b\w/g,i=>i.toUpperCase()):s.charAt(0).toUpperCase()+s.slice(1):""}replace(e,t,s="",i="g"){if(e==null)return"";const r=String(e);if(t==null||t==="")return r;if(t instanceof RegExp)return r.replace(t,String(s));const n=String(t),a=n.match(/^\/(.+)\/([a-z]*)$/i);if(a){const[,o,l]=a;try{return r.replace(new RegExp(o,l),String(s))}catch{}}return String(i).includes("g")?r.split(n).join(String(s)):r.replace(n,String(s))}truncate(e,t=50,s="..."){const i=String(e);return i.length<=t?i:i.substring(0,t)+s}truncate_front(e,t=8,s="..."){const i=String(e);return i.length<=t?i:`${s}${i.slice(-t)}`}truncate_middle(e,t=8,s="***"){const i=String(e);if(i.length<=t)return i;const r=Math.floor(t/2),n=i.substring(0,r),a=i.substring(i.length-r);return`${n}${s}${a}`}slug(e,t="-"){return String(e).toLowerCase().replace(/[^\w\s-]/g,"").replace(/\s+/g,t).replace(new RegExp(`${t}+`,"g"),t).replace(new RegExp(`^${t}|${t}$`,"g"),"")}initials(e,t=2){return String(e).split(/\s+/).filter(r=>r.length>0).slice(0,t).map(r=>r.charAt(0).toUpperCase()).join("")}mask(e,t="*",s=4){const i=String(e);if(i.length<=s)return i;const r=t.repeat(Math.max(0,i.length-s)),n=i.slice(-s);return r+n}email(e,t={}){const s=String(e).trim();if(!s)return"";if(t.link===!1)return s;const i=t.subject?`?subject=${encodeURIComponent(t.subject)}`:"",r=t.body?`&body=${encodeURIComponent(t.body)}`:"",n=t.class?` class="${t.class}"`:"";return`<a href="mailto:${s}${i}${r}"${n}>${s}</a>`}phone(e,t="US",s=!0){let i=String(e).replace(/\D/g,""),r=i;return t==="US"&&(i.length===10?r=`(${i.slice(0,3)}) ${i.slice(3,6)}-${i.slice(6)}`:i.length===11&&i[0]==="1"&&(r=`+1 (${i.slice(1,4)}) ${i.slice(4,7)}-${i.slice(7)}`)),s?`<a href="tel:${i}">${r}</a>`:r}url(e,t=null,s=!0){let i=String(e).trim();return i?(/^https?:\/\//.test(i)||(i="https://"+i),`<a href="${i}"${s?' target="_blank"':""}${s?' rel="noopener noreferrer"':""}>${t||i}</a>`):""}badge(e,t="auto"){if(Array.isArray(e))return e.map(n=>this.badge(n,t)).join(" ");const s=String(e);if(typeof t=="string"&&t.includes("=")){const n=Object.fromEntries(t.split(",").map(l=>l.split("=").map(d=>d.trim()))),a=n[s]||n[s.toLowerCase()]||this.inferBadgeType(s);return`<span class="badge ${a?`bg-${a}`:"bg-secondary"}">${s}</span>`}const i=t==="auto"?this.inferBadgeType(s):t;return`<span class="badge ${i?`bg-${i}`:"bg-secondary"}">${s}</span>`}badgeClass(e,t="auto"){const s=String(e),i=t==="auto"?this.inferBadgeType(s):t;return i?`bg-${i}`:"bg-secondary"}inferBadgeType(e){const t=e.toLowerCase();return["active","pass","success","complete","completed","approved","done","true","on","yes"].includes(t)?"success":["error","failed","fail","rejected","deleted","cancelled","false","off","no","declined"].includes(t)?"danger":["warning","pending","review","processing","uploading"].includes(t)?"warning":["info","new","draft"].includes(t)?"info":(["inactive","disabled","archived","suspended"].includes(t),"secondary")}status(e){return this._status(e)}status_icon(e){return this._status(e,{},{},!1,!0)}status_text(e){return this._status(e,{},{},!0,!1)}_status(e,t={},s={},i=!1,r=!1){const n=String(e).toLowerCase(),a={active:"bi bi-check-circle-fill",approved:"bi bi-check-circle-fill",declined:"bi bi-x-circle-fill",inactive:"bi bi-pause-circle-fill",pending:"bi bi-clock-fill",success:"bi bi-check-circle-fill",error:"bi bi-exclamation-triangle-fill",warning:"bi bi-exclamation-triangle-fill"},o={active:"success",approved:"success",declined:"danger",inactive:"secondary",pending:"warning",success:"success",error:"danger",warning:"warning"},l=t[n]||a[n]||"",d=s[n]||o[n]||"secondary";let h="";!i&&l&&(h=`<i class="${l}"></i>`);let u="";return r||(u=e),`<span class="text-${d}">${h}${h?" ":""}${u}</span>`}boolean(e,t="True",s="False",i=!1){const r=e?t:s;return i?`<span class="text-${e?"success":"danger"}">${r}</span>`:r}bool(e){return e==null||e===0||e===""||e===!1||e==="false"?!1:e===!0||e==="true"?!0:!(Array.isArray(e)&&e.length===0||e&&typeof e=="object"&&e.constructor===Object&&Object.keys(e).length===0)}icon(e,t={}){const s=String(e).toLowerCase(),i=t[s]||"";return i?`<i class="${i}"></i>`:""}yesnoicon(e,t="bi bi-check-circle-fill text-success",s="bi bi-x-circle-fill text-danger"){return e?`<i class="${t}"></i>`:`<i class="${s}"></i>`}image(e,t="thumbnail",s="img-fluid",i=""){const r=this._extractImageUrl(e,t);return r?`<img src="${r}" class="${s}" alt="${i}" />`:""}avatar(e,t="md",s="rounded-circle",i=""){const r=this._extractImageUrl(e,"square_sm")||Ot,n={xs:"width: 1.5rem; height: 1.5rem;",sm:"width: 2rem; height: 2rem;",md:"width: 3rem; height: 3rem;",lg:"width: 4rem; height: 4rem;",xl:"width: 5rem; height: 5rem;"},a=n[t]||n.md,l=`object-fit-cover ${s}`.trim();return`<img src="${r}" class="${l}" style="${a}" alt="${i}" />`}tooltip(e,t="",s="top",i=""){if(e==null)return"";const r=String(e),n=i==="html"?t:this.escapeHtml(t);return`<span data-bs-toggle="tooltip" data-bs-placement="${s}" ${i==="html"?'data-bs-html="true"':""} data-bs-title="${n}">${r}</span>`}_extractImageUrl(e,t="thumbnail"){if(!e)return null;if(typeof e=="string")return e;if(typeof e=="object"){if(e.attributes&&(e=e.attributes),t==="thumbnail"&&e.thumbnail&&typeof e.thumbnail=="string")return e.thumbnail;if(e.renditions&&typeof e.renditions=="object"){const s=e.renditions[t];if(s&&s.url)return s.url;const i=Object.values(e.renditions);if(i.length>0&&i[0].url)return i[0].url}if(e.url)return e.url}return null}default(e,t=""){return e==null||e===""?t:e}equals(e,t,s,i=""){return e==t?s:i}plural(e,t,s=null,i=!0){if(e==null||t===null||t===void 0)return i?`${e} ${t}`:t||"";const r=parseInt(e);if(isNaN(r))return i?`${e} ${t}`:t||"";const n=Math.abs(r)===1?t:s||t+"s";return i?`${r} ${n}`:n}formatList(e,t={}){if(!Array.isArray(e))return String(e);const{conjunction:s="and",limit:i=null,moreText:r="others"}=t;if(e.length===0)return"";if(e.length===1)return String(e[0]);let n=e.slice(),a=!1;if(i&&e.length>i&&(n=e.slice(0,i),a=!0),a){const o=e.length-i;return`${n.join(", ")}, ${s} ${o} ${r}`}return n.length===2?`${n[0]} ${s} ${n[1]}`:`${n.slice(0,-1).join(", ")}, ${s} ${n[n.length-1]}`}duration(e,t="ms",s=!1,i=2){if(e==null)return"";const r=parseFloat(e);if(isNaN(r))return String(e);let n;switch(t){case"s":case"sec":case"seconds":n=r*1e3;break;case"m":case"min":case"minutes":n=r*6e4;break;case"h":case"hr":case"hours":n=r*36e5;break;case"d":case"day":case"days":n=r*864e5;break;default:n=r}const a=[{name:"day",short:"d",value:864e5},{name:"hour",short:"h",value:36e5},{name:"minute",short:"m",value:6e4},{name:"second",short:"s",value:1e3}];if(n===0)return s?"0s":"0 seconds";const o=Math.abs(n),l=n<0?"-":"",d=[];let h=o;for(const u of a)if(h>=u.value){const m=Math.floor(h/u.value);h=h%u.value;const p=s?u.short:m===1?u.name:u.name+"s";if(d.push(s?`${m}${p}`:`${m} ${p}`),d.length>=i)break}return d.length===0?s?`${Math.round(o)}ms`:`${Math.round(o)} milliseconds`:l+(s?d.join(""):d.join(" "))}hash(e,t=8,s="",i="..."){if(e==null)return"";const r=String(e);return r.length<=t?s+r:s+r.substring(0,t)+i}stripHtml(e){return e==null?"":String(e).replace(/<[^>]*>/g,"")}highlight(e,t,s="highlight"){if(e==null||!t)return String(e||"");const i=String(t).replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=new RegExp(`(${i})`,"gi");return String(e).replace(r,`<mark class="${s}">$1</mark>`)}hex(e,t=!1,s=!1){if(e==null)return"";let i="";const r=n=>Array.from(n).map(a=>a.toString(16).padStart(2,"0")).join("");if(typeof e=="number"){let n=Math.abs(Math.trunc(e)).toString(16);n.length%2&&(n="0"+n),i=n}else if(e instanceof Uint8Array)i=r(e);else if(e instanceof ArrayBuffer)i=r(new Uint8Array(e));else if(Array.isArray(e)&&e.every(n=>typeof n=="number"))i=r(Uint8Array.from(e.map(n=>n&255)));else{const a=new TextEncoder().encode(String(e));i=r(a)}return t&&(i=i.toUpperCase()),(s?"0x":"")+i}unhex(e){if(e==null)return"";let t=String(e).trim();if((t.startsWith("0x")||t.startsWith("0X"))&&(t=t.slice(2)),t=t.replace(/\s+/g,""),t.length===0)return"";t.length%2!==0&&(t="0"+t);const s=new Uint8Array(t.length/2);for(let i=0;i<t.length;i+=2){const r=parseInt(t.slice(i,i+2),16);if(Number.isNaN(r))return String(e);s[i/2]=r}try{return new TextDecoder().decode(s)}catch{let r="";for(const n of s)r+=String.fromCharCode(n);return r}}json(e,t=2){try{return JSON.stringify(e,null,t)}catch{return String(e)}}has(e){return this.formatters.has(e.toLowerCase())}unregister(e){return this.formatters.delete(e.toLowerCase())}listFormatters(){return Array.from(this.formatters.keys()).sort()}iter(e){return e==null?[]:Array.isArray(e)?e:typeof e=="object"?Object.entries(e).map(([t,s])=>({key:t,value:s})):[{key:"0",value:e}]}}const V=new jt;window.dataFormatter=V;const Qe=new Set(["__proto__","constructor","prototype"]),Xe=(c,e)=>c!=null&&Object.prototype.hasOwnProperty.call(c,e);class ${static getContextData(e,t){if(!t||e==null)return;let s=t,i="",r=0,n=-1;for(let o=0;o<t.length;o++){const l=t[o];if(l==="(")r++;else if(l===")")r--;else if(l==="|"&&r===0){n=o;break}}n>-1&&(s=t.substring(0,n).trim(),i=t.substring(n+1).trim());const a=this.getNestedValue(e,s);return i?V.pipe(a,i,e):a}static getNestedValue(e,t){if(!t||e==null||t.split(".").some(r=>Qe.has(r)))return;if(!t.includes(".")){if(t in e){const r=e[t];return typeof r=="function"?r===Object.prototype[t]?void 0:r.call(e):r}return}const s=t.split(".");let i=e;for(let r=0;r<s.length;r++){const n=s[r];if(i==null)return;if(r===0)if(Xe(i,n)){const a=i[n];typeof a=="function"?i=a.call(e):i=a}else return;else{if(i&&typeof i.getContextValue=="function"){const a=s.slice(r).join(".");return i.getContextValue(a)}if(Array.isArray(i)&&!isNaN(n))i=i[parseInt(n)];else if(Xe(i,n))i=i[n];else return}}return i}static isNullOrUndefined(e){return e==null}static deepClone(e){if(e===null||typeof e!="object")return e;if(e instanceof Date)return new Date(e.getTime());if(e instanceof Array)return e.map(t=>this.deepClone(t));if(e instanceof Object){const t={};for(const s in e)e.hasOwnProperty(s)&&(t[s]=this.deepClone(e[s]));return t}}static deepMerge(e,...t){if(!t.length)return e;const s=t.shift();if(this.isObject(e)&&this.isObject(s))for(const i in s)this.isObject(s[i])?(e[i]||Object.assign(e,{[i]:{}}),this.deepMerge(e[i],s[i])):Object.assign(e,{[i]:s[i]});return this.deepMerge(e,...t)}static isObject(e){return e&&typeof e=="object"&&!Array.isArray(e)}static debounce(e,t){let s;return function(...r){const n=()=>{clearTimeout(s),e(...r)};clearTimeout(s),s=setTimeout(n,t)}}static throttle(e,t){let s;return function(...i){s||(e.apply(this,i),s=!0,setTimeout(()=>s=!1,t))}}static generateId(e=""){const t=Date.now().toString(36),s=Math.random().toString(36).substr(2,9);return e?`${e}_${t}_${s}`:`${t}_${s}`}static escapeHtml(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(e).replace(/[&<>"'`=\/]/g,s=>t[s])}static checkPasswordStrength(e){if(!e||typeof e!="string")return{score:0,strength:"invalid",feedback:["Password must be a non-empty string"],details:{length:0,hasLowercase:!1,hasUppercase:!1,hasNumbers:!1,hasSpecialChars:!1,hasCommonPatterns:!1,isCommonPassword:!1}};const t=[],s={length:e.length,hasLowercase:/[a-z]/.test(e),hasUppercase:/[A-Z]/.test(e),hasNumbers:/[0-9]/.test(e),hasSpecialChars:/[^a-zA-Z0-9]/.test(e),hasCommonPatterns:!1,isCommonPassword:!1};let i=0;e.length<6?t.push("Password should be at least 6 characters long"):e.length<8?(i+=1,t.push("Consider using at least 8 characters for better security")):e.length<12?i+=3:i+=4,s.hasLowercase?i+=1:t.push("Include lowercase letters"),s.hasUppercase?i+=1:t.push("Include uppercase letters"),s.hasNumbers?i+=1:t.push("Include numbers"),s.hasSpecialChars?i+=2:t.push("Include special characters (!@#$%^&* etc.)");const r=[/123/,/abc/i,/qwerty/i,/asdf/i,/(.)\1{2,}/,/password/i,/admin/i,/user/i,/login/i];for(const o of r)if(o.test(e)){s.hasCommonPatterns=!0,i-=1,t.push("Avoid common patterns and dictionary words");break}["123456","password","123456789","12345678","12345","1234567","1234567890","qwerty","abc123","111111","123123","admin","letmein","welcome","monkey","password123","123qwe","qwerty123","000000","dragon","sunshine","princess","azerty","1234","iloveyou","trustno1","superman","shadow","master","jennifer"].includes(e.toLowerCase())&&(s.isCommonPassword=!0,i=Math.max(0,i-3),t.push("This password is too common and easily guessed"));let a;return i<2?a="very-weak":i<4?a="weak":i<6?a="fair":i<8?a="good":a="strong",i>=7&&t.length===0?t.push("Strong password! Consider using a password manager."):i>=5&&t.length<=1&&t.push("Good password strength. Consider adding more variety."),{score:Math.max(0,i),strength:a,feedback:t,details:s}}static generatePassword(e={}){const s={...{length:12,includeLowercase:!0,includeUppercase:!0,includeNumbers:!0,includeSpecialChars:!0,customChars:"",excludeAmbiguous:!1},...e};if(s.length<4)throw new Error("Password length must be at least 4 characters");let i="abcdefghijklmnopqrstuvwxyz",r="ABCDEFGHIJKLMNOPQRSTUVWXYZ",n="0123456789",a="!@#$%^&*()_+-=[]{}|;:,.<>?";s.excludeAmbiguous&&(i=i.replace(/[il]/g,""),r=r.replace(/[IOL]/g,""),n=n.replace(/[01]/g,""),a=a.replace(/[|]/g,""));let o="";const l=[];if(s.customChars?o=s.customChars:(s.includeLowercase&&(o+=i,l.push(i[Math.floor(Math.random()*i.length)])),s.includeUppercase&&(o+=r,l.push(r[Math.floor(Math.random()*r.length)])),s.includeNumbers&&(o+=n,l.push(n[Math.floor(Math.random()*n.length)])),s.includeSpecialChars&&(o+=a,l.push(a[Math.floor(Math.random()*a.length)]))),!o)throw new Error("No character types selected for password generation");let d="";for(const h of l)d+=h;for(let h=d.length;h<s.length;h++)d+=o[Math.floor(Math.random()*o.length)];return d.split("").sort(()=>Math.random()-.5).join("")}static parseQueryString(e){const t={},s=new URLSearchParams(e);for(const[i,r]of s.entries())t[i]=r;return t}static toQueryString(e){return new URLSearchParams(e).toString()}static wrapData(e,t=null,s=3){return!e||typeof e!="object"||e instanceof Date||e instanceof RegExp||e instanceof Error||s<=0||typeof e.getContextValue=="function"?e:Array.isArray(e)?e.map(i=>i&&typeof i=="object"&&!i.getContextValue?new Ee(i,t):i):new Ee(e,t)}}class Ee{constructor(e,t=null){if(Object.defineProperty(this,"_data",{value:e,writable:!1,enumerable:!1,configurable:!1}),Object.defineProperty(this,"_rootContext",{value:t,writable:!1,enumerable:!1,configurable:!1}),e&&typeof e=="object"){for(const s in e)if(e.hasOwnProperty(s)){const i=e[s];this[s]=$.wrapData(i,t)}}}getContextValue(e){let t=e,s="",i=0,r=-1;for(let a=0;a<e.length;a++){const o=e[a];if(o==="(")i++;else if(o===")")i--;else if(o==="|"&&i===0){r=a;break}}r>-1&&(t=e.substring(0,r).trim(),s=e.substring(r+1).trim());let n;return t in this&&!Qe.has(t)&&t!=="_data"&&t!=="_rootContext"?n=this[t]:n=$.getNestedValue(this._data,t),s&&n!==void 0?V.pipe(n,s,this._rootContext||this._data):n}has(e){return this._data&&this._data.hasOwnProperty(e)}toJSON(){return this._data}}$.DataWrapper=Ee,typeof window<"u"&&(window.utils=$);const Ht=new Set(["__proto__","constructor","prototype"]),zt=Object.prototype.toString,le=Array.isArray||function(c){return zt.call(c)==="[object Array]"},me=function(c){return typeof c=="function"},et=function(c){return c!==null&&typeof c=="object"};function qt(){return typeof window>"u"?null:window.MOJO?.dataFormatter?window.MOJO.dataFormatter:window.dataFormatter?window.dataFormatter:null}const tt=function(c){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(c).replace(/[&<>"'`=\/]/g,function(t){return e[t]})};class st{constructor(e){this.string=e,this.tail=e,this.pos=0}eos(){return this.tail===""}scan(e){const t=this.tail.match(e);if(!t||t.index!==0)return"";const s=t[0];return this.tail=this.tail.substring(s.length),this.pos+=s.length,s}scanUntil(e){const t=this.tail.search(e);let s;switch(t){case-1:s=this.tail,this.tail="";break;case 0:s="";break;default:s=this.tail.substring(0,t),this.tail=this.tail.substring(t)}return this.pos+=s.length,s}}class we{constructor(e,t){this.view=e,this.cache={".":this.view},this.parent=t,this.view?._cacheId||this.view&&typeof this.view=="object"&&(this.view._cacheId=Math.random().toString(36).substring(2))}push(e){return new we(e,this)}lookup(e){if(this.renderCache&&this.view?._cacheId){const i=`${this.view._cacheId}:${e}`;if(this.renderCache.has(i))return this.renderCache.get(i)}if(e===".")return this.view;if(e&&(e.startsWith(".")?e.slice(1):e).split("|")[0].split(".").some(r=>Ht.has(r)))return;if(e&&e.startsWith(".")){let i=e.substring(1),r=!1,n=null;const a=i.indexOf("|");if(a!==-1&&(n=i.substring(a+1).trim(),i=i.substring(0,a).trim()),i.endsWith("|iter")&&(i=i.substring(0,i.length-5),r=!0),this.view&&typeof this.view=="object"){let o;if(typeof this.view.getContextValue=="function")try{o=this.view.getContextValue(i),o!==void 0&&me(o)&&(o=o.call(this.view))}catch{o=void 0}if(o===void 0&&(i.indexOf(".")>0?o=$.getNestedValue(this.view,i):i in this.view&&(o=this.view[i],me(o)&&(o===Object.prototype[i]?o=void 0:o=o.call(this.view)))),n&&o!==void 0)try{const l=qt();l&&typeof l.pipe=="function"&&(o=l.pipe(o,n,this))}catch{}return le(o)?r?o:o.length>0:et(o)?r?Object.entries(o).map(([l,d])=>({key:l,value:d})):Object.keys(o).length>0:o}return}const t=this.cache;let s;if(t.hasOwnProperty(e))s=t[e];else{let i=this,r,n,a,o=!1;for(;i;){if(i.view&&typeof i.view.getContextValue=="function")try{r=i.view.getContextValue(e),r!==void 0&&(o=!0)}catch{o=!1}if(!o)if(e.indexOf(".")>0)for(r=i.view,n=e.split("."),a=0;r!=null&&a<n.length;)if(r&&typeof r.getContextValue=="function"&&a<n.length)try{const l=n.slice(a).join(".");r=r.getContextValue(l),a=n.length,r!==void 0&&(o=!0)}catch{a===n.length-1&&(o=Fe(r,n[a])||it(r,n[a])),r=r[n[a++]]}else a===n.length-1&&(o=Fe(r,n[a])||it(r,n[a])),r=r[n[a++]];else r=i.view[e],o=Fe(i.view,e);if(o){s=r;break}i=i.parent}t[e]=s}if(me(s)){const i=e.split("|")[0].split(".").pop();if(s===Object.prototype[i])s=void 0;else try{s=s.call(this.view)}catch(r){if(r instanceof TypeError&&/^Class constructor /.test(r.message))s=void 0;else throw r}}if(this.renderCache&&this.view?._cacheId){const i=`${this.view._cacheId}:${e}`;this.renderCache.set(i,s)}return s}}function Fe(c,e){return c!=null&&typeof c=="object"&&e in c}function it(c,e){return c!=null&&typeof c!="object"&&c.hasOwnProperty&&c.hasOwnProperty(e)}class rt{constructor(){this.templateCache=new Map}clearCache(){this.templateCache.clear()}parse(e,t){t=t||["{{","}}"];const s=e+":"+t.join(":");let i=this.templateCache.get(s);return i==null&&(i=this.parseTemplate(e,t),this.templateCache.set(s,i)),i}parseTemplate(e,t){if(!e)return[];const s=t[0],i=t[1],r=new st(e),n=[];let a,o,l,d,h;const u=new RegExp(De(s)+"\\s*"),m=new RegExp("\\s*"+De(i)),p=new RegExp("\\s*"+De("}"+i));for(;!r.eos();){if(a=r.pos,l=r.scanUntil(u),l)for(let f=0;f<l.length;++f)d=l.charAt(f),d===`
15
+ `?n.push(["text",d]):n.push(["text",d]);if(!r.scan(u))break;if(o=r.scan(/[#^\/>{&=!]/),o||(o="name"),r.scan(/\s*/),o==="="?(l=r.scanUntil(/\s*=/),r.scan(/\s*=/),r.scanUntil(m)):o==="{"?(l=r.scanUntil(p),r.scan(p),o="&"):l=r.scanUntil(m),r.scan(m),o==="#"||o==="^")h=[o,l,a,r.pos],n.push(h);else if(o==="/"){let f;for(let g=n.length-1;g>=0;--g)if((n[g][0]==="#"||n[g][0]==="^")&&n[g][1]===l){f=n[g];break}f&&f.length===4&&f.push(r.pos),n.push([o,l,a,r.pos])}else n.push([o,l,a,r.pos])}return this.nestSections(this.squashTokens(n))}squashTokens(e){const t=[];let s,i;for(let r=0;r<e.length;++r)s=e[r],s&&(s[0]==="text"&&i&&i[0]==="text"?(i[1]+=s[1],i[3]=s[3]):(t.push(s),i=s));return t}nestSections(e){const t=[];let s=t;const i=[];for(let r=0;r<e.length;++r){const n=e[r];switch(n[0]){case"#":case"^":const a=[n[0],n[1],n[2],n[3],[],n[4]||null];s.push(a),i.push(a),s=a[4];break;case"/":const o=i.pop();o&&(o[5]=n[2],s=i.length>0?i[i.length-1][4]:t);break;default:s.push(n)}}return t}render(e,t,s,i){const r=this.getConfigTags(i)||["{{","}}"],n=this.parse(e,r),a=new Map;return this.renderTokens(n,new we(t),s,e,i,a)}renderTokens(e,t,s,i,r,n){n&&!t.renderCache&&(t.renderCache=n);let a="";for(let o=0;o<e.length;++o){const l=e[o];let d;switch(l[0]){case"#":if(d=t.lookup(l[1]),!d)continue;const h=l[4];if(!h||!le(h)){console.warn(`MUSTACHE WARNING - Section ${l[1]} has no child tokens:`,l);continue}if(le(d))for(let u=0;u<d.length;++u){const m=t.push(d[u]);t.renderCache&&(m.renderCache=t.renderCache);const p=this.renderTokens(h,m,s,i,r,n);a+=p}else if(typeof d=="object"||typeof d=="string"||typeof d=="number"){const u=t.push(d);t.renderCache&&(u.renderCache=t.renderCache),a+=this.renderTokens(h,u,s,i,r,n)}else if(me(d)){const u=i==null?null:i.slice(l[3],l[5]);d=d.call(t.view,u,m=>this.render(m,t.view,s,r)),d!=null&&(a+=d)}else d&&(a+=this.renderTokens(h,t,s,i,r,n));break;case"^":if(d=t.lookup(l[1]),!d||le(d)&&d.length===0){const u=l[4];u&&le(u)&&(a+=this.renderTokens(u,t,s,i,r,n))}break;case">":if(!s)continue;d=me(s)?s(l[1]):s[l[1]],d!=null&&(a+=this.render(d,t.view,s,r));break;case"&":d=t.lookup(l[1]),d!=null&&(a+=d);break;case"name":d=t.lookup(l[1]),d!=null&&(a+=tt(d));break;case"text":a+=l[1];break}}return a}getConfigTags(e){return et(e)&&le(e.tags)?e.tags:null}}function De(c){return c.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}const ke=new rt,D={name:"MOJO Mustache",version:"1.0.0",tags:["{{","}}"],Scanner:st,Context:we,Writer:rt,escape:tt,clearCache(){return ke.clearCache()},parse(c,e){return ke.parse(c,e)},render(c,e,t,s){if(typeof c!="string")throw new TypeError('Invalid template! Template should be a "string"');return e&&typeof e=="object"&&!e.getContextValue&&typeof e.toJSON!="function"&&(e=$.wrapData(e)),ke.render(c,e,t,s)}};class Bt{constructor(e){this.view=e,this.domListeners=[],this.debounceTimers=new Map}_enterDispatchChain(e){const t=e._mojoDispatch;let s;return e._mojoDispatch=new Promise(i=>{s=i}),{prior:t,done:s}}bind(e){if(this.unbind(),!e)return;const t=async a=>{const{prior:o,done:l}=this._enterDispatchChain(a);try{o&&await o;const d=a.target.closest("[data-action]");if(d&&this.shouldHandle(d,a)){const u=d.getAttribute("data-action");if(d.tagName==="A"&&a.preventDefault(),this.hideTooltip(d),await this.dispatch(u,a,d)){a.preventDefault(),a.stopPropagation(),a.handledByChild=!0;return}}const h=a.target.closest("a[href], [data-page]");if(h&&!h.hasAttribute("data-action")&&this.shouldHandle(h,a)){if(a.ctrlKey||a.metaKey||a.shiftKey||a.button===1)return;if(h.tagName==="A"){const u=h.getAttribute("href");if(u&&u!=="#"&&!u.startsWith("#")&&(this.view.isExternalLink(u)||h.hasAttribute("data-external")))return}this.hideTooltip(h),a.preventDefault(),a.stopPropagation(),a.handledByChild=!0,h.hasAttribute("data-page")?await this.view.handlePageNavigation(h):await this.view.handleHrefNavigation(h)}}finally{l()}},s=async a=>{const{prior:o,done:l}=this._enterDispatchChain(a);try{o&&await o;const d=a.target.closest("[data-change-action]");if(d&&this.shouldHandle(d,a)){const u=d.getAttribute("data-change-action");await this.dispatchChange(u,a,d)&&(a.stopPropagation(),a.handledByChild=!0);return}const h=a.target.closest("[data-action]");if(h&&this.isFormControl(h)&&this.shouldHandle(h,a)){const u=h.getAttribute("data-action");await this.dispatch(u,a,h)&&(a.stopPropagation(),a.handledByChild=!0)}}finally{l()}},i=a=>{const o=a.target.closest("[data-change-action]");if(o&&this.shouldHandle(o,a)&&a.target.matches('[data-filter="live-search"]')){const m=o.getAttribute("data-change-action"),p=parseInt(o.getAttribute("data-filter-debounce"))||300,f=`change-${m}-${o.getAttribute("data-container")||"default"}`;this.debounceTimers.has(f)&&clearTimeout(this.debounceTimers.get(f));const g=setTimeout(()=>{this.debounceTimers.delete(f),this.dispatchChange(m,a,o).then(b=>{b&&(a.stopPropagation(),a.handledByChild=!0)})},p);this.debounceTimers.set(f,g);return}const l=a.target.closest("[data-action]");if(!l||!this.isFormControl(l)||l.hasAttribute("data-change-action")||!this.shouldHandle(l,a))return;const d=l.getAttribute("data-action"),h=l.getAttribute("data-action-debounce"),u=h!=null&&parseInt(h)||0;if(u>0){const m=`action-${d}-${l.getAttribute("data-container")||"default"}`;this.debounceTimers.has(m)&&clearTimeout(this.debounceTimers.get(m));const p=setTimeout(()=>{this.debounceTimers.delete(m),this.dispatch(d,a,l).then(f=>{f&&(a.stopPropagation(),a.handledByChild=!0)})},u);this.debounceTimers.set(m,p);return}this.dispatch(d,a,l).then(m=>{m&&(a.stopPropagation(),a.handledByChild=!0)})},r=async a=>{if(a.target.matches('[data-filter="search"]'))return;const o=a.target.closest("[data-keydown-action]")||a.target.closest("[data-change-action]");if(!o)return;const{prior:l,done:d}=this._enterDispatchChain(a);try{if(l&&await l,!this.shouldHandle(o,a))return;let h=["Enter"];if(o.getAttribute("data-change-keys")&&(h=o.getAttribute("data-change-keys").split(",").map(u=>u.trim())),h.includes("*")||h.includes(a.key)){const u=o.getAttribute("data-keydown-action")||o.getAttribute("data-change-action");await this.dispatch(u,a,o)&&(a.preventDefault(),a.stopPropagation(),a.handledByChild=!0)}}finally{d()}},n=a=>{const o=a.target.closest("form[data-action]");if(!o||!this.shouldHandle(o,a))return;a.preventDefault();const l=o.getAttribute("data-action");this.dispatch(l,a,o)};e.addEventListener("click",t),e.addEventListener("change",s),e.addEventListener("input",i),e.addEventListener("keydown",r),e.addEventListener("submit",n),this.domListeners.push({el:e,type:"click",fn:t},{el:e,type:"change",fn:s},{el:e,type:"input",fn:i},{el:e,type:"keydown",fn:r},{el:e,type:"submit",fn:n})}unbind(){for(const{el:e,type:t,fn:s}of this.domListeners)e.removeEventListener(t,s);this.domListeners=[];for(const e of this.debounceTimers.values())clearTimeout(e);this.debounceTimers.clear()}hideDropdown(e){const s=e.closest(".dropdown-menu").closest(".dropdown");if(!s)return;const i=s.querySelector('[data-bs-toggle="dropdown"]');i&&window.bootstrap?.Dropdown&&window.bootstrap.Dropdown.getInstance(i)?.hide()}hideTooltip(e){if(e&&window.bootstrap?.Tooltip){const t=window.bootstrap.Tooltip.getInstance(e);t&&t.dispose()}}hideAllTooltips(){window.bootstrap?.Tooltip&&document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(t=>{const s=window.bootstrap.Tooltip.getInstance(t);s&&s.hide()})}async dispatch(e,t,s){const i=this.view,r=l=>l.includes("-")?l.split("-").map(d=>d[0].toUpperCase()+d.slice(1)).join(""):l[0].toUpperCase()+l.slice(1),n=`handleAction${r(e)}`;if(typeof i[n]=="function")try{return t.preventDefault(),await i[n](t,s),!0}catch(l){return console.error(`Error in action ${e}:`,l),i.handleActionError(e,l,t,s),!0}const a=`onAction${r(e)}`;if(typeof i[a]=="function")try{return await i[a](t,s)?(s.closest(".dropdown-menu")&&this.hideDropdown(s),t.preventDefault(),t.stopPropagation(),!0):!1}catch(l){return console.error(`Error in action ${e}:`,l),i.handleActionError(e,l,t,s),!0}const o=`onPassThruAction${r(e)}`;if(typeof i[o]=="function")try{return await i[o](t,s),!1}catch(l){return console.error(`Error in action ${e}:`,l),i.handleActionError(e,l,t,s),!0}if(typeof i.onActionDefault=="function")try{return await i.onActionDefault(e,t,s)}catch(l){return console.error(`Error in default action handler for ${e}:`,l),i.handleActionError(e,l,t,s),!0}return i.emit?.(`action:${e}`,{action:e,event:t,element:s}),!1}async dispatchChange(e,t,s){const i=this.view,n=`onChange${(a=>a.includes("-")?a.split("-").map(o=>o[0].toUpperCase()+o.slice(1)).join(""):a[0].toUpperCase()+a.slice(1))(e)}`;if(typeof i[n]=="function")try{return await i[n](t,s),!0}catch(a){return console.error(`Error in onChange ${e}:`,a),i.handleActionError?.(e,a,t,s),!0}return await this.dispatch(e,t,s)}isFormControl(e){if(!e||!e.tagName)return!1;const t=e.tagName;return t==="INPUT"||t==="TEXTAREA"||t==="SELECT"}shouldHandle(e,t){return!!(this.owns(e)||this.contains(e)&&!t.handledByChild)}owns(e){const t=this.view.element;if(!t||!t.contains(e))return!1;for(const s of Object.values(this.view.children))if(s.element&&s.element.contains(e))return!1;return!0}contains(e){return!!this.view.element&&this.view.element.contains(e)}}const Ie={on(c,e,t){this._listeners||(this._listeners={}),this._listeners[c]||(this._listeners[c]=[]);const s={callback:e,context:t,fn:t?e.bind(t):e};return this._listeners[c].push(s),this},off(c,e,t){return!this._listeners||!this._listeners[c]?this:(e?(this._listeners[c]=this._listeners[c].filter(s=>s.callback!==e||arguments.length===3&&s.context!==t),this._listeners[c].length===0&&delete this._listeners[c]):delete this._listeners[c],this)},once(c,e,t){const s=(...i)=>{this.off(c,s),(t?e.bind(t):e).apply(t||this,i)};return this.on(c,s),this},emit(c,...e){if(!this._listeners||!this._listeners[c])return this;const t=this._listeners[c].slice();for(const s of t)try{s.fn.apply(s.context||this,e)}catch(i){console&&console.error&&console.error(`Error in ${c} event handler:`,i)}return this}};typeof window<"u"&&(window.Mustache=D);class C{constructor(e={}){this.tagName=e.tagName??"div",this.className=e.className??"mojo-view",this.style=e.style??null,this.id=e.id??C._genId(),this.containerId=e.containerId??null,this.container=e.container??null,typeof this.container=="string"&&(this.containerId=this.container,this.container=null),this.parent=e.parent??null,this.children=e.children??{},this.template=e.template||e.templateUrl||"",this.data=e.data??{},this.isRendering=!1,this._renderQueued=!1,this.lastRenderTime=0,this.mounted=!1,this.debug=e.debug??!1,this.app=e.app??null,this.cacheTemplate=e.cacheTemplate??!0,this.enableTooltips=e.enableTooltips??!1,this.options={...e},this.element=this._ensureElement(),this.events=new Bt(this),e.model&&this.setModel(e.model)}async onInit(){}async onInitView(){this.initialized||(this.initialized=!0,await this.onInit())}async onBeforeRender(){}async onAfterRender(){}async onBeforeMount(){}async onAfterMount(){}async onBeforeUnmount(){}async onAfterUnmount(){}async onBeforeDestroy(){}async onAfterDestroy(){}setModel(e={}){let t=e!==this.model;if(!t)return this;this.model&&this.model.off&&this.model.off("change",this._onModelChange,this),this.model=e,this.model&&this.model.on&&this.model.on("change",this._onModelChange,this);for(const s in this.children){const i=this.children[s];i&&typeof i.setModel=="function"&&i.setModel(e)}return t&&this._onModelChange(),this}_onModelChange(e,t){t&&t.skipRender||this.isMounted()&&this.render()}setTemplate(e){return this.template=e??"",this}addChild(e,t){try{if(!e||typeof e!="object")return this;t&&((t.containerId||t.container)&&(e.containerId=t.containerId||t.container),t.id&&(e.id=t.id),t.lazyMount===!0&&(e._lazyMount=!0)),e.parent=this,this.getApp()&&(e.app=this.app),this.children[e.id]=e}catch(s){C._warn("addChild error",s)}return e}removeChild(e){try{const t=typeof e=="string"?e:e&&e.id;if(!t)return this;const s=this.children[t];s&&(Promise.resolve(s.destroy()).catch(i=>C._warn("removeChild destroy error",i)),delete this.children[t])}catch(t){C._warn("removeChild error",t)}return this}getChild(e){return this.children[e]}async updateData(e,t=!1){return Object.assign(this.data,e),t&&this.isMounted()&&await this.render(),this}toggleClass(e,t){return t===void 0&&(t=!this.element.classList.contains(e)),this.element.classList.toggle(e,t),this}addClass(e){return this.element.classList.add(e),this}setClass(e){return this.element.className=e,this}removeClass(e){return this.element.classList.remove(e),this}canRender(){if(this.isRendering)return!1;const e=Date.now();if(this.options.renderCooldown>0&&e-this.lastRenderTime<this.options.renderCooldown)return C._warn(`View ${this.id}: Render called too quickly, cooldown active`),!1;if(this.options.noAppend&&this.parent)if(this.parent.contains(this.containerId||this.container)){if(this.containerId&&!document.getElementById(this.containerId))return!1;if(this.container&&!document.contains(this.container))return!1}else return!1;return!0}async render(e=!0,t=null){const s=Date.now();if(this.isRendering)return this._renderQueued=!0,this._renderQueuedArgs={allowMount:e,container:t},this;if(!this.canRender())return this;this.isRendering=!0,this.lastRenderTime=s;try{this.initialized||await this.onInitView(),this.unbindEvents(),await this.onBeforeRender(),this.getViewData&&(this.data=await this.getViewData());const i=await this.renderTemplate();this.element.innerHTML=i,e&&!this.isMounted()&&await this.mount(t),await this._renderChildren(),await this.onAfterRender(),this.bindEvents()}catch(i){C._warn(`Render error in ${this.id}`,i)}finally{this.isRendering=!1}if(this._renderQueued){this._renderQueued=!1;const i=this._renderQueuedArgs||{allowMount:!0,container:null};this._renderQueuedArgs=null,await this.render(i.allowMount,i.container)}return this}async _renderChildren(){const e=[];for(const t in this.children){const s=this.children[t];if(s){if(s.parent=this,s._lazyMount&&!s._lazyTriggered){e.push(s);continue}await Promise.resolve(s.render()).catch(i=>C._warn(`Child render error (${t})`,i))}}e.length&&this._setupLazyMountObserver(e)}_setupLazyMountObserver(e){if(typeof IntersectionObserver>"u"){e.forEach(t=>{t._lazyTriggered=!0,Promise.resolve(t.render()).catch(s=>C._warn(`Lazy child render error (${t.id})`,s))});return}this._lazyObserver||(this._lazyObserver=new IntersectionObserver((t,s)=>{for(const i of t){if(!i.isIntersecting)continue;const r=i.target.__mojoLazyChild;s.unobserve(i.target),!(!r||r._lazyTriggered)&&(r._lazyTriggered=!0,Promise.resolve(r.render()).catch(n=>C._warn(`Lazy child render error (${r.id})`,n)))}},{rootMargin:"120px 0px",threshold:.01}));for(const t of e){const s=this.getChildElement(t.containerId);s&&(s.__mojoLazyChild=t,s.style.minHeight||(s.classList.add("mojo-lazy-placeholder"),s.style.minHeight="1px"),this._lazyObserver.observe(s),requestAnimationFrame(()=>{if(t._lazyTriggered)return;const i=s.getBoundingClientRect(),r=typeof window<"u"?window.innerHeight:0,n=typeof window<"u"?window.innerWidth:0;i.top<r+120&&i.bottom>-120&&i.left<n&&i.right>0&&(t._lazyTriggered=!0,this._lazyObserver?.unobserve(s),Promise.resolve(t.render()).catch(o=>C._warn(`Lazy child render error (${t.id})`,o)))}))}}async _unmountChildren(){for(const e in this.children){const t=this.children[e];t&&t.unbindEvents()}}isMounted(){return this.element?.isConnected}getChildElementById(e,t=null){const s=e.startsWith("#")?e.substring(1):e;return t?t.querySelector(`#${s}`):this.element.querySelector(`#${s}`)}getChildElement(e){if(e.startsWith("#"))return this.getChildElementById(e);let t=this.element?.querySelector(`[data-container="${e}"]`);return t||this.getChildElementById(e)}getContainer(){return this.replaceById?this.parent?this.parent.getChildElementById(this.id):null:this.containerId?this.parent?this.parent.getChildElement(this.containerId):this.getChildElementById(this.containerId,document.body):null}async mount(e=null){if(await this.onBeforeMount(),e||(e=this.getContainer()),this.containerId&&!e){console.error(`Container not found for ${this.containerId}`);return}e&&this.replaceById?e.replaceWith(this.element):e?e.replaceChildren(this.element):!this.containerId&&this.parent?this.parent.element.appendChild(this.element):!this.containerId&&!this.parent&&this.options.allowAppendToBody?(console.log("APPENDING TO BODY!!!!"),document.body.appendChild(this.element)):console.error(`Container not found for ${this.containerId}`),await this.onAfterMount(),this.mounted=!0}async unmount(){!this.element||!this.element.parentNode||(await this.onBeforeUnmount(),await this._unmountChildren(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),this.events.unbind(),await this.onAfterUnmount(),this.mounted=!1)}async destroy(){try{this.events.unbind(),this._lazyObserver&&(this._lazyObserver.disconnect(),this._lazyObserver=null);for(const e in this.children){const t=this.children[e];t&&await Promise.resolve(t.destroy()).catch(s=>C._warn(`Child destroy error (${e})`,s))}this.mounted=!1,this.element&&this.element.parentNode&&(await this.onBeforeDestroy(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),await this.onAfterDestroy())}catch(e){C._warn(`Destroy error in ${this.id}`,e)}}_ensureElement(){try{if(this.element&&this.element.tagName?.toLowerCase()===this.tagName)return this._syncAttrs(),this.element;const e=document.createElement(this.tagName);return this.element=e,this.el=e,this._syncAttrs(),e}catch(e){C._warn("ensureElement error",e);const t=document.createElement("div");return t.id=this.id||C._genId(),t}}_syncAttrs(){try{if(!this.element)return;this.id&&(this.element.id=this.id),this.element.className=this.className||"",this.style==null?this.element.removeAttribute("style"):this.element.style.cssText=String(this.style)}catch(e){C._warn("_syncAttrs error",e)}}bindEvents(){this.events.bind(this.element),this.enableTooltips&&this.initializeTooltips()}unbindEvents(){this.events.unbind(),this.enableTooltips&&this.disposeTooltips()}async renderTemplate(){const e=await this.getTemplate();if(!e)return"";const t=this.getPartials();return D.render(e,this,t)}renderTemplateString(e,t,s){return D.render(e,t,s)}getPartials(){return{}}async getTemplate(){if(this._templateCache&&this.cacheTemplate)return this._templateCache;const e=this.template||this.templateUrl;if(!e)throw new Error("Template not found");let t="";if(typeof e=="string")if(e.includes("<")||e.includes("{"))t=e;else try{let s=e;this.app||(this.app=this.getApp()),this.app&&this.app.basePath&&!s.startsWith("/")&&!s.startsWith("http://")&&!s.startsWith("https://")&&(s=`${this.app.basePath.endsWith("/")?this.app.basePath.slice(0,-1):this.app.basePath}/${s}`);const i=await fetch(s);if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);t=await i.text()}catch(s){C._warn(`Failed to load template from ${e}: ${s}`),this.showError?.(`Failed to load template from ${e}: ${s.message}`)}else typeof e=="function"&&(t=await this.template(this.data,this.state));return this.cacheTemplate&&t&&typeof e!="function"&&(this._templateCache=t),t}getContextValue(e){const t=$.getContextData(this,e);return e&&e.startsWith("data.")&&t&&typeof t=="object"?$.wrapData(t,this):e&&e.startsWith("model.")&&e!=="model"&&t&&typeof t=="object"&&typeof t.getContextValue!="function"?$.wrapData(t,null):t}async handlePageNavigation(e){const t=e.getAttribute("data-page"),s=e.getAttribute("data-params");let i={};if(s)try{i=JSON.parse(s)}catch{console.warn("Invalid JSON in data-params:",s)}const r=this.getApp();if(r){r.showPage(t,i);return}const n=this.findRouter();n&&typeof n.navigateToPage=="function"?await n.navigateToPage(t,i):console.error(`No router found for page navigation to '${t}'`)}async handleHrefNavigation(e){const t=e.getAttribute("href");if(this.isExternalLink(t)||e.hasAttribute("data-external"))return;const s=this.findRouter();if(s){if(s.options&&s.options.mode==="param"&&t.startsWith("?")){const r="/"+t;await s.navigate(r);return}if(s.options&&s.options.mode==="hash"&&t.startsWith("#")){await s.navigate(t);return}const i=this.hrefToRoutePath(t);await s.navigate(i)}else console.warn("No router found for navigation, using default behavior"),window.location.href=t}isExternalLink(e){return e?e.startsWith("/")&&this.getApp()?!e.startsWith(this.findRouter().basePath):e.startsWith("#")||e.startsWith("mailto:")||e.startsWith("tel:")||e.startsWith("http://")||e.startsWith("https://")||e.startsWith("//"):!0}hrefToRoutePath(e){if(e.startsWith("/")){const t=this.findRouter();if(t&&t.options&&t.options.base){const s=t.options.base;if(e.startsWith(s))return e.substring(s.length)||"/"}return e}return e.startsWith("./")?e.substring(2):e}findRouter(){return this.getApp(),this.app?.router||null}getApp(){if(this.app)return this.app;const e=[window.__app__,window.MOJO?.app,window.APP,window.app,window.WebApp,window.matchUUID?window[window.matchUUID]():window[window.matchUUID]];return this.app=e.find(t=>t&&typeof t.showPage=="function")||null,this.app}checkPermissions(e){if(!e)return!0;const t=this.getApp()?.activeUser;return!!(t&&typeof t.hasPermission=="function"&&t.hasPermission(e))}handleActionError(e,t,s,i){this.showError(`Action '${e}' failed: ${t}`,s,i)}escapeHtml(e){return typeof e!="string"?e:e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}contains(e){if(typeof e=="string"){if(!this.element)return!1;e=document.getElementById(e)}return e?this.element.contains(e):!1}initializeTooltips(){if(!this.element||!window.bootstrap?.Tooltip)return;this.disposeTooltips(),[...this.element.querySelectorAll('[data-bs-toggle="tooltip"]')].map(t=>{const s=t.getAttribute("data-tooltip-theme"),i=t.getAttribute("data-tooltip-size");let r="";s&&(r+=`tooltip-${s} `),i&&(r+=`tooltip-${i}`);const n={},a=r.trim();return a&&(n.customClass=a),new window.bootstrap.Tooltip(t,n)})}disposeTooltips(){if(!this.element||!window.bootstrap?.Tooltip)return;this.element.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(t=>{const s=window.bootstrap.Tooltip.getInstance(t);s&&s.dispose()})}async showError(e){console.error(`View ${this.id} error:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showError=="function"){await t.showError(e);return}alert(`Error: ${e}`)}async showSuccess(e){this.debug&&console.log(`View ${this.id} success:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showSuccess=="function"){await t.showSuccess(e);return}alert(`Success: ${e}`)}async showInfo(e){console.info(`View ${this.id} info:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showInfo=="function"){await t.showInfo(e);return}alert(`Info: ${e}`)}async showWarning(e){console.warn(`View ${this.id} warning:`,e);const t=this.getApp?this.getApp():this.app||null;if(t&&typeof t.showWarning=="function"){await t.showWarning(e);return}alert(`Warning: ${e}`)}async onActionCopyToClipboard(e,t){try{const i=(t?.closest("[data-clipboard]")||t)?.getAttribute("data-clipboard")||"";if(!i)return!0;if(navigator.clipboard&&window.isSecureContext)await navigator.clipboard.writeText(i);else{const a=document.createElement("textarea");a.value=i,document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a)}const r=t.querySelector("i"),n=r&&r.className;return r&&(r.className="bi bi-check",setTimeout(()=>{r.className=n},1e3)),!0}catch(s){return console.warn("Copy to clipboard failed:",s),!0}}static _genId(){return`view_${Math.random().toString(36).substr(2,9)}`}static _warn(e,t){try{t?console.warn(`[View] ${e}:`,t):console.warn(`[View] ${e}`)}catch{}}}Object.assign(C.prototype,Ie);class x extends C{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:x._baseZIndex}static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=x._openDialogs;if(e.length===0||t.length===0)return;const s=[...t].sort((n,a)=>(n._dialogZIndex||0)-(a._dialogZIndex||0)),r=document.querySelector(".table-fullscreen")||document.body;e.forEach((n,a)=>{if(a>=s.length)return;const o=s[a];n.style.zIndex=o._dialogZIndex-5,n.parentNode!==r&&r.appendChild(n)})}static updateAllBackdropStacking(){x.fixAllBackdropStacking()}static getMountTarget(){return document.querySelector(".table-fullscreen")||document.body}constructor(e={}){const t=e.id||`modal-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;super({...e,id:t,tagName:"div",className:`modal ${e.fade!==!1?"fade":""} ${e.className||""}`.trim().replace(/\s+/g," "),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=e.centered!==void 0?e.centered:!1,this.scrollable=e.scrollable!==void 0?e.scrollable:!1,this.autoSize=e.autoSize||e.size==="auto",this.backdrop=e.backdrop!==void 0?e.backdrop:!0,this.keyboard=e.keyboard!==void 0?e.keyboard:!0,this.focus=e.focus!==void 0?e.focus:!0,this.header=e.header!==void 0?e.header:!0,this.headerContent=e.headerContent||null,this.headerView=null,this.closeButton=e.closeButton!==void 0?e.closeButton:!0,this.contextMenu=e.contextMenu||null,this._processHeaderContent(this.headerContent),this.body=e.body??e.view??e.message??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=e.autoShow!==void 0?e.autoShow:!1,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(e){if(e instanceof C||e&&typeof e=="object"&&typeof e.render=="function")this.bodyView=e,this.body="",this.addChild(this.bodyView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.bodyView=t,this.body="",this.addChild(this.bodyView)):t instanceof Promise?(this.bodyPromise=t,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=t}catch(t){console.error("ModalView: error processing body function:",t),this.body=e}else this.body=e}_processHeaderContent(e){if(e instanceof C)this.headerView=e,this.headerContent=null,this.addChild(this.headerView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.headerView=t,this.headerContent=null,this.addChild(this.headerView)):t instanceof Promise?(this.headerPromise=t,this.headerContent='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.headerContent=t}catch(t){console.error("ModalView: error processing headerContent function:",t),this.headerContent=e}else this.headerContent=e}_processFooterContent(e){if(e instanceof C)this.footerView=e,this.footer=null,this.addChild(this.footerView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.footerView=t,this.footer=null,this.addChild(this.footerView)):t instanceof Promise?(this.footerPromise=t,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=t}catch(t){console.error("ModalView: error processing footer function:",t),this.footer=e}else this.footer=e}async getTemplate(){const e=["modal-dialog"];return this.size&&this.size!=="auto"&&(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")),`
16
16
  <div class="${e.join(" ")}">
17
17
  <div class="modal-content">
18
18
  ${await this.buildHeader()}
@@ -27,7 +27,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
27
27
  ${this.title?`<h5 class="modal-title" id="${this.titleId}">${this.title}</h5>`:""}
28
28
  ${e}
29
29
  </div>
30
- `}async buildContextMenu(){const e=await this.filterContextMenuItems();if(e.length===0)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",s=this.contextMenu.buttonClass||"btn btn-link p-1 mojo-modal-context-menu-btn",i=e.map(r=>{if(r.type==="divider")return'<li><hr class="dropdown-divider"></li>';const n=r.icon?`<i class="${r.icon} me-2"></i>`:"",a=r.label||"";if(r.href)return`<li><a class="dropdown-item" href="${r.href}"${r.target?` target="${r.target}"`:""}>${n}${a}</a></li>`;if(r.action){const o=Object.keys(r).filter(l=>l.startsWith("data-")).map(l=>`${l}="${r[l]}"`).join(" ");return`<li><a class="dropdown-item" data-action="${r.action}" ${o}>${n}${a}</a></li>`}return""}).join("");return`
30
+ `}async buildContextMenu(){const e=await this.filterContextMenuItems();if(e.length===0)return this.closeButton?'<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>':"";const t=this.escapeHtml(this.contextMenu.icon||"bi-three-dots-vertical"),s=this.escapeHtml(this.contextMenu.buttonClass||"btn btn-link p-1 mojo-modal-context-menu-btn"),i=e.map(r=>{if(r.type==="divider")return'<li><hr class="dropdown-divider"></li>';const n=r.icon?`<i class="${this.escapeHtml(r.icon)} me-2"></i>`:"",a=this.escapeHtml(r.label||"");if(r.href)return`<li><a class="dropdown-item" href="${this.escapeHtml(r.href)}"${r.target?` target="${this.escapeHtml(r.target)}"`:""}>${n}${a}</a></li>`;if(r.action){const o=Object.keys(r).filter(l=>l.startsWith("data-")).map(l=>`${l}="${this.escapeHtml(r[l])}"`).join(" ");return`<li><a class="dropdown-item" data-action="${this.escapeHtml(r.action)}" ${o}>${n}${a}</a></li>`}return""}).join("");return`
31
31
  <div class="dropdown">
32
32
  <button class="${s}" type="button" data-bs-toggle="dropdown" aria-expanded="false">
33
33
  <i class="${t}"></i>
@@ -45,14 +45,14 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
45
45
  ${t.icon?`<i class="bi ${t.icon} me-1"></i>`:""}
46
46
  ${t.text||"Button"}
47
47
  </button>
48
- `}).join("");return`<div class="modal-footer ${this.footerClass}">${e}</div>`}return""}async mount(e=null){if(this.mounted||this.destroyed)return;if(!this.element)throw new Error("Cannot mount modal without element");return await this.onBeforeMount(),x.getMountTarget().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(),!(typeof window>"u"||!window.bootstrap?.Modal)&&(this.backdrop==="static"&&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){console.warn("ModalView auto-sizing: required elements not found");return}if(this.bodyView&&!this.bodyView.element){setTimeout(()=>this.applyAutoSizing(),50);return}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 r=t.getBoundingClientRect(),n=40,a=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-n);let o=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-n),l=Math.max(this.minWidth,Math.ceil(r.width+20)),d=Math.max(this.minHeight,Math.ceil(r.height));this.maxHeight&&(o=Math.min(this.maxHeight,o),e.style.maxHeight=`${o}px`),l=Math.min(l,a);const h=r.height>o;e.style.maxWidth=`${l}px`,e.style.width=`${l}px`,h&&(e.classList.contains("modal-dialog-scrollable")||e.classList.add("modal-dialog-scrollable"),t.style.maxHeight=`${o}px`,d=o),this.autoSizedWidth=l,this.autoSizedHeight=d,this._originalStyles=i}catch(e){console.error("ModalView: error in auto-sizing:",e);const t=this.element?.querySelector(".modal-dialog");t&&(t.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("ModalView: error resetting auto-sizing:",e)}}bindBootstrapEvents(){this.element.addEventListener("show.bs.modal",e=>{const t=x._openDialogs.length,i=x.getFullscreenAwareZIndex().modal+t*20;this.element.style.zIndex=i,this._dialogZIndex=i,this._backdropZIndex=i-10,x._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(()=>x.fixAllBackdropStacking(),50),this.onShown&&this.onShown(e),this.emit("shown",{dialog:this,relatedTarget:e.relatedTarget}),this.focus){const t=this.element.querySelector('input:not([type="hidden"]), textarea, select');t&&t.focus()}}),this.element.addEventListener("hide.bs.modal",e=>{const t=this.element.querySelector(":focus");if(t&&t.blur(),this.onHide&&this.onHide(e)===!1){e.preventDefault();return}this.emit("hide",{dialog:this})}),this.element.addEventListener("hidden.bs.modal",e=>{const t=x._openDialogs.indexOf(this);t>-1&&x._openDialogs.splice(t,1),x._openDialogs.length>0&&(document.body.classList.add("modal-open"),setTimeout(()=>x.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)}isShown(){return this.element?.classList.contains("show")||!1}getModal(){return this.modal}handleUpdate(){this.modal&&this.modal.handleUpdate()}async setContent(e){if(e instanceof S){this.bodyView&&(await this.bodyView.destroy(),this.removeChild(this.bodyView)),this.bodyView=e,this.body="",this.addChild(this.bodyView);const t=this.element?.querySelector(".modal-body");t&&(t.innerHTML="",await this.bodyView.render(t))}else{this.body=e;const t=this.element?.querySelector(".modal-body");t&&(t.innerHTML=e)}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=`
48
+ `}).join("");return`<div class="modal-footer ${this.footerClass}">${e}</div>`}return""}async mount(e=null){if(this.mounted||this.destroyed)return;if(!this.element)throw new Error("Cannot mount modal without element");return await this.onBeforeMount(),x.getMountTarget().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(),!(typeof window>"u"||!window.bootstrap?.Modal)&&(this.backdrop==="static"&&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){console.warn("ModalView auto-sizing: required elements not found");return}if(this.bodyView&&!this.bodyView.element){setTimeout(()=>this.applyAutoSizing(),50);return}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 r=t.getBoundingClientRect(),n=40,a=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-n);let o=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-n),l=Math.max(this.minWidth,Math.ceil(r.width+20)),d=Math.max(this.minHeight,Math.ceil(r.height));this.maxHeight&&(o=Math.min(this.maxHeight,o),e.style.maxHeight=`${o}px`),l=Math.min(l,a);const h=r.height>o;e.style.maxWidth=`${l}px`,e.style.width=`${l}px`,h&&(e.classList.contains("modal-dialog-scrollable")||e.classList.add("modal-dialog-scrollable"),t.style.maxHeight=`${o}px`,d=o),this.autoSizedWidth=l,this.autoSizedHeight=d,this._originalStyles=i}catch(e){console.error("ModalView: error in auto-sizing:",e);const t=this.element?.querySelector(".modal-dialog");t&&(t.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("ModalView: error resetting auto-sizing:",e)}}bindBootstrapEvents(){this.element.addEventListener("show.bs.modal",e=>{const t=x._openDialogs.length,i=x.getFullscreenAwareZIndex().modal+t*20;this.element.style.zIndex=i,this._dialogZIndex=i,this._backdropZIndex=i-10,x._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(()=>x.fixAllBackdropStacking(),50),this.onShown&&this.onShown(e),this.emit("shown",{dialog:this,relatedTarget:e.relatedTarget}),this.focus){const t=this.element.querySelector('input:not([type="hidden"]), textarea, select');t&&t.focus()}}),this.element.addEventListener("hide.bs.modal",e=>{const t=this.element.querySelector(":focus");if(t&&t.blur(),this.onHide&&this.onHide(e)===!1){e.preventDefault();return}this.emit("hide",{dialog:this})}),this.element.addEventListener("hidden.bs.modal",e=>{const t=x._openDialogs.indexOf(this);t>-1&&x._openDialogs.splice(t,1),x._openDialogs.length>0&&(document.body.classList.add("modal-open"),setTimeout(()=>x.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)}isShown(){return this.element?.classList.contains("show")||!1}getModal(){return this.modal}handleUpdate(){this.modal&&this.modal.handleUpdate()}async setContent(e){if(e instanceof C){this.bodyView&&(await this.bodyView.destroy(),this.removeChild(this.bodyView)),this.bodyView=e,this.body="",this.addChild(this.bodyView);const t=this.element?.querySelector(".modal-body");t&&(t.innerHTML="",await this.bodyView.render(t))}else{this.body=e;const t=this.element?.querySelector(".modal-body");t&&(t.innerHTML=e)}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=`
49
49
  <div class="text-center py-4">
50
50
  <div class="spinner-border text-primary mb-3" role="status">
51
51
  <span class="visually-hidden">Loading...</span>
52
52
  </div>
53
53
  <p>${t}</p>
54
54
  </div>
55
- `:this.bodyView&&s.replaceChildren(this.bodyView.element))}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()}async onBeforeDestroy(){this.headerView&&await this.headerView.destroy(),this.bodyView&&await this.bodyView.destroy(),this.footerView&&await this.footerView.destroy(),await super.onBeforeDestroy(),this.modal&&(this.modal.dispose(),this.modal=null)}}let L=null,K=0,ce=null;const Ut=`
55
+ `:this.bodyView&&s.replaceChildren(this.bodyView.element))}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()}async onBeforeDestroy(){this.headerView&&await this.headerView.destroy(),this.bodyView&&await this.bodyView.destroy(),this.footerView&&await this.footerView.destroy(),await super.onBeforeDestroy(),this.modal&&(this.modal.dispose(),this.modal=null)}}let P=null,Z=0,ce=null;const Ut=`
56
56
  .mojo-loading-overlay {
57
57
  position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
58
58
  background: rgba(255, 255, 255, 0.4);
@@ -85,13 +85,13 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
85
85
  white-space: nowrap;
86
86
  }
87
87
  @keyframes mojo-spin { to { transform: rotate(360deg); } }
88
- `,ke={show(c){typeof c=="string"&&(c={message:c});const{message:e="Loading...",timeout:t=3e4}=c||{};if(K++,K===1){ce&&clearTimeout(ce);const i=x.getFullscreenAwareZIndex().modal+1e3;L||(L=document.createElement("div"),L.className="mojo-loading-overlay",L.innerHTML=`
88
+ `,Me={show(c){typeof c=="string"&&(c={message:c});const{message:e="Loading...",timeout:t=3e4}=c||{};if(Z++,Z===1){ce&&clearTimeout(ce);const i=x.getFullscreenAwareZIndex().modal+1e3;P||(P=document.createElement("div"),P.className="mojo-loading-overlay",P.innerHTML=`
89
89
  <div class="mojo-loading-card">
90
90
  <div class="mojo-loading-spinner"></div>
91
91
  <div class="mojo-loading-message">${e}</div>
92
92
  </div>
93
93
  <style>${Ut}</style>
94
- `,document.body.appendChild(L)),L.style.zIndex=String(i);const r=L.querySelector(".mojo-loading-message");r&&(r.textContent=e),requestAnimationFrame(()=>{L&&L.classList.add("show")}),t>0&&(ce=setTimeout(()=>{console.error("BusyIndicator timed out."),ke.hide(!0)},t))}else if(L){const s=L.querySelector(".mojo-loading-message");s&&(s.textContent=e)}},hide(c=!1){c?K=0:K--,!(K>0)&&(K=0,ce&&(clearTimeout(ce),ce=null),L&&(L.classList.remove("show"),setTimeout(()=>{L&&K===0&&(L.remove(),L=null)},200)))},isShown(){return L!==null&&K>0}},Wt=`
94
+ `,document.body.appendChild(P)),P.style.zIndex=String(i);const r=P.querySelector(".mojo-loading-message");r&&(r.textContent=e),requestAnimationFrame(()=>{P&&P.classList.add("show")}),t>0&&(ce=setTimeout(()=>{console.error("BusyIndicator timed out."),Me.hide(!0)},t))}else if(P){const s=P.querySelector(".mojo-loading-message");s&&(s.textContent=e)}},hide(c=!1){c?Z=0:Z--,!(Z>0)&&(Z=0,ce&&(clearTimeout(ce),ce=null),P&&(P.classList.remove("show"),setTimeout(()=>{P&&Z===0&&(P.remove(),P=null)},200)))},isShown(){return P!==null&&Z>0}},Wt=`
95
95
  max-height: 60vh;
96
96
  overflow-y: auto;
97
97
  background: #1e1e1e;
@@ -119,12 +119,12 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
119
119
  .dialog-code-block .token.attr-name { color: #9cdcfe; }
120
120
  .dialog-code-block .token.attr-value { color: #ce9178; }
121
121
  .dialog-code-block ::selection { background: #264f78; }
122
- `;class me extends S{constructor(e={}){super({tagName:"div",className:"mojo-code-viewer",...e}),this.code=e.code||"",this.language=e.language||"javascript"}async getTemplate(){return me.formatCode(this.code,this.language)}static formatCode(e,t="javascript"){let s;window.Prism&&window.Prism.languages[t]?s=window.Prism.highlight(e,window.Prism.languages[t],t):s=String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;");const i=window.Prism?`language-${t}`:"";return`
122
+ `;class pe extends C{constructor(e={}){super({tagName:"div",className:"mojo-code-viewer",...e}),this.code=e.code||"",this.language=e.language||"javascript"}async getTemplate(){return pe.formatCode(this.code,this.language)}static formatCode(e,t="javascript"){let s;window.Prism&&window.Prism.languages[t]?s=window.Prism.highlight(e,window.Prism.languages[t],t):s=String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;");const i=window.Prism?`language-${t}`:"";return`
123
123
  <style>${Yt}</style>
124
124
  <pre class="${i} dialog-code-block" style="${Wt}">
125
125
  <code class="${i}" style="color: inherit; background: transparent; text-shadow: none;">${s}</code>
126
126
  </pre>
127
- `}static highlightCodeBlocks(e=document){window.Prism&&window.Prism.highlightAllUnder&&window.Prism.highlightAllUnder(e)}}class Gt extends S{constructor(e={}){super({tagName:"div",className:"mojo-html-preview",...e}),this.html=e.html||e.content||"",this.height=e.height||500}async getTemplate(){return`
127
+ `}static highlightCodeBlocks(e=document){window.Prism&&window.Prism.highlightAllUnder&&window.Prism.highlightAllUnder(e)}}class Gt extends C{constructor(e={}){super({tagName:"div",className:"mojo-html-preview",...e}),this.html=e.html||e.content||"",this.height=e.height||500}async getTemplate(){return`
128
128
  <div class="html-preview-container">
129
129
  <div class="d-flex justify-content-between align-items-center mb-2">
130
130
  <small class="text-muted">Preview (sandboxed)</small>
@@ -139,7 +139,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
139
139
  frameborder="0"
140
140
  ></iframe>
141
141
  </div>
142
- `}async onAfterMount(){await super.onAfterMount(),this._writeIframe()}onActionRefresh(){this._writeIframe()}_writeIframe(){const e=this.element?.querySelector(".mojo-html-preview-frame");if(!e)return;const t=e.contentDocument||e.contentWindow?.document;t&&(t.open(),t.write(this.html),t.close())}setHtml(e){this.html=e,this._writeIframe()}}class Q{constructor(e={},t={}){this.endpoint=t.endpoint||this.constructor.endpoint||"",this.id=e.id||null,this.attributes={...e},this._=this.attributes,this.originalAttributes={...e},this.errors={},this.loading=!1,this.rest=ne,this.collection=t.collection||null,this.options={idAttribute:"id",timestamps:!0,...t}}getContextValue(e){return this.get(e)}get(e){return!e.includes(".")&&!e.includes("|")&&this[e]!==void 0?typeof this[e]=="function"?this[e]():this[e]:$.getContextData(this.attributes,e)}set(e,t,s={}){const i=JSON.parse(JSON.stringify(this.attributes));let r=!1;if(e!=null){if(typeof e=="object"){for(const[n,a]of Object.entries(e))r=this._setNestedAttribute(n,a)||r;e.id!==void 0&&(this.id=e.id)}else e==="id"?(this.id=t,r=!0):r=this._setNestedAttribute(e,t);if(r&&!s.silent)if(this.emit("change",this,s),typeof e=="string")this.emit(`change:${e}`,t,this);else for(const[n,a]of Object.entries(e)){const o=this._getNestedValue(n);JSON.stringify(this._getNestedValue(n,i))!==JSON.stringify(o)&&this.emit(`change:${n}`,o,this)}}}_setNestedAttribute(e,t){if(!e.includes(".")){const l=this.attributes[e];return this.attributes[e]=t,this[e]=t,l!==t}const s=e.split("."),i=s[0];(!this.attributes[i]||typeof this.attributes[i]!="object")&&(this.attributes[i]={}),(!this[i]||typeof this[i]!="object")&&(this[i]={});const r=this._getNestedValue(e);let n=this.attributes[i],a=this[i];for(let l=1;l<s.length-1;l++){const d=s[l];(!n[d]||typeof n[d]!="object")&&(n[d]={}),(!a[d]||typeof a[d]!="object")&&(a[d]={}),n=n[d],a=a[d]}const o=s[s.length-1];return n[o]=t,a[o]=t,JSON.stringify(r)!==JSON.stringify(t)}_getNestedValue(e,t=this.attributes){if(!e.includes("."))return t[e];const s=e.split(".");let i=t;for(const r of s){if(i==null||typeof i!="object")return;i=i[r]}return i}getData(){return this.attributes}getId(){return this.id}async fetch(e={}){let t=e.url;if(!t){const n=e.id||this.getId();if(!n&&this.options.requiresId!==!1)throw new Error("Model: ID is required for fetching");t=this.buildUrl(n)}const s=JSON.stringify({url:t,params:e.params});if(e.debounceMs&&e.debounceMs>0)return this._debouncedFetch(s,e);if(this.currentRequest&&this.currentRequestKey!==s&&(console.info("Model: Cancelling previous request for new parameters"),this.abortController?.abort(),this.currentRequest=null),this.currentRequest&&this.currentRequestKey===s)return console.info("Model: Duplicate request in progress, returning existing promise"),this.currentRequest;const i=Date.now();if(this.lastFetchTime&&i-this.lastFetchTime<100)return console.info("Model: Rate limited, skipping fetch"),this;this.loading=!0,this.errors={},this.lastFetchTime=i,this.currentRequestKey=s,this.abortController=new AbortController,this.currentRequest=this._performFetch(t,e,this.abortController);try{return await this.currentRequest}catch(n){if(n.name==="AbortError")return console.info("Model: Request was cancelled"),this;throw n}finally{this.currentRequest=null,this.currentRequestKey=null,this.abortController=null}}async _debouncedFetch(e,t){return this.debouncedFetchTimeout&&clearTimeout(this.debouncedFetchTimeout),this.cancel(),new Promise((s,i)=>{this.debouncedFetchTimeout=setTimeout(async()=>{try{const r=await this.fetch({...t,debounceMs:0});s(r)}catch(r){i(r)}},t.debounceMs)})}async _performFetch(e,t,s){try{t.graph&&(!t.params||!t.params.graph)&&(t.params||(t.params={}),t.params.graph=t.graph);const i=await this.rest.GET(e,t.params,{signal:s.signal});return i.success?i.data.status?(this.originalAttributes={...this.attributes},i.data.data&&this.set(i.data.data),this.errors={}):this.errors=i.data:this.errors=i.errors||{},i}catch(i){if(i.name==="AbortError")throw console.info("Model: Fetch was cancelled"),i;return this.errors={fetch:i.message},{success:!1,error:i.message,status:i.status||500}}finally{this.loading=!1}}async save(e,t={}){const s=!this.id,i=s?"POST":"PUT",r=s?this.buildUrl():this.buildUrl(this.id);this.loading=!0,this.errors={};try{const n=await this.rest[i](r,e,t.params);return n.success?n.data.status?(this.originalAttributes={...this.attributes},this.set(n.data.data,null,t),this.errors={}):this.errors=n.data:this.errors=n.errors||{},n}catch(n){return{success:!1,error:n.message,status:n.status||500}}finally{this.loading=!1}}async destroy(e={}){if(!this.id)return this.errors={destroy:"Cannot destroy model without ID"},{success:!1,error:"Cannot destroy model without ID",status:400};const t=this.buildUrl(this.id);this.loading=!0,this.errors={};try{const s=await this.rest.DELETE(t,e.params);return s.success?(this.attributes={},this.originalAttributes={},this.id=null,this.errors={}):this.errors=s.errors||{},s}catch(s){return this.errors={destroy:s.message},{success:!1,error:s.message,status:s.status||500}}finally{this.loading=!1}}isDirty(){return JSON.stringify(this.attributes)!==JSON.stringify(this.originalAttributes)}getChangedAttributes(){const e={};for(const[t,s]of Object.entries(this.attributes))this.originalAttributes[t]!==s&&(e[t]=s);return e}reset(){for(const e of Object.keys(this.attributes))e in this.originalAttributes||delete this[e];for(const[e,t]of Object.entries(this.originalAttributes))this[e]=t;this.attributes={...this.originalAttributes},this._=this.attributes,this.errors={}}buildUrl(e=null){let t=this.endpoint;return e&&(t=t.endsWith("/")?`${t}${e}`:`${t}/${e}`),t}toJSON(){return{id:this.id,...this.attributes}}validate(){if(this.errors={},this.constructor.validations)for(const[e,t]of Object.entries(this.constructor.validations))this.validateField(e,t);return Object.keys(this.errors).length===0}validateField(e,t){const s=this.get(e),i=Array.isArray(t)?t:[t];for(const r of i)if(typeof r=="function"){const n=r(s,this);if(n!==!0){this.errors[e]=n||`${e} is invalid`;break}}else if(typeof r=="object"){if(r.required&&(s==null||s==="")){this.errors[e]=r.message||`${e} is required`;break}if(r.minLength&&s&&s.length<r.minLength){this.errors[e]=r.message||`${e} must be at least ${r.minLength} characters`;break}if(r.maxLength&&s&&s.length>r.maxLength){this.errors[e]=r.message||`${e} must be no more than ${r.maxLength} characters`;break}if(r.pattern&&s&&!r.pattern.test(s)){this.errors[e]=r.message||`${e} format is invalid`;break}}}static async find(e,t={}){const s=new this({},t);return await s.fetch({id:e,...t}),s}static create(e={},t={}){return new this(e,t)}cancel(){return this.currentRequest&&this.abortController?(console.info("Model: Manually cancelling active request"),this.abortController.abort(),!0):this.debouncedFetchTimeout?(clearTimeout(this.debouncedFetchTimeout),this.debouncedFetchTimeout=null,!0):!1}isFetching(){return!!this.currentRequest}async showError(e){await(await Promise.resolve().then(()=>N)).default.alert(e,"Error",{size:"md",class:"text-danger"})}}Object.assign(Q.prototype,Ie);class de{constructor(e={},t=null){if(Array.isArray(e)?(t=e,e=t||{}):t=t||e.data||[],this.ModelClass=e.ModelClass||Q,this.models=[],this.loading=!1,this.errors={},this.meta={},this.rest=ne,t&&this.add(t),this.params={start:0,size:e.size||10,...e.params},this.endpoint=e.endpoint||this.ModelClass.endpoint||"",!this.endpoint){let s=new this.ModelClass;this.endpoint=s.endpoint}this.restEnabled=!!this.endpoint,e.restEnabled!==void 0&&(this.restEnabled=e.restEnabled),this.options={parse:!0,reset:!0,preloaded:!1,...e}}getModelName(){return this.ModelClass.name}async fetch(e={}){const t=JSON.stringify({...this.params,...e});if(this.currentRequest&&this.currentRequestKey!==t&&(console.info("Collection: Cancelling previous request for new parameters"),this.abortController?.abort(),this.currentRequest=null),this.currentRequest&&this.currentRequestKey===t)return console.info("Collection: Duplicate request in progress, returning existing promise"),this.currentRequest;const s=Date.now();if(this.options.rateLimiting&&this.lastFetchTime&&s-this.lastFetchTime<100)return console.info("Collection: Rate limited, skipping fetch"),{success:!0,message:"Rate limited, skipping fetch",data:{data:this.toJSON()}};if(!this.restEnabled)return console.info("Collection: REST disabled, skipping fetch"),{success:!0,message:"REST disabled, skipping fetch",data:{data:this.toJSON()}};if(this.options.preloaded&&this.models.length>0)return console.info("Collection: Using preloaded data, skipping fetch"),{success:!0,message:"Using preloaded data, skipping fetch",data:{data:this.toJSON()}};const r=this.buildUrl();this.loading=!0,this.errors={},this.lastFetchTime=s,this.currentRequestKey=t,this.abortController=new AbortController,this.currentRequest=this._performFetch(r,e,this.abortController);try{return await this.currentRequest}catch(n){return n.name==="AbortError"?(console.info("Collection: Request was cancelled"),{success:!1,error:"Request cancelled",status:0}):{success:!1,error:n.message,status:n.status||500}}finally{this.currentRequest=null,this.currentRequestKey=null,this.abortController=null}}async _performFetch(e,t,s){const i={...this.params,...t};console.log("Fetching collection data from",e,i);try{this.emit("fetch:start");const r=await this.rest.GET(e,i,{signal:s.signal});if(r.success&&r.data.status){const n=this.options.parse?this.parse(r):r.data;t.reset!==!1&&this.options.reset&&this.reset(),this.add(n,{silent:t.silent}),this.errors={},this.emit("fetch:success")}else r.data&&r.data.error?(this.errors=r.data,this.emit("fetch:error",{message:r.data.error,error:r.data})):(this.errors=r.errors||{},this.emit("fetch:error",{error:r.errors}));return r}catch(r){return r.name==="AbortError"?(console.info("Collection: Fetch was cancelled"),{success:!1,error:"Request cancelled",status:0}):(this.errors={fetch:r.message},this.emit("fetch:error",{message:r.message,error:r}),{success:!1,error:r.message,status:r.status||500})}finally{this.loading=!1,this.emit("fetch:end")}}async updateParams(e,t=!1,s=0){return await this.setParams({...this.params,...e},t,s)}async setParams(e,t=!1,s=0){return this.params=e,t&&this.restEnabled?s>0?(this.debouncedFetchTimeout&&clearTimeout(this.debouncedFetchTimeout),this.cancel(),new Promise((i,r)=>{this.debouncedFetchTimeout=setTimeout(async()=>{try{const n=await this.fetch();i(n)}catch(n){r(n)}},s)})):this.fetch():Promise.resolve(this)}async fetchMore({pageDelta:e=1}={}){if(!this.restEnabled)return{success:!1,message:"REST disabled, cannot fetchMore"};const t=this.params.size||10,s=this.params.start||0,i=s+e*t;return this.meta&&typeof this.meta.count=="number"&&i>=this.meta.count?{success:!0,message:"No more results",data:{data:[],status:"ok",count:this.meta.count,start:s,size:t}}:(this.params={...this.params,start:i},this.emit("fetch:more",{start:i,pageDelta:e,collection:this}),this.fetch({reset:!1}))}async fetchOne(e,t={}){if(!e)return console.warn("Collection: fetchOne requires an ID"),null;if(!this.restEnabled)return console.info("Collection: REST disabled, cannot fetch single item"),null;try{const s=new this.ModelClass({id:e},{endpoint:this.endpoint,collection:this}),i=await s.fetch(t);if(i.success){if(t.addToCollection===!0){const r=this.get(s.id);r?t.merge!==!1&&r.set(s.attributes):this.add(s,{silent:t.silent})}return s}else return console.warn("Collection: fetchOne failed -",i.error||"Unknown error"),null}catch(s){return console.error("Collection: fetchOne error -",s.message),null}}async download(e="json",t={}){if(!this.restEnabled)return console.warn("Collection: REST is not enabled, cannot download from remote."),{success:!1,message:"Remote downloads are not enabled for this collection."};const s=this.buildUrl(),i={...this.params};delete i.start,delete i.size,i.download_format=e;const r=`export-${this.getModelName().toLowerCase()}`,n=this._buildDateRangeSuffix(i),a=`${r}${n}.${e}`,l={json:"application/json",csv:"text/csv"}[e]||"*/*";return i.filename=a,this.rest.download(s,i,{...t,filename:a,headers:{Accept:l}})}_buildDateRangeSuffix(e={}){const t=e.dr_start,s=e.dr_end;if(!t&&!s)return"";const i=a=>a?String(a).replace(/[^\dA-Za-z_-]/g,"-"):"",r=[],n=e.dr_field||"daterange";return r.push(i(n)),t&&r.push(`from-${i(e.dr_start)}`),s&&r.push(`to-${i(e.dr_end)}`),`-${r.filter(Boolean).join("-")}`}parse(e){return e.data&&Array.isArray(e.data.data)?(this.meta={size:e.data.size||10,start:e.data.start||0,count:e.data.count||0,status:e.data.status,graph:e.data.graph,...e.meta},e.data.data):Array.isArray(e.data)?e.data:Array.isArray(e)?e:[e]}add(e,t={}){const s=Array.isArray(e)?e:[e],i=[];for(const r of s){let n;r instanceof this.ModelClass?(n=r,n.collection||(n.collection=this)):n=new this.ModelClass(r,{endpoint:this.endpoint,collection:this});const a=this.models.findIndex(o=>o.id===n.id);a!==-1?t.merge!==!1&&this.models[a].set(n.attributes):(this.models.push(n),i.push(n))}return!t.silent&&i.length>0&&(this.emit("add",{models:i,collection:this}),this.emit("update",{collection:this})),i}remove(e,t={}){const s=Array.isArray(e)?e:[e],i=[];for(const r of s){let n=-1;if(typeof r=="string"||typeof r=="number"?n=this.models.findIndex(a=>a.id==r):n=this.models.indexOf(r),n!==-1){const a=this.models.splice(n,1)[0];a.collection===this&&(a.collection=null),i.push(a)}}return!t.silent&&i.length>0&&(this.emit("remove",{models:i,collection:this}),this.emit("update",{collection:this})),i}reset(e=null,t={}){const s=[...this.models];return this.models=[],e&&this.add(e,{silent:!0,...t}),t.silent||this.emit("reset",{collection:this,previousModels:s}),this}get(e){return this.models.find(t=>t.id==e)}at(e){return this.models[e]}length(){return this.models.length}isEmpty(){return this.models.length===0}where(e){return typeof e=="function"?this.models.filter(e):typeof e=="object"?this.models.filter(t=>Object.entries(e).every(([s,i])=>t.get(s)===i)):[]}findWhere(e){const t=this.where(e);return t.length>0?t[0]:void 0}forEach(e,t){if(typeof e!="function")throw new TypeError("Callback must be a function");return this.models.forEach((s,i)=>{e.call(t,s,i,this)}),this}sort(e,t={}){if(typeof e=="string"){const s=e;e=(i,r)=>{const n=i.get(s),a=r.get(s);return n<a?-1:n>a?1:0}}return this.models.sort(e),t.silent||this.emit("sort",{collection:this}),this}toJSON(){return this.models.map(e=>e.toJSON())}cancel(){return this.currentRequest&&this.abortController?(console.info("Collection: Manually cancelling active request"),this.abortController.abort(),!0):!1}isFetching(){return!!this.currentRequest}buildUrl(){return this.endpoint}*[Symbol.iterator](){for(const e of this.models)yield e}static fromArray(e,t=[],s={}){const i=new this({ModelClass:e,...s});return i.add(t,{silent:!0}),i}}Object.assign(de.prototype,Ie);class Jt{constructor(e={}){this.options={containerId:"toast-container",position:"top-end",autohide:!0,defaultDelay:3e3,maxToasts:5,...e},this.toasts=new Map,this.toastCounter=0,this.init()}init(){this.createContainer()}createContainer(){let e=document.getElementById(this.options.containerId);e||(e=document.createElement("div"),e.id=this.options.containerId,e.className=`toast-container position-fixed ${this.getPositionClasses()}`,e.style.zIndex="1070",e.setAttribute("aria-live","polite"),e.setAttribute("aria-atomic","true"),document.body.appendChild(e)),this.container=e}getPositionClasses(){const e={"top-start":"top-0 start-0 p-3","top-center":"top-0 start-50 translate-middle-x p-3","top-end":"top-0 end-0 p-3","middle-start":"top-50 start-0 translate-middle-y p-3","middle-center":"top-50 start-50 translate-middle p-3","middle-end":"top-50 end-0 translate-middle-y p-3","bottom-start":"bottom-0 start-0 p-3","bottom-center":"bottom-0 start-50 translate-middle-x p-3","bottom-end":"bottom-0 end-0 p-3"};return e[this.options.position]||e["top-end"]}success(e,t={}){return this.show(e,"success",{icon:"bi-check-circle-fill",...t})}error(e,t={}){return this.show(e,"error",{icon:"bi-exclamation-triangle-fill",autohide:!0,...t})}info(e,t={}){return this.show(e,"info",{icon:"bi-info-circle-fill",...t})}warning(e,t={}){return this.show(e,"warning",{icon:"bi-exclamation-triangle-fill",...t})}plain(e,t={}){return this.show(e,"plain",{...t})}show(e,t="info",s={}){this.enforceMaxToasts();const i=`toast-${++this.toastCounter}`,r={title:this.getDefaultTitle(t),icon:this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,...s},n=this.createToastElement(i,e,t,r);if(this.container.appendChild(n),typeof bootstrap>"u")throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const a=new bootstrap.Toast(n,{autohide:r.autohide,delay:r.delay});return this.toasts.set(i,{element:n,bootstrap:a,type:t,message:e}),n.addEventListener("hidden.bs.toast",()=>{this.cleanup(i)}),a.show(),{id:i,hide:()=>{try{a.hide()}catch(o){console.warn("Error hiding toast:",o)}},dispose:()=>this.cleanup(i),updateProgress:s.updateProgress||null}}showView(e,t="info",s={}){this.enforceMaxToasts();const i=`toast-${++this.toastCounter}`,r={title:s.title||this.getDefaultTitle(t),icon:s.icon||this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,size:"md",...s},n=this.createViewToastElement(i,e,t,r);if(this.container.appendChild(n),typeof bootstrap>"u")throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const a=new bootstrap.Toast(n,{autohide:r.autohide,delay:r.delay});this.toasts.set(i,{element:n,bootstrap:a,type:t,view:e,message:"View toast"}),n.addEventListener("hidden.bs.toast",()=>{this.cleanupView(i)});const o=n.querySelector(".toast-view-body");return o&&e&&e.render(!0,o),a.show(),{id:i,view:e,hide:()=>{try{a.hide()}catch(l){console.warn("Error hiding view toast:",l)}},dispose:()=>this.cleanupView(i),updateProgress:l=>{e&&typeof e.updateProgress=="function"&&e.updateProgress(l)}}}createToastElement(e,t,s,i){const r=document.createElement("div");r.id=e,r.className=`toast toast-service-${s}${i.size?` toast-${i.size}`:""}`,r.setAttribute("role","alert"),r.setAttribute("aria-live","assertive"),r.setAttribute("aria-atomic","true");const n=i.title||i.icon?this.createToastHeader(i,s):"",a=this.createToastBody(t,i.icon&&!i.title);return r.innerHTML=`
142
+ `}async onAfterMount(){await super.onAfterMount(),this._writeIframe()}onActionRefresh(){this._writeIframe()}_writeIframe(){const e=this.element?.querySelector(".mojo-html-preview-frame");if(!e)return;const t=e.contentDocument||e.contentWindow?.document;t&&(t.open(),t.write(this.html),t.close())}setHtml(e){this.html=e,this._writeIframe()}}class Q{constructor(e={},t={}){this.endpoint=t.endpoint||this.constructor.endpoint||"",this.id=e.id||null,this.attributes={...e},this._=this.attributes,this.originalAttributes={...e},this.errors={},this.loading=!1,this.rest=ne,this.collection=t.collection||null,this.options={idAttribute:"id",timestamps:!0,...t}}getContextValue(e){return this.get(e)}get(e){return!e.includes(".")&&!e.includes("|")&&this[e]!==void 0?typeof this[e]=="function"?this[e]():this[e]:$.getContextData(this.attributes,e)}set(e,t,s={}){const i=JSON.parse(JSON.stringify(this.attributes));let r=!1;if(e!=null){if(typeof e=="object"){for(const[n,a]of Object.entries(e))r=this._setNestedAttribute(n,a)||r;e.id!==void 0&&(this.id=e.id)}else e==="id"?(this.id=t,r=!0):r=this._setNestedAttribute(e,t);if(r&&!s.silent)if(this.emit("change",this,s),typeof e=="string")this.emit(`change:${e}`,t,this);else for(const[n,a]of Object.entries(e)){const o=this._getNestedValue(n);JSON.stringify(this._getNestedValue(n,i))!==JSON.stringify(o)&&this.emit(`change:${n}`,o,this)}}}_setNestedAttribute(e,t){if(!e.includes(".")){const l=this.attributes[e];return this.attributes[e]=t,this[e]=t,l!==t}const s=e.split("."),i=s[0];(!this.attributes[i]||typeof this.attributes[i]!="object")&&(this.attributes[i]={}),(!this[i]||typeof this[i]!="object")&&(this[i]={});const r=this._getNestedValue(e);let n=this.attributes[i],a=this[i];for(let l=1;l<s.length-1;l++){const d=s[l];(!n[d]||typeof n[d]!="object")&&(n[d]={}),(!a[d]||typeof a[d]!="object")&&(a[d]={}),n=n[d],a=a[d]}const o=s[s.length-1];return n[o]=t,a[o]=t,JSON.stringify(r)!==JSON.stringify(t)}_getNestedValue(e,t=this.attributes){if(!e.includes("."))return t[e];const s=e.split(".");let i=t;for(const r of s){if(i==null||typeof i!="object")return;i=i[r]}return i}getData(){return this.attributes}getId(){return this.id}async fetch(e={}){let t=e.url;if(!t){const n=e.id||this.getId();if(!n&&this.options.requiresId!==!1)throw new Error("Model: ID is required for fetching");t=this.buildUrl(n)}const s=JSON.stringify({url:t,params:e.params});if(e.debounceMs&&e.debounceMs>0)return this._debouncedFetch(s,e);if(this.currentRequest&&this.currentRequestKey!==s&&(console.info("Model: Cancelling previous request for new parameters"),this.abortController?.abort(),this.currentRequest=null),this.currentRequest&&this.currentRequestKey===s)return console.info("Model: Duplicate request in progress, returning existing promise"),this.currentRequest;const i=Date.now();if(this.lastFetchTime&&i-this.lastFetchTime<100)return console.info("Model: Rate limited, skipping fetch"),this;this.loading=!0,this.errors={},this.lastFetchTime=i,this.currentRequestKey=s,this.abortController=new AbortController,this.currentRequest=this._performFetch(t,e,this.abortController);try{return await this.currentRequest}catch(n){if(n.name==="AbortError")return console.info("Model: Request was cancelled"),this;throw n}finally{this.currentRequest=null,this.currentRequestKey=null,this.abortController=null}}async _debouncedFetch(e,t){return this.debouncedFetchTimeout&&clearTimeout(this.debouncedFetchTimeout),this.cancel(),new Promise((s,i)=>{this.debouncedFetchTimeout=setTimeout(async()=>{try{const r=await this.fetch({...t,debounceMs:0});s(r)}catch(r){i(r)}},t.debounceMs)})}async _performFetch(e,t,s){try{t.graph&&(!t.params||!t.params.graph)&&(t.params||(t.params={}),t.params.graph=t.graph);const i=await this.rest.GET(e,t.params,{signal:s.signal});return i.success?i.data.status?(this.originalAttributes={...this.attributes},i.data.data&&this.set(i.data.data),this.errors={}):this.errors=i.data:this.errors=i.errors||{},i}catch(i){if(i.name==="AbortError")throw console.info("Model: Fetch was cancelled"),i;return this.errors={fetch:i.message},{success:!1,error:i.message,status:i.status||500}}finally{this.loading=!1}}async save(e,t={}){const s=!this.id,i=s?"POST":"PUT",r=s?this.buildUrl():this.buildUrl(this.id);this.loading=!0,this.errors={};try{const n=await this.rest[i](r,e,t.params);return n.success?n.data.status?(this.originalAttributes={...this.attributes},this.set(n.data.data,null,t),this.errors={}):this.errors=n.data:this.errors=n.errors||{},n}catch(n){return{success:!1,error:n.message,status:n.status||500}}finally{this.loading=!1}}async destroy(e={}){if(!this.id)return this.errors={destroy:"Cannot destroy model without ID"},{success:!1,error:"Cannot destroy model without ID",status:400};const t=this.buildUrl(this.id);this.loading=!0,this.errors={};try{const s=await this.rest.DELETE(t,e.params);return s.success?(this.attributes={},this.originalAttributes={},this.id=null,this.errors={}):this.errors=s.errors||{},s}catch(s){return this.errors={destroy:s.message},{success:!1,error:s.message,status:s.status||500}}finally{this.loading=!1}}isDirty(){return JSON.stringify(this.attributes)!==JSON.stringify(this.originalAttributes)}getChangedAttributes(){const e={};for(const[t,s]of Object.entries(this.attributes))this.originalAttributes[t]!==s&&(e[t]=s);return e}reset(){for(const e of Object.keys(this.attributes))e in this.originalAttributes||delete this[e];for(const[e,t]of Object.entries(this.originalAttributes))this[e]=t;this.attributes={...this.originalAttributes},this._=this.attributes,this.errors={}}buildUrl(e=null){let t=this.endpoint;return e&&(t=t.endsWith("/")?`${t}${e}`:`${t}/${e}`),t}toJSON(){return{id:this.id,...this.attributes}}validate(){if(this.errors={},this.constructor.validations)for(const[e,t]of Object.entries(this.constructor.validations))this.validateField(e,t);return Object.keys(this.errors).length===0}validateField(e,t){const s=this.get(e),i=Array.isArray(t)?t:[t];for(const r of i)if(typeof r=="function"){const n=r(s,this);if(n!==!0){this.errors[e]=n||`${e} is invalid`;break}}else if(typeof r=="object"){if(r.required&&(s==null||s==="")){this.errors[e]=r.message||`${e} is required`;break}if(r.minLength&&s&&s.length<r.minLength){this.errors[e]=r.message||`${e} must be at least ${r.minLength} characters`;break}if(r.maxLength&&s&&s.length>r.maxLength){this.errors[e]=r.message||`${e} must be no more than ${r.maxLength} characters`;break}if(r.pattern&&s&&!r.pattern.test(s)){this.errors[e]=r.message||`${e} format is invalid`;break}}}static async find(e,t={}){const s=new this({},t);return await s.fetch({id:e,...t}),s}static create(e={},t={}){return new this(e,t)}cancel(){return this.currentRequest&&this.abortController?(console.info("Model: Manually cancelling active request"),this.abortController.abort(),!0):this.debouncedFetchTimeout?(clearTimeout(this.debouncedFetchTimeout),this.debouncedFetchTimeout=null,!0):!1}isFetching(){return!!this.currentRequest}async showError(e){await(await Promise.resolve().then(()=>R)).default.alert(e,"Error",{size:"md",class:"text-danger"})}}Object.assign(Q.prototype,Ie);class de{constructor(e={},t=null){if(Array.isArray(e)?(t=e,e=t||{}):t=t||e.data||[],this.ModelClass=e.ModelClass||Q,this.models=[],this.loading=!1,this.errors={},this.meta={},this.rest=ne,t&&this.add(t),this.params={start:0,size:e.size||10,...e.params},this.endpoint=e.endpoint||this.ModelClass.endpoint||"",!this.endpoint){let s=new this.ModelClass;this.endpoint=s.endpoint}this.restEnabled=!!this.endpoint,e.restEnabled!==void 0&&(this.restEnabled=e.restEnabled),this.options={parse:!0,reset:!0,preloaded:!1,...e}}getModelName(){return this.ModelClass.name}async fetch(e={}){const t=JSON.stringify({...this.params,...e});if(this.currentRequest&&this.currentRequestKey!==t&&(console.info("Collection: Cancelling previous request for new parameters"),this.abortController?.abort(),this.currentRequest=null),this.currentRequest&&this.currentRequestKey===t)return console.info("Collection: Duplicate request in progress, returning existing promise"),this.currentRequest;const s=Date.now();if(this.options.rateLimiting&&this.lastFetchTime&&s-this.lastFetchTime<100)return console.info("Collection: Rate limited, skipping fetch"),{success:!0,message:"Rate limited, skipping fetch",data:{data:this.toJSON()}};if(!this.restEnabled)return console.info("Collection: REST disabled, skipping fetch"),{success:!0,message:"REST disabled, skipping fetch",data:{data:this.toJSON()}};if(this.options.preloaded&&this.models.length>0)return console.info("Collection: Using preloaded data, skipping fetch"),{success:!0,message:"Using preloaded data, skipping fetch",data:{data:this.toJSON()}};const r=this.buildUrl();this.loading=!0,this.errors={},this.lastFetchTime=s,this.currentRequestKey=t,this.abortController=new AbortController,this.currentRequest=this._performFetch(r,e,this.abortController);try{return await this.currentRequest}catch(n){return n.name==="AbortError"?(console.info("Collection: Request was cancelled"),{success:!1,error:"Request cancelled",status:0}):{success:!1,error:n.message,status:n.status||500}}finally{this.currentRequest=null,this.currentRequestKey=null,this.abortController=null}}async _performFetch(e,t,s){const i={...this.params,...t};console.log("Fetching collection data from",e,i);try{this.emit("fetch:start");const r=await this.rest.GET(e,i,{signal:s.signal});if(r.success&&r.data.status){const n=this.options.parse?this.parse(r):r.data;t.reset!==!1&&this.options.reset&&this.reset(),this.add(n,{silent:t.silent}),this.errors={},this.emit("fetch:success")}else r.data&&r.data.error?(this.errors=r.data,this.emit("fetch:error",{message:r.data.error,error:r.data})):(this.errors=r.errors||{},this.emit("fetch:error",{error:r.errors}));return r}catch(r){return r.name==="AbortError"?(console.info("Collection: Fetch was cancelled"),{success:!1,error:"Request cancelled",status:0}):(this.errors={fetch:r.message},this.emit("fetch:error",{message:r.message,error:r}),{success:!1,error:r.message,status:r.status||500})}finally{this.loading=!1,this.emit("fetch:end")}}async updateParams(e,t=!1,s=0){return await this.setParams({...this.params,...e},t,s)}async setParams(e,t=!1,s=0){return this.params=e,t&&this.restEnabled?s>0?(this.debouncedFetchTimeout&&clearTimeout(this.debouncedFetchTimeout),this.cancel(),new Promise((i,r)=>{this.debouncedFetchTimeout=setTimeout(async()=>{try{const n=await this.fetch();i(n)}catch(n){r(n)}},s)})):this.fetch():Promise.resolve(this)}async fetchMore({pageDelta:e=1}={}){if(!this.restEnabled)return{success:!1,message:"REST disabled, cannot fetchMore"};const t=this.params.size||10,s=this.params.start||0,i=s+e*t;return this.meta&&typeof this.meta.count=="number"&&i>=this.meta.count?{success:!0,message:"No more results",data:{data:[],status:"ok",count:this.meta.count,start:s,size:t}}:(this.params={...this.params,start:i},this.emit("fetch:more",{start:i,pageDelta:e,collection:this}),this.fetch({reset:!1}))}async fetchOne(e,t={}){if(!e)return console.warn("Collection: fetchOne requires an ID"),null;if(!this.restEnabled)return console.info("Collection: REST disabled, cannot fetch single item"),null;try{const s=new this.ModelClass({id:e},{endpoint:this.endpoint,collection:this}),i=await s.fetch(t);if(i.success){if(t.addToCollection===!0){const r=this.get(s.id);r?t.merge!==!1&&r.set(s.attributes):this.add(s,{silent:t.silent})}return s}else return console.warn("Collection: fetchOne failed -",i.error||"Unknown error"),null}catch(s){return console.error("Collection: fetchOne error -",s.message),null}}async download(e="json",t={}){if(!this.restEnabled)return console.warn("Collection: REST is not enabled, cannot download from remote."),{success:!1,message:"Remote downloads are not enabled for this collection."};const s=this.buildUrl(),i={...this.params};delete i.start,delete i.size,i.download_format=e;const r=`export-${this.getModelName().toLowerCase()}`,n=this._buildDateRangeSuffix(i),a=`${r}${n}.${e}`,l={json:"application/json",csv:"text/csv"}[e]||"*/*";return i.filename=a,this.rest.download(s,i,{...t,filename:a,headers:{Accept:l}})}_buildDateRangeSuffix(e={}){const t=e.dr_start,s=e.dr_end;if(!t&&!s)return"";const i=a=>a?String(a).replace(/[^\dA-Za-z_-]/g,"-"):"",r=[],n=e.dr_field||"daterange";return r.push(i(n)),t&&r.push(`from-${i(e.dr_start)}`),s&&r.push(`to-${i(e.dr_end)}`),`-${r.filter(Boolean).join("-")}`}parse(e){return e.data&&Array.isArray(e.data.data)?(this.meta={size:e.data.size||10,start:e.data.start||0,count:e.data.count||0,status:e.data.status,graph:e.data.graph,...e.meta},e.data.data):Array.isArray(e.data)?e.data:Array.isArray(e)?e:[e]}add(e,t={}){const s=Array.isArray(e)?e:[e],i=[];for(const r of s){let n;r instanceof this.ModelClass?(n=r,n.collection||(n.collection=this)):n=new this.ModelClass(r,{endpoint:this.endpoint,collection:this});const a=this.models.findIndex(o=>o.id===n.id);a!==-1?t.merge!==!1&&this.models[a].set(n.attributes):(this.models.push(n),i.push(n))}return!t.silent&&i.length>0&&(this.emit("add",{models:i,collection:this}),this.emit("update",{collection:this})),i}remove(e,t={}){const s=Array.isArray(e)?e:[e],i=[];for(const r of s){let n=-1;if(typeof r=="string"||typeof r=="number"?n=this.models.findIndex(a=>a.id==r):n=this.models.indexOf(r),n!==-1){const a=this.models.splice(n,1)[0];a.collection===this&&(a.collection=null),i.push(a)}}return!t.silent&&i.length>0&&(this.emit("remove",{models:i,collection:this}),this.emit("update",{collection:this})),i}reset(e=null,t={}){const s=[...this.models];return this.models=[],e&&this.add(e,{silent:!0,...t}),t.silent||this.emit("reset",{collection:this,previousModels:s}),this}get(e){return this.models.find(t=>t.id==e)}at(e){return this.models[e]}length(){return this.models.length}isEmpty(){return this.models.length===0}where(e){return typeof e=="function"?this.models.filter(e):typeof e=="object"?this.models.filter(t=>Object.entries(e).every(([s,i])=>t.get(s)===i)):[]}findWhere(e){const t=this.where(e);return t.length>0?t[0]:void 0}forEach(e,t){if(typeof e!="function")throw new TypeError("Callback must be a function");return this.models.forEach((s,i)=>{e.call(t,s,i,this)}),this}sort(e,t={}){if(typeof e=="string"){const s=e;e=(i,r)=>{const n=i.get(s),a=r.get(s);return n<a?-1:n>a?1:0}}return this.models.sort(e),t.silent||this.emit("sort",{collection:this}),this}toJSON(){return this.models.map(e=>e.toJSON())}cancel(){return this.currentRequest&&this.abortController?(console.info("Collection: Manually cancelling active request"),this.abortController.abort(),!0):!1}isFetching(){return!!this.currentRequest}buildUrl(){return this.endpoint}*[Symbol.iterator](){for(const e of this.models)yield e}static fromArray(e,t=[],s={}){const i=new this({ModelClass:e,...s});return i.add(t,{silent:!0}),i}}Object.assign(de.prototype,Ie);class Jt{constructor(e={}){this.options={containerId:"toast-container",position:"top-end",autohide:!0,defaultDelay:3e3,maxToasts:5,...e},this.toasts=new Map,this.toastCounter=0,this.init()}init(){this.createContainer()}createContainer(){let e=document.getElementById(this.options.containerId);e||(e=document.createElement("div"),e.id=this.options.containerId,e.className=`toast-container position-fixed ${this.getPositionClasses()}`,e.style.zIndex="1070",e.setAttribute("aria-live","polite"),e.setAttribute("aria-atomic","true"),document.body.appendChild(e)),this.container=e}getPositionClasses(){const e={"top-start":"top-0 start-0 p-3","top-center":"top-0 start-50 translate-middle-x p-3","top-end":"top-0 end-0 p-3","middle-start":"top-50 start-0 translate-middle-y p-3","middle-center":"top-50 start-50 translate-middle p-3","middle-end":"top-50 end-0 translate-middle-y p-3","bottom-start":"bottom-0 start-0 p-3","bottom-center":"bottom-0 start-50 translate-middle-x p-3","bottom-end":"bottom-0 end-0 p-3"};return e[this.options.position]||e["top-end"]}success(e,t={}){return this.show(e,"success",{icon:"bi-check-circle-fill",...t})}error(e,t={}){return this.show(e,"error",{icon:"bi-exclamation-triangle-fill",autohide:!0,...t})}info(e,t={}){return this.show(e,"info",{icon:"bi-info-circle-fill",...t})}warning(e,t={}){return this.show(e,"warning",{icon:"bi-exclamation-triangle-fill",...t})}plain(e,t={}){return this.show(e,"plain",{...t})}show(e,t="info",s={}){this.enforceMaxToasts();const i=`toast-${++this.toastCounter}`,r={title:this.getDefaultTitle(t),icon:this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,...s},n=this.createToastElement(i,e,t,r);if(this.container.appendChild(n),typeof bootstrap>"u")throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const a=new bootstrap.Toast(n,{autohide:r.autohide,delay:r.delay});return this.toasts.set(i,{element:n,bootstrap:a,type:t,message:e}),n.addEventListener("hidden.bs.toast",()=>{this.cleanup(i)}),a.show(),{id:i,hide:()=>{try{a.hide()}catch(o){console.warn("Error hiding toast:",o)}},dispose:()=>this.cleanup(i),updateProgress:s.updateProgress||null}}showView(e,t="info",s={}){this.enforceMaxToasts();const i=`toast-${++this.toastCounter}`,r={title:s.title||this.getDefaultTitle(t),icon:s.icon||this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,size:"md",...s},n=this.createViewToastElement(i,e,t,r);if(this.container.appendChild(n),typeof bootstrap>"u")throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const a=new bootstrap.Toast(n,{autohide:r.autohide,delay:r.delay});this.toasts.set(i,{element:n,bootstrap:a,type:t,view:e,message:"View toast"}),n.addEventListener("hidden.bs.toast",()=>{this.cleanupView(i)});const o=n.querySelector(".toast-view-body");return o&&e&&e.render(!0,o),a.show(),{id:i,view:e,hide:()=>{try{a.hide()}catch(l){console.warn("Error hiding view toast:",l)}},dispose:()=>this.cleanupView(i),updateProgress:l=>{e&&typeof e.updateProgress=="function"&&e.updateProgress(l)}}}createToastElement(e,t,s,i){const r=document.createElement("div");r.id=e,r.className=`toast toast-service-${s}${i.size?` toast-${i.size}`:""}`,r.setAttribute("role","alert"),r.setAttribute("aria-live","assertive"),r.setAttribute("aria-atomic","true");const n=i.title||i.icon?this.createToastHeader(i,s):"",a=this.createToastBody(t,i.icon&&!i.title);return r.innerHTML=`
143
143
  ${n}
144
144
  ${a}
145
145
  `,r}createViewToastElement(e,t,s,i){const r=document.createElement("div");r.id=e,r.className=`toast toast-service-${s}${i.size?` toast-${i.size}`:""}`,r.setAttribute("role","alert"),r.setAttribute("aria-live","assertive"),r.setAttribute("aria-atomic","true");const n=i.title||i.icon?this.createToastHeader(i,s):"",a=this.createViewToastBody();return r.innerHTML=`
@@ -160,7 +160,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
160
160
  ${t?`<i class="${this.getDefaultIcon("info")} toast-service-icon me-2"></i>`:""}
161
161
  <span>${this.escapeHtml(e)}</span>
162
162
  </div>
163
- `}getDefaultTitle(e){return{success:"Success",error:"Error",warning:"Warning",info:"Information",plain:""}[e]||"Notification"}getDefaultIcon(e){return{success:"bi-check-circle-fill",error:"bi-exclamation-triangle-fill",warning:"bi-exclamation-triangle-fill",info:"bi-info-circle-fill",plain:""}[e]||"bi-info-circle-fill"}enforceMaxToasts(){if(Array.from(this.toasts.values()).length>=this.options.maxToasts){const t=this.toasts.keys().next().value,s=this.toasts.get(t);s&&s.bootstrap.hide()}}cleanup(e){const t=this.toasts.get(e);if(t){try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}cleanupView(e){const t=this.toasts.get(e);if(t){if(t.view&&typeof t.view.dispose=="function")try{t.view.dispose()}catch(s){console.warn("Error disposing view in toast:",s)}try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}hideAll(){this.toasts.forEach((e,t)=>{e.bootstrap.hide()})}clearAll(){this.toasts.forEach((e,t)=>{this.cleanup(t)})}getTimeString(){return new Date().toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}dispose(){this.clearAll(),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container)}getStats(){const e={total:this.toasts.size,byType:{}};return this.toasts.forEach(t=>{e.byType[t.type]=(e.byType[t.type]||0)+1}),e}setOptions(e){this.options={...this.options,...e},e.position&&this.container&&(this.container.className=`toast-container position-fixed ${this.getPositionClasses()}`)}}class Le extends S{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=V.pipe(this.filesize,"filesize"),this.progress=0,this.percentage=0,this.loaded=0,this.total=this.filesize,this.loadedFormatted="0 B",this.totalFormatted=this.filesizeFormatted,this.status="Starting upload...",this.showCancel=e.showCancel!==!1,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return`
163
+ `}getDefaultTitle(e){return{success:"Success",error:"Error",warning:"Warning",info:"Information",plain:""}[e]||"Notification"}getDefaultIcon(e){return{success:"bi-check-circle-fill",error:"bi-exclamation-triangle-fill",warning:"bi-exclamation-triangle-fill",info:"bi-info-circle-fill",plain:""}[e]||"bi-info-circle-fill"}enforceMaxToasts(){if(Array.from(this.toasts.values()).length>=this.options.maxToasts){const t=this.toasts.keys().next().value,s=this.toasts.get(t);s&&s.bootstrap.hide()}}cleanup(e){const t=this.toasts.get(e);if(t){try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}cleanupView(e){const t=this.toasts.get(e);if(t){if(t.view&&typeof t.view.dispose=="function")try{t.view.dispose()}catch(s){console.warn("Error disposing view in toast:",s)}try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}hideAll(){this.toasts.forEach((e,t)=>{e.bootstrap.hide()})}clearAll(){this.toasts.forEach((e,t)=>{this.cleanup(t)})}getTimeString(){return new Date().toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}dispose(){this.clearAll(),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container)}getStats(){const e={total:this.toasts.size,byType:{}};return this.toasts.forEach(t=>{e.byType[t.type]=(e.byType[t.type]||0)+1}),e}setOptions(e){this.options={...this.options,...e},e.position&&this.container&&(this.container.className=`toast-container position-fixed ${this.getPositionClasses()}`)}}class Pe extends C{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=V.pipe(this.filesize,"filesize"),this.progress=0,this.percentage=0,this.loaded=0,this.total=this.filesize,this.loadedFormatted="0 B",this.totalFormatted=this.filesizeFormatted,this.status="Starting upload...",this.showCancel=e.showCancel!==!1,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return`
164
164
  <div class="progress-view">
165
165
  <div class="d-flex justify-content-between align-items-start mb-2">
166
166
  <div class="flex-grow-1 min-width-0">
@@ -199,7 +199,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
199
199
  </small>
200
200
  </div>
201
201
  </div>
202
- `}updateProgress(e){this.cancelled||this.completed||(this.progress=e.progress,this.percentage=e.percentage,this.loaded=e.loaded,this.total=e.total||this.filesize,this.loadedFormatted=V.pipe(this.loaded,"filesize"),this.totalFormatted=V.pipe(this.total,"filesize"),this.percentage<100?this.status=`Uploading... ${this.percentage}%`:this.status="Finalizing upload...",this.render())}markCompleted(e="Upload completed!"){this.completed=!0,this.progress=1,this.percentage=100,this.status=e,this.render()}markFailed(e="Upload failed"){this.status=e,this.render()}markCancelled(){this.cancelled=!0,this.status="Upload cancelled",this.render()}async onActionCancel(e,t,s){if(!(this.cancelled||this.completed)&&(s.disabled=!0,this.markCancelled(),this.emit("cancel"),typeof this.onCancel=="function"))try{await this.onCancel()}catch(i){console.error("Error in cancel callback:",i)}}setFilename(e){this.filename=e,this.render()}setFilesize(e){this.filesize=e,this.filesizeFormatted=V.pipe(e,"filesize"),this.total=e,this.totalFormatted=this.filesizeFormatted,this.render()}getPercentage(){return this.percentage}isCompleted(){return this.completed}isCancelled(){return this.cancelled}getStats(){return{filename:this.filename,filesize:this.filesize,progress:this.progress,percentage:this.percentage,loaded:this.loaded,total:this.total,cancelled:this.cancelled,completed:this.completed,status:this.status}}}class Zt{constructor(e,t={}){if(this.fileModel=e,this.options={file:null,name:null,group:null,description:null,onProgress:null,onComplete:null,onError:null,showToast:!0,...t},!this.options.file||!(this.options.file instanceof File))throw new Error("FileUpload requires a valid File object");this.cancelled=!1,this.uploadRequest=null,this.progressToast=null,this.progressView=null,this.toastService=null,this.options.showToast&&(this.toastService=new Jt),this.promise=this._startUpload()}async _startUpload(){try{this.options.showToast&&this._showProgressToast();let e;try{e=await this._initiateUpload()}catch(i){throw new Error(`Failed to initiate upload: ${i.message}`)}if(this.cancelled)throw new Error("Upload cancelled");if(!e||!e.upload_url)throw new Error("Invalid upload response: missing upload URL");let t;if(typeof e.upload_url=="string")t={url:e.upload_url,method:"PUT",fields:null,headers:{}};else if(e.upload_url&&typeof e.upload_url=="object"&&e.upload_url.upload_url)t={url:e.upload_url.upload_url,method:e.upload_url.method||"POST",fields:e.upload_url.fields||null,headers:e.upload_url.headers||{}};else throw new Error(`Invalid upload response: unrecognised upload_url format. Server returned: ${JSON.stringify(e.upload_url)}`);let s;try{s=await this._performUpload(t)}catch(i){throw new Error(`File upload failed: ${i.message}`)}if(this.cancelled)throw new Error("Upload cancelled");try{await this._completeUpload()}catch(i){console.warn("Failed to mark upload as completed:",i)}return this._onComplete(this.fileModel),this.fileModel}catch(e){throw e.message!=="Upload cancelled"&&this._onError(e),e}}async _initiateUpload(){try{const e={filename:this.options.name||this.options.file.name,file_size:this.options.file.size,content_type:this.options.file.type};this.options.group&&(e.group=this.options.group),this.options.description&&(e.description=this.options.description);const t=await this.fileModel.rest.POST("/api/fileman/upload/initiate",e);if(!t)throw new Error("No response from upload initiation API");if(!t.data)throw new Error("Upload initiation response missing data");if(!t.data.status){const s=t.data.error||"Upload initiation failed";throw new Error(s)}if(!t.data.data)throw new Error("Upload initiation response missing data payload");return t.data.data.id&&this.fileModel.set("id",t.data.data.id),t.data.data}catch(e){throw e.message==="Network Error"||e.name==="TypeError"?new Error("Network error during upload initiation. Please check your connection."):e}}async _performUpload(e){return new Promise((t,s)=>{if(!(this.options.file instanceof File)){s(new Error("Only single File objects are supported"));return}const{url:i,method:r,fields:n,headers:a}=e,o=r==="POST"&&n!==null,l=new XMLHttpRequest;this.uploadRequest=l,l.upload.onprogress=u=>{this.cancelled||this._onProgress({progress:u.loaded/u.total,loaded:u.loaded,total:u.total,percentage:Math.round(u.loaded/u.total*100)})},l.onload=()=>{l.status>=200&&l.status<300?t({data:l.response,status:l.status,statusText:l.statusText,xhr:l}):s(new Error(`Upload failed: ${l.status} ${l.statusText}`))},l.onerror=()=>s(new Error("Upload failed: Network error")),l.ontimeout=()=>s(new Error("Upload timed out — file may be too large or connection too slow")),l.onabort=()=>s(new Error("Upload cancelled"));let d=i;i.startsWith("/")&&!i.startsWith("/api/")&&(d="/api"+i);const h=this.fileModel.rest.buildUrl(d);if(l.open(r,h),l.timeout=3e4,o){for(const[m,p]of Object.entries(a||{}))m.toLowerCase()!=="content-type"&&l.setRequestHeader(m,p);const u=new FormData;for(const[m,p]of Object.entries(n))u.append(m,p);u.append("file",this.options.file),l.send(u)}else{l.setRequestHeader("Content-Type",this.options.file.type);for(const[u,m]of Object.entries(a||{}))u.toLowerCase()!=="content-type"&&l.setRequestHeader(u,m);l.send(this.options.file)}})}async _completeUpload(){try{const e=await this.fileModel.save({action:"mark_as_completed"});if(!e)throw new Error("No response from upload completion API");if(e.data&&!e.data.status){const t=e.data.error||"Failed to mark upload as completed";throw new Error(t)}return e}catch(e){throw e.message==="Network Error"||e.name==="TypeError"?new Error("Network error during upload completion. The file may have uploaded successfully."):e}}_onProgress(e){this.progressToast&&this.progressToast.updateProgress&&this.progressToast.updateProgress(e),typeof this.options.onProgress=="function"&&this.options.onProgress(e)}_onComplete(e){this.progressView&&this.progressView.markCompleted("Upload completed successfully!"),this.progressToast&&setTimeout(()=>{try{this.progressToast&&typeof this.progressToast.hide=="function"&&this.progressToast.hide()}catch(t){console.warn("Error hiding progress toast:",t)}},2e3),typeof this.options.onComplete=="function"&&this.options.onComplete(e)}_onError(e){if(this.progressToast)try{this.progressToast.hide()}catch(t){console.warn("Error hiding progress toast on error:",t)}this.toastService&&this.toastService.error(`Upload failed: ${e.message}`),typeof this.options.onError=="function"&&this.options.onError(e)}_showProgressToast(){this.progressView=new Le({filename:this.options.name||this.options.file.name,filesize:this.options.file.size,showCancel:!0,onCancel:()=>this.cancel()}),this.progressToast=this.toastService.showView(this.progressView,"info",{title:"File Upload",autohide:!1,dismissible:!1})}cancel(){return this.cancelled?!1:(this.cancelled=!0,this.uploadRequest&&typeof this.uploadRequest.abort=="function"&&this.uploadRequest.abort(),this.progressView&&this.progressView.markCancelled(),this.progressToast&&setTimeout(()=>{try{this.progressToast&&typeof this.progressToast.hide=="function"&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast on cancel:",e)}},1500),!0)}isCancelled(){return this.cancelled}then(e,t){return this.promise.then(e,t)}catch(e){return this.promise.catch(e)}finally(e){return this.promise.finally(e)}getStats(){return{filename:this.options.file.name,size:this.options.file.size,type:this.options.file.type,cancelled:this.cancelled,group:this.options.group,description:this.options.description}}}class G extends Q{constructor(e={}){super(e,{endpoint:"/api/group"})}}class nt extends de{constructor(e={}){super({ModelClass:G,endpoint:"/api/group",size:10,...e})}}const at={org:"Organization",platform:"Platform",division:"Division",department:"Department",team:"Team",merchant:"Merchant",partner:"Partner",client:"Client",iso:"ISO",sales:"Sales",reseller:"Reseller",location:"Location",region:"Region",route:"Route",project:"Project",inventory:"Inventory",test:"Testing",misc:"Miscellaneous",qa:"Quality Assurance"},ot=Object.entries(at).map(([c,e])=>({value:c,label:e})),lt=[{value:"America/New_York",label:"Eastern Time (ET)"},{value:"America/Chicago",label:"Central Time (CT)"},{value:"America/Denver",label:"Mountain Time (MT)"},{value:"America/Los_Angeles",label:"Pacific Time (PT)"},{value:"America/Anchorage",label:"Alaska Time (AKT)"},{value:"Pacific/Honolulu",label:"Hawaii Time (HT)"},{value:"UTC",label:"UTC"},{value:"Europe/London",label:"London (GMT/BST)"},{value:"Europe/Paris",label:"Paris (CET/CEST)"},{value:"Europe/Berlin",label:"Berlin (CET/CEST)"},{value:"Asia/Tokyo",label:"Tokyo (JST)"},{value:"Asia/Shanghai",label:"Shanghai (CST)"},{value:"Australia/Sydney",label:"Sydney (AEST)"}],ct=Array.from({length:24},(c,e)=>{let t;return e===0?t="Midnight":e===12?t="Noon":t=`${e%12===0?12:e%12} ${e<12?"AM":"PM"}`,{value:e,label:t}});function dt(){return{avatar:{type:"image",name:"avatar",size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your avatar",help:"Square images work best",columns:12},name:{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name",columns:12},kind:{name:"kind",type:"combo",label:"Group Kind",required:!0,placeholder:"Type or select kind...",options:ot,columns:12},parent:{type:"collection",name:"parent",label:"Parent Group",Collection:nt,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300,columns:12},isActive:{name:"is_active",type:"switch",label:"Is Active",columns:12},uuid:{name:"uuid",type:"text",label:"UUID",placeholder:"32-character hex string",columns:12},shortName:{name:"metadata.short_name",type:"text",label:"Short Name",placeholder:"Enter short name",columns:6},domain:{name:"metadata.domain",type:"text",label:"Default Domain",placeholder:"Enter domain",columns:6},authDomain:{name:"metadata.auth_domain",type:"text",label:"Auth Domain",placeholder:"auth.example.com",help:"Used for white-label login pages.",columns:6},portal:{name:"metadata.portal",type:"text",label:"Default Portal",placeholder:"https://…",columns:6},timezone:{name:"metadata.timezone",type:"select",label:"Timezone",options:lt,columns:6},eodHour:{name:"metadata.eod_hour",type:"select",label:"End of Day Hour",options:ct,columns:6},emailTemplate:{name:"metadata.email_template",type:"text",label:"Email Template (Prefix)",placeholder:"Enter template prefix",columns:12}}}const Pe={get create(){const c=dt();return{title:"Create Group",fields:[c.name,c.kind,c.parent]}},get edit(){return{...this.detailed,title:"Edit Group"}},get detailed(){const c=dt();return{title:"Group Details",fields:[{type:"tabset",name:"group-detail",tabs:[{label:"Profile",fields:[c.name,c.kind,c.parent,c.isActive]},{label:"Identity",fields:[c.uuid,c.shortName,c.domain,c.authDomain,c.portal]},{label:"Localization",fields:[c.timezone,c.eodHour]},{label:"Branding",fields:[c.emailTemplate]},{label:"Avatar",fields:[c.avatar]}]}]}}};G.EDIT_FORM=Pe.edit,G.ADD_FORM=Pe.create,G.CREATE_FORM=Pe.create,G.FORM_DIALOG_CONFIG={size:"lg"},G.GroupKindOptions=ot,G.GroupKinds=at,G.TimezoneOptions=lt,G.EodHourOptions=ct;class w extends Q{constructor(e={}){super(e,{endpoint:"/api/user"})}hasPermission(e){if(this.get("is_superuser"))return!0;if(Array.isArray(e))return e.some(i=>this.hasPermission(i));const t=e.startsWith("sys."),s=t?e.substring(4):e;return!!(this._hasPermission(s)||this._hasPermission("admin")||!t&&this.member&&this.member.hasPermission(e))}_hasPermission(e){const t=this.get("permissions");if(!t)return!1;if(t[e]==!0)return!0;const s=w.GRANULAR_TO_CATEGORY[e];return!!(s&&t[s]==!0)}hasPerm(e){return this.hasPermission(e)}}w.CATEGORY_PERMISSIONS=[{name:"admin",label:"System Admin",tooltip:"Full access to everything — permission equivalent of superuser"},{name:"view_admin",label:"Admin Panel",tooltip:"Access the admin panel, Mojo, and system tools"},{name:"security",label:"Security",tooltip:"Incidents, events, rules, tickets, firewall, bouncer, GeoIP, system logs"},{name:"users",label:"Users",tooltip:"User records, passkeys, TOTP, API keys, OAuth, devices, locations"},{name:"groups",label:"Groups",tooltip:"Groups, members, group API keys, settings"},{name:"comms",label:"Communications",tooltip:"Email, phone, SMS, push notifications, chat, notifications"},{name:"jobs",label:"Jobs",tooltip:"Jobs, job events, job logs, runners, queue control, system stats"},{name:"metrics",label:"Metrics",tooltip:"Metrics recording, fetching, categories, values, permissions"},{name:"files",label:"Files",tooltip:"File managers, files, renditions, vault files, vault data, S3 buckets"},{name:"assistant",label:"Mojo",tooltip:"Access to Mojo"}],w.GRANULAR_PERMISSION_TABS=[{label:"Account",permissions:[{name:"view_users",label:"View Users"},{name:"manage_users",label:"Manage Users"},{name:"view_groups",label:"View Groups"},{name:"manage_groups",label:"Manage Groups"},{name:"manage_group",label:"Manage Own Group"},{name:"view_members",label:"View Members"},{name:"manage_settings",label:"Manage Settings"}]},{label:"Communication",permissions:[{name:"manage_chat",label:"Manage Chat"},{name:"manage_aws",label:"Manage Email (AWS)"},{name:"view_notifications",label:"View Notifications"},{name:"manage_notifications",label:"Manage Notifications"},{name:"send_notifications",label:"Send Notifications"},{name:"view_devices",label:"View Push Devices"},{name:"manage_devices",label:"Manage Push Devices"},{name:"manage_push_config",label:"Push Config"},{name:"view_phone_numbers",label:"View Phone Numbers"},{name:"manage_phone_numbers",label:"Manage Phone Numbers"},{name:"manage_phone_config",label:"Phone Config"},{name:"view_sms",label:"View SMS"},{name:"manage_sms",label:"Manage SMS"},{name:"send_sms",label:"Send SMS"}]},{label:"Platform",permissions:[{name:"view_security",label:"View Security"},{name:"manage_security",label:"Manage Security"},{name:"view_logs",label:"View Logs"},{name:"manage_logs",label:"Manage Logs"},{name:"view_jobs",label:"View Jobs"},{name:"manage_jobs",label:"Manage Jobs"},{name:"view_metrics",label:"View Metrics"},{name:"manage_metrics",label:"Manage Metrics"},{name:"write_metrics",label:"Write Metrics"},{name:"view_fileman",label:"View File Managers"},{name:"manage_files",label:"Manage Files"},{name:"view_vault",label:"View Vault"},{name:"manage_vault",label:"Manage Vault"},{name:"manage_docit",label:"Manage Docs"},{name:"manage_shortlinks",label:"Manage Shortlinks"},{name:"view_geofence",label:"View Geofence Config"},{name:"manage_geofence",label:"Manage Geofence Config"},{name:"bypass_geofence",label:"Bypass Geofence (Whitelist)",tooltip:"Exempts this user from ALL geofence rules on authenticated requests. Login-time geofencing still applies until backend post-login support lands."}]}],w.CATEGORY_GRANULAR_MAP={security:["view_security","manage_security"],users:["view_users","manage_users","view_members"],groups:["view_groups","manage_groups","manage_group"],comms:["manage_chat","manage_aws","view_notifications","manage_notifications","send_notifications","view_devices","manage_devices","manage_push_config","view_phone_numbers","manage_phone_numbers","manage_phone_config","view_sms","manage_sms","send_sms"],jobs:["view_jobs","manage_jobs"],metrics:["view_metrics","manage_metrics","write_metrics"],files:["view_fileman","manage_files","view_vault","manage_vault"]},w.APP_CATEGORY_PERMISSIONS=[],w.APP_GRANULAR_PERMISSIONS=[],w._permSwitch=function(c){return{name:`permissions.${c.name}`,type:"switch",label:c.label,columns:6,...c.tooltip?{tooltip:c.tooltip}:{}}},w.PERMISSIONS=[],w.PERMISSION_FIELDS=[],w.CATEGORY_PERMISSION_FIELDS=[],w.GRANULAR_PERMISSION_FIELDS=[],w.SYSTEM_PERMISSION_FIELDS=[],w.APP_PERMISSION_FIELDS=[],w.GRANULAR_TO_CATEGORY={},w.rebuildPermissions=function(){const c=w._permSwitch;w.PERMISSIONS.length=0,w.PERMISSIONS.push(...w.CATEGORY_PERMISSIONS,...w.GRANULAR_PERMISSION_TABS.flatMap(i=>i.permissions),...w.APP_CATEGORY_PERMISSIONS,...w.APP_GRANULAR_PERMISSIONS),w.PERMISSION_FIELDS.length=0,w.PERMISSION_FIELDS.push(...w.PERMISSIONS.map(c));const e=[{label:"System",fields:w.CATEGORY_PERMISSIONS.map(c)}];w.APP_CATEGORY_PERMISSIONS.length>0&&e.push({label:"App",fields:w.APP_CATEGORY_PERMISSIONS.map(c)}),w.CATEGORY_PERMISSION_FIELDS.length=0,w.CATEGORY_PERMISSION_FIELDS.push({type:"tabset",tabs:e});const t=w.GRANULAR_PERMISSION_TABS.map(i=>({label:i.label,fields:i.permissions.map(c)}));w.APP_GRANULAR_PERMISSIONS.length>0&&t.push({label:"App",fields:w.APP_GRANULAR_PERMISSIONS.map(c)}),w.GRANULAR_PERMISSION_FIELDS.length=0,w.GRANULAR_PERMISSION_FIELDS.push({type:"tabset",tabs:t}),w.SYSTEM_PERMISSION_FIELDS.length=0,w.SYSTEM_PERMISSION_FIELDS.push({type:"tabset",tabs:[{label:"System",fields:w.CATEGORY_PERMISSIONS.map(c)},...w.GRANULAR_PERMISSION_TABS.map(i=>({label:i.label,fields:i.permissions.map(c)}))]}),w.APP_PERMISSION_FIELDS.length=0;const s=[];w.APP_CATEGORY_PERMISSIONS.length>0&&s.push({label:"Categories",fields:w.APP_CATEGORY_PERMISSIONS.map(c)}),w.APP_GRANULAR_PERMISSIONS.length>0&&s.push({label:"Permissions",fields:w.APP_GRANULAR_PERMISSIONS.map(c)}),s.length>0&&w.APP_PERMISSION_FIELDS.push({type:"tabset",tabs:s});for(const i of Object.keys(w.GRANULAR_TO_CATEGORY))delete w.GRANULAR_TO_CATEGORY[i];for(const[i,r]of Object.entries(w.CATEGORY_GRANULAR_MAP))for(const n of r)w.GRANULAR_TO_CATEGORY[n]=i},w.registerCategoryMap=function(c){if(!c)return;let e=!1;for(const[t,s]of Object.entries(c)){if(!Array.isArray(s))continue;const i=w.CATEGORY_GRANULAR_MAP[t]||[];w.CATEGORY_GRANULAR_MAP[t]=Array.from(new Set([...i,...s])),e=!0}e&&w.rebuildPermissions()},w.registerPermissions=function(c){if(c){if(Array.isArray(c.categories)&&w.APP_CATEGORY_PERMISSIONS.push(...c.categories),Array.isArray(c.granularPermissions)&&w.APP_GRANULAR_PERMISSIONS.push(...c.granularPermissions),Array.isArray(c.granularTabs)&&w.GRANULAR_PERMISSION_TABS.push(...c.granularTabs),c.categoryGranularMap)for(const[e,t]of Object.entries(c.categoryGranularMap)){if(!Array.isArray(t))continue;const s=w.CATEGORY_GRANULAR_MAP[e]||[];w.CATEGORY_GRANULAR_MAP[e]=Array.from(new Set([...s,...t]))}w.rebuildPermissions()}},w.rebuildPermissions();const ht={create:{title:"Create User",fields:[{name:"email",type:"text",label:"Email",required:!0},{name:"phone_number",type:"text",label:"Phone number",columns:12},{name:"display_name",type:"text",label:"Display Name"}]},edit:{title:"Edit User",fields:[{name:"email",type:"email",label:"Email",columns:12},{name:"display_name",type:"text",label:"Display Name",columns:12},{name:"phone_number",type:"text",label:"Phone number",columns:12},{type:"collection",name:"org",label:"Organization",Collection:nt,labelField:"name",valueField:"id",columns:12}]},permissions:{fields:w.PERMISSION_FIELDS}},Kt={detailed:{title:"Detailed User Information",columns:2,showEmptyValues:!0,emptyValueText:"Not set",fields:[{name:"id",label:"User ID",type:"number",colSize:3},{name:"display_name",label:"Display Name",type:"text",format:'capitalize|default("Unnamed User")',colSize:9},{name:"username",label:"Username",type:"text",format:"lowercase",colSize:6},{name:"email",label:"Email Address",type:"email",colSize:6},{name:"phone_number",label:"Phone Number",type:"phone",format:'phone|default("Not provided")',colSize:6},{name:"is_active",label:"Account Status",type:"boolean",colSize:6},{name:"last_login",label:"Last Login",type:"datetime",format:"relative",colSize:6},{name:"last_activity",label:"Last Activity",type:"datetime",format:"relative",colSize:6},{name:"avatar.url",label:"Avatar",type:"url",colSize:12},{name:"permissions",label:"User Permissions",type:"dataview",dataViewColumns:2,showEmptyValues:!1},{name:"metadata",label:"User Metadata",type:"dataview",dataViewColumns:1},{name:"avatar",label:"Avatar Details",type:"dataview",dataViewColumns:1}]}};w.DATA_VIEW=Kt.detailed,w.EDIT_FORM=ht.edit,w.ADD_FORM=ht.create;class ut extends Q{constructor(e={}){super(e,{endpoint:"/api/fileman/manager"})}}const mt={create:{title:"Add Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,value:"s3://BUCKET_NAME/OPTION_FOLDER",placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6}]},edit:{title:"Edit Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"allowed_origins",type:"text",label:"Domains Who Can Upload",cols:12},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6},{name:"is_public",type:"switch",label:"Is Public",default:!0,cols:6}]}};let pt=class extends Q{constructor(e={}){super(e,{endpoint:"/api/fileman/file"})}isImage(){return this.get("category")==="image"}getCategory(){return this.get("category")||this._inferCategoryFromContentType()}_inferCategoryFromContentType(){const e=(this.get("content_type")||"").toLowerCase();return e?e.startsWith("image/")?"image":e.startsWith("video/")?"video":e.startsWith("audio/")?"audio":e==="application/pdf"?"pdf":e.startsWith("text/")||e==="application/msword"||e.startsWith("application/vnd.openxmlformats-officedocument.wordprocessingml")||e==="application/vnd.oasis.opendocument.text"?"document":e==="application/vnd.ms-excel"||e.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml")||e==="application/vnd.oasis.opendocument.spreadsheet"?"spreadsheet":e==="application/vnd.ms-powerpoint"||e.startsWith("application/vnd.openxmlformats-officedocument.presentationml")||e==="application/vnd.oasis.opendocument.presentation"?"presentation":e==="application/zip"||e==="application/x-rar-compressed"||e==="application/x-7z-compressed"||e==="application/x-tar"||e==="application/gzip"?"archive":"other":"other"}hasRenditions(){const e=this.get("renditions");return!!(e&&Object.keys(e).length)}isUploadPending(){const e=this.get("upload_status");return!!(e&&e!=="completed"&&e!=="failed")}regenerateRenditions(e){const t=this.id||this.get("id");if(!t)return Promise.reject(new Error("Cannot regenerate renditions on an unsaved file"));const s=Array.isArray(e)&&e.length?{regenerate_renditions:e}:{regenerate_renditions:!0};return this.rest.POST(`${this.endpoint}/${t}`,s)}share(e=!0){const t=this.id||this.get("id");return t?this.rest.POST(`${this.endpoint}/${t}`,{share:e}):Promise.reject(new Error("Cannot share an unsaved file"))}getRenditions(){const e=this.get("renditions");return e?Object.values(e):[]}getBestImageRendition(){const e=this.getRenditions().filter(t=>t&&typeof t.content_type=="string"&&t.content_type.startsWith("image/"));return e.length?e.reduce((t,s)=>{const i=(parseInt(t.width)||0)*(parseInt(t.height)||0);return(parseInt(s.width)||0)*(parseInt(s.height)||0)>i?s:t}):null}getThumbnailUrl(){const e=this.get("renditions")||{};if(e.thumbnail&&e.thumbnail.url)return e.thumbnail.url;const t=this.getBestImageRendition();return t?t.url:null}upload(e={}){return new Zt(this,e)}};const Qt={edit:{title:"Edit File Backend",fields:[]}};ut.ADD_FORM=mt.create,ut.EDIT_FORM=mt.edit,pt.EDIT_FORM=Qt.edit;class v{static _renderAndAwait(e,{buttons:t=null,rejectOnDismiss:s=!1,onAction:i=null,cleanup:r=null}={}){const n=x.getMountTarget();return new Promise((a,o)=>{let l=!1;const d=u=>{l||(l=!0,a(u))},h=u=>{l||(l=!0,o(u))};(async()=>{try{await e.render(!0,n)}catch(u){h(u);return}t&&t.length>0&&e.element&&e.element.querySelectorAll(".modal-footer button").forEach((m,p)=>{const f=t[p];f&&m.addEventListener("click",async g=>{if(l)return;const b=f.value!==void 0?f.value:f.action??p;if(typeof f.handler=="function"){try{const y=await f.handler({dialog:e,button:f,index:p,event:g});if(y===null||y===!1)return;const C=y===!0||y===void 0?b:y;f.dismiss||e.hide(),d(C)}catch(y){console.error("Modal button handler error:",y)}return}if(typeof i=="function"&&f.action){try{const y=await i(f.action,{dialog:e,button:f,index:p,event:g});if(y===null||y===!1)return;const C=y===!0||y===void 0?b:y;f.dismiss||e.hide(),d(C)}catch(y){console.error("Modal onAction error:",y)}return}f.dismiss||e.hide(),d(b)})}),e.on("hidden",()=>{l||(s?h(new Error("Dialog dismissed")):d(null)),setTimeout(async()=>{try{typeof r=="function"&&await r(e)}catch(u){console.error("Modal cleanup error:",u)}try{await e.destroy()}catch(u){console.error("Modal destroy error:",u)}e.element?.parentNode&&e.element.parentNode.removeChild(e.element)},100)}),e.show()})()})}static async dialog(e={}){if(typeof e=="string"){const p=arguments[0],f=arguments[1]||"Alert";e={...arguments[2]||{},body:p,title:f}}const{title:t="Dialog",content:s,body:i,view:r,message:n,size:a="md",centered:o=!0,buttons:l=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:d=!1,...h}=e,u=i??r??n??s??"",m=new x({title:t,body:u,size:a,centered:o,buttons:l,...h});return v._renderAndAwait(m,{buttons:l,rejectOnDismiss:d})}static async drawer(e={}){const{eyebrow:t,title:s,meta:i=[],view:r,body:n,size:a="lg",...o}=e,l=i.length?`
202
+ `}updateProgress(e){this.cancelled||this.completed||(this.progress=e.progress,this.percentage=e.percentage,this.loaded=e.loaded,this.total=e.total||this.filesize,this.loadedFormatted=V.pipe(this.loaded,"filesize"),this.totalFormatted=V.pipe(this.total,"filesize"),this.percentage<100?this.status=`Uploading... ${this.percentage}%`:this.status="Finalizing upload...",this.render())}markCompleted(e="Upload completed!"){this.completed=!0,this.progress=1,this.percentage=100,this.status=e,this.render()}markFailed(e="Upload failed"){this.status=e,this.render()}markCancelled(){this.cancelled=!0,this.status="Upload cancelled",this.render()}async onActionCancel(e,t,s){if(!(this.cancelled||this.completed)&&(s.disabled=!0,this.markCancelled(),this.emit("cancel"),typeof this.onCancel=="function"))try{await this.onCancel()}catch(i){console.error("Error in cancel callback:",i)}}setFilename(e){this.filename=e,this.render()}setFilesize(e){this.filesize=e,this.filesizeFormatted=V.pipe(e,"filesize"),this.total=e,this.totalFormatted=this.filesizeFormatted,this.render()}getPercentage(){return this.percentage}isCompleted(){return this.completed}isCancelled(){return this.cancelled}getStats(){return{filename:this.filename,filesize:this.filesize,progress:this.progress,percentage:this.percentage,loaded:this.loaded,total:this.total,cancelled:this.cancelled,completed:this.completed,status:this.status}}}class Kt{constructor(e,t={}){if(this.fileModel=e,this.options={file:null,name:null,group:null,description:null,onProgress:null,onComplete:null,onError:null,showToast:!0,...t},!this.options.file||!(this.options.file instanceof File))throw new Error("FileUpload requires a valid File object");this.cancelled=!1,this.uploadRequest=null,this.progressToast=null,this.progressView=null,this.toastService=null,this.options.showToast&&(this.toastService=new Jt),this.promise=this._startUpload()}async _startUpload(){try{this.options.showToast&&this._showProgressToast();let e;try{e=await this._initiateUpload()}catch(i){throw new Error(`Failed to initiate upload: ${i.message}`)}if(this.cancelled)throw new Error("Upload cancelled");if(!e||!e.upload_url)throw new Error("Invalid upload response: missing upload URL");let t;if(typeof e.upload_url=="string")t={url:e.upload_url,method:"PUT",fields:null,headers:{}};else if(e.upload_url&&typeof e.upload_url=="object"&&e.upload_url.upload_url)t={url:e.upload_url.upload_url,method:e.upload_url.method||"POST",fields:e.upload_url.fields||null,headers:e.upload_url.headers||{}};else throw new Error(`Invalid upload response: unrecognised upload_url format. Server returned: ${JSON.stringify(e.upload_url)}`);let s;try{s=await this._performUpload(t)}catch(i){throw new Error(`File upload failed: ${i.message}`)}if(this.cancelled)throw new Error("Upload cancelled");try{await this._completeUpload()}catch(i){console.warn("Failed to mark upload as completed:",i)}return this._onComplete(this.fileModel),this.fileModel}catch(e){throw e.message!=="Upload cancelled"&&this._onError(e),e}}async _initiateUpload(){try{const e={filename:this.options.name||this.options.file.name,file_size:this.options.file.size,content_type:this.options.file.type};this.options.group&&(e.group=this.options.group),this.options.description&&(e.description=this.options.description);const t=await this.fileModel.rest.POST("/api/fileman/upload/initiate",e);if(!t)throw new Error("No response from upload initiation API");if(!t.data)throw new Error("Upload initiation response missing data");if(!t.data.status){const s=t.data.error||"Upload initiation failed";throw new Error(s)}if(!t.data.data)throw new Error("Upload initiation response missing data payload");return t.data.data.id&&this.fileModel.set("id",t.data.data.id),t.data.data}catch(e){throw e.message==="Network Error"||e.name==="TypeError"?new Error("Network error during upload initiation. Please check your connection."):e}}async _performUpload(e){return new Promise((t,s)=>{if(!(this.options.file instanceof File)){s(new Error("Only single File objects are supported"));return}const{url:i,method:r,fields:n,headers:a}=e,o=r==="POST"&&n!==null,l=new XMLHttpRequest;this.uploadRequest=l,l.upload.onprogress=u=>{this.cancelled||this._onProgress({progress:u.loaded/u.total,loaded:u.loaded,total:u.total,percentage:Math.round(u.loaded/u.total*100)})},l.onload=()=>{l.status>=200&&l.status<300?t({data:l.response,status:l.status,statusText:l.statusText,xhr:l}):s(new Error(`Upload failed: ${l.status} ${l.statusText}`))},l.onerror=()=>s(new Error("Upload failed: Network error")),l.ontimeout=()=>s(new Error("Upload timed out — file may be too large or connection too slow")),l.onabort=()=>s(new Error("Upload cancelled"));let d=i;i.startsWith("/")&&!i.startsWith("/api/")&&(d="/api"+i);const h=this.fileModel.rest.buildUrl(d);if(l.open(r,h),l.timeout=3e4,o){for(const[m,p]of Object.entries(a||{}))m.toLowerCase()!=="content-type"&&l.setRequestHeader(m,p);const u=new FormData;for(const[m,p]of Object.entries(n))u.append(m,p);u.append("file",this.options.file),l.send(u)}else{l.setRequestHeader("Content-Type",this.options.file.type);for(const[u,m]of Object.entries(a||{}))u.toLowerCase()!=="content-type"&&l.setRequestHeader(u,m);l.send(this.options.file)}})}async _completeUpload(){try{const e=await this.fileModel.save({action:"mark_as_completed"});if(!e)throw new Error("No response from upload completion API");if(e.data&&!e.data.status){const t=e.data.error||"Failed to mark upload as completed";throw new Error(t)}return e}catch(e){throw e.message==="Network Error"||e.name==="TypeError"?new Error("Network error during upload completion. The file may have uploaded successfully."):e}}_onProgress(e){this.progressToast&&this.progressToast.updateProgress&&this.progressToast.updateProgress(e),typeof this.options.onProgress=="function"&&this.options.onProgress(e)}_onComplete(e){this.progressView&&this.progressView.markCompleted("Upload completed successfully!"),this.progressToast&&setTimeout(()=>{try{this.progressToast&&typeof this.progressToast.hide=="function"&&this.progressToast.hide()}catch(t){console.warn("Error hiding progress toast:",t)}},2e3),typeof this.options.onComplete=="function"&&this.options.onComplete(e)}_onError(e){if(this.progressToast)try{this.progressToast.hide()}catch(t){console.warn("Error hiding progress toast on error:",t)}this.toastService&&this.toastService.error(`Upload failed: ${e.message}`),typeof this.options.onError=="function"&&this.options.onError(e)}_showProgressToast(){this.progressView=new Pe({filename:this.options.name||this.options.file.name,filesize:this.options.file.size,showCancel:!0,onCancel:()=>this.cancel()}),this.progressToast=this.toastService.showView(this.progressView,"info",{title:"File Upload",autohide:!1,dismissible:!1})}cancel(){return this.cancelled?!1:(this.cancelled=!0,this.uploadRequest&&typeof this.uploadRequest.abort=="function"&&this.uploadRequest.abort(),this.progressView&&this.progressView.markCancelled(),this.progressToast&&setTimeout(()=>{try{this.progressToast&&typeof this.progressToast.hide=="function"&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast on cancel:",e)}},1500),!0)}isCancelled(){return this.cancelled}then(e,t){return this.promise.then(e,t)}catch(e){return this.promise.catch(e)}finally(e){return this.promise.finally(e)}getStats(){return{filename:this.options.file.name,size:this.options.file.size,type:this.options.file.type,cancelled:this.cancelled,group:this.options.group,description:this.options.description}}}class G extends Q{constructor(e={}){super(e,{endpoint:"/api/group"})}}class nt extends de{constructor(e={}){super({ModelClass:G,endpoint:"/api/group",size:10,...e})}}const at={org:"Organization",platform:"Platform",division:"Division",department:"Department",team:"Team",merchant:"Merchant",partner:"Partner",client:"Client",iso:"ISO",sales:"Sales",reseller:"Reseller",location:"Location",region:"Region",route:"Route",project:"Project",inventory:"Inventory",test:"Testing",misc:"Miscellaneous",qa:"Quality Assurance"},ot=Object.entries(at).map(([c,e])=>({value:c,label:e})),lt=[{value:"America/New_York",label:"Eastern Time (ET)"},{value:"America/Chicago",label:"Central Time (CT)"},{value:"America/Denver",label:"Mountain Time (MT)"},{value:"America/Los_Angeles",label:"Pacific Time (PT)"},{value:"America/Anchorage",label:"Alaska Time (AKT)"},{value:"Pacific/Honolulu",label:"Hawaii Time (HT)"},{value:"UTC",label:"UTC"},{value:"Europe/London",label:"London (GMT/BST)"},{value:"Europe/Paris",label:"Paris (CET/CEST)"},{value:"Europe/Berlin",label:"Berlin (CET/CEST)"},{value:"Asia/Tokyo",label:"Tokyo (JST)"},{value:"Asia/Shanghai",label:"Shanghai (CST)"},{value:"Australia/Sydney",label:"Sydney (AEST)"}],ct=Array.from({length:24},(c,e)=>{let t;return e===0?t="Midnight":e===12?t="Noon":t=`${e%12===0?12:e%12} ${e<12?"AM":"PM"}`,{value:e,label:t}});function dt(){return{avatar:{type:"image",name:"avatar",size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your avatar",help:"Square images work best",columns:12},name:{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name",columns:12},kind:{name:"kind",type:"combo",label:"Group Kind",required:!0,placeholder:"Type or select kind...",options:ot,columns:12},parent:{type:"collection",name:"parent",label:"Parent Group",Collection:nt,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300,columns:12},isActive:{name:"is_active",type:"switch",label:"Is Active",columns:12},uuid:{name:"uuid",type:"text",label:"UUID",placeholder:"32-character hex string",columns:12},shortName:{name:"metadata.short_name",type:"text",label:"Short Name",placeholder:"Enter short name",columns:6},domain:{name:"metadata.domain",type:"text",label:"Default Domain",placeholder:"Enter domain",columns:6},authDomain:{name:"metadata.auth_domain",type:"text",label:"Auth Domain",placeholder:"auth.example.com",help:"Used for white-label login pages.",columns:6},portal:{name:"metadata.portal",type:"text",label:"Default Portal",placeholder:"https://…",columns:6},timezone:{name:"metadata.timezone",type:"select",label:"Timezone",options:lt,columns:6},eodHour:{name:"metadata.eod_hour",type:"select",label:"End of Day Hour",options:ct,columns:6},emailTemplate:{name:"metadata.email_template",type:"text",label:"Email Template (Prefix)",placeholder:"Enter template prefix",columns:12}}}const Le={get create(){const c=dt();return{title:"Create Group",fields:[c.name,c.kind,c.parent]}},get edit(){return{...this.detailed,title:"Edit Group"}},get detailed(){const c=dt();return{title:"Group Details",fields:[{type:"tabset",name:"group-detail",tabs:[{label:"Profile",fields:[c.name,c.kind,c.parent,c.isActive]},{label:"Identity",fields:[c.uuid,c.shortName,c.domain,c.authDomain,c.portal]},{label:"Localization",fields:[c.timezone,c.eodHour]},{label:"Branding",fields:[c.emailTemplate]},{label:"Avatar",fields:[c.avatar]}]}]}}};G.EDIT_FORM=Le.edit,G.ADD_FORM=Le.create,G.CREATE_FORM=Le.create,G.FORM_DIALOG_CONFIG={size:"lg"},G.GroupKindOptions=ot,G.GroupKinds=at,G.TimezoneOptions=lt,G.EodHourOptions=ct;class w extends Q{constructor(e={}){super(e,{endpoint:"/api/user"})}hasPermission(e){if(this.get("is_superuser"))return!0;if(Array.isArray(e))return e.some(i=>this.hasPermission(i));const t=e.startsWith("sys."),s=t?e.substring(4):e;return!!(this._hasPermission(s)||this._hasPermission("admin")||!t&&this.member&&this.member.hasPermission(e))}_hasPermission(e){const t=this.get("permissions");if(!t)return!1;if(t[e]==!0)return!0;const s=w.GRANULAR_TO_CATEGORY[e];return!!(s&&t[s]==!0)}hasPerm(e){return this.hasPermission(e)}}w.CATEGORY_PERMISSIONS=[{name:"admin",label:"System Admin",tooltip:"Full access to everything — permission equivalent of superuser"},{name:"view_admin",label:"Admin Panel",tooltip:"Access the admin panel, Mojo, and system tools"},{name:"security",label:"Security",tooltip:"Incidents, events, rules, tickets, firewall, bouncer, GeoIP, system logs"},{name:"users",label:"Users",tooltip:"User records, passkeys, TOTP, API keys, OAuth, devices, locations"},{name:"groups",label:"Groups",tooltip:"Groups, members, group API keys, settings"},{name:"comms",label:"Communications",tooltip:"Email, phone, SMS, push notifications, chat, notifications"},{name:"jobs",label:"Jobs",tooltip:"Jobs, job events, job logs, runners, queue control, system stats"},{name:"metrics",label:"Metrics",tooltip:"Metrics recording, fetching, categories, values, permissions"},{name:"files",label:"Files",tooltip:"File managers, files, renditions, vault files, vault data, S3 buckets"},{name:"assistant",label:"Mojo",tooltip:"Access to Mojo"}],w.GRANULAR_PERMISSION_TABS=[{label:"Account",permissions:[{name:"view_users",label:"View Users"},{name:"manage_users",label:"Manage Users"},{name:"view_groups",label:"View Groups"},{name:"manage_groups",label:"Manage Groups"},{name:"manage_group",label:"Manage Own Group"},{name:"view_members",label:"View Members"},{name:"manage_settings",label:"Manage Settings"}]},{label:"Communication",permissions:[{name:"manage_chat",label:"Manage Chat"},{name:"manage_aws",label:"Manage Email (AWS)"},{name:"view_notifications",label:"View Notifications"},{name:"manage_notifications",label:"Manage Notifications"},{name:"send_notifications",label:"Send Notifications"},{name:"view_devices",label:"View Push Devices"},{name:"manage_devices",label:"Manage Push Devices"},{name:"manage_push_config",label:"Push Config"},{name:"view_phone_numbers",label:"View Phone Numbers"},{name:"manage_phone_numbers",label:"Manage Phone Numbers"},{name:"manage_phone_config",label:"Phone Config"},{name:"view_sms",label:"View SMS"},{name:"manage_sms",label:"Manage SMS"},{name:"send_sms",label:"Send SMS"}]},{label:"Platform",permissions:[{name:"view_security",label:"View Security"},{name:"manage_security",label:"Manage Security"},{name:"view_logs",label:"View Logs"},{name:"manage_logs",label:"Manage Logs"},{name:"view_jobs",label:"View Jobs"},{name:"manage_jobs",label:"Manage Jobs"},{name:"view_metrics",label:"View Metrics"},{name:"manage_metrics",label:"Manage Metrics"},{name:"write_metrics",label:"Write Metrics"},{name:"view_fileman",label:"View File Managers"},{name:"manage_files",label:"Manage Files"},{name:"view_vault",label:"View Vault"},{name:"manage_vault",label:"Manage Vault"},{name:"manage_docit",label:"Manage Docs"},{name:"manage_shortlinks",label:"Manage Shortlinks"},{name:"view_geofence",label:"View Geofence Config"},{name:"manage_geofence",label:"Manage Geofence Config"},{name:"bypass_geofence",label:"Bypass Geofence (Whitelist)",tooltip:"Exempts this user from ALL geofence rules on authenticated requests. Login-time geofencing still applies until backend post-login support lands."}]}],w.CATEGORY_GRANULAR_MAP={security:["view_security","manage_security"],users:["view_users","manage_users","view_members"],groups:["view_groups","manage_groups","manage_group"],comms:["manage_chat","manage_aws","view_notifications","manage_notifications","send_notifications","view_devices","manage_devices","manage_push_config","view_phone_numbers","manage_phone_numbers","manage_phone_config","view_sms","manage_sms","send_sms"],jobs:["view_jobs","manage_jobs"],metrics:["view_metrics","manage_metrics","write_metrics"],files:["view_fileman","manage_files","view_vault","manage_vault"]},w.APP_CATEGORY_PERMISSIONS=[],w.APP_GRANULAR_PERMISSIONS=[],w._permSwitch=function(c){return{name:`permissions.${c.name}`,type:"switch",label:c.label,columns:6,...c.tooltip?{tooltip:c.tooltip}:{}}},w.PERMISSIONS=[],w.PERMISSION_FIELDS=[],w.CATEGORY_PERMISSION_FIELDS=[],w.GRANULAR_PERMISSION_FIELDS=[],w.SYSTEM_PERMISSION_FIELDS=[],w.APP_PERMISSION_FIELDS=[],w.GRANULAR_TO_CATEGORY={},w.rebuildPermissions=function(){const c=w._permSwitch;w.PERMISSIONS.length=0,w.PERMISSIONS.push(...w.CATEGORY_PERMISSIONS,...w.GRANULAR_PERMISSION_TABS.flatMap(i=>i.permissions),...w.APP_CATEGORY_PERMISSIONS,...w.APP_GRANULAR_PERMISSIONS),w.PERMISSION_FIELDS.length=0,w.PERMISSION_FIELDS.push(...w.PERMISSIONS.map(c));const e=[{label:"System",fields:w.CATEGORY_PERMISSIONS.map(c)}];w.APP_CATEGORY_PERMISSIONS.length>0&&e.push({label:"App",fields:w.APP_CATEGORY_PERMISSIONS.map(c)}),w.CATEGORY_PERMISSION_FIELDS.length=0,w.CATEGORY_PERMISSION_FIELDS.push({type:"tabset",tabs:e});const t=w.GRANULAR_PERMISSION_TABS.map(i=>({label:i.label,fields:i.permissions.map(c)}));w.APP_GRANULAR_PERMISSIONS.length>0&&t.push({label:"App",fields:w.APP_GRANULAR_PERMISSIONS.map(c)}),w.GRANULAR_PERMISSION_FIELDS.length=0,w.GRANULAR_PERMISSION_FIELDS.push({type:"tabset",tabs:t}),w.SYSTEM_PERMISSION_FIELDS.length=0,w.SYSTEM_PERMISSION_FIELDS.push({type:"tabset",tabs:[{label:"System",fields:w.CATEGORY_PERMISSIONS.map(c)},...w.GRANULAR_PERMISSION_TABS.map(i=>({label:i.label,fields:i.permissions.map(c)}))]}),w.APP_PERMISSION_FIELDS.length=0;const s=[];w.APP_CATEGORY_PERMISSIONS.length>0&&s.push({label:"Categories",fields:w.APP_CATEGORY_PERMISSIONS.map(c)}),w.APP_GRANULAR_PERMISSIONS.length>0&&s.push({label:"Permissions",fields:w.APP_GRANULAR_PERMISSIONS.map(c)}),s.length>0&&w.APP_PERMISSION_FIELDS.push({type:"tabset",tabs:s});for(const i of Object.keys(w.GRANULAR_TO_CATEGORY))delete w.GRANULAR_TO_CATEGORY[i];for(const[i,r]of Object.entries(w.CATEGORY_GRANULAR_MAP))for(const n of r)w.GRANULAR_TO_CATEGORY[n]=i},w.registerCategoryMap=function(c){if(!c)return;let e=!1;for(const[t,s]of Object.entries(c)){if(!Array.isArray(s))continue;const i=w.CATEGORY_GRANULAR_MAP[t]||[];w.CATEGORY_GRANULAR_MAP[t]=Array.from(new Set([...i,...s])),e=!0}e&&w.rebuildPermissions()},w.registerPermissions=function(c){if(c){if(Array.isArray(c.categories)&&w.APP_CATEGORY_PERMISSIONS.push(...c.categories),Array.isArray(c.granularPermissions)&&w.APP_GRANULAR_PERMISSIONS.push(...c.granularPermissions),Array.isArray(c.granularTabs)&&w.GRANULAR_PERMISSION_TABS.push(...c.granularTabs),c.categoryGranularMap)for(const[e,t]of Object.entries(c.categoryGranularMap)){if(!Array.isArray(t))continue;const s=w.CATEGORY_GRANULAR_MAP[e]||[];w.CATEGORY_GRANULAR_MAP[e]=Array.from(new Set([...s,...t]))}w.rebuildPermissions()}},w.rebuildPermissions();const ht={create:{title:"Create User",fields:[{name:"email",type:"text",label:"Email",required:!0},{name:"phone_number",type:"text",label:"Phone number",columns:12},{name:"display_name",type:"text",label:"Display Name"}]},edit:{title:"Edit User",fields:[{name:"email",type:"email",label:"Email",columns:12},{name:"display_name",type:"text",label:"Display Name",columns:12},{name:"phone_number",type:"text",label:"Phone number",columns:12},{type:"collection",name:"org",label:"Organization",Collection:nt,labelField:"name",valueField:"id",columns:12}]},permissions:{fields:w.PERMISSION_FIELDS}},Zt={detailed:{title:"Detailed User Information",columns:2,showEmptyValues:!0,emptyValueText:"Not set",fields:[{name:"id",label:"User ID",type:"number",colSize:3},{name:"display_name",label:"Display Name",type:"text",format:'capitalize|default("Unnamed User")',colSize:9},{name:"username",label:"Username",type:"text",format:"lowercase",colSize:6},{name:"email",label:"Email Address",type:"email",colSize:6},{name:"phone_number",label:"Phone Number",type:"phone",format:'phone|default("Not provided")',colSize:6},{name:"is_active",label:"Account Status",type:"boolean",colSize:6},{name:"last_login",label:"Last Login",type:"datetime",format:"relative",colSize:6},{name:"last_activity",label:"Last Activity",type:"datetime",format:"relative",colSize:6},{name:"avatar.url",label:"Avatar",type:"url",colSize:12},{name:"permissions",label:"User Permissions",type:"dataview",dataViewColumns:2,showEmptyValues:!1},{name:"metadata",label:"User Metadata",type:"dataview",dataViewColumns:1},{name:"avatar",label:"Avatar Details",type:"dataview",dataViewColumns:1}]}};w.DATA_VIEW=Zt.detailed,w.EDIT_FORM=ht.edit,w.ADD_FORM=ht.create;class ut extends Q{constructor(e={}){super(e,{endpoint:"/api/fileman/manager"})}}const mt={create:{title:"Add Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,value:"s3://BUCKET_NAME/OPTION_FOLDER",placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6}]},edit:{title:"Edit Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"allowed_origins",type:"text",label:"Domains Who Can Upload",cols:12},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6},{name:"is_public",type:"switch",label:"Is Public",default:!0,cols:6}]}};let pt=class extends Q{constructor(e={}){super(e,{endpoint:"/api/fileman/file"})}isImage(){return this.get("category")==="image"}getCategory(){return this.get("category")||this._inferCategoryFromContentType()}_inferCategoryFromContentType(){const e=(this.get("content_type")||"").toLowerCase();return e?e.startsWith("image/")?"image":e.startsWith("video/")?"video":e.startsWith("audio/")?"audio":e==="application/pdf"?"pdf":e.startsWith("text/")||e==="application/msword"||e.startsWith("application/vnd.openxmlformats-officedocument.wordprocessingml")||e==="application/vnd.oasis.opendocument.text"?"document":e==="application/vnd.ms-excel"||e.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml")||e==="application/vnd.oasis.opendocument.spreadsheet"?"spreadsheet":e==="application/vnd.ms-powerpoint"||e.startsWith("application/vnd.openxmlformats-officedocument.presentationml")||e==="application/vnd.oasis.opendocument.presentation"?"presentation":e==="application/zip"||e==="application/x-rar-compressed"||e==="application/x-7z-compressed"||e==="application/x-tar"||e==="application/gzip"?"archive":"other":"other"}hasRenditions(){const e=this.get("renditions");return!!(e&&Object.keys(e).length)}isUploadPending(){const e=this.get("upload_status");return!!(e&&e!=="completed"&&e!=="failed")}regenerateRenditions(e){const t=this.id||this.get("id");if(!t)return Promise.reject(new Error("Cannot regenerate renditions on an unsaved file"));const s=Array.isArray(e)&&e.length?{regenerate_renditions:e}:{regenerate_renditions:!0};return this.rest.POST(`${this.endpoint}/${t}`,s)}share(e=!0){const t=this.id||this.get("id");return t?this.rest.POST(`${this.endpoint}/${t}`,{share:e}):Promise.reject(new Error("Cannot share an unsaved file"))}getRenditions(){const e=this.get("renditions");return e?Object.values(e):[]}getBestImageRendition(){const e=this.getRenditions().filter(t=>t&&typeof t.content_type=="string"&&t.content_type.startsWith("image/"));return e.length?e.reduce((t,s)=>{const i=(parseInt(t.width)||0)*(parseInt(t.height)||0);return(parseInt(s.width)||0)*(parseInt(s.height)||0)>i?s:t}):null}getThumbnailUrl(){const e=this.get("renditions")||{};if(e.thumbnail&&e.thumbnail.url)return e.thumbnail.url;const t=this.getBestImageRendition();return t?t.url:null}upload(e={}){return new Kt(this,e)}};const Qt={edit:{title:"Edit File Backend",fields:[]}};ut.ADD_FORM=mt.create,ut.EDIT_FORM=mt.edit,pt.EDIT_FORM=Qt.edit;class v{static _renderAndAwait(e,{buttons:t=null,rejectOnDismiss:s=!1,onAction:i=null,cleanup:r=null}={}){const n=x.getMountTarget();return new Promise((a,o)=>{let l=!1;const d=u=>{l||(l=!0,a(u))},h=u=>{l||(l=!0,o(u))};(async()=>{try{await e.render(!0,n)}catch(u){h(u);return}t&&t.length>0&&e.element&&e.element.querySelectorAll(".modal-footer button").forEach((m,p)=>{const f=t[p];f&&m.addEventListener("click",async g=>{if(l)return;const b=f.value!==void 0?f.value:f.action??p;if(typeof f.handler=="function"){try{const y=await f.handler({dialog:e,button:f,index:p,event:g});if(y===null||y===!1)return;const _=y===!0||y===void 0?b:y;f.dismiss||e.hide(),d(_)}catch(y){console.error("Modal button handler error:",y)}return}if(typeof i=="function"&&f.action){try{const y=await i(f.action,{dialog:e,button:f,index:p,event:g});if(y===null||y===!1)return;const _=y===!0||y===void 0?b:y;f.dismiss||e.hide(),d(_)}catch(y){console.error("Modal onAction error:",y)}return}f.dismiss||e.hide(),d(b)})}),e.on("hidden",()=>{l||(s?h(new Error("Dialog dismissed")):d(null)),setTimeout(async()=>{try{typeof r=="function"&&await r(e)}catch(u){console.error("Modal cleanup error:",u)}try{await e.destroy()}catch(u){console.error("Modal destroy error:",u)}e.element?.parentNode&&e.element.parentNode.removeChild(e.element)},100)}),e.show()})()})}static async dialog(e={}){if(typeof e=="string"){const p=arguments[0],f=arguments[1]||"Alert";e={...arguments[2]||{},body:p,title:f}}const{title:t="Dialog",content:s,body:i,view:r,message:n,size:a="md",centered:o=!0,buttons:l=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:d=!1,...h}=e,u=i??r??n??s??"",m=new x({title:t,body:u,size:a,centered:o,buttons:l,...h});return v._renderAndAwait(m,{buttons:l,rejectOnDismiss:d})}static async drawer(e={}){const{eyebrow:t,title:s,meta:i=[],view:r,body:n,size:a="lg",...o}=e,l=i.length?`
203
203
  <div class="modal-drawer-meta">
204
204
  ${i.map(u=>typeof u=="string"?`<span>${v._esc(u)}</span>`:`<span>${u.icon?`<i class="${v._esc(u.icon)} me-1"></i>`:""}${v._esc(u.text||"")}</span>`).join("")}
205
205
  </div>`:"",d=`
@@ -208,20 +208,20 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
208
208
  <h2 class="modal-drawer-title">${v._esc(s||"")}</h2>
209
209
  ${l}
210
210
  </div>
211
- `;let h;if(r&&typeof r=="object"&&typeof r.render=="function"){const u=class extends S{async getTemplate(){return`${d}<div class="modal-drawer-body" data-container="drawer-body"></div>`}async onInit(){r.containerId="drawer-body",this.addChild(r)}};h=new u}else h=`${d}<div class="modal-drawer-body">${n||""}</div>`;return v.dialog({header:!1,body:h,size:a,centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...o})}static _esc(e){const t=typeof document<"u"?document.createElement("div"):null;return t?(t.textContent=String(e??""),t.innerHTML):String(e??"")}static async show(e,t={}){return v.dialog({header:t.title!==void 0?!!t.title:!1,title:t.title||void 0,body:e,size:"lg",centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...t})}static async detail(e,t={}){return v.show(e,{size:"lg",header:!1,noBodyPadding:!0,buttons:[],...t})}static async showModel(e,t={}){const s=e.constructor,i=s?.VIEW_CLASS;if(!i)throw new Error(`Modal.showModel: No VIEW_CLASS defined on ${s?.name||"model"}. Set ${s?.name||"Model"}.VIEW_CLASS = YourView to use this method.`);const r=new i({model:e});return v.show(r,t)}static async showModelById(e,t,s={}){const i=new e({id:t});return await i.fetch(),i.id?v.showModel(i,s):(v.alert({message:`Could not find ${e.name||"record"} with ID: ${t}`,type:"warning"}),null)}static async showModelView(e,t={}){const s=e.constructor,i=s?.VIEW_CLASS;if(!i)throw new Error(`Modal.showModelView: No VIEW_CLASS defined on ${s?.name||"model"}.`);const r=new i({model:e});return v.dialog({header:!1,body:r,size:"lg",centered:!1,...t})}static async alert(e={},t,s){let i;typeof e=="string"?i={message:e,...t!==void 0?{title:t}:{},...s||{}}:i={...e};const{message:r="",title:n="Alert",type:a="info",icon:o,className:l,...d}=i,h=a==="danger"?"error":a,m=[`modal-alert modal-alert-${h}`,l].filter(Boolean).join(" "),f=o!==void 0?o:{info:"bi-info-circle",success:"bi-check-circle",warning:"bi-exclamation-triangle",error:"bi-x-circle"}[h],g=f?`<i class="bi ${f} modal-alert-icon"></i>`:"",b=`<span class="modal-alert-headline">${n}</span>`;return v.dialog({title:`${g}${b}`,body:`<p class="modal-alert-message">${r}</p>`,size:"sm",centered:!0,className:m,buttons:[{text:"OK",class:"btn-primary",value:!0}],...d})}static async confirm(e,t="Confirm",s={}){let i;typeof e=="object"&&e!==null?(s=e,i=s.message,t=s.title||t):i=e;const r=[{text:s.cancelText||"Cancel",class:"btn-secondary",dismiss:!0,action:"cancel"},{text:s.confirmText||"Confirm",class:s.confirmClass||"btn-primary",action:"confirm"}],n=new x({title:t,body:`<p>${i}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:r,...s});return await v._renderAndAwait(n,{buttons:r})==="confirm"}static async prompt(e,t="Input",s={}){const i=`prompt-input-${Date.now()}`,r=s.defaultValue||"",n=s.inputType||"text",a=s.placeholder||"",o=[{text:"Cancel",class:"btn-secondary",dismiss:!0},{text:"OK",class:"btn-primary",action:"ok"}],l=new x({title:t,body:`
211
+ `;let h;if(r&&typeof r=="object"&&typeof r.render=="function"){const u=class extends C{async getTemplate(){return`${d}<div class="modal-drawer-body" data-container="drawer-body"></div>`}async onInit(){r.containerId="drawer-body",this.addChild(r)}};h=new u}else h=`${d}<div class="modal-drawer-body">${n||""}</div>`;return v.dialog({header:!1,body:h,size:a,centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...o})}static _esc(e){const t=typeof document<"u"?document.createElement("div"):null;return t?(t.textContent=String(e??""),t.innerHTML):String(e??"")}static async show(e,t={}){return v.dialog({header:t.title!==void 0?!!t.title:!1,title:t.title||void 0,body:e,size:"lg",centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...t})}static async detail(e,t={}){return v.show(e,{size:"lg",header:!1,noBodyPadding:!0,buttons:[],...t})}static async showModel(e,t={}){const s=e.constructor,i=s?.VIEW_CLASS;if(!i)throw new Error(`Modal.showModel: No VIEW_CLASS defined on ${s?.name||"model"}. Set ${s?.name||"Model"}.VIEW_CLASS = YourView to use this method.`);const r=new i({model:e});return v.show(r,t)}static async showModelById(e,t,s={}){const i=new e({id:t});return await i.fetch(),i.id?v.showModel(i,s):(v.alert({message:`Could not find ${e.name||"record"} with ID: ${t}`,type:"warning"}),null)}static async showModelView(e,t={}){const s=e.constructor,i=s?.VIEW_CLASS;if(!i)throw new Error(`Modal.showModelView: No VIEW_CLASS defined on ${s?.name||"model"}.`);const r=new i({model:e});return v.dialog({header:!1,body:r,size:"lg",centered:!1,...t})}static async alert(e={},t,s){let i;typeof e=="string"?i={message:e,...t!==void 0?{title:t}:{},...s||{}}:i={...e};const{message:r="",title:n="Alert",type:a="info",icon:o,className:l,...d}=i,h=a==="danger"?"error":a,m=[`modal-alert modal-alert-${h}`,l].filter(Boolean).join(" "),f=o!==void 0?o:{info:"bi-info-circle",success:"bi-check-circle",warning:"bi-exclamation-triangle",error:"bi-x-circle"}[h],g=f?`<i class="bi ${f} modal-alert-icon"></i>`:"",b=`<span class="modal-alert-headline">${n}</span>`;return v.dialog({title:`${g}${b}`,body:`<p class="modal-alert-message">${r}</p>`,size:"sm",centered:!0,className:m,buttons:[{text:"OK",class:"btn-primary",value:!0}],...d})}static async confirm(e,t="Confirm",s={}){let i;typeof e=="object"&&e!==null?(s=e,i=s.message,t=s.title||t):i=e;const r=[{text:s.cancelText||"Cancel",class:"btn-secondary",dismiss:!0,action:"cancel"},{text:s.confirmText||"Confirm",class:s.confirmClass||"btn-primary",action:"confirm"}],n=new x({title:t,body:`<p>${i}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:r,...s});return await v._renderAndAwait(n,{buttons:r})==="confirm"}static async prompt(e,t="Input",s={}){const i=`prompt-input-${Date.now()}`,r=s.defaultValue||"",n=s.inputType||"text",a=s.placeholder||"",o=[{text:"Cancel",class:"btn-secondary",dismiss:!0},{text:"OK",class:"btn-primary",action:"ok"}],l=new x({title:t,body:`
212
212
  <p>${e}</p>
213
213
  <input type="${n}"
214
214
  class="form-control"
215
215
  id="${i}"
216
216
  value="${r}"
217
217
  placeholder="${a}">
218
- `,size:s.size||"sm",centered:!0,backdrop:"static",buttons:o,...s});return l.on("shown",()=>{const d=l.element.querySelector(`#${i}`);d&&(d.focus(),d.select())}),v._renderAndAwait(l,{buttons:o,onAction:async d=>{if(d!=="ok")return null;const h=l.element.querySelector(`#${i}`);return h?h.value:null}})}static showError(e){return v.alert(e,"Error",{type:"error"})}static async form(e={}){const{title:t="Form",formConfig:s={},size:i="md",centered:r=!0,submitText:n="Submit",cancelText:a="Cancel",...o}=e,l=(await Promise.resolve().then(()=>It)).default,d=new l({fileHandling:e.fileHandling||"base64",data:e.data,defaults:e.defaults,model:e.model,formConfig:{fields:s.fields||e.fields,...s,submitButton:!1,resetButton:!1}}),h=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],u=new x({title:t,body:d,size:i,centered:r,buttons:h,...o});return v._renderAndAwait(u,{buttons:h,onAction:async m=>{if(m==="cancel")return u.hide(),null;if(m!=="submit")return null;if(!d.validate())return d.focusFirstError(),!1;if(e.autoSave&&e.model){u.setLoading(!0);const p=await d.saveModel();return p.success?p:(u.setLoading(!1),await u.render(),u.getApp()?.toast?.error(p.message),!1)}try{return await d.getFormData()}catch(p){return console.error("Modal.form: error collecting form data:",p),d.showError("Error collecting form data"),!1}},cleanup:async()=>{try{await d.destroy()}catch{}}})}static async modelForm(e={}){const{title:t="Edit",formConfig:s={},size:i="md",centered:r=!0,submitText:n="Save",cancelText:a="Cancel",model:o,fields:l,...d}=e;if(!o)throw new Error("Modal.modelForm requires a model");const h=(await Promise.resolve().then(()=>It)).default,u=new h({fileHandling:e.fileHandling||"base64",model:o,data:e.data,defaults:e.defaults,formConfig:{fields:l||s.fields||[],...s,submitButton:!1,resetButton:!1}}),m=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],p=new x({title:t,body:u,size:i,centered:r,buttons:m,...d});return v._renderAndAwait(p,{buttons:m,onAction:async f=>{if(f==="cancel")return p.hide(),null;if(f!=="submit")return null;p.setLoading(!0,"Saving...");try{const g=await u.handleSubmit();if(g.success)return g;p.setLoading(!1);let b=g.error;return g.data?.error&&(b=g.data.error),p.getApp()?.toast?.error(b),!1}catch(g){return console.error("Modal.modelForm: error saving:",g),await p.setContent(u),u.showError(g.message||"An error occurred while saving"),!1}},cleanup:async()=>{try{await u.destroy()}catch{}}})}static async data(e={}){const{title:t="Data View",data:s={},model:i=null,fields:r=[],columns:n=2,responsive:a=!0,showEmptyValues:o=!1,emptyValueText:l="—",size:d="lg",centered:h=!0,closeText:u="Close",...m}=e,p=(await Promise.resolve().then(()=>Fs)).default,f=new p({data:s,model:i,fields:r,columns:n,responsive:a,showEmptyValues:o,emptyValueText:l}),g=[{text:u,class:"btn-secondary",value:"close"}],b=new x({title:t,body:f,size:d,centered:h,buttons:g,...m});return f.on("field:click",y=>b.emit("dataview:field:click",y)),f.on("error",y=>b.emit("dataview:error",y)),v._renderAndAwait(b,{buttons:g,cleanup:async()=>{try{await f.destroy()}catch{}}})}static async code(e={}){const{code:t="",language:s="javascript",title:i="Source Code",size:r="lg",...n}=e,a=new me({code:t,language:s}),o=[{text:"Copy to Clipboard",class:"btn-primary",icon:"bi-clipboard",action:"copy"},{text:"Close",class:"btn-secondary",dismiss:!0}],l=new x({title:i,body:a,size:r,scrollable:!0,buttons:o,...n});return v._renderAndAwait(l,{buttons:o,onAction:async d=>{if(d!=="copy")return null;if(!navigator.clipboard)return!1;try{await navigator.clipboard.writeText(t),v._showCopySuccess(l)}catch(h){console.error("Modal.code: clipboard write failed:",h)}return!1}})}static _showCopySuccess(e){const t=e.element?.querySelector('[data-action="copy"]');if(!t)return;const s=t.innerHTML;t.innerHTML='<i class="bi bi-check me-1"></i>Copied!',t.classList.remove("btn-primary"),t.classList.add("btn-success"),t.disabled=!0,setTimeout(()=>{t.innerHTML=s,t.classList.remove("btn-success"),t.classList.add("btn-primary"),t.disabled=!1},2e3)}static async htmlPreview(e={}){const{html:t=e.content||"",title:s="HTML Preview",size:i="lg",height:r=500,...n}=e,a=new Gt({html:t,height:r}),o=[{text:"Close",class:"btn-secondary",dismiss:!0}],l=new x({title:s,body:a,size:i,scrollable:!1,buttons:o,...n});return v._renderAndAwait(l,{buttons:o})}static async updateModelImage(e={},t={}){const s=e.upload||!1,i=t.name||e.field||"image",r={title:"Upload Your Avatar",model:null,autoSave:!s,size:"sm",fields:[{type:"image",name:i,size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your image",...t}],...e},n=await v.form(r);if(!s||!n||!e.model)return n;const a=n[i];if(!a||!a.startsWith("data:"))return n;const o=a.split(","),d=o[0]?.match(/:(.*?);/)?.[1]||"image/png",h=atob(o[1]);let u=h.length;const m=new Uint8Array(u);for(;u--;)m[u]=h.charCodeAt(u);const p=d.split("/")[1]||"png",f=typeof window<"u"&&window.File||globalThis.File;if(!f)throw new Error("File API is not available in this environment");const g=new f([m],`${i}.${p}`,{type:d}),b=new pt;return await b.upload({file:g,name:`${i}.${p}`,description:e.uploadDescription||`${i} upload`,showToast:!0}),e.model.save({[i]:b.id})}static loading(e){ke.show(e)}static hideLoading(e){ke.hide(e)}static showBusy(e){return v.loading(e)}static hideBusy(e){return v.hideLoading(e)}}const N=Object.freeze(Object.defineProperty({__proto__:null,default:v},Symbol.toStringTag,{value:"Module"}));class ve{constructor(e={}){this.config=e,this.initPluginRegistry(),this.name=e.name||"MOJO App",this.version=e.version||"1.0.0",this.debug=e.debug||!1,this.container=e.container||"#app",this.layoutType=e.layout||"portal",this.layoutConfig=e.layoutConfig||{},e.sidebar&&(this.layoutConfig.sidebarConfig=e.sidebar),e.topbar&&(this.layoutConfig.topbarConfig=e.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=e.pageContainer||"#page-container",this.basePath=e.basePath||"",this.routerMode=e.routerMode||e.router?.mode||"param",this.basePath=e.basePath||e.router?.base||"",this.defaultRoute=e.defaultRoute||"home",this.session=e.session||{},this.router=null,this.navigation=e.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new Vt,this.rest=ne,this.modal=v,e.api&&this.rest.configure(e.api);const t=(this.name||"mojo").replace(/\s+/g,"_").toLowerCase();this.theme=new Nt({storageKey:`${t}:theme`,eventBus:this.events}),this.theme.init(),this.router=new Te({mode:this.routerMode==="param"?"params":this.routerMode,basePath:this.basePath,defaultRoute:this.defaultRoute,eventEmitter:this.events}),this.events.on("route:changed",async s=>{const{pageName:i,params:r,query:n}=s;await this.showPage(i,n,r,{fromRouter:!0})}),typeof window<"u"&&(window.MOJO=window.MOJO||{},window.MOJO.router=this.router),this.setupFocusTracking(),this.pageCache=new Map,this.pageClasses=new Map,this.componentClasses=new Map,this.modelClasses=new Map,this.modelRefClasses=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");return}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(){if(!this.router){console.error("Router not initialized");return}this.events.on("route:notfound",async e=>{console.warn(`Route not found: ${e.path}`),this._show404(e.path)}),this.router.start(),console.log(`Router started in ${this.routerMode} mode`)}setupPageContainer(){const e=typeof this.container=="string"?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(typeof e!="string"||!e)return console.error("registerPage: pageName must be a non-empty string"),this;if(typeof t!="function")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 i=s.route||`/${e}`;i.startsWith("/")||(i=`/${i}`),s.route=i,this.router.addRoute(i,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 r={pageName:e,...i,app:this},n=new s(r);return i.route&&(n.route=i.route),this.pageCache.set(e,n),console.log(`Created page: ${e} with route: ${n.route}`),n}catch(r){return console.error(`Failed to create page ${e}:`,r),null}}async showPage(e,t={},s={},i={}){const{fromRouter:r=!1,replace:n=!1,force:a=!1}=i;try{let o,l;typeof e=="string"?(l=e,o=this.getOrCreatePage(e)):e&&typeof e=="object"&&(o=e,l=e.pageName);const d=this.currentPage;if(!o){this._show404(l,s,t,r);return}if(this.events.emit("page:showing",{page:o,pageName:o.pageName,params:s,query:t,fromRouter:r}),!o.canEnter()){this._showDeniedPage(o,s,t,r);return}d&&d!==o&&await this._exitOldPage(d),await o.onParams(s,t),d!==o&&await o.onEnter(),o.syncUrl(),this.events.emit("page:show",{page:o,pageName:o.pageName,params:s,query:t,fromRouter:r}),await o.render(),this.currentPage=o,console.log(`✅ Showing page: ${o.pageName}`,{query:t,params:s})}catch(o){console.error("Error in showPage:",o),this.showError(`Failed to load page: ${o.message}`),e!=="error"&&await this.showPage("error",{},{error:o,originalPage:e},{fromRouter:r})}}async _show404(e,t,s,i){const r=this.getOrCreatePage("404");r&&(r.setInfo&&r.setInfo(e),await this._exitOldPage(this.currentPage),await r.render(),this.currentPage=r,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:i}))}async _showDeniedPage(e,t,s,i){const r=this.getOrCreatePage("denied");r.setDeniedPage&&r.setDeniedPage(e),await this._exitOldPage(this.currentPage),await r.render(),this.currentPage=r,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){console.error("Router not initialized");return}let i=e;if(Object.keys(t).length>0){const r=new URLSearchParams(t).toString();i+=(e.includes("?")?"&":"?")+r}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():typeof this.pageContainer=="string"?document.querySelector(this.pageContainer):this.pageContainer}async showError(e){try{await(await Promise.resolve().then(()=>N)).default.alert(e,"Error",{size:"md",type:"error"})}catch(t){this.events.emit("notification",{message:e,type:"error"}),typeof window<"u"&&window?.console&&console.error("[WebApp] showError fallback:",t),typeof window<"u"&&alert(`Error: ${e}`)}}async showSuccess(e){try{await(await Promise.resolve().then(()=>N)).default.alert(e,"Success",{size:"md",type:"success"})}catch(t){this.events.emit("notification",{message:e,type:"success"}),typeof window<"u"&&window?.console&&console.warn("[WebApp] showSuccess fallback:",t),typeof window<"u"&&alert(`Success: ${e}`)}}async showInfo(e){try{await(await Promise.resolve().then(()=>N)).default.alert(e,"Information",{size:"md",type:"info"})}catch(t){this.events.emit("notification",{message:e,type:"info"}),typeof window<"u"&&window?.console&&console.info("[WebApp] showInfo fallback:",t),typeof window<"u"&&alert(`Info: ${e}`)}}async showWarning(e){try{await(await Promise.resolve().then(()=>N)).default.alert(e,"Warning",{size:"md",type:"warning"})}catch(t){this.events.emit("notification",{message:e,type:"warning"}),typeof window<"u"&&window?.console&&console.warn("[WebApp] showWarning fallback:",t),typeof window<"u"&&alert(`Warning: ${e}`)}}showNotification(e,t="info"){this.events.emit("notification",{message:e,type:t})}async showLoading(e={}){typeof e=="string"&&(e={message:e});try{(await Promise.resolve().then(()=>N)).default.showBusy(e)}catch(t){typeof window<"u"&&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(()=>N)).default.hideBusy()}catch(e){typeof window<"u"&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelView(e,t={}){try{return await(await Promise.resolve().then(()=>N)).default.showModelView(e,t)}catch(s){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showModelForm(e={}){try{return await(await Promise.resolve().then(()=>N)).default.modelForm(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showModelForm failed:",t),t}}async showForm(e={}){try{return await(await Promise.resolve().then(()=>N)).default.form(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showForm failed:",t),t}}async showDialog(e={}){try{return await(await Promise.resolve().then(()=>N)).default.dialog(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async showAlert(e={}){try{return await(await Promise.resolve().then(()=>N)).default.dialog(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async confirm(e,t="Confirm",s={}){return await(await Promise.resolve().then(()=>N)).default.confirm(e,t,s)}setTheme(e){return this.theme.set(e),this}getTheme(){return this.theme.getPreference()}getResolvedTheme(){return this.theme.getResolved()}setupFocusTracking(){if(typeof window>"u")return;this.isFocused=!document.hidden;const e=()=>{const i=this.isFocused;this.isFocused=!document.hidden,i!==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)}registerModelRef(e,t){this.modelRefClasses.set(e,t)}getModelByRef(e){return this.modelRefClasses.get(e)}setupRest(){this.rest=ne,ne.configure(this.api)}async destroy(){console.log("Destroying WebApp..."),this.router&&this.router.stop(),this._focusHandlers&&typeof window<"u"&&(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 t=>{try{t.destroy&&await t.destroy()}catch(s){console.error("Error destroying page:",s)}})),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(),typeof window<"u"&&window.MOJO&&delete window.MOJO.router,this.isStarted=!1,console.log(`✨ ${this.name} destroyed`)}buildPagePath(e,t,s){let i=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(r=>{(typeof t[r]=="string"||typeof t[r]=="number")&&(i=i.replace(`:${r}`,t[r]))}),s&&Object.keys(s).length>0){const r=new URLSearchParams(s).toString();i+=(i.includes("?")?"&":"?")+r}return i}validateDefaultRoute(){this.pageClasses.has(this.defaultRoute)?console.log(`✅ Default route '${this.defaultRoute}' is registered`):(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 ve(e)}initPluginRegistry(){typeof window<"u"&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.app=this)}static registerPlugin(e,t){typeof window<"u"&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.plugins[e]=t,console.debug(`MOJO Plugin registered: ${e}`))}}class pe extends S{constructor(e={}){e.tagName=e.tagName||"main",e.className=e.className||"mojo-page";const t=e.pageName||"";t&&!e.id&&(e.id="page_"+t.toLowerCase().replace(/\s+/g,"_")),super(e),this.pageName=e.pageName||this.constructor.pageName||"",this.route=e.route||this.constructor.route||"",this.title=e.title||this.pageName||"",!this.id&&this.constructor.pageName&&!e.pageName&&(this.id="page_"+this.constructor.pageName.toLowerCase().replace(/\s+/g,"_")),this.pageIcon=e.icon||e.pageIcon||this.constructor.pageIcon||"bi bi-file-text",this.displayName=e.displayName||this.constructor.displayName||this.pageName||"",this.pageDescription=e.pageDescription||this.constructor.pageDescription||"",this.params={},this.query={},this.matched=!1,this.isActive=!1,this.pageOptions={title:e.title||this.pageName||"Untitled Page",description:e.description||"",requiresAuth:e.requiresAuth||!1,...e.pageOptions},this.savedState=null,console.log(`Page ${this.pageName} constructed with route: ${this.route}`)}async onParams(e={},t={}){this.params=e,this.query=t}canEnter(){if(this.options.permissions){const e=this.getApp().activeUser;if(!e||!e.hasPermission(this.options.permissions))return!1}return!(this.options.requiresGroup&&!this.getApp().activeGroup)}async onEnter(){this.isActive=!0,this._wasExited=!1,await this.onInitView(),this.savedState&&(this.restoreState(this.savedState),this.savedState=null),this.pageOptions&&this.pageOptions.title&&typeof document<"u"&&(document.title=this.pageOptions.title),this.emit("activated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} entered`)}async onExit(){this.savedState=this.captureState(),this.isActive=!1,this._wasExited=!0,this._clearScheduledRefreshes(),this.emit("deactivated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} exiting`)}scheduleRefresh(e,t,s={}){if(this._scheduledRefreshes||(this._scheduledRefreshes=[]),typeof e!="function"||!(t>0))return null;const i=async()=>{try{await e()}catch(a){console.warn(`[Page ${this.pageName}] scheduleRefresh handler error:`,a)}};s.immediate&&i();const r=setInterval(i,t),n={id:r,tier:s.tier||null,handler:i,intervalMs:t};return this._scheduledRefreshes.push(n),{cancel:()=>{clearInterval(r),this._scheduledRefreshes=(this._scheduledRefreshes||[]).filter(a=>a!==n)}}}async runScheduledRefreshes(e=null){const t=this._scheduledRefreshes||[],s=e?t.filter(i=>i.tier===e):t;await Promise.allSettled(s.map(i=>i.handler()))}_clearScheduledRefreshes(){if(this._scheduledRefreshes){for(const e of this._scheduledRefreshes)clearInterval(e.id);this._scheduledRefreshes=[]}}async render(e=!0,t=null){return this._wasExited&&!this.isActive?this:super.render(e,t)}async onGroupChange(e){}getMetadata(){return{name:this.pageName,displayName:this.displayName||this.pageName,icon:this.pageIcon,description:this.pageDescription,route:this.route,isActive:this.isActive}}async onActionDefault(e){console.log(`Default action '${e}' triggered on page: ${this.pageName}`)}async makeActive(){this.getApp().showPage(this)}async onActionNavigate(e,t){e.preventDefault();const s=t.dataset.page;this.getApp().showPage(s)}captureState(){return this.element?{scrollTop:this.element.scrollTop,formData:this.captureFormData(),custom:this.captureCustomState()}:null}restoreState(e){!e||!this.element||(this.element.scrollTop=e.scrollTop||0,this.restoreFormData(e.formData),e.custom&&this.restoreCustomState(e.custom))}captureFormData(){const e={};return this.element&&this.element.querySelectorAll("input, select, textarea").forEach(t=>{t.name&&(t.type==="checkbox"?e[t.name]=t.checked:t.type==="radio"?t.checked&&(e[t.name]=t.value):e[t.name]=t.value)}),e}restoreFormData(e){!e||!this.element||Object.entries(e).forEach(([t,s])=>{const i=this.element.querySelector(`[name="${t}"]`);if(i)if(i.type==="checkbox")i.checked=s;else if(i.type==="radio"){const r=this.element.querySelector(`[name="${t}"][value="${s}"]`);r&&(r.checked=!0)}else i.value=s})}captureCustomState(){return{}}restoreCustomState(e){}setMeta(e={}){if(!(typeof document>"u")){if(e.title&&(document.title=e.title,this.pageOptions.title=e.title),e.description){let t=document.querySelector('meta[name="description"]');t||(t=document.createElement("meta"),t.name="description",document.head.appendChild(t)),t.content=e.description,this.pageOptions.description=e.description}Object.entries(e).forEach(([t,s])=>{if(t!=="title"&&t!=="description"){let i=document.querySelector(`meta[name="${t}"]`);i||(i=document.createElement("meta"),i.name=t,document.head.appendChild(i)),i.content=s}})}}showError(e){if(super.showError(e),this.element){const t=document.createElement("div");t.className="alert alert-danger alert-dismissible fade show",t.innerHTML=`
218
+ `,size:s.size||"sm",centered:!0,backdrop:"static",buttons:o,...s});return l.on("shown",()=>{const d=l.element.querySelector(`#${i}`);d&&(d.focus(),d.select())}),v._renderAndAwait(l,{buttons:o,onAction:async d=>{if(d!=="ok")return null;const h=l.element.querySelector(`#${i}`);return h?h.value:null}})}static showError(e){return v.alert(e,"Error",{type:"error"})}static async form(e={}){const{title:t="Form",formConfig:s={},size:i="md",centered:r=!0,submitText:n="Submit",cancelText:a="Cancel",...o}=e,l=(await Promise.resolve().then(()=>It)).default,d=new l({fileHandling:e.fileHandling||"base64",data:e.data,defaults:e.defaults,model:e.model,formConfig:{fields:s.fields||e.fields,...s,submitButton:!1,resetButton:!1}}),h=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],u=new x({title:t,body:d,size:i,centered:r,buttons:h,...o});return v._renderAndAwait(u,{buttons:h,onAction:async m=>{if(m==="cancel")return u.hide(),null;if(m!=="submit")return null;if(!d.validate())return d.focusFirstError(),!1;if(e.autoSave&&e.model){u.setLoading(!0);const p=await d.saveModel();return p.success?p:(u.setLoading(!1),await u.render(),u.getApp()?.toast?.error(p.message),!1)}try{return await d.getFormData()}catch(p){return console.error("Modal.form: error collecting form data:",p),d.showError("Error collecting form data"),!1}},cleanup:async()=>{try{await d.destroy()}catch{}}})}static async modelForm(e={}){const{title:t="Edit",formConfig:s={},size:i="md",centered:r=!0,submitText:n="Save",cancelText:a="Cancel",model:o,fields:l,...d}=e;if(!o)throw new Error("Modal.modelForm requires a model");const h=(await Promise.resolve().then(()=>It)).default,u=new h({fileHandling:e.fileHandling||"base64",model:o,data:e.data,defaults:e.defaults,formConfig:{fields:l||s.fields||[],...s,submitButton:!1,resetButton:!1}}),m=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],p=new x({title:t,body:u,size:i,centered:r,buttons:m,...d});return v._renderAndAwait(p,{buttons:m,onAction:async f=>{if(f==="cancel")return p.hide(),null;if(f!=="submit")return null;p.setLoading(!0,"Saving...");try{const g=await u.handleSubmit();if(g.success)return g;p.setLoading(!1);let b=g.error;return g.data?.error&&(b=g.data.error),p.getApp()?.toast?.error(b),!1}catch(g){return console.error("Modal.modelForm: error saving:",g),await p.setContent(u),u.showError(g.message||"An error occurred while saving"),!1}},cleanup:async()=>{try{await u.destroy()}catch{}}})}static async data(e={}){const{title:t="Data View",data:s={},model:i=null,fields:r=[],columns:n=2,responsive:a=!0,showEmptyValues:o=!1,emptyValueText:l="—",size:d="lg",centered:h=!0,closeText:u="Close",...m}=e,p=(await Promise.resolve().then(()=>Fs)).default,f=new p({data:s,model:i,fields:r,columns:n,responsive:a,showEmptyValues:o,emptyValueText:l}),g=[{text:u,class:"btn-secondary",value:"close"}],b=new x({title:t,body:f,size:d,centered:h,buttons:g,...m});return f.on("field:click",y=>b.emit("dataview:field:click",y)),f.on("error",y=>b.emit("dataview:error",y)),v._renderAndAwait(b,{buttons:g,cleanup:async()=>{try{await f.destroy()}catch{}}})}static async code(e={}){const{code:t="",language:s="javascript",title:i="Source Code",size:r="lg",...n}=e,a=new pe({code:t,language:s}),o=[{text:"Copy to Clipboard",class:"btn-primary",icon:"bi-clipboard",action:"copy"},{text:"Close",class:"btn-secondary",dismiss:!0}],l=new x({title:i,body:a,size:r,scrollable:!0,buttons:o,...n});return v._renderAndAwait(l,{buttons:o,onAction:async d=>{if(d!=="copy")return null;if(!navigator.clipboard)return!1;try{await navigator.clipboard.writeText(t),v._showCopySuccess(l)}catch(h){console.error("Modal.code: clipboard write failed:",h)}return!1}})}static _showCopySuccess(e){const t=e.element?.querySelector('[data-action="copy"]');if(!t)return;const s=t.innerHTML;t.innerHTML='<i class="bi bi-check me-1"></i>Copied!',t.classList.remove("btn-primary"),t.classList.add("btn-success"),t.disabled=!0,setTimeout(()=>{t.innerHTML=s,t.classList.remove("btn-success"),t.classList.add("btn-primary"),t.disabled=!1},2e3)}static async htmlPreview(e={}){const{html:t=e.content||"",title:s="HTML Preview",size:i="lg",height:r=500,...n}=e,a=new Gt({html:t,height:r}),o=[{text:"Close",class:"btn-secondary",dismiss:!0}],l=new x({title:s,body:a,size:i,scrollable:!1,buttons:o,...n});return v._renderAndAwait(l,{buttons:o})}static async updateModelImage(e={},t={}){const s=e.upload||!1,i=t.name||e.field||"image",r={title:"Upload Your Avatar",model:null,autoSave:!s,size:"sm",fields:[{type:"image",name:i,size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your image",...t}],...e},n=await v.form(r);if(!s||!n||!e.model)return n;const a=n[i];if(!a||!a.startsWith("data:"))return n;const o=a.split(","),d=o[0]?.match(/:(.*?);/)?.[1]||"image/png",h=atob(o[1]);let u=h.length;const m=new Uint8Array(u);for(;u--;)m[u]=h.charCodeAt(u);const p=d.split("/")[1]||"png",f=typeof window<"u"&&window.File||globalThis.File;if(!f)throw new Error("File API is not available in this environment");const g=new f([m],`${i}.${p}`,{type:d}),b=new pt;return await b.upload({file:g,name:`${i}.${p}`,description:e.uploadDescription||`${i} upload`,showToast:!0}),e.model.save({[i]:b.id})}static loading(e){Me.show(e)}static hideLoading(e){Me.hide(e)}static showBusy(e){return v.loading(e)}static hideBusy(e){return v.hideLoading(e)}}const R=Object.freeze(Object.defineProperty({__proto__:null,default:v},Symbol.toStringTag,{value:"Module"}));class ve{constructor(e={}){this.config=e,this.initPluginRegistry(),this.name=e.name||"MOJO App",this.version=e.version||"1.0.0",this.debug=e.debug||!1,this.container=e.container||"#app",this.layoutType=e.layout||"portal",this.layoutConfig=e.layoutConfig||{},e.sidebar&&(this.layoutConfig.sidebarConfig=e.sidebar),e.topbar&&(this.layoutConfig.topbarConfig=e.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=e.pageContainer||"#page-container",this.basePath=e.basePath||"",this.routerMode=e.routerMode||e.router?.mode||"param",this.basePath=e.basePath||e.router?.base||"",this.defaultRoute=e.defaultRoute||"home",this.session=e.session||{},this.router=null,this.navigation=e.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new Vt,this.rest=ne,this.modal=v,e.api&&this.rest.configure(e.api);const t=(this.name||"mojo").replace(/\s+/g,"_").toLowerCase();this.theme=new Rt({storageKey:`${t}:theme`,eventBus:this.events}),this.theme.init(),this.router=new Te({mode:this.routerMode==="param"?"params":this.routerMode,basePath:this.basePath,defaultRoute:this.defaultRoute,eventEmitter:this.events}),this.events.on("route:changed",async s=>{const{pageName:i,params:r,query:n}=s;await this.showPage(i,n,r,{fromRouter:!0})}),typeof window<"u"&&(window.MOJO=window.MOJO||{},window.MOJO.router=this.router),this.setupFocusTracking(),this.pageCache=new Map,this.pageClasses=new Map,this.componentClasses=new Map,this.modelClasses=new Map,this.modelRefClasses=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");return}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(){if(!this.router){console.error("Router not initialized");return}this.events.on("route:notfound",async e=>{console.warn(`Route not found: ${e.path}`),this._show404(e.path)}),this.router.start(),console.log(`Router started in ${this.routerMode} mode`)}setupPageContainer(){const e=typeof this.container=="string"?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(typeof e!="string"||!e)return console.error("registerPage: pageName must be a non-empty string"),this;if(typeof t!="function")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 i=s.route||`/${e}`;i.startsWith("/")||(i=`/${i}`),s.route=i,this.router.addRoute(i,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 r={pageName:e,...i,app:this},n=new s(r);return i.route&&(n.route=i.route),this.pageCache.set(e,n),console.log(`Created page: ${e} with route: ${n.route}`),n}catch(r){return console.error(`Failed to create page ${e}:`,r),null}}async showPage(e,t={},s={},i={}){const{fromRouter:r=!1,replace:n=!1,force:a=!1}=i;try{let o,l;typeof e=="string"?(l=e,o=this.getOrCreatePage(e)):e&&typeof e=="object"&&(o=e,l=e.pageName);const d=this.currentPage;if(!o){this._show404(l,s,t,r);return}if(this.events.emit("page:showing",{page:o,pageName:o.pageName,params:s,query:t,fromRouter:r}),!o.canEnter()){this._showDeniedPage(o,s,t,r);return}d&&d!==o&&await this._exitOldPage(d),await o.onParams(s,t),d!==o&&await o.onEnter(),o.syncUrl(),this.events.emit("page:show",{page:o,pageName:o.pageName,params:s,query:t,fromRouter:r}),await o.render(),this.currentPage=o,console.log(`✅ Showing page: ${o.pageName}`,{query:t,params:s})}catch(o){console.error("Error in showPage:",o),this.showError(`Failed to load page: ${o.message}`),e!=="error"&&await this.showPage("error",{},{error:o,originalPage:e},{fromRouter:r})}}async _show404(e,t,s,i){const r=this.getOrCreatePage("404");r&&(r.setInfo&&r.setInfo(e),await this._exitOldPage(this.currentPage),await r.render(),this.currentPage=r,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:i}))}async _showDeniedPage(e,t,s,i){const r=this.getOrCreatePage("denied");r.setDeniedPage&&r.setDeniedPage(e),await this._exitOldPage(this.currentPage),await r.render(),this.currentPage=r,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){console.error("Router not initialized");return}let i=e;if(Object.keys(t).length>0){const r=new URLSearchParams(t).toString();i+=(e.includes("?")?"&":"?")+r}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():typeof this.pageContainer=="string"?document.querySelector(this.pageContainer):this.pageContainer}async showError(e){try{await(await Promise.resolve().then(()=>R)).default.alert(e,"Error",{size:"md",type:"error"})}catch(t){this.events.emit("notification",{message:e,type:"error"}),typeof window<"u"&&window?.console&&console.error("[WebApp] showError fallback:",t),typeof window<"u"&&alert(`Error: ${e}`)}}async showSuccess(e){try{await(await Promise.resolve().then(()=>R)).default.alert(e,"Success",{size:"md",type:"success"})}catch(t){this.events.emit("notification",{message:e,type:"success"}),typeof window<"u"&&window?.console&&console.warn("[WebApp] showSuccess fallback:",t),typeof window<"u"&&alert(`Success: ${e}`)}}async showInfo(e){try{await(await Promise.resolve().then(()=>R)).default.alert(e,"Information",{size:"md",type:"info"})}catch(t){this.events.emit("notification",{message:e,type:"info"}),typeof window<"u"&&window?.console&&console.info("[WebApp] showInfo fallback:",t),typeof window<"u"&&alert(`Info: ${e}`)}}async showWarning(e){try{await(await Promise.resolve().then(()=>R)).default.alert(e,"Warning",{size:"md",type:"warning"})}catch(t){this.events.emit("notification",{message:e,type:"warning"}),typeof window<"u"&&window?.console&&console.warn("[WebApp] showWarning fallback:",t),typeof window<"u"&&alert(`Warning: ${e}`)}}showNotification(e,t="info"){this.events.emit("notification",{message:e,type:t})}async showLoading(e={}){typeof e=="string"&&(e={message:e});try{(await Promise.resolve().then(()=>R)).default.showBusy(e)}catch(t){typeof window<"u"&&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(()=>R)).default.hideBusy()}catch(e){typeof window<"u"&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelView(e,t={}){try{return await(await Promise.resolve().then(()=>R)).default.showModelView(e,t)}catch(s){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showModelForm(e={}){try{return await(await Promise.resolve().then(()=>R)).default.modelForm(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showModelForm failed:",t),t}}async showForm(e={}){try{return await(await Promise.resolve().then(()=>R)).default.form(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showForm failed:",t),t}}async showDialog(e={}){try{return await(await Promise.resolve().then(()=>R)).default.dialog(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async showAlert(e={}){try{return await(await Promise.resolve().then(()=>R)).default.dialog(e)}catch(t){throw typeof window<"u"&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async confirm(e,t="Confirm",s={}){return await(await Promise.resolve().then(()=>R)).default.confirm(e,t,s)}setTheme(e){return this.theme.set(e),this}getTheme(){return this.theme.getPreference()}getResolvedTheme(){return this.theme.getResolved()}setupFocusTracking(){if(typeof window>"u")return;this.isFocused=!document.hidden;const e=()=>{const i=this.isFocused;this.isFocused=!document.hidden,i!==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)}registerModelRef(e,t){this.modelRefClasses.set(e,t)}getModelByRef(e){return this.modelRefClasses.get(e)}setupRest(){this.rest=ne,ne.configure(this.api)}async destroy(){console.log("Destroying WebApp..."),this.router&&this.router.stop(),this._focusHandlers&&typeof window<"u"&&(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 t=>{try{t.destroy&&await t.destroy()}catch(s){console.error("Error destroying page:",s)}})),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(),typeof window<"u"&&window.MOJO&&delete window.MOJO.router,this.isStarted=!1,console.log(`✨ ${this.name} destroyed`)}buildPagePath(e,t,s){let i=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(r=>{(typeof t[r]=="string"||typeof t[r]=="number")&&(i=i.replace(`:${r}`,t[r]))}),s&&Object.keys(s).length>0){const r=new URLSearchParams(s).toString();i+=(i.includes("?")?"&":"?")+r}return i}validateDefaultRoute(){this.pageClasses.has(this.defaultRoute)?console.log(`✅ Default route '${this.defaultRoute}' is registered`):(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 ve(e)}initPluginRegistry(){typeof window<"u"&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.app=this)}static registerPlugin(e,t){typeof window<"u"&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.plugins[e]=t,console.debug(`MOJO Plugin registered: ${e}`))}}class fe extends C{constructor(e={}){e.tagName=e.tagName||"main",e.className=e.className||"mojo-page";const t=e.pageName||"";t&&!e.id&&(e.id="page_"+t.toLowerCase().replace(/\s+/g,"_")),super(e),this.pageName=e.pageName||this.constructor.pageName||"",this.route=e.route||this.constructor.route||"",this.title=e.title||this.pageName||"",!this.id&&this.constructor.pageName&&!e.pageName&&(this.id="page_"+this.constructor.pageName.toLowerCase().replace(/\s+/g,"_")),this.pageIcon=e.icon||e.pageIcon||this.constructor.pageIcon||"bi bi-file-text",this.displayName=e.displayName||this.constructor.displayName||this.pageName||"",this.pageDescription=e.pageDescription||this.constructor.pageDescription||"",this.params={},this.query={},this.matched=!1,this.isActive=!1,this.pageOptions={title:e.title||this.pageName||"Untitled Page",description:e.description||"",requiresAuth:e.requiresAuth||!1,...e.pageOptions},this.savedState=null,console.log(`Page ${this.pageName} constructed with route: ${this.route}`)}async onParams(e={},t={}){this.params=e,this.query=t}canEnter(){if(this.options.permissions){const e=this.getApp().activeUser;if(!e||!e.hasPermission(this.options.permissions))return!1}return!(this.options.requiresGroup&&!this.getApp().activeGroup)}async onEnter(){this.isActive=!0,this._wasExited=!1,await this.onInitView(),this.savedState&&(this.restoreState(this.savedState),this.savedState=null),this.pageOptions&&this.pageOptions.title&&typeof document<"u"&&(document.title=this.pageOptions.title),this.emit("activated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} entered`)}async onExit(){this.savedState=this.captureState(),this.isActive=!1,this._wasExited=!0,this._clearScheduledRefreshes(),this.emit("deactivated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} exiting`)}scheduleRefresh(e,t,s={}){if(this._scheduledRefreshes||(this._scheduledRefreshes=[]),typeof e!="function"||!(t>0))return null;const i=async()=>{try{await e()}catch(a){console.warn(`[Page ${this.pageName}] scheduleRefresh handler error:`,a)}};s.immediate&&i();const r=setInterval(i,t),n={id:r,tier:s.tier||null,handler:i,intervalMs:t};return this._scheduledRefreshes.push(n),{cancel:()=>{clearInterval(r),this._scheduledRefreshes=(this._scheduledRefreshes||[]).filter(a=>a!==n)}}}async runScheduledRefreshes(e=null){const t=this._scheduledRefreshes||[],s=e?t.filter(i=>i.tier===e):t;await Promise.allSettled(s.map(i=>i.handler()))}_clearScheduledRefreshes(){if(this._scheduledRefreshes){for(const e of this._scheduledRefreshes)clearInterval(e.id);this._scheduledRefreshes=[]}}async render(e=!0,t=null){return this._wasExited&&!this.isActive?this:super.render(e,t)}async onGroupChange(e){}getMetadata(){return{name:this.pageName,displayName:this.displayName||this.pageName,icon:this.pageIcon,description:this.pageDescription,route:this.route,isActive:this.isActive}}async onActionDefault(e){console.log(`Default action '${e}' triggered on page: ${this.pageName}`)}async makeActive(){this.getApp().showPage(this)}async onActionNavigate(e,t){e.preventDefault();const s=t.dataset.page;this.getApp().showPage(s)}captureState(){return this.element?{scrollTop:this.element.scrollTop,formData:this.captureFormData(),custom:this.captureCustomState()}:null}restoreState(e){!e||!this.element||(this.element.scrollTop=e.scrollTop||0,this.restoreFormData(e.formData),e.custom&&this.restoreCustomState(e.custom))}captureFormData(){const e={};return this.element&&this.element.querySelectorAll("input, select, textarea").forEach(t=>{t.name&&(t.type==="checkbox"?e[t.name]=t.checked:t.type==="radio"?t.checked&&(e[t.name]=t.value):e[t.name]=t.value)}),e}restoreFormData(e){!e||!this.element||Object.entries(e).forEach(([t,s])=>{const i=this.element.querySelector(`[name="${t}"]`);if(i)if(i.type==="checkbox")i.checked=s;else if(i.type==="radio"){const r=this.element.querySelector(`[name="${t}"][value="${s}"]`);r&&(r.checked=!0)}else i.value=s})}captureCustomState(){return{}}restoreCustomState(e){}setMeta(e={}){if(!(typeof document>"u")){if(e.title&&(document.title=e.title,this.pageOptions.title=e.title),e.description){let t=document.querySelector('meta[name="description"]');t||(t=document.createElement("meta"),t.name="description",document.head.appendChild(t)),t.content=e.description,this.pageOptions.description=e.description}Object.entries(e).forEach(([t,s])=>{if(t!=="title"&&t!=="description"){let i=document.querySelector(`meta[name="${t}"]`);i||(i=document.createElement("meta"),i.name=t,document.head.appendChild(i)),i.content=s}})}}showError(e){if(super.showError(e),this.element){const t=document.createElement("div");t.className="alert alert-danger alert-dismissible fade show",t.innerHTML=`
219
219
  ${e}
220
220
  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
221
221
  `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},5e3)}}showSuccess(e){if(super.showSuccess(e),this.element){const t=document.createElement("div");t.className="alert alert-success alert-dismissible fade show",t.innerHTML=`
222
222
  ${e}
223
223
  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
224
- `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},3e3)}}async onBeforeRender(){await super.onBeforeRender(),this.setMeta({title:this.pageOptions.title,description:this.pageOptions.description})}async onAfterMount(){await super.onAfterMount(),typeof document<"u"&&this.pageName&&document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}async onBeforeDestroy(){await super.onBeforeDestroy(),typeof document<"u"&&this.pageName&&document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}navigate(e,t={},s={}){if(this.app&&this.app.router)return this.app.router.navigate(e,s);if(typeof window<"u"&&window.MOJO?.router)return window.MOJO.router.navigate(e,s);console.error("No router available for navigation")}getRoute(){if(this.route){let e=this.route;return typeof e=="string"&&e.startsWith("/")&&(e=e.substring(1)),e}return this.pageName}syncUrl(e=!0){this.updateBrowserUrl(this.query,!1,!1)}updateBrowserUrl(e=null,t=!1,s=!1){this.getApp(),this.app.router.updateBrowserUrl(this.getRoute(),e,t,s)}static define(e){class t extends pe{constructor(i={}){super({...e,...i})}}return t.template=e.template,t.pageName=e.pageName,t.route=e.route,t}}class X{static _plugins=[];static _renderers=new Map;static register(e){return!e||typeof e!="object"?(console.warn("[FormPlugins] register called with invalid plugin:",e),()=>{}):!e.id||typeof e.id!="string"?(console.warn('[FormPlugins] plugin must have a unique string "id"',e),()=>{}):(this.unregister(e.id),e.fieldTypes&&typeof e.fieldTypes=="object"&&Object.entries(e.fieldTypes).forEach(([t,s])=>{typeof s=="function"?this._renderers.set(t,{renderer:s,pluginId:e.id}):console.warn(`[FormPlugins] renderer for type "${t}" is not a function`)}),this._plugins.push(e),()=>this.unregister(e.id))}static unregister(e){if(e){this._plugins=this._plugins.filter(t=>t.id!==e);for(const[t,s]of this._renderers.entries())s?.pluginId===e&&this._renderers.delete(t)}}static getRenderer(e){return this._renderers.get(e)?.renderer||null}static hasRenderer(e){return this._renderers.has(e)}static getPlugins(){return[...this._plugins]}static _invoke(e,t,...s){const i=e?.[t];if(typeof i=="function")try{return i.apply(e,s)}catch(r){console.error(`[FormPlugins] ${t} error from plugin "${e.id}":`,r)}}static onFormBuilderInit(e){this._plugins.forEach(t=>this._invoke(t,"onFormBuilderInit",e))}static onFormViewInit(e){this._plugins.forEach(t=>this._invoke(t,"onFormViewInit",e))}static onFormViewAfterRender(e){this._plugins.forEach(t=>this._invoke(t,"onAfterRender",e))}static onFieldInit(e,t,s){this._plugins.forEach(i=>this._invoke(i,"onFieldInit",e,t,s))}static onFieldChange(e,t,s){this._plugins.forEach(i=>this._invoke(i,"onFieldChange",e,t,s))}}class O extends S{static VARIANT_CLASSES={minimal:"nav tab-view-variant-minimal mb-3",traditional:"nav nav-tabs mb-3",underline:"nav tab-view-variant-underline mb-3","underline-all":"nav tab-view-variant-underline-all mb-3",pills:"nav tab-view-variant-pills mb-3","pills-solid":"nav tab-view-variant-pills-solid mb-3",segmented:"nav tab-view-variant-segmented mb-3","btn-group":"nav tab-view-variant-btn-group mb-3"};static VARIANT_ALIASES={buttongroup:"btn-group",btngroup:"btn-group"};static DEFAULT_VARIANT="underline-all";constructor(e={}){const{tabs:t,activeTab:s,tabsClass:i,variant:r,contentClass:n,minWidth:a,enableResponsive:o,tabPadding:l,dropdownStyle:d,enableTransitions:h,transitionDuration:u,...m}=e;super({tagName:"div",className:"tab-view",...m}),this.tabs={},this.tabLabels=Object.keys(this.tabs),this.activeTab=s||this.tabLabels[0]||null;const p=r!=null?Object.prototype.hasOwnProperty.call(O.VARIANT_ALIASES,r)?O.VARIANT_ALIASES[r]:r:null;p!=null&&!Object.prototype.hasOwnProperty.call(O.VARIANT_CLASSES,p)?(console.warn(`TabView: unknown variant "${r}". Falling back to "${O.DEFAULT_VARIANT}". Valid: ${Object.keys(O.VARIANT_CLASSES).join(", ")} (aliases: ${Object.keys(O.VARIANT_ALIASES).join(", ")}).`),this.variant=O.DEFAULT_VARIANT):this.variant=p||O.DEFAULT_VARIANT,this.tabsClass=i||O.VARIANT_CLASSES[this.variant],this.contentClass=n||"tab-content",this.enableTransitions=h!==!1,this.transitionDuration=u||150,this.dropdownStyle=d||"select",this.minWidth=a||300,this.enableResponsive=o!==!1,this.tabPadding=l||80,this.currentMode="tabs",this.tabWidthCache=new Map,this.lastContainerWidth=0,this.resizeObserver=null,this._measurementSpan=null,this._tabComputedStyle=null,this.isMobileMode=!1,this.hasOverflow=!1;for(const[f,g]of Object.entries(t))this.addTab(f,g);this.handleResize=this.handleResize.bind(this)}async renderTemplate(){const e=this.buildTabNavigation(),t=this.buildTabContent();return`
224
+ `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.parentNode.removeChild(t)},3e3)}}async onBeforeRender(){await super.onBeforeRender(),this.setMeta({title:this.pageOptions.title,description:this.pageOptions.description})}async onAfterMount(){await super.onAfterMount(),typeof document<"u"&&this.pageName&&document.body.classList.add(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}async onBeforeDestroy(){await super.onBeforeDestroy(),typeof document<"u"&&this.pageName&&document.body.classList.remove(`page-${this.pageName.toLowerCase().replace(/\s+/g,"-")}`)}navigate(e,t={},s={}){if(this.app&&this.app.router)return this.app.router.navigate(e,s);if(typeof window<"u"&&window.MOJO?.router)return window.MOJO.router.navigate(e,s);console.error("No router available for navigation")}getRoute(){if(this.route){let e=this.route;return typeof e=="string"&&e.startsWith("/")&&(e=e.substring(1)),e}return this.pageName}syncUrl(e=!0){this.updateBrowserUrl(this.query,!1,!1)}updateBrowserUrl(e=null,t=!1,s=!1){this.getApp(),this.app.router.updateBrowserUrl(this.getRoute(),e,t,s)}static define(e){class t extends fe{constructor(i={}){super({...e,...i})}}return t.template=e.template,t.pageName=e.pageName,t.route=e.route,t}}class X{static _plugins=[];static _renderers=new Map;static register(e){return!e||typeof e!="object"?(console.warn("[FormPlugins] register called with invalid plugin:",e),()=>{}):!e.id||typeof e.id!="string"?(console.warn('[FormPlugins] plugin must have a unique string "id"',e),()=>{}):(this.unregister(e.id),e.fieldTypes&&typeof e.fieldTypes=="object"&&Object.entries(e.fieldTypes).forEach(([t,s])=>{typeof s=="function"?this._renderers.set(t,{renderer:s,pluginId:e.id}):console.warn(`[FormPlugins] renderer for type "${t}" is not a function`)}),this._plugins.push(e),()=>this.unregister(e.id))}static unregister(e){if(e){this._plugins=this._plugins.filter(t=>t.id!==e);for(const[t,s]of this._renderers.entries())s?.pluginId===e&&this._renderers.delete(t)}}static getRenderer(e){return this._renderers.get(e)?.renderer||null}static hasRenderer(e){return this._renderers.has(e)}static getPlugins(){return[...this._plugins]}static _invoke(e,t,...s){const i=e?.[t];if(typeof i=="function")try{return i.apply(e,s)}catch(r){console.error(`[FormPlugins] ${t} error from plugin "${e.id}":`,r)}}static onFormBuilderInit(e){this._plugins.forEach(t=>this._invoke(t,"onFormBuilderInit",e))}static onFormViewInit(e){this._plugins.forEach(t=>this._invoke(t,"onFormViewInit",e))}static onFormViewAfterRender(e){this._plugins.forEach(t=>this._invoke(t,"onAfterRender",e))}static onFieldInit(e,t,s){this._plugins.forEach(i=>this._invoke(i,"onFieldInit",e,t,s))}static onFieldChange(e,t,s){this._plugins.forEach(i=>this._invoke(i,"onFieldChange",e,t,s))}}class N extends C{static VARIANT_CLASSES={minimal:"nav tab-view-variant-minimal mb-3",traditional:"nav nav-tabs mb-3",underline:"nav tab-view-variant-underline mb-3","underline-all":"nav tab-view-variant-underline-all mb-3",pills:"nav tab-view-variant-pills mb-3","pills-solid":"nav tab-view-variant-pills-solid mb-3",segmented:"nav tab-view-variant-segmented mb-3","btn-group":"nav tab-view-variant-btn-group mb-3"};static VARIANT_ALIASES={buttongroup:"btn-group",btngroup:"btn-group"};static DEFAULT_VARIANT="underline-all";constructor(e={}){const{tabs:t,activeTab:s,tabsClass:i,variant:r,contentClass:n,minWidth:a,enableResponsive:o,tabPadding:l,dropdownStyle:d,enableTransitions:h,transitionDuration:u,...m}=e;super({tagName:"div",className:"tab-view",...m}),this.tabs={},this.tabLabels=Object.keys(this.tabs),this.activeTab=s||this.tabLabels[0]||null;const p=r!=null?Object.prototype.hasOwnProperty.call(N.VARIANT_ALIASES,r)?N.VARIANT_ALIASES[r]:r:null;p!=null&&!Object.prototype.hasOwnProperty.call(N.VARIANT_CLASSES,p)?(console.warn(`TabView: unknown variant "${r}". Falling back to "${N.DEFAULT_VARIANT}". Valid: ${Object.keys(N.VARIANT_CLASSES).join(", ")} (aliases: ${Object.keys(N.VARIANT_ALIASES).join(", ")}).`),this.variant=N.DEFAULT_VARIANT):this.variant=p||N.DEFAULT_VARIANT,this.tabsClass=i||N.VARIANT_CLASSES[this.variant],this.contentClass=n||"tab-content",this.enableTransitions=h!==!1,this.transitionDuration=u||150,this.dropdownStyle=d||"select",this.minWidth=a||300,this.enableResponsive=o!==!1,this.tabPadding=l||80,this.currentMode="tabs",this.tabWidthCache=new Map,this.lastContainerWidth=0,this.resizeObserver=null,this._measurementSpan=null,this._tabComputedStyle=null,this.isMobileMode=!1,this.hasOverflow=!1;for(const[f,g]of Object.entries(t))this.addTab(f,g);this.handleResize=this.handleResize.bind(this)}async renderTemplate(){const e=this.buildTabNavigation(),t=this.buildTabContent();return`
225
225
  <div class="tab-view-container">
226
226
  ${e}
227
227
  ${t}
@@ -312,7 +312,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
312
312
  <div class="${this.contentClass}">
313
313
  ${e}
314
314
  </div>
315
- `}getTabId(e){return`tab-${e.toLowerCase().replace(/[^a-z0-9]/g,"-")}-${this.id}`}async showTab(e,t={}){const{force:s=!1}=t;if(!this.tabs[e])return console.warn(`TabView: Tab "${e}" does not exist`),!1;if(this.activeTab===e&&!s){const r=this.tabs[e];if(r&&r.isMounted()&&this.element.contains(r.element))return!0}const i=this.activeTab;this.activeTab=e;try{return await this.updateTabNavigation(e,i),await this.updateTabContent(e,i),this.emit("tab:changed",{activeTab:e,previousTab:i}),!0}catch(r){return console.error("TabView: Error showing tab:",r),this.activeTab=i,!1}}async updateTabNavigation(e,t){if(!this.element)return;if(this.currentMode==="dropdown"){await this.reRenderNavigation();return}if(t){const i=this.element.querySelector(`[data-tab-label="${t}"]`);i&&(i.classList.remove("active"),i.setAttribute("aria-selected","false"))}const s=this.element.querySelector(`[data-tab-label="${e}"]`);s&&(s.classList.add("active"),s.setAttribute("aria-selected","true"))}async updateTabContent(e,t){if(!this.element)return;const s=this.getTabId(e),i=t?this.getTabId(t):null,r=this.element.querySelector(`#${s}`),n=i?this.element.querySelector(`#${i}`):null,a=this.tabs[e];if(this.enableTransitions){if(n&&n.classList.contains("show")&&(n.classList.remove("show"),await new Promise(o=>{const l=this._getTransitionDuration(n)||this.transitionDuration;setTimeout(o,l)}),n.classList.remove("active")),a){const o=this.element.querySelector(`[data-container="${s}-content"]`);o&&!a.isMounted()&&await a.render(!0,o)}r&&(r.classList.add("active"),r.offsetHeight,r.classList.add("show"))}else{if(n&&n.classList.remove("show","active"),a){const o=this.element.querySelector(`[data-container="${s}-content"]`);o&&!a.isMounted()&&await a.render(!0,o)}r&&r.classList.add("show","active")}a&&a.onTabActivated&&await a.onTabActivated()}_getTransitionDuration(e){if(!e||typeof window>"u"||!window.getComputedStyle)return 0;const i=(window.getComputedStyle(e).transitionDuration||"0s").match(/^([0-9.]+)(m?s)$/);if(!i)return 0;const r=parseFloat(i[1]);return i[2]==="s"?r*1e3:r}async onActionShowTab(e,t){const s=t.getAttribute("data-tab-label");s&&await this.showTab(s)}_initializeMeasurementStyles(){if(!this.element||this._tabComputedStyle)return;const e=this.element.querySelector(".nav-link");if(e&&typeof window.getComputedStyle=="function"){const t=window.getComputedStyle(e);this._tabComputedStyle={font:t.font,letterSpacing:t.letterSpacing};const s=parseFloat(t.paddingLeft)||0,i=parseFloat(t.paddingRight)||0;this.tabPadding=s+i+12}}async onAfterRender(){await super.onAfterRender(),this._initializeMeasurementStyles(),this.enableResponsive&&this.setupResponsiveHandling(),this.activeTab&&this.tabs[this.activeTab]&&await this.showTab(this.activeTab,{force:!0})}async onAfterMount(){await super.onAfterMount()}async onBeforeDestroy(){await super.onBeforeDestroy(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),typeof window<"u"&&window.removeEventListener("resize",this.handleResize),this._measurementSpan&&this._measurementSpan.parentElement&&this._measurementSpan.parentElement.removeChild(this._measurementSpan),this._measurementSpan=null;for(const[e,t]of Object.entries(this.tabs))t&&typeof t.destroy=="function"&&await t.destroy()}async onSectionActivated(){const e=this.activeTab?this.tabs[this.activeTab]:null;e?.onTabActivated&&await e.onTabActivated()}getActiveTab(){return this.activeTab}getTabLabels(){return[...this.tabLabels]}getTab(e){return this.tabs[e]||null}async addTab(e,t,s=!1){return this.tabs[e]?(console.warn(`TabView: Tab "${e}" already exists`),!1):t.options.permissions&&!this.getApp().activeUser.hasPerm(t.options.permissions)?!1:(this.tabs[e]=t,t.containerId=this.getTabId(e),t.parent=this,this.tabLabels=Object.keys(this.tabs),(!this.activeTab||s)&&(this.activeTab=e),this.isMounted()&&(await this.render(),(s||this.activeTab===e)&&await this.showTab(e)),this.emit("tab:added",{label:e,view:t}),!0)}async removeTab(e){if(!this.tabs[e])return console.warn(`TabView: Tab "${e}" does not exist`),!1;const t=this.tabs[e];return t&&typeof t.destroy=="function"&&await t.destroy(),delete this.tabs[e],this.tabLabels=Object.keys(this.tabs),this.activeTab===e&&(this.activeTab=this.tabLabels[0]||null),this.isMounted()&&(await this.render(),this.activeTab&&await this.showTab(this.activeTab)),this.emit("tab:removed",{label:e,view:t}),!0}calculateTabWidth(e){if(this.tabWidthCache.has(e))return this.tabWidthCache.get(e);if(typeof document>"u"){const i=e.length*8+this.tabPadding;return this.tabWidthCache.set(e,i),i}this._measurementSpan||(this._measurementSpan=document.createElement("span"),this._measurementSpan.style.visibility="hidden",this._measurementSpan.style.position="absolute",this._measurementSpan.style.whiteSpace="nowrap");const t=this._measurementSpan;this._tabComputedStyle?(t.style.font=this._tabComputedStyle.font,t.style.letterSpacing=this._tabComputedStyle.letterSpacing):(t.style.fontSize="14px",t.style.fontFamily="system-ui, -apple-system, sans-serif"),t.textContent=e,document.body.appendChild(t);const s=t.offsetWidth+this.tabPadding;return document.body.removeChild(t),this.tabWidthCache.set(e,s),s}getTotalTabWidth(){return this.tabLabels.reduce((e,t)=>e+this.calculateTabWidth(t),0)}getContainerWidth(){return this.element?(this.element.parentElement||this.element).offsetWidth||this.minWidth:this.minWidth}shouldUseDropdown(){if(!this.enableResponsive)return!1;const e=this.getContainerWidth(),t=this.getTotalTabWidth();return e<Math.max(t,this.minWidth)}setupResponsiveHandling(){if(!(!this.element||!this.enableResponsive))if(this.updateNavigationMode(),typeof ResizeObserver<"u"){this.resizeObserver=new ResizeObserver(()=>{this.handleResize()});const e=this.element.parentElement||this.element;this.resizeObserver.observe(e)}else window.addEventListener("resize",this.handleResize)}async handleResize(){const e=this.getContainerWidth();Math.abs(e-this.lastContainerWidth)>50&&(this.lastContainerWidth=e,await this.updateNavigationMode())}async updateNavigationMode(){const t=this.shouldUseDropdown()?"dropdown":"tabs";t!==this.currentMode&&(this.currentMode=t,this.isMounted()&&await this.reRenderNavigation(),this.emit("navigation:modeChanged",{mode:this.currentMode,containerWidth:this.getContainerWidth(),totalTabWidth:this.getTotalTabWidth()}))}async reRenderNavigation(){if(!this.element)return;const e=this.element.querySelector("[data-tab-mode]");if(e){const t=this.buildTabNavigation();e.outerHTML=t}}getNavigationMode(){return this.currentMode}async setNavigationMode(e){if(e!=="tabs"&&e!=="dropdown"){console.warn('TabView: Invalid navigation mode. Use "tabs" or "dropdown"');return}this.currentMode=e,this.isMounted()&&await this.reRenderNavigation()}clearWidthCache(){this.tabWidthCache.clear()}static create(e={}){return new O(e)}}class fe{constructor(e={}){this.fields=e.fields||[],this.structureOnly=e.structureOnly||!1,this.fields.forEach(t=>{t.cols&&!t.columns?(t.columns=t.cols,delete t.cols):t.columns||(t.columns=12),t.type==="group"&&t.fields&&t.fields.forEach(s=>{s.cols&&!s.columns?(s.columns=s.cols,delete s.cols):s.columns||(s.columns=12)})}),this.options={formClass:"needs-validation",formMethod:"POST",formAction:"",groupClass:"row mb-3",fieldWrapper:"",labelClass:"form-label",inputClass:"form-control",errorClass:"invalid-feedback",helpClass:"form-text",submitButton:!1,resetButton:!1,...e.options},this.buttons=e.buttons||[],this.data=e.data||{},this.errors=e.errors||{},this.initializeTemplates()}initializeTemplates(){X.onFormBuilderInit?.(this),this.templates={input:`
315
+ `}getTabId(e){return`tab-${e.toLowerCase().replace(/[^a-z0-9]/g,"-")}-${this.id}`}async showTab(e,t={}){const{force:s=!1}=t;if(!this.tabs[e])return console.warn(`TabView: Tab "${e}" does not exist`),!1;if(this.activeTab===e&&!s){const r=this.tabs[e];if(r&&r.isMounted()&&this.element.contains(r.element))return!0}const i=this.activeTab;this.activeTab=e;try{return await this.updateTabNavigation(e,i),await this.updateTabContent(e,i),this.emit("tab:changed",{activeTab:e,previousTab:i}),!0}catch(r){return console.error("TabView: Error showing tab:",r),this.activeTab=i,!1}}async updateTabNavigation(e,t){if(!this.element)return;if(this.currentMode==="dropdown"){await this.reRenderNavigation();return}if(t){const i=this.element.querySelector(`[data-tab-label="${t}"]`);i&&(i.classList.remove("active"),i.setAttribute("aria-selected","false"))}const s=this.element.querySelector(`[data-tab-label="${e}"]`);s&&(s.classList.add("active"),s.setAttribute("aria-selected","true"))}async updateTabContent(e,t){if(!this.element)return;const s=this.getTabId(e),i=t?this.getTabId(t):null,r=this.element.querySelector(`#${s}`),n=i?this.element.querySelector(`#${i}`):null,a=this.tabs[e];if(this.enableTransitions){if(n&&n.classList.contains("show")&&(n.classList.remove("show"),await new Promise(o=>{const l=this._getTransitionDuration(n)||this.transitionDuration;setTimeout(o,l)}),n.classList.remove("active")),a){const o=this.element.querySelector(`[data-container="${s}-content"]`);o&&!a.isMounted()&&await a.render(!0,o)}r&&(r.classList.add("active"),r.offsetHeight,r.classList.add("show"))}else{if(n&&n.classList.remove("show","active"),a){const o=this.element.querySelector(`[data-container="${s}-content"]`);o&&!a.isMounted()&&await a.render(!0,o)}r&&r.classList.add("show","active")}a&&a.onTabActivated&&await a.onTabActivated()}_getTransitionDuration(e){if(!e||typeof window>"u"||!window.getComputedStyle)return 0;const i=(window.getComputedStyle(e).transitionDuration||"0s").match(/^([0-9.]+)(m?s)$/);if(!i)return 0;const r=parseFloat(i[1]);return i[2]==="s"?r*1e3:r}async onActionShowTab(e,t){const s=t.getAttribute("data-tab-label");s&&await this.showTab(s)}_initializeMeasurementStyles(){if(!this.element||this._tabComputedStyle)return;const e=this.element.querySelector(".nav-link");if(e&&typeof window.getComputedStyle=="function"){const t=window.getComputedStyle(e);this._tabComputedStyle={font:t.font,letterSpacing:t.letterSpacing};const s=parseFloat(t.paddingLeft)||0,i=parseFloat(t.paddingRight)||0;this.tabPadding=s+i+12}}async onAfterRender(){await super.onAfterRender(),this._initializeMeasurementStyles(),this.enableResponsive&&this.setupResponsiveHandling(),this.activeTab&&this.tabs[this.activeTab]&&await this.showTab(this.activeTab,{force:!0})}async onAfterMount(){await super.onAfterMount()}async onBeforeDestroy(){await super.onBeforeDestroy(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),typeof window<"u"&&window.removeEventListener("resize",this.handleResize),this._measurementSpan&&this._measurementSpan.parentElement&&this._measurementSpan.parentElement.removeChild(this._measurementSpan),this._measurementSpan=null;for(const[e,t]of Object.entries(this.tabs))t&&typeof t.destroy=="function"&&await t.destroy()}async onSectionActivated(){const e=this.activeTab?this.tabs[this.activeTab]:null;e?.onTabActivated&&await e.onTabActivated()}getActiveTab(){return this.activeTab}getTabLabels(){return[...this.tabLabels]}getTab(e){return this.tabs[e]||null}async addTab(e,t,s=!1){return this.tabs[e]?(console.warn(`TabView: Tab "${e}" already exists`),!1):t.options.permissions&&!this.getApp().activeUser.hasPerm(t.options.permissions)?!1:(this.tabs[e]=t,t.containerId=this.getTabId(e),t.parent=this,this.tabLabels=Object.keys(this.tabs),(!this.activeTab||s)&&(this.activeTab=e),this.isMounted()&&(await this.render(),(s||this.activeTab===e)&&await this.showTab(e)),this.emit("tab:added",{label:e,view:t}),!0)}async removeTab(e){if(!this.tabs[e])return console.warn(`TabView: Tab "${e}" does not exist`),!1;const t=this.tabs[e];return t&&typeof t.destroy=="function"&&await t.destroy(),delete this.tabs[e],this.tabLabels=Object.keys(this.tabs),this.activeTab===e&&(this.activeTab=this.tabLabels[0]||null),this.isMounted()&&(await this.render(),this.activeTab&&await this.showTab(this.activeTab)),this.emit("tab:removed",{label:e,view:t}),!0}calculateTabWidth(e){if(this.tabWidthCache.has(e))return this.tabWidthCache.get(e);if(typeof document>"u"){const i=e.length*8+this.tabPadding;return this.tabWidthCache.set(e,i),i}this._measurementSpan||(this._measurementSpan=document.createElement("span"),this._measurementSpan.style.visibility="hidden",this._measurementSpan.style.position="absolute",this._measurementSpan.style.whiteSpace="nowrap");const t=this._measurementSpan;this._tabComputedStyle?(t.style.font=this._tabComputedStyle.font,t.style.letterSpacing=this._tabComputedStyle.letterSpacing):(t.style.fontSize="14px",t.style.fontFamily="system-ui, -apple-system, sans-serif"),t.textContent=e,document.body.appendChild(t);const s=t.offsetWidth+this.tabPadding;return document.body.removeChild(t),this.tabWidthCache.set(e,s),s}getTotalTabWidth(){return this.tabLabels.reduce((e,t)=>e+this.calculateTabWidth(t),0)}getContainerWidth(){return this.element?(this.element.parentElement||this.element).offsetWidth||this.minWidth:this.minWidth}shouldUseDropdown(){if(!this.enableResponsive)return!1;const e=this.getContainerWidth(),t=this.getTotalTabWidth();return e<Math.max(t,this.minWidth)}setupResponsiveHandling(){if(!(!this.element||!this.enableResponsive))if(this.updateNavigationMode(),typeof ResizeObserver<"u"){this.resizeObserver=new ResizeObserver(()=>{this.handleResize()});const e=this.element.parentElement||this.element;this.resizeObserver.observe(e)}else window.addEventListener("resize",this.handleResize)}async handleResize(){const e=this.getContainerWidth();Math.abs(e-this.lastContainerWidth)>50&&(this.lastContainerWidth=e,await this.updateNavigationMode())}async updateNavigationMode(){const t=this.shouldUseDropdown()?"dropdown":"tabs";t!==this.currentMode&&(this.currentMode=t,this.isMounted()&&await this.reRenderNavigation(),this.emit("navigation:modeChanged",{mode:this.currentMode,containerWidth:this.getContainerWidth(),totalTabWidth:this.getTotalTabWidth()}))}async reRenderNavigation(){if(!this.element)return;const e=this.element.querySelector("[data-tab-mode]");if(e){const t=this.buildTabNavigation();e.outerHTML=t}}getNavigationMode(){return this.currentMode}async setNavigationMode(e){if(e!=="tabs"&&e!=="dropdown"){console.warn('TabView: Invalid navigation mode. Use "tabs" or "dropdown"');return}this.currentMode=e,this.isMounted()&&await this.reRenderNavigation()}clearWidthCache(){this.tabWidthCache.clear()}static create(e={}){return new N(e)}}class ge{constructor(e={}){this.fields=e.fields||[],this.structureOnly=e.structureOnly||!1,this.fields.forEach(t=>{t.cols&&!t.columns?(t.columns=t.cols,delete t.cols):t.columns||(t.columns=12),t.type==="group"&&t.fields&&t.fields.forEach(s=>{s.cols&&!s.columns?(s.columns=s.cols,delete s.cols):s.columns||(s.columns=12)})}),this.options={formClass:"needs-validation",formMethod:"POST",formAction:"",groupClass:"row mb-3",fieldWrapper:"",labelClass:"form-label",inputClass:"form-control",errorClass:"invalid-feedback",helpClass:"form-text",submitButton:!1,resetButton:!1,...e.options},this.buttons=e.buttons||[],this.data=e.data||{},this.errors=e.errors||{},this.initializeTemplates()}initializeTemplates(){X.onFormBuilderInit?.(this),this.templates={input:`
316
316
  <div class="mojo-form-control">
317
317
  {{#label}}
318
318
  <label for="{{fieldId}}" class="{{labelClass}}">
@@ -660,14 +660,14 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
660
660
  </div>
661
661
  </div>
662
662
  </div>
663
- `}buildFieldHTML(e){const{type:t,columns:s,class:i=""}=e;let r="";const n=X&&typeof X.getRenderer=="function"?X.getRenderer(t):null;if(typeof n=="function")try{const d=n(this,e);d!=null&&(r=String(d))}catch(d){console.error("FormPlugins custom renderer error:",d)}if(!r)switch(t){case"text":r=this.renderTextField(e);break;case"email":r=this.renderEmailField(e);break;case"password":r=this.renderPasswordField(e);break;case"number":r=this.renderNumberField(e);break;case"tel":r=this.renderTelField(e);break;case"url":r=this.renderUrlField(e);break;case"search":r=this.renderSearchField(e);break;case"hex":r=this.renderHexField(e);break;case"textarea":r=this.renderTextareaField(e);break;case"htmlpreview":r=this.renderHtmlPreviewField(e);break;case"json":r=this.renderJsonField(e);break;case"select":r=this.renderSelectField(e);break;case"multiselect":r=this.renderMultiSelectField(e);break;case"checkbox":r=this.renderCheckboxField(e);break;case"toggle":case"switch":r=this.renderSwitchField(e);break;case"radio":r=this.renderRadioField(e);break;case"date":r=this.renderDateField(e);break;case"datetime":r=this.renderDateTimeField(e);break;case"time":r=this.renderTimeField(e);break;case"file":r=this.renderFileField(e);break;case"image":r=this.renderImageField(e);break;case"color":r=this.renderColorField(e);break;case"range":r=this.renderRangeField(e);break;case"hidden":r=this.renderHiddenField(e);break;case"button":r=this.renderButton(e);break;case"divider":r=this.renderDivider(e);break;case"html":r=this.renderHtmlField(e);break;case"heading":case"header":r=this.renderHeaderField(e);break;case"tag":case"tags":r=this.renderTagField(e);break;case"collection":r=this.renderCollectionField(e);break;case"collectionmultiselect":case"collection-multiselect":r=this.renderCollectionMultiSelectField(e);break;case"datepicker":r=this.renderDatePickerField(e);break;case"monthpicker":r=this.renderDatePickerField({...e,precision:"month"});break;case"yearpicker":r=this.renderDatePickerField({...e,precision:"year"});break;case"daterange":r=this.renderDateRangeField(e);break;case"monthrange":r=this.renderDateRangeField({...e,precision:"month"});break;case"yearrange":r=this.renderDateRangeField({...e,precision:"year"});break;case"timepicker":r=this.renderTimePickerField(e);break;case"datetimepicker":r=this.renderDateTimePickerField(e);break;case"checklistdropdown":r=this.renderChecklistDropdownField(e);break;case"buttongroup":r=this.renderButtonGroupField(e);break;case"combo":case"combobox":case"autocomplete":r=this.renderComboField(e);break;case"tabset":r=this.renderTabsetField(e);break;default:console.warn(`Unknown field type: ${t}`),r=this.renderTextField(e)}let a;if(this.isAutoSizingField(e))a=`col ${i}`.trim();else if(typeof s=="object"&&s!==null){const d=[];s.xs&&d.push(`col-${s.xs}`),s.sm&&d.push(`col-sm-${s.sm}`),s.md&&d.push(`col-md-${s.md}`),s.lg&&d.push(`col-lg-${s.lg}`),s.xl&&d.push(`col-xl-${s.xl}`),s.xxl&&d.push(`col-xxl-${s.xxl}`),d.length===0&&d.push("col-12"),i&&d.push(i),a=d.join(" ")}else a=`col-${s} ${i}`.trim();let o="",l="";if(e.showWhen){const d=e.showWhen,h=Array.isArray(d.value)?d.value:[d.value];o=` data-show-when-field="${d.field}" data-show-when-value="${h.join(",")}"`,d.negate&&(o+=' data-show-when-negate="true"');let u=this.data[d.field];if(u==null){const g=this._findField(d.field,this.fields);g&&(u=g.value)}const m=String(u??""),p=h.map(String).includes(m);(d.negate?!p:p)||(l=' style="display:none"')}return`<div class="${a}"${o}${l}>${r}</div>`}_findField(e,t){for(const s of t){if(s.name===e)return s;if(s.fields){const i=this._findField(e,s.fields);if(i)return i}if(s.tabs){for(const i of s.tabs)if(i.fields){const r=this._findField(e,i.fields);if(r)return r}}}return null}getFieldId(e){return e?`field_${e.replace(/[.\s\[\]]/g,"_")}`:`field_${Math.random().toString(36).substr(2,9)}`}renderTextField(e){return this.renderInputField(e,"text")}renderEmailField(e){return this.renderInputField(e,"email")}renderPasswordField(e){const t=e.passwordUsage||"current",s=t==="new"||t==="new-password"?"new-password":"current-password",i={...e.attributes||{},autocomplete:e.attributes&&e.attributes.autocomplete||s};return this.renderInputField({...e,showToggle:e.showToggle!==!1,attributes:i},"password")}renderNumberField(e){const{min:t,max:s,step:i=1,...r}=e,n=[];return t!==void 0&&n.push(`min="${t}"`),s!==void 0&&n.push(`max="${s}"`),i!==void 0&&n.push(`step="${i}"`),this.renderInputField({...r,attributes:{...r.attributes,...n.reduce((a,o)=>{const[l,d]=o.split("=");return a[l]=d.replace(/"/g,""),a},{})}},"number")}renderTelField(e){return this.renderInputField(e,"tel")}renderUrlField(e){return this.renderInputField(e,"url")}renderSearchField(e){const t={...e,attributes:{"data-filter":"live-search","data-change-action":"filter-search","data-filter-debounce":e.debounce||"300",...e.attributes}};return this.renderInputField(t,"search")}renderHexField(e){const{hexType:t="color",allowPrefix:s=!0,minLength:i,maxLength:r,...n}=e;let a,o,l,d,h;switch(t){case"color":a=s?"^#?[0-9A-Fa-f]{6}$":"^[0-9A-Fa-f]{6}$",o=6,l=s?7:6,d=s?"#FF0000":"FF0000",h=h||"Enter a valid hex color (e.g., "+d+")";break;case"color-short":a=s?"^#?[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$":"^[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$",o=s?4:3,l=s?7:6,d=s?"#F00 or #FF0000":"F00 or FF0000",h=h||"Enter a valid hex color (3 or 6 digits)";break;case"string":a="^[0-9A-Fa-f]+$",o=i||1,l=r||64,d="ABCDEF123456",h=h||"Only hexadecimal characters (0-9, A-F) allowed";break;default:a=s?"^#?[0-9A-Fa-f]+$":"^[0-9A-Fa-f]+$",o=i||1,l=r||64,d=s?"#ABCDEF or ABCDEF":"ABCDEF",h=h||"Enter hexadecimal characters only"}const u={...n,pattern:a,minLength:o,maxLength:l,placeholder:n.placeholder||d,help:n.help||h,attributes:{"data-hex-type":t,"data-allow-prefix":s,style:"text-transform: uppercase;",...n.attributes}};return this.renderInputField(u,"text")}renderInputField(e,t="text"){const{name:s,label:i,value:r="",placeholder:n="",required:a=!1,disabled:o=!1,readonly:l=!1,class:d="",attributes:h={},help:u=e.helpText||e.help||""}=e,m=`${this.options.inputClass} ${d}`.trim(),p=this.errors[s],f=this.getFieldValue(s)??r,g=Object.entries(h).map(([C,_])=>`${C}="${this.escapeHtml(_)}"`).join(" "),b=this.getFieldId(s),y={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:b,name:s,type:t,fieldValue:f,label:i||null,placeholder:n||null,help:u||null,tooltip:e.tooltip||null,error:p||null,required:a,disabled:o,readonly:l,attrs:g,showCopy:!!e.showCopy};if(t==="password"&&(e.showToggle||e.strengthMeter||e.capsLockWarning)){const C={...y,showToggle:!!e.showToggle,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return D.render(this.templates.password,C)}if(t==="password"){const C={...y,showToggle:e.showToggle!==!1,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return D.render(this.templates.password,C)}return D.render(this.templates.input,y)}renderTextareaField(e){const{name:t,label:s,value:i="",placeholder:r="",required:n=!1,disabled:a=!1,readonly:o=!1,rows:l=3,cols:d,class:h="",attributes:u={},help:m=e.helpText||e.help||""}=e,p=`${this.options.inputClass} ${h}`.trim(),f=this.errors[t],g=this.getFieldValue(t)??i,b=Object.entries(u).map(([_,A])=>`${_}="${this.escapeHtml(A)}"`).join(" "),y=this.getFieldId(t),C={labelClass:this.options.labelClass,inputClass:p,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:y,name:t,fieldValue:g,label:s||null,placeholder:r||null,help:m||null,tooltip:e.tooltip||null,error:f||null,rows:l||3,required:n,disabled:a,readonly:o,showCopy:!!e.showCopy,attrs:b};return D.render(this.templates.textarea,C)}renderHtmlPreviewField(e){const{name:t,label:s,value:i="",placeholder:r="",required:n=!1,disabled:a=!1,readonly:o=!1,rows:l=5,class:d="",attributes:h={},help:u=e.helpText||e.help||""}=e,m=`${this.options.inputClass} ${d}`.trim(),p=this.errors[t],f=this.getFieldValue(t)??i,g=Object.entries(h).map(([C,_])=>`${C}="${this.escapeHtml(_)}"`).join(" "),b=this.getFieldId(t),y={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:b,name:t,fieldValue:f,label:s||null,placeholder:r||null,help:u||null,tooltip:e.tooltip||null,error:p||null,rows:l||5,required:n,disabled:a,readonly:o,attrs:g,showCopy:!!e.showCopy};return D.render(this.templates.htmlpreview,y)}renderJsonField(e){const{name:t,label:s,placeholder:i="",required:r=!1,disabled:n=!1,readonly:a=!1,rows:o=3,class:l="",attributes:d={},help:h=e.helpText||e.help||""}=e,u=this.getFieldValue(e.name)??e.value??{};let m=u;if(typeof u=="object"&&u!==null)try{m=JSON.stringify(u,null,2)}catch{m="{}"}else typeof u!="string"&&(m=String(u));const p=`${this.options.inputClass} ${l}`.trim(),f=this.errors[t],g=this.getFieldId(t),b=Object.entries({...d,"data-field-type":"json"}).map(([C,_])=>`${C}="${this.escapeHtml(_)}"`).join(" "),y={labelClass:this.options.labelClass,inputClass:p,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:t,fieldValue:m,label:s||null,placeholder:i||null,help:h||null,tooltip:e.tooltip||null,error:f||null,rows:o||3,required:r,disabled:n,readonly:a,attrs:b};return D.render(this.templates.textarea,y)}renderSelectField(e){const{name:t,label:s,options:i=[],value:r="",required:n=!1,disabled:a=!1,multiple:o=!1,searchable:l=!1,class:d="",attributes:h={},help:u=e.helpText||e.help||"",start:m=e.start,end:p=e.end,step:f=e.step,format:g=e.format,prefix:b=e.prefix,suffix:y=e.suffix}=e,C=`form-select ${d}`.trim(),_=this.errors[t],F=this.getFieldValue(t)??r,j=Object.entries(h).map(([M,z])=>`${M}="${this.escapeHtml(z)}"`).join(" "),I=this.getFieldId(t);let R=[...i];if(m!==void 0&&p!==void 0){const M=f!==void 0?f:1,z=this.generateSelectOptions(m,p,M,{format:g,prefix:b,suffix:y});R=[...R,...z]}let oe="";Array.isArray(R)&&(oe=R.map(M=>{if(typeof M=="string"){const z=M===F?"selected":"";return`<option value="${this.escapeHtml(M)}" ${z}>${this.escapeHtml(M)}</option>`}else if(M&&typeof M=="object"){const z=M.value==F?"selected":"";return`<option value="${this.escapeHtml(M.value)}" ${z}>${this.escapeHtml(M.label||M.text||M.value)}</option>`}return""}).join(""));const be=l?`
663
+ `}buildFieldHTML(e){const{type:t,columns:s,class:i=""}=e;let r="";const n=X&&typeof X.getRenderer=="function"?X.getRenderer(t):null;if(typeof n=="function")try{const d=n(this,e);d!=null&&(r=String(d))}catch(d){console.error("FormPlugins custom renderer error:",d)}if(!r)switch(t){case"text":r=this.renderTextField(e);break;case"email":r=this.renderEmailField(e);break;case"password":r=this.renderPasswordField(e);break;case"number":r=this.renderNumberField(e);break;case"tel":r=this.renderTelField(e);break;case"url":r=this.renderUrlField(e);break;case"search":r=this.renderSearchField(e);break;case"hex":r=this.renderHexField(e);break;case"textarea":r=this.renderTextareaField(e);break;case"htmlpreview":r=this.renderHtmlPreviewField(e);break;case"json":r=this.renderJsonField(e);break;case"select":r=this.renderSelectField(e);break;case"multiselect":r=this.renderMultiSelectField(e);break;case"checkbox":r=this.renderCheckboxField(e);break;case"toggle":case"switch":r=this.renderSwitchField(e);break;case"radio":r=this.renderRadioField(e);break;case"date":r=this.renderDateField(e);break;case"datetime":r=this.renderDateTimeField(e);break;case"time":r=this.renderTimeField(e);break;case"file":r=this.renderFileField(e);break;case"image":r=this.renderImageField(e);break;case"color":r=this.renderColorField(e);break;case"range":r=this.renderRangeField(e);break;case"hidden":r=this.renderHiddenField(e);break;case"button":r=this.renderButton(e);break;case"divider":r=this.renderDivider(e);break;case"html":r=this.renderHtmlField(e);break;case"heading":case"header":r=this.renderHeaderField(e);break;case"tag":case"tags":r=this.renderTagField(e);break;case"collection":r=this.renderCollectionField(e);break;case"collectionmultiselect":case"collection-multiselect":r=this.renderCollectionMultiSelectField(e);break;case"datepicker":r=this.renderDatePickerField(e);break;case"monthpicker":r=this.renderDatePickerField({...e,precision:"month"});break;case"yearpicker":r=this.renderDatePickerField({...e,precision:"year"});break;case"daterange":r=this.renderDateRangeField(e);break;case"monthrange":r=this.renderDateRangeField({...e,precision:"month"});break;case"yearrange":r=this.renderDateRangeField({...e,precision:"year"});break;case"timepicker":r=this.renderTimePickerField(e);break;case"datetimepicker":r=this.renderDateTimePickerField(e);break;case"checklistdropdown":r=this.renderChecklistDropdownField(e);break;case"buttongroup":r=this.renderButtonGroupField(e);break;case"combo":case"combobox":case"autocomplete":r=this.renderComboField(e);break;case"tabset":r=this.renderTabsetField(e);break;default:console.warn(`Unknown field type: ${t}`),r=this.renderTextField(e)}let a;if(this.isAutoSizingField(e))a=`col ${i}`.trim();else if(typeof s=="object"&&s!==null){const d=[];s.xs&&d.push(`col-${s.xs}`),s.sm&&d.push(`col-sm-${s.sm}`),s.md&&d.push(`col-md-${s.md}`),s.lg&&d.push(`col-lg-${s.lg}`),s.xl&&d.push(`col-xl-${s.xl}`),s.xxl&&d.push(`col-xxl-${s.xxl}`),d.length===0&&d.push("col-12"),i&&d.push(i),a=d.join(" ")}else a=`col-${s} ${i}`.trim();let o="",l="";if(e.showWhen){const d=e.showWhen,h=Array.isArray(d.value)?d.value:[d.value];o=` data-show-when-field="${d.field}" data-show-when-value="${h.join(",")}"`,d.negate&&(o+=' data-show-when-negate="true"');let u=this.data[d.field];if(u==null){const g=this._findField(d.field,this.fields);g&&(u=g.value)}const m=String(u??""),p=h.map(String).includes(m);(d.negate?!p:p)||(l=' style="display:none"')}return`<div class="${a}"${o}${l}>${r}</div>`}_findField(e,t){for(const s of t){if(s.name===e)return s;if(s.fields){const i=this._findField(e,s.fields);if(i)return i}if(s.tabs){for(const i of s.tabs)if(i.fields){const r=this._findField(e,i.fields);if(r)return r}}}return null}getFieldId(e){return e?`field_${e.replace(/[.\s\[\]]/g,"_")}`:`field_${Math.random().toString(36).substr(2,9)}`}renderTextField(e){return this.renderInputField(e,"text")}renderEmailField(e){return this.renderInputField(e,"email")}renderPasswordField(e){const t=e.passwordUsage||"current",s=t==="new"||t==="new-password"?"new-password":"current-password",i={...e.attributes||{},autocomplete:e.attributes&&e.attributes.autocomplete||s};return this.renderInputField({...e,showToggle:e.showToggle!==!1,attributes:i},"password")}renderNumberField(e){const{min:t,max:s,step:i=1,...r}=e,n=[];return t!==void 0&&n.push(`min="${t}"`),s!==void 0&&n.push(`max="${s}"`),i!==void 0&&n.push(`step="${i}"`),this.renderInputField({...r,attributes:{...r.attributes,...n.reduce((a,o)=>{const[l,d]=o.split("=");return a[l]=d.replace(/"/g,""),a},{})}},"number")}renderTelField(e){return this.renderInputField(e,"tel")}renderUrlField(e){return this.renderInputField(e,"url")}renderSearchField(e){const t={...e,attributes:{"data-filter":"live-search","data-change-action":"filter-search","data-filter-debounce":e.debounce||"300",...e.attributes}};return this.renderInputField(t,"search")}renderHexField(e){const{hexType:t="color",allowPrefix:s=!0,minLength:i,maxLength:r,...n}=e;let a,o,l,d,h;switch(t){case"color":a=s?"^#?[0-9A-Fa-f]{6}$":"^[0-9A-Fa-f]{6}$",o=6,l=s?7:6,d=s?"#FF0000":"FF0000",h=h||"Enter a valid hex color (e.g., "+d+")";break;case"color-short":a=s?"^#?[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$":"^[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$",o=s?4:3,l=s?7:6,d=s?"#F00 or #FF0000":"F00 or FF0000",h=h||"Enter a valid hex color (3 or 6 digits)";break;case"string":a="^[0-9A-Fa-f]+$",o=i||1,l=r||64,d="ABCDEF123456",h=h||"Only hexadecimal characters (0-9, A-F) allowed";break;default:a=s?"^#?[0-9A-Fa-f]+$":"^[0-9A-Fa-f]+$",o=i||1,l=r||64,d=s?"#ABCDEF or ABCDEF":"ABCDEF",h=h||"Enter hexadecimal characters only"}const u={...n,pattern:a,minLength:o,maxLength:l,placeholder:n.placeholder||d,help:n.help||h,attributes:{"data-hex-type":t,"data-allow-prefix":s,style:"text-transform: uppercase;",...n.attributes}};return this.renderInputField(u,"text")}renderInputField(e,t="text"){const{name:s,label:i,value:r="",placeholder:n="",required:a=!1,disabled:o=!1,readonly:l=!1,class:d="",attributes:h={},help:u=e.helpText||e.help||""}=e,m=`${this.options.inputClass} ${d}`.trim(),p=this.errors[s],f=this.getFieldValue(s)??r,g=Object.entries(h).map(([_,S])=>`${_}="${this.escapeHtml(S)}"`).join(" "),b=this.getFieldId(s),y={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:b,name:s,type:t,fieldValue:f,label:i||null,placeholder:n||null,help:u||null,tooltip:e.tooltip||null,error:p||null,required:a,disabled:o,readonly:l,attrs:g,showCopy:!!e.showCopy};if(t==="password"&&(e.showToggle||e.strengthMeter||e.capsLockWarning)){const _={...y,showToggle:!!e.showToggle,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return D.render(this.templates.password,_)}if(t==="password"){const _={...y,showToggle:e.showToggle!==!1,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return D.render(this.templates.password,_)}return D.render(this.templates.input,y)}renderTextareaField(e){const{name:t,label:s,value:i="",placeholder:r="",required:n=!1,disabled:a=!1,readonly:o=!1,rows:l=3,cols:d,class:h="",attributes:u={},help:m=e.helpText||e.help||""}=e,p=`${this.options.inputClass} ${h}`.trim(),f=this.errors[t],g=this.getFieldValue(t)??i,b=Object.entries(u).map(([S,A])=>`${S}="${this.escapeHtml(A)}"`).join(" "),y=this.getFieldId(t),_={labelClass:this.options.labelClass,inputClass:p,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:y,name:t,fieldValue:g,label:s||null,placeholder:r||null,help:m||null,tooltip:e.tooltip||null,error:f||null,rows:l||3,required:n,disabled:a,readonly:o,showCopy:!!e.showCopy,attrs:b};return D.render(this.templates.textarea,_)}renderHtmlPreviewField(e){const{name:t,label:s,value:i="",placeholder:r="",required:n=!1,disabled:a=!1,readonly:o=!1,rows:l=5,class:d="",attributes:h={},help:u=e.helpText||e.help||""}=e,m=`${this.options.inputClass} ${d}`.trim(),p=this.errors[t],f=this.getFieldValue(t)??i,g=Object.entries(h).map(([_,S])=>`${_}="${this.escapeHtml(S)}"`).join(" "),b=this.getFieldId(t),y={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:b,name:t,fieldValue:f,label:s||null,placeholder:r||null,help:u||null,tooltip:e.tooltip||null,error:p||null,rows:l||5,required:n,disabled:a,readonly:o,attrs:g,showCopy:!!e.showCopy};return D.render(this.templates.htmlpreview,y)}renderJsonField(e){const{name:t,label:s,placeholder:i="",required:r=!1,disabled:n=!1,readonly:a=!1,rows:o=3,class:l="",attributes:d={},help:h=e.helpText||e.help||""}=e,u=this.getFieldValue(e.name)??e.value??{};let m=u;if(typeof u=="object"&&u!==null)try{m=JSON.stringify(u,null,2)}catch{m="{}"}else typeof u!="string"&&(m=String(u));const p=`${this.options.inputClass} ${l}`.trim(),f=this.errors[t],g=this.getFieldId(t),b=Object.entries({...d,"data-field-type":"json"}).map(([_,S])=>`${_}="${this.escapeHtml(S)}"`).join(" "),y={labelClass:this.options.labelClass,inputClass:p,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:t,fieldValue:m,label:s||null,placeholder:i||null,help:h||null,tooltip:e.tooltip||null,error:f||null,rows:o||3,required:r,disabled:n,readonly:a,attrs:b};return D.render(this.templates.textarea,y)}renderSelectField(e){const{name:t,label:s,options:i=[],value:r="",required:n=!1,disabled:a=!1,multiple:o=!1,searchable:l=!1,class:d="",attributes:h={},help:u=e.helpText||e.help||"",start:m=e.start,end:p=e.end,step:f=e.step,format:g=e.format,prefix:b=e.prefix,suffix:y=e.suffix}=e,_=`form-select ${d}`.trim(),S=this.errors[t],F=this.getFieldValue(t)??r,j=Object.entries(h).map(([k,H])=>`${k}="${this.escapeHtml(H)}"`).join(" "),I=this.getFieldId(t);let O=[...i];if(m!==void 0&&p!==void 0){const k=f!==void 0?f:1,H=this.generateSelectOptions(m,p,k,{format:g,prefix:b,suffix:y});O=[...O,...H]}let oe="";Array.isArray(O)&&(oe=O.map(k=>{if(typeof k=="string"){const H=k===F?"selected":"";return`<option value="${this.escapeHtml(k)}" ${H}>${this.escapeHtml(k)}</option>`}else if(k&&typeof k=="object"){const H=k.value==F?"selected":"";return`<option value="${this.escapeHtml(k.value)}" ${H}>${this.escapeHtml(k.label||k.text||k.value)}</option>`}return""}).join(""));const be=l?`
664
664
  <input type="text"
665
665
  class="form-control form-control-sm mb-2"
666
666
  placeholder="Search options..."
667
667
  data-filter="live-search"
668
668
  data-change-action="filter-select-options"
669
669
  data-target="${I}">
670
- `:"",ye={labelClass:this.options.labelClass,inputClass:C,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:I,name:t,label:s||null,help:u||null,tooltip:e.tooltip||null,error:_||null,searchInput:l?be:null,optionsHTML:oe,required:n,disabled:a,multiple:o,attrs:j};return D.render(this.templates.select,ye)}renderMultiSelectField(e){const{name:t,label:s,options:i=[],value:r=[],required:n=!1,disabled:a=!1,maxHeight:o=300,help:l=e.helpText||e.help||""}=e,d=e.placeholder||e.placeHolder||"Select...";this.getFieldId(t);const h=this.errors[t],u=e.value??this.getFieldValue(t)??r;return`
670
+ `:"",ye={labelClass:this.options.labelClass,inputClass:_,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:I,name:t,label:s||null,help:u||null,tooltip:e.tooltip||null,error:S||null,searchInput:l?be:null,optionsHTML:oe,required:n,disabled:a,multiple:o,attrs:j};return D.render(this.templates.select,ye)}renderMultiSelectField(e){const{name:t,label:s,options:i=[],value:r=[],required:n=!1,disabled:a=!1,maxHeight:o=300,help:l=e.helpText||e.help||""}=e,d=e.placeholder||e.placeHolder||"Select...";this.getFieldId(t);const h=this.errors[t],u=e.value??this.getFieldValue(t)??r;return`
671
671
  <div class="multiselect-placeholder"
672
672
  data-field-name="${t}"
673
673
  data-field-type="multiselect"
@@ -681,7 +681,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
681
681
  </select>
682
682
  <small class="form-text text-muted">This will be enhanced with MultiSelectDropdown component</small>
683
683
  </div>
684
- `}renderCheckboxField(e){const{name:t,label:s,value:i=!1,required:r=!1,disabled:n=!1,class:a="",attributes:o={},help:l=e.helpText||e.help||""}=e,d=this.errors[t],h=this.getFieldValue(t)??i,u=h===!0||h==="true"||h==="1",m=Object.entries(o).map(([g,b])=>`${g}="${this.escapeHtml(b)}"`).join(" "),p=this.getFieldId(t),f={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:p,name:t,label:s||null,help:l||null,tooltip:e.tooltip||null,error:d||null,value:i,fieldClass:a,checked:u,required:r,disabled:n,attrs:m};return D.render(this.templates.checkbox,f)}renderSwitchField(e){const{name:t,label:s,value:i=!1,required:r=!1,disabled:n=!1,size:a="md",class:o="",attributes:l={},help:d=e.helpText||e.help||""}=e,h=this.errors[t],u=this.getFieldValue(t)??i,m=u===!0||u==="true"||u==="1",p=Object.entries(l).map(([y,C])=>`${y}="${this.escapeHtml(C)}"`).join(" "),f=this.getFieldId(t),g=a!=="md"?`form-switch-${a}`:"",b={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:f,name:t,label:s||null,help:d||null,tooltip:e.tooltip||null,error:h||null,value:i,sizeClass:g,fieldClass:o,checked:m,required:r,disabled:n,attrs:p};return D.render(this.templates.switch,b)}renderRadioField(e){const{name:t,label:s,options:i=[],value:r="",disabled:n=!1,inline:a=!1,class:o="",attributes:l={},help:d=e.helpText||e.help||""}=e,h=this.errors[t],u=this.getFieldValue(t)??r,m=Object.entries(l).map(([f,g])=>`${f}="${this.escapeHtml(g)}"`).join(" ");let p="";return Array.isArray(i)&&(p=i.map((f,g)=>{const b=`${t}_${g}`,y=typeof f=="string"?f:f.value,C=typeof f=="string"?f:f.label||f.text||f.value,_=y===u?"checked":"";return`
684
+ `}renderCheckboxField(e){const{name:t,label:s,value:i=!1,required:r=!1,disabled:n=!1,class:a="",attributes:o={},help:l=e.helpText||e.help||""}=e,d=this.errors[t],h=this.getFieldValue(t)??i,u=h===!0||h==="true"||h==="1",m=Object.entries(o).map(([g,b])=>`${g}="${this.escapeHtml(b)}"`).join(" "),p=this.getFieldId(t),f={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:p,name:t,label:s||null,help:l||null,tooltip:e.tooltip||null,error:d||null,value:i,fieldClass:a,checked:u,required:r,disabled:n,attrs:m};return D.render(this.templates.checkbox,f)}renderSwitchField(e){const{name:t,label:s,value:i=!1,required:r=!1,disabled:n=!1,size:a="md",class:o="",attributes:l={},help:d=e.helpText||e.help||""}=e,h=this.errors[t],u=this.getFieldValue(t)??i,m=u===!0||u==="true"||u==="1",p=Object.entries(l).map(([y,_])=>`${y}="${this.escapeHtml(_)}"`).join(" "),f=this.getFieldId(t),g=a!=="md"?`form-switch-${a}`:"",b={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:f,name:t,label:s||null,help:d||null,tooltip:e.tooltip||null,error:h||null,value:i,sizeClass:g,fieldClass:o,checked:m,required:r,disabled:n,attrs:p};return D.render(this.templates.switch,b)}renderRadioField(e){const{name:t,label:s,options:i=[],value:r="",disabled:n=!1,inline:a=!1,class:o="",attributes:l={},help:d=e.helpText||e.help||""}=e,h=this.errors[t],u=this.getFieldValue(t)??r,m=Object.entries(l).map(([f,g])=>`${f}="${this.escapeHtml(g)}"`).join(" ");let p="";return Array.isArray(i)&&(p=i.map((f,g)=>{const b=`${t}_${g}`,y=typeof f=="string"?f:f.value,_=typeof f=="string"?f:f.label||f.text||f.value,S=y===u?"checked":"";return`
685
685
  <div class="form-check ${a?"form-check-inline":""}">
686
686
  <input
687
687
  type="radio"
@@ -689,13 +689,13 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
689
689
  name="${t}"
690
690
  class="form-check-input ${h?"is-invalid":""}"
691
691
  value="${this.escapeHtml(y)}"
692
- ${_}
692
+ ${S}
693
693
  ${n?"disabled":""}
694
694
 
695
695
  ${m}
696
696
  >
697
697
  <label class="form-check-label" for="${b}">
698
- ${this.escapeHtml(C)}
698
+ ${this.escapeHtml(_)}
699
699
  </label>
700
700
  </div>
701
701
  `}).join("")),`
@@ -709,7 +709,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
709
709
  ${d?`<div class="${this.options.helpClass}">${this.escapeHtml(d)}</div>`:""}
710
710
  ${h?`<div class="${this.options.errorClass}">${this.escapeHtml(h)}</div>`:""}
711
711
  </div>
712
- `}renderDateField(e){return this.renderInputField(e,"date")}renderDateTimeField(e){return this.renderInputField(e,"datetime-local")}renderTimeField(e){return this.renderInputField(e,"time")}renderFileField(e){const{name:t,label:s,required:i=!1,disabled:r=!1,multiple:n=!1,accept:a="*/*",class:o="",attributes:l={},help:d=e.helpText||e.help||""}=e,h=`${this.options.inputClass} ${o}`.trim(),u=this.errors[t],m=Object.entries(l).map(([g,b])=>`${g}="${this.escapeHtml(b)}"`).join(" "),p=this.getFieldId(t),f={labelClass:this.options.labelClass,inputClass:h,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:p,name:t,label:s||null,help:d||null,tooltip:e.tooltip||null,error:u||null,accept:a,required:i,disabled:r,multiple:n,attrs:m};return D.render(this.templates.file,f)}renderImageField(e){const{name:t,label:s,required:i=!1,disabled:r=!1,accept:n="image/*",class:a="",attributes:o={},help:l=e.helpText||e.help||"",size:d="md",allowDrop:h=!0,placeholder:u="Drop image here or click to upload"}=e,m=`${this.options.inputClass} ${a}`.trim(),p=this.errors[t],f=this.getFieldId(t),g=`${f}_dropzone`,b=`${f}_preview`,y={xs:{width:48,height:48,containerClass:"image-field-xs"},sm:{width:96,height:96,containerClass:"image-field-sm"},md:{width:150,height:150,containerClass:"image-field-md"},lg:{width:200,height:200,containerClass:"image-field-lg"},xl:{width:300,height:300,containerClass:"image-field-xl"}},C=y[d]||y.md,_=Object.entries(o).map(([I,R])=>`${I}="${this.escapeHtml(R)}"`).join(" "),A=this.getFieldValue(t),F=this.extractImageUrl(A,d),j={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:f,name:t,label:s||null,help:l||null,tooltip:e.tooltip||null,error:p||null,dropZoneId:g,previewId:b,containerClass:C.containerClass,width:C.width,height:C.height,accept:n,imageUrl:F,placeholderText:r?"No image":u||"",cursor:r?"default":"pointer",allowDrop:h,showRemove:!r,required:i,disabled:r,attrs:_};return D.render(this.templates.image,j)}extractImageUrl(e,t="md"){if(!e)return null;if(typeof e=="string")return e;if(typeof e=="object"&&e.url){if(e.renditions){const s={xs:["thumbnail_sm","thumbnail","square_sm"],sm:["thumbnail","thumbnail_sm","square_sm"],md:["thumbnail_md","thumbnail","thumbnail_lg"],lg:["thumbnail_lg","thumbnail_md","thumbnail"],xl:["original","thumbnail_lg"]},i=s[t]||s.md;for(const r of i)if(e.renditions[r]&&e.renditions[r].url)return e.renditions[r].url}return e.url}return null}renderColorField(e){const{name:t,label:s,value:i="",placeholder:r="",required:n=!1,disabled:a=!1,readonly:o=!1,class:l="",attributes:d={},help:h=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),m=this.errors[t],p=this.getFieldValue(t)??i,f=Object.entries(d).map(([y,C])=>`${y}="${this.escapeHtml(C)}"`).join(" "),g=this.getFieldId(t),b={labelClass:this.options.labelClass,inputClass:u,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:t,fieldValue:p,label:s||null,placeholder:r||null,help:h||null,tooltip:e.tooltip||null,error:m||null,required:n,disabled:a,readonly:o,attrs:f};return D.render(this.templates.color,b)}renderRangeField(e){const{name:t,label:s,min:i=0,max:r=100,step:n=1,value:a=i,disabled:o=!1,class:l="",attributes:d={},help:h=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),m=this.errors[t],p=this.getFieldValue(t)??a,f=Object.entries(d).map(([y,C])=>`${y}="${this.escapeHtml(C)}"`).join(" "),g=this.getFieldId(t),b={labelClass:this.options.labelClass,inputClass:u,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:t,label:s||null,help:h||null,tooltip:e.tooltip||null,error:m||null,min:i,max:r,step:n,fieldValue:p,disabled:o,attrs:f};return D.render(this.templates.range,b)}renderHiddenField(e){const{name:t,value:s=""}=e,i=this.getFieldValue(t)??s;return`<input type="hidden" name="${t}" value="${this.escapeHtml(i)}">`}renderButton(e){const{name:t="",label:s="Button",type:i="button",action:r="",class:n="btn-secondary",disabled:a=!1,attributes:o={}}=e;let l=r;l||(i==="submit"?l="submit-form":i==="reset"&&(l="reset-form"));const d=Object.entries(o).map(([h,u])=>`${h}="${this.escapeHtml(u)}"`).join(" ");return`
712
+ `}renderDateField(e){return this.renderInputField(e,"date")}renderDateTimeField(e){return this.renderInputField(e,"datetime-local")}renderTimeField(e){return this.renderInputField(e,"time")}renderFileField(e){const{name:t,label:s,required:i=!1,disabled:r=!1,multiple:n=!1,accept:a="*/*",class:o="",attributes:l={},help:d=e.helpText||e.help||""}=e,h=`${this.options.inputClass} ${o}`.trim(),u=this.errors[t],m=Object.entries(l).map(([g,b])=>`${g}="${this.escapeHtml(b)}"`).join(" "),p=this.getFieldId(t),f={labelClass:this.options.labelClass,inputClass:h,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:p,name:t,label:s||null,help:d||null,tooltip:e.tooltip||null,error:u||null,accept:a,required:i,disabled:r,multiple:n,attrs:m};return D.render(this.templates.file,f)}renderImageField(e){const{name:t,label:s,required:i=!1,disabled:r=!1,accept:n="image/*",class:a="",attributes:o={},help:l=e.helpText||e.help||"",size:d="md",allowDrop:h=!0,placeholder:u="Drop image here or click to upload"}=e,m=`${this.options.inputClass} ${a}`.trim(),p=this.errors[t],f=this.getFieldId(t),g=`${f}_dropzone`,b=`${f}_preview`,y={xs:{width:48,height:48,containerClass:"image-field-xs"},sm:{width:96,height:96,containerClass:"image-field-sm"},md:{width:150,height:150,containerClass:"image-field-md"},lg:{width:200,height:200,containerClass:"image-field-lg"},xl:{width:300,height:300,containerClass:"image-field-xl"}},_=y[d]||y.md,S=Object.entries(o).map(([I,O])=>`${I}="${this.escapeHtml(O)}"`).join(" "),A=this.getFieldValue(t),F=this.extractImageUrl(A,d),j={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:f,name:t,label:s||null,help:l||null,tooltip:e.tooltip||null,error:p||null,dropZoneId:g,previewId:b,containerClass:_.containerClass,width:_.width,height:_.height,accept:n,imageUrl:F,placeholderText:r?"No image":u||"",cursor:r?"default":"pointer",allowDrop:h,showRemove:!r,required:i,disabled:r,attrs:S};return D.render(this.templates.image,j)}extractImageUrl(e,t="md"){if(!e)return null;if(typeof e=="string")return e;if(typeof e=="object"&&e.url){if(e.renditions){const s={xs:["thumbnail_sm","thumbnail","square_sm"],sm:["thumbnail","thumbnail_sm","square_sm"],md:["thumbnail_md","thumbnail","thumbnail_lg"],lg:["thumbnail_lg","thumbnail_md","thumbnail"],xl:["original","thumbnail_lg"]},i=s[t]||s.md;for(const r of i)if(e.renditions[r]&&e.renditions[r].url)return e.renditions[r].url}return e.url}return null}renderColorField(e){const{name:t,label:s,value:i="",placeholder:r="",required:n=!1,disabled:a=!1,readonly:o=!1,class:l="",attributes:d={},help:h=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),m=this.errors[t],p=this.getFieldValue(t)??i,f=Object.entries(d).map(([y,_])=>`${y}="${this.escapeHtml(_)}"`).join(" "),g=this.getFieldId(t),b={labelClass:this.options.labelClass,inputClass:u,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:t,fieldValue:p,label:s||null,placeholder:r||null,help:h||null,tooltip:e.tooltip||null,error:m||null,required:n,disabled:a,readonly:o,attrs:f};return D.render(this.templates.color,b)}renderRangeField(e){const{name:t,label:s,min:i=0,max:r=100,step:n=1,value:a=i,disabled:o=!1,class:l="",attributes:d={},help:h=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),m=this.errors[t],p=this.getFieldValue(t)??a,f=Object.entries(d).map(([y,_])=>`${y}="${this.escapeHtml(_)}"`).join(" "),g=this.getFieldId(t),b={labelClass:this.options.labelClass,inputClass:u,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:t,label:s||null,help:h||null,tooltip:e.tooltip||null,error:m||null,min:i,max:r,step:n,fieldValue:p,disabled:o,attrs:f};return D.render(this.templates.range,b)}renderHiddenField(e){const{name:t,value:s=""}=e,i=this.getFieldValue(t)??s;return`<input type="hidden" name="${t}" value="${this.escapeHtml(i)}">`}renderButton(e){const{name:t="",label:s="Button",type:i="button",action:r="",class:n="btn-secondary",disabled:a=!1,attributes:o={}}=e;let l=r;l||(i==="submit"?l="submit-form":i==="reset"&&(l="reset-form"));const d=Object.entries(o).map(([h,u])=>`${h}="${this.escapeHtml(u)}"`).join(" ");return`
713
713
  <button
714
714
  type="button"
715
715
  ${t?`name="${t}"`:""}
@@ -754,13 +754,13 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
754
754
  ${u?`<div class="${this.options.helpClass}">${this.escapeHtml(u)}</div>`:""}
755
755
  ${p?`<div class="${this.options.errorClass}">${this.escapeHtml(p)}</div>`:""}
756
756
  </div>
757
- `}renderCollectionField(e){const{name:t,label:s,value:i="",placeholder:r="Search...",required:n=!1,disabled:a=!1,readonly:o=!1,Collection:l,labelField:d="name",valueField:h="id",maxItems:u=10,emptyFetch:m=!1,debounceMs:p=300,requiresActiveGroup:f=!1,help:g=e.helpText||e.help||""}=e,b=this.getFieldId(t),y=this.errors[t],C=this.getFieldValue(t)??i;return`
757
+ `}renderCollectionField(e){const{name:t,label:s,value:i="",placeholder:r="Search...",required:n=!1,disabled:a=!1,readonly:o=!1,Collection:l,labelField:d="name",valueField:h="id",maxItems:u=10,emptyFetch:m=!1,debounceMs:p=300,requiresActiveGroup:f=!1,help:g=e.helpText||e.help||""}=e,b=this.getFieldId(t),y=this.errors[t],_=this.getFieldValue(t)??i;return`
758
758
  <div class="mojo-form-control">
759
759
  ${s?`<label for="${b}" class="${this.options.labelClass}">${this.escapeHtml(s)}${n?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
760
760
  <div class="collection-select-placeholder"
761
761
  data-field-name="${t}"
762
762
  data-field-type="collection"
763
- data-field-config='${JSON.stringify({name:t,value:C,placeholder:r,labelField:d,valueField:h,maxItems:u,emptyFetch:m,debounceMs:p,disabled:a,readonly:o,required:n,requiresActiveGroup:f})}'>
763
+ data-field-config='${JSON.stringify({name:t,value:_,placeholder:r,labelField:d,valueField:h,maxItems:u,emptyFetch:m,debounceMs:p,disabled:a,readonly:o,required:n,requiresActiveGroup:f})}'>
764
764
  <input type="text"
765
765
  id="${b}"
766
766
  name="${t}_display"
@@ -769,62 +769,62 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
769
769
  ${a?"disabled":""}
770
770
  ${o?"readonly":""}
771
771
 
772
- <input type="hidden" name="${t}" value="${this.escapeHtml(C)}">
772
+ <input type="hidden" name="${t}" value="${this.escapeHtml(_)}">
773
773
  <small class="form-text text-muted">This will be enhanced with CollectionSelect component</small>
774
774
  </div>
775
775
  ${g?`<div class="${this.options.helpClass}">${this.escapeHtml(g)}</div>`:""}
776
776
  ${y?`<div class="${this.options.errorClass}">${this.escapeHtml(y)}</div>`:""}
777
777
  </div>
778
- `}renderCollectionMultiSelectField(e){const{name:t,label:s,value:i=[],required:r=!1,disabled:n=!1,Collection:a,collectionParams:o={},labelField:l="name",valueField:d="id",excludeIds:h=[],ignoreIds:u=[],size:m=8,maxHeight:p=null,showSelectAll:f=!0,enableSearch:g=!1,searchPlaceholder:b="Search...",searchDebounce:y=400,requiresActiveGroup:C=!1,help:_=e.helpText||e.help||""}=e;this.getFieldId(t);const A=this.errors[t],F=this.getFieldValue(t)??i;return`
778
+ `}renderCollectionMultiSelectField(e){const{name:t,label:s,value:i=[],required:r=!1,disabled:n=!1,Collection:a,collectionParams:o={},labelField:l="name",valueField:d="id",excludeIds:h=[],ignoreIds:u=[],size:m=8,maxHeight:p=null,showSelectAll:f=!0,enableSearch:g=!1,searchPlaceholder:b="Search...",searchDebounce:y=400,requiresActiveGroup:_=!1,help:S=e.helpText||e.help||""}=e;this.getFieldId(t);const A=this.errors[t],F=this.getFieldValue(t)??i;return`
779
779
  <div class="mojo-form-control">
780
780
  ${s?`<label class="${this.options.labelClass}">${this.escapeHtml(s)}${r?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
781
781
  <div class="collection-multiselect-placeholder"
782
782
  data-field-name="${t}"
783
783
  data-field-type="collectionmultiselect"
784
- data-field-config='${JSON.stringify({name:t,value:F,labelField:l,valueField:d,excludeIds:h,ignoreIds:u,size:m,maxHeight:p,showSelectAll:f,enableSearch:g,searchPlaceholder:b,searchDebounce:y,disabled:n,required:r,requiresActiveGroup:C})}'>
784
+ data-field-config='${JSON.stringify({name:t,value:F,labelField:l,valueField:d,excludeIds:h,ignoreIds:u,size:m,maxHeight:p,showSelectAll:f,enableSearch:g,searchPlaceholder:b,searchDebounce:y,disabled:n,required:r,requiresActiveGroup:_})}'>
785
785
  <input type="hidden" name="${t}" value="${this.escapeHtml(JSON.stringify(F))}">
786
786
  <small class="form-text text-muted">This will be enhanced with CollectionMultiSelect component</small>
787
787
  </div>
788
- ${_?`<div class="${this.options.helpClass}">${this.escapeHtml(_)}</div>`:""}
788
+ ${S?`<div class="${this.options.helpClass}">${this.escapeHtml(S)}</div>`:""}
789
789
  ${A?`<div class="${this.options.errorClass}">${this.escapeHtml(A)}</div>`:""}
790
790
  </div>
791
- `}renderDatePickerField(e){const{name:t,label:s,value:i="",precision:r="day",placeholder:n,required:a=!1,disabled:o=!1,readonly:l=!1,min:d=null,max:h=null,format:u=null,displayFormat:m=null,disabledDates:p=[],firstDay:f=1,lang:g="en-US",autoApply:b=!0,inline:y=!1,help:C=e.helpText||e.help||""}=e,_=this.getFieldId(t),A=this.errors[t],F=this.getFieldValue(t)??i;return`
791
+ `}renderDatePickerField(e){const{name:t,label:s,value:i="",precision:r="day",placeholder:n,required:a=!1,disabled:o=!1,readonly:l=!1,min:d=null,max:h=null,format:u=null,displayFormat:m=null,disabledDates:p=[],firstDay:f=1,lang:g="en-US",autoApply:b=!0,inline:y=!1,help:_=e.helpText||e.help||""}=e,S=this.getFieldId(t),A=this.errors[t],F=this.getFieldValue(t)??i;return`
792
792
  <div class="mojo-form-control">
793
- ${s?`<label for="${_}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
793
+ ${s?`<label for="${S}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
794
794
  <div class="date-picker-placeholder"
795
795
  data-field-name="${t}"
796
796
  data-field-type="datepicker"
797
797
  data-field-config='${JSON.stringify({name:t,value:F,precision:r,placeholder:n,min:d,max:h,format:u,displayFormat:m,disabledDates:p,firstDay:f,lang:g,autoApply:b,inline:y,disabled:o,readonly:l,required:a})}'></div>
798
- ${C?`<div class="${this.options.helpClass}">${this.escapeHtml(C)}</div>`:""}
798
+ ${_?`<div class="${this.options.helpClass}">${this.escapeHtml(_)}</div>`:""}
799
799
  ${A?`<div class="${this.options.errorClass}">${this.escapeHtml(A)}</div>`:""}
800
800
  </div>
801
- `}renderDateRangeField(e){const{name:t,startName:s,endName:i,fieldName:r,label:n,startDate:a="",endDate:o="",precision:l="day",placeholder:d,required:h=!1,disabled:u=!1,readonly:m=!1,min:p=null,max:f=null,format:g=null,displayFormat:b=null,outputFormat:y="date",separator:C=" – ",months:_=null,presets:A=null,autoApply:F=!0,inline:j=!1,help:I=e.helpText||e.help||""}=e,R=this.getFieldId(t||s||"daterange"),oe=this.errors[t],be=s||(t?t+"_start":""),ye=i||(t?t+"_end":""),M=this.getFieldValue(be)||a,z=this.getFieldValue(ye)||o;return`
801
+ `}renderDateRangeField(e){const{name:t,startName:s,endName:i,fieldName:r,label:n,startDate:a="",endDate:o="",precision:l="day",placeholder:d,required:h=!1,disabled:u=!1,readonly:m=!1,min:p=null,max:f=null,format:g=null,displayFormat:b=null,outputFormat:y="date",separator:_=" – ",months:S=null,presets:A=null,autoApply:F=!0,inline:j=!1,help:I=e.helpText||e.help||""}=e,O=this.getFieldId(t||s||"daterange"),oe=this.errors[t],be=s||(t?t+"_start":""),ye=i||(t?t+"_end":""),k=this.getFieldValue(be)||a,H=this.getFieldValue(ye)||o;return`
802
802
  <div class="mojo-form-control">
803
- ${n?`<label for="${R}" class="${this.options.labelClass}">${this.escapeHtml(n)}${h?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
803
+ ${n?`<label for="${O}" class="${this.options.labelClass}">${this.escapeHtml(n)}${h?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
804
804
  <div class="date-range-picker-placeholder"
805
805
  data-field-name="${t||s||"daterange"}"
806
806
  data-field-type="daterange"
807
- data-field-config='${JSON.stringify({name:t,startName:s,endName:i,fieldName:r,startDate:M,endDate:z,precision:l,placeholder:d,min:p,max:f,format:g,displayFormat:b,outputFormat:y,separator:C,months:_,presets:A,autoApply:F,inline:j,disabled:u,readonly:m,required:h})}'></div>
807
+ data-field-config='${JSON.stringify({name:t,startName:s,endName:i,fieldName:r,startDate:k,endDate:H,precision:l,placeholder:d,min:p,max:f,format:g,displayFormat:b,outputFormat:y,separator:_,months:S,presets:A,autoApply:F,inline:j,disabled:u,readonly:m,required:h})}'></div>
808
808
  ${I?`<div class="${this.options.helpClass}">${this.escapeHtml(I)}</div>`:""}
809
809
  ${oe?`<div class="${this.options.errorClass}">${this.escapeHtml(oe)}</div>`:""}
810
810
  </div>
811
- `}renderTimePickerField(e){const{name:t,label:s,value:i="",format:r="24h",step:n=1,min:a=null,max:o=null,placeholder:l,required:d=!1,disabled:h=!1,readonly:u=!1,timezone:m=!1,timezones:p=null,outputFormat:f="string",autoApply:g=!1,inline:b=!1,help:y=e.helpText||e.help||""}=e,C=this.getFieldId(t),_=this.errors[t],A=this.getFieldValue(t)??i;return`
811
+ `}renderTimePickerField(e){const{name:t,label:s,value:i="",format:r="24h",step:n=1,min:a=null,max:o=null,placeholder:l,required:d=!1,disabled:h=!1,readonly:u=!1,timezone:m=!1,timezones:p=null,outputFormat:f="string",autoApply:g=!1,inline:b=!1,help:y=e.helpText||e.help||""}=e,_=this.getFieldId(t),S=this.errors[t],A=this.getFieldValue(t)??i;return`
812
812
  <div class="mojo-form-control">
813
- ${s?`<label for="${C}" class="${this.options.labelClass}">${this.escapeHtml(s)}${d?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
813
+ ${s?`<label for="${_}" class="${this.options.labelClass}">${this.escapeHtml(s)}${d?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
814
814
  <div class="time-picker-placeholder"
815
815
  data-field-name="${t}"
816
816
  data-field-type="timepicker"
817
817
  data-field-config='${JSON.stringify({name:t,value:A,format:r,step:n,min:a,max:o,placeholder:l,timezone:m,timezones:p,outputFormat:f,autoApply:g,inline:b,disabled:h,readonly:u,required:d})}'></div>
818
818
  ${y?`<div class="${this.options.helpClass}">${this.escapeHtml(y)}</div>`:""}
819
- ${_?`<div class="${this.options.errorClass}">${this.escapeHtml(_)}</div>`:""}
819
+ ${S?`<div class="${this.options.errorClass}">${this.escapeHtml(S)}</div>`:""}
820
820
  </div>
821
- `}renderDateTimePickerField(e){const{name:t,label:s,value:i="",displayFormat:r=null,timeFormat:n="24h",timeStep:a=1,min:o=null,max:l=null,placeholder:d,required:h=!1,disabled:u=!1,readonly:m=!1,disabledDates:p=[],firstDay:f=1,lang:g="en-US",timezone:b=!1,timezones:y=null,outputFormat:C="string",autoApply:_=!1,inline:A=!1,help:F=e.helpText||e.help||""}=e,j=this.getFieldId(t),I=this.errors[t],R=this.getFieldValue(t)??i;return`
821
+ `}renderDateTimePickerField(e){const{name:t,label:s,value:i="",displayFormat:r=null,timeFormat:n="24h",timeStep:a=1,min:o=null,max:l=null,placeholder:d,required:h=!1,disabled:u=!1,readonly:m=!1,disabledDates:p=[],firstDay:f=1,lang:g="en-US",timezone:b=!1,timezones:y=null,outputFormat:_="string",autoApply:S=!1,inline:A=!1,help:F=e.helpText||e.help||""}=e,j=this.getFieldId(t),I=this.errors[t],O=this.getFieldValue(t)??i;return`
822
822
  <div class="mojo-form-control">
823
823
  ${s?`<label for="${j}" class="${this.options.labelClass}">${this.escapeHtml(s)}${h?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
824
824
  <div class="datetime-picker-placeholder"
825
825
  data-field-name="${t}"
826
826
  data-field-type="datetimepicker"
827
- data-field-config='${JSON.stringify({name:t,value:R,displayFormat:r,timeFormat:n,timeStep:a,min:o,max:l,placeholder:d,disabledDates:p,firstDay:f,lang:g,timezone:b,timezones:y,outputFormat:C,autoApply:_,inline:A,disabled:u,readonly:m,required:h})}'></div>
827
+ data-field-config='${JSON.stringify({name:t,value:O,displayFormat:r,timeFormat:n,timeStep:a,min:o,max:l,placeholder:d,disabledDates:p,firstDay:f,lang:g,timezone:b,timezones:y,outputFormat:_,autoApply:S,inline:A,disabled:u,readonly:m,required:h})}'></div>
828
828
  ${F?`<div class="${this.options.helpClass}">${this.escapeHtml(F)}</div>`:""}
829
829
  ${I?`<div class="${this.options.errorClass}">${this.escapeHtml(I)}</div>`:""}
830
830
  </div>
@@ -846,7 +846,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
846
846
  ${o?`<div class="${this.options.helpClass}">${this.escapeHtml(o)}</div>`:""}
847
847
  ${h?`<div class="${this.options.errorClass}">${this.escapeHtml(h)}</div>`:""}
848
848
  </div>
849
- `}renderTabsetField(e){const{tabs:t=[],name:s=`tabset-${Date.now()}`,variant:i,navClass:r,contentClass:n="tab-content"}=e,a=i&&Object.prototype.hasOwnProperty.call(O.VARIANT_CLASSES,i)?i:O.DEFAULT_VARIANT,o=r||O.VARIANT_CLASSES[a],l=String(s).toLowerCase().replace(/[^a-z0-9]/g,"-"),d=t.map((u,m)=>{const p=`${l}-pane-${m}`,f=m===0;return`
849
+ `}renderTabsetField(e){const{tabs:t=[],name:s=`tabset-${Date.now()}`,variant:i,navClass:r,contentClass:n="tab-content"}=e,a=i&&Object.prototype.hasOwnProperty.call(N.VARIANT_CLASSES,i)?i:N.DEFAULT_VARIANT,o=r||N.VARIANT_CLASSES[a],l=String(s).toLowerCase().replace(/[^a-z0-9]/g,"-"),d=t.map((u,m)=>{const p=`${l}-pane-${m}`,f=m===0;return`
850
850
  <li class="nav-item" role="presentation">
851
851
  <button class="nav-link ${f?"active":""}"
852
852
  id="${p}-tab"
@@ -878,7 +878,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
878
878
  ${h}
879
879
  </div>
880
880
  </div>
881
- `}generateSelectOptions(e,t,s=1,i={}){const{format:r,prefix:n="",suffix:a=""}=i,o=[],l=e<=t?Math.abs(s):-Math.abs(s);for(let d=e;e<=t?d<=t:d>=t;d+=l){let h=String(d);if(typeof r=="function")h=r(d);else if(r==="padded"||r==="pad"){const u=String(Math.max(Math.abs(e),Math.abs(t))).length;h=String(d).padStart(u,"0")}else r==="ordinal"&&(h=this.formatOrdinal(d));h=`${n}${h}${a}`,o.push({value:d,label:h})}return o}formatOrdinal(e){const t=e%10,s=e%100;return t===1&&s!==11?e+"st":t===2&&s!==12?e+"nd":t===3&&s!==13?e+"rd":e+"th"}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}renderTooltipIcon(e){return!e||!e.tooltip?"":` <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="${this.escapeHtml(e.tooltip)}" style="font-size: 0.75rem; cursor: help;"></i>`}}const Xt={enableFileDrop(c={}){if(this._fileDropConfig={acceptedTypes:c.acceptedTypes||["*/*"],maxFileSize:c.maxFileSize||10*1024*1024,dropZoneSelector:c.dropZoneSelector||null,visualFeedback:c.visualFeedback!==!1,multiple:c.multiple||!1,validateOnDrop:c.validateOnDrop!==!1,dragOverClass:c.dragOverClass||"drag-over",dragActiveClass:c.dragActiveClass||"drag-active"},this._fileDropState={isDragActive:!1,dragCounter:0},this._boundFileDropHandlers={dragEnter:this._onFileDropDragEnter.bind(this),dragOver:this._onFileDropDragOver.bind(this),dragLeave:this._onFileDropDragLeave.bind(this),drop:this._onFileDropDrop.bind(this),preventDefault:this._onFileDropPreventDefault.bind(this)},this.element)this._setupFileDropListeners();else{const t=this.onAfterRender.bind(this);this.onAfterRender=async()=>{await t(),this._setupFileDropListeners()}}const e=this.onBeforeDestroy.bind(this);this.onBeforeDestroy=async()=>{this._cleanupFileDropListeners(),await e()}},resolveMaxUploadSize(c,e){const t=[c,this.getApp?.()?.config?.max_upload_size,e];for(const s of t){const i=Number(s);if(Number.isFinite(i)&&i>0)return i}return 10*1024*1024},_setupFileDropListeners(){if(!this._fileDropConfig)return;const c=this._getFileDropZone();if(!c){console.warn("FileDropMixin: Drop zone not found");return}this._fileDropZone=c,c.addEventListener("dragenter",this._boundFileDropHandlers.dragEnter),c.addEventListener("dragover",this._boundFileDropHandlers.dragOver),c.addEventListener("dragleave",this._boundFileDropHandlers.dragLeave),c.addEventListener("drop",this._boundFileDropHandlers.drop),["dragenter","dragover","dragleave","drop"].forEach(e=>{document.addEventListener(e,this._boundFileDropHandlers.preventDefault)})},_cleanupFileDropListeners(){this._boundFileDropHandlers&&(this._fileDropZone&&(this._fileDropZone.removeEventListener("dragenter",this._boundFileDropHandlers.dragEnter),this._fileDropZone.removeEventListener("dragover",this._boundFileDropHandlers.dragOver),this._fileDropZone.removeEventListener("dragleave",this._boundFileDropHandlers.dragLeave),this._fileDropZone.removeEventListener("drop",this._boundFileDropHandlers.drop)),["dragenter","dragover","dragleave","drop"].forEach(c=>{document.removeEventListener(c,this._boundFileDropHandlers.preventDefault)}),this._fileDropZone=null,this._boundFileDropHandlers=null,this._fileDropConfig=null,this._fileDropState=null)},_getFileDropZone(){return this._fileDropConfig.dropZoneSelector?this.element.querySelector(this._fileDropConfig.dropZoneSelector):this.element},_onFileDropPreventDefault(c){c.preventDefault(),c.stopPropagation()},_onFileDropDragEnter(c){this._onFileDropPreventDefault(c),this._fileDropState.dragCounter++,this._fileDropState.isDragActive||(this._fileDropState.isDragActive=!0,this._applyFileDropVisualFeedback(!0))},_onFileDropDragOver(c){this._onFileDropPreventDefault(c),c.dataTransfer.dropEffect="copy"},_onFileDropDragLeave(c){this._onFileDropPreventDefault(c),this._fileDropState.dragCounter--,this._fileDropState.dragCounter<=0&&(this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1))},async _onFileDropDrop(c){this._onFileDropPreventDefault(c),this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1);const e=Array.from(c.dataTransfer.files);if(e.length===0)return;const t=this._fileDropConfig.multiple?e:[e[0]];let s={valid:!0,errors:[]};if(this._fileDropConfig.validateOnDrop&&(s=this._validateFileDropFiles(t),!s.valid)){typeof this.onFileDropError=="function"&&await this.onFileDropError(new Error(s.errors.join(", ")),c,t);return}if(typeof this.onFileDrop=="function")try{await this.onFileDrop(t,c,s)}catch(i){typeof this.onFileDropError=="function"?await this.onFileDropError(i,c,t):console.error("FileDropMixin: Error in onFileDrop callback:",i)}else console.warn("FileDropMixin: No onFileDrop method found on view")},_applyFileDropVisualFeedback(c){if(!this._fileDropConfig.visualFeedback||!this._fileDropZone)return;const{dragOverClass:e,dragActiveClass:t}=this._fileDropConfig;c?this._fileDropZone.classList.add(e,t):this._fileDropZone.classList.remove(e,t)},_validateFileDropFiles(c){const e=[],t=this._fileDropConfig;for(const s of c){if(!this._isFileDropTypeAccepted(s.type)){e.push(`File type "${s.type}" is not accepted for file "${s.name}"`);continue}s.size>t.maxFileSize&&e.push(`File "${s.name}" (${this._formatFileDropSize(s.size)}) exceeds maximum size (${this._formatFileDropSize(t.maxFileSize)})`)}return{valid:e.length===0,errors:e}},_isFileDropTypeAccepted(c){const{acceptedTypes:e}=this._fileDropConfig;return e.includes("*/*")?!0:e.some(t=>{if(t===c)return!0;if(t.endsWith("/*")){const s=t.split("/")[0];return c.startsWith(s+"/")}return!1})},_formatFileDropSize(c){if(c===0)return"0 Bytes";const e=1024,t=["Bytes","KB","MB","GB"],s=Math.floor(Math.log(c)/Math.log(e));return parseFloat((c/Math.pow(e,s)).toFixed(2))+" "+t[s]}};function es(c){Object.assign(c.prototype,Xt)}class Ve extends S{constructor(e={}){const{name:t,value:s="",placeholder:i="Add tags...",maxTags:r=50,allowDuplicates:n=!1,separator:a=",",trimTags:o=!0,minLength:l=1,maxLength:d=50,disabled:h=!1,readonly:u=!1,class:m="",tagClass:p="badge bg-primary",inputClass:f="form-control",...g}=e;super({tagName:"div",className:`tag-input-view ${m}`,...g}),this.name=t,this.placeholder=i,this.maxTags=r,this.allowDuplicates=n,this.separator=a,this.trimTags=o,this.minLength=l,this.maxLength=d,this.disabled=h,this.readonly=u,this.tagClass=p,this.inputClass=f,this.tags=[],this.focusedTagIndex=-1,s&&(this.tags=this.parseTagString(s))}async renderTemplate(){const e=this.renderTags(),t=this.renderHiddenInput(),s=this.renderInput();return`
881
+ `}generateSelectOptions(e,t,s=1,i={}){const{format:r,prefix:n="",suffix:a=""}=i,o=[],l=e<=t?Math.abs(s):-Math.abs(s);for(let d=e;e<=t?d<=t:d>=t;d+=l){let h=String(d);if(typeof r=="function")h=r(d);else if(r==="padded"||r==="pad"){const u=String(Math.max(Math.abs(e),Math.abs(t))).length;h=String(d).padStart(u,"0")}else r==="ordinal"&&(h=this.formatOrdinal(d));h=`${n}${h}${a}`,o.push({value:d,label:h})}return o}formatOrdinal(e){const t=e%10,s=e%100;return t===1&&s!==11?e+"st":t===2&&s!==12?e+"nd":t===3&&s!==13?e+"rd":e+"th"}escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}renderTooltipIcon(e){return!e||!e.tooltip?"":` <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="${this.escapeHtml(e.tooltip)}" style="font-size: 0.75rem; cursor: help;"></i>`}}const Xt={enableFileDrop(c={}){if(this._fileDropConfig={acceptedTypes:c.acceptedTypes||["*/*"],maxFileSize:c.maxFileSize||10*1024*1024,dropZoneSelector:c.dropZoneSelector||null,visualFeedback:c.visualFeedback!==!1,multiple:c.multiple||!1,validateOnDrop:c.validateOnDrop!==!1,dragOverClass:c.dragOverClass||"drag-over",dragActiveClass:c.dragActiveClass||"drag-active"},this._fileDropState={isDragActive:!1,dragCounter:0},this._boundFileDropHandlers={dragEnter:this._onFileDropDragEnter.bind(this),dragOver:this._onFileDropDragOver.bind(this),dragLeave:this._onFileDropDragLeave.bind(this),drop:this._onFileDropDrop.bind(this),preventDefault:this._onFileDropPreventDefault.bind(this)},this.element)this._setupFileDropListeners();else{const t=this.onAfterRender.bind(this);this.onAfterRender=async()=>{await t(),this._setupFileDropListeners()}}const e=this.onBeforeDestroy.bind(this);this.onBeforeDestroy=async()=>{this._cleanupFileDropListeners(),await e()}},resolveMaxUploadSize(c,e){const t=[c,this.getApp?.()?.config?.max_upload_size,e];for(const s of t){const i=Number(s);if(Number.isFinite(i)&&i>0)return i}return 10*1024*1024},_setupFileDropListeners(){if(!this._fileDropConfig)return;const c=this._getFileDropZone();if(!c){console.warn("FileDropMixin: Drop zone not found");return}this._fileDropZone=c,c.addEventListener("dragenter",this._boundFileDropHandlers.dragEnter),c.addEventListener("dragover",this._boundFileDropHandlers.dragOver),c.addEventListener("dragleave",this._boundFileDropHandlers.dragLeave),c.addEventListener("drop",this._boundFileDropHandlers.drop),["dragenter","dragover","dragleave","drop"].forEach(e=>{document.addEventListener(e,this._boundFileDropHandlers.preventDefault)})},_cleanupFileDropListeners(){this._boundFileDropHandlers&&(this._fileDropZone&&(this._fileDropZone.removeEventListener("dragenter",this._boundFileDropHandlers.dragEnter),this._fileDropZone.removeEventListener("dragover",this._boundFileDropHandlers.dragOver),this._fileDropZone.removeEventListener("dragleave",this._boundFileDropHandlers.dragLeave),this._fileDropZone.removeEventListener("drop",this._boundFileDropHandlers.drop)),["dragenter","dragover","dragleave","drop"].forEach(c=>{document.removeEventListener(c,this._boundFileDropHandlers.preventDefault)}),this._fileDropZone=null,this._boundFileDropHandlers=null,this._fileDropConfig=null,this._fileDropState=null)},_getFileDropZone(){return this._fileDropConfig.dropZoneSelector?this.element.querySelector(this._fileDropConfig.dropZoneSelector):this.element},_onFileDropPreventDefault(c){c.preventDefault(),c.stopPropagation()},_onFileDropDragEnter(c){this._onFileDropPreventDefault(c),this._fileDropState.dragCounter++,this._fileDropState.isDragActive||(this._fileDropState.isDragActive=!0,this._applyFileDropVisualFeedback(!0))},_onFileDropDragOver(c){this._onFileDropPreventDefault(c),c.dataTransfer.dropEffect="copy"},_onFileDropDragLeave(c){this._onFileDropPreventDefault(c),this._fileDropState.dragCounter--,this._fileDropState.dragCounter<=0&&(this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1))},async _onFileDropDrop(c){this._onFileDropPreventDefault(c),this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1);const e=Array.from(c.dataTransfer.files);if(e.length===0)return;const t=this._fileDropConfig.multiple?e:[e[0]];let s={valid:!0,errors:[]};if(this._fileDropConfig.validateOnDrop&&(s=this._validateFileDropFiles(t),!s.valid)){typeof this.onFileDropError=="function"&&await this.onFileDropError(new Error(s.errors.join(", ")),c,t);return}if(typeof this.onFileDrop=="function")try{await this.onFileDrop(t,c,s)}catch(i){typeof this.onFileDropError=="function"?await this.onFileDropError(i,c,t):console.error("FileDropMixin: Error in onFileDrop callback:",i)}else console.warn("FileDropMixin: No onFileDrop method found on view")},_applyFileDropVisualFeedback(c){if(!this._fileDropConfig.visualFeedback||!this._fileDropZone)return;const{dragOverClass:e,dragActiveClass:t}=this._fileDropConfig;c?this._fileDropZone.classList.add(e,t):this._fileDropZone.classList.remove(e,t)},_validateFileDropFiles(c){const e=[],t=this._fileDropConfig;for(const s of c){if(!this._isFileDropTypeAccepted(s.type)){e.push(`File type "${s.type}" is not accepted for file "${s.name}"`);continue}s.size>t.maxFileSize&&e.push(`File "${s.name}" (${this._formatFileDropSize(s.size)}) exceeds maximum size (${this._formatFileDropSize(t.maxFileSize)})`)}return{valid:e.length===0,errors:e}},_isFileDropTypeAccepted(c){const{acceptedTypes:e}=this._fileDropConfig;return e.includes("*/*")?!0:e.some(t=>{if(t===c)return!0;if(t.endsWith("/*")){const s=t.split("/")[0];return c.startsWith(s+"/")}return!1})},_formatFileDropSize(c){if(c===0)return"0 Bytes";const e=1024,t=["Bytes","KB","MB","GB"],s=Math.floor(Math.log(c)/Math.log(e));return parseFloat((c/Math.pow(e,s)).toFixed(2))+" "+t[s]}};function es(c){Object.assign(c.prototype,Xt)}class Ve extends C{constructor(e={}){const{name:t,value:s="",placeholder:i="Add tags...",maxTags:r=50,allowDuplicates:n=!1,separator:a=",",trimTags:o=!0,minLength:l=1,maxLength:d=50,disabled:h=!1,readonly:u=!1,class:m="",tagClass:p="badge bg-primary",inputClass:f="form-control",...g}=e;super({tagName:"div",className:`tag-input-view ${m}`,...g}),this.name=t,this.placeholder=i,this.maxTags=r,this.allowDuplicates=n,this.separator=a,this.trimTags=o,this.minLength=l,this.maxLength=d,this.disabled=h,this.readonly=u,this.tagClass=p,this.inputClass=f,this.tags=[],this.focusedTagIndex=-1,s&&(this.tags=this.parseTagString(s))}async renderTemplate(){const e=this.renderTags(),t=this.renderHiddenInput(),s=this.renderInput();return`
882
882
  <div class="tag-input-container">
883
883
  <div class="tag-input-wrapper border rounded p-2"
884
884
  data-action="focus-input"
@@ -924,7 +924,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
924
924
  value="${this.escapeHtml(this.getTagString())}"
925
925
  class="tag-input-hidden">
926
926
  `:""}async onAfterRender(){await super.onAfterRender(),this.updateTagCount()}async onActionFocusInput(e,t){this.focus()}focus(){const e=this.element.querySelector(".tag-input-field");e&&!this.disabled&&e.focus(),this.focusedTagIndex=-1}async onActionRemoveTag(e,t){e.stopPropagation();const s=parseInt(t.getAttribute("data-tag-index"));s>=0&&s<this.tags.length&&await this.removeTag(s)}async onChangeInputChange(e,t){const s=t.value,i=s.slice(-1);if(i===this.separator||i===`
927
- `){e.preventDefault();const r=s.slice(0,-1);r.trim()&&(await this.addTag(r),t.value="");return}}bindEvents(){this.__bnd_keydown||(this.__bnd_keydown=this.handleInputKeydown.bind(this)),this.element.addEventListener("keydown",this.__bnd_keydown),this.events.bind(this.element)}unbindEvents(){this.__bnd_keydown&&this.element.removeEventListener("keydown",this.__bnd_keydown),this.events.unbind()}handleInputKeydown(e){const t=e.target,s=t.value||"";switch(e.key){case"Enter":case"Tab":case",":s.trim()&&(e.preventDefault(),this.addTag(s),t.value="");break;case"Backspace":s===""&&this.tags.length>0&&(e.preventDefault(),this.focusedTagIndex>=0?(this.removeTag(this.focusedTagIndex),this.focusedTagIndex==0?this.focus():this.focusTag(this.focusedTagIndex-1)):this.removeTag(this.tags.length-1));break;case"ArrowLeft":if(s===""&&this.tags.length>0)if(e.preventDefault(),this.focusedTagIndex>=0){const i=this.focusedTagIndex-1;i>=0?this.focusTag(i):this.focus()}else this.focusTag(this.tags.length-1);break;case"ArrowRight":if(s===""&&this.tags.length>0)if(e.preventDefault(),this.focusedTagIndex>=0){const i=this.focusedTagIndex+1;i<this.tags.length?this.focusTag(i):this.focus()}else this.focusTag(0);break;case"Escape":t.value="",t.blur();break}}async addTag(e){if(this.readonly||this.disabled)return!1;const t=this.trimTags?e.trim():e;return this.isValidTag(t)?!this.allowDuplicates&&this.tags.includes(t)?(this.showTagError(`Tag "${t}" already exists`),!1):this.tags.length>=this.maxTags?(this.showTagError(`Maximum ${this.maxTags} tags allowed`),!1):(this.tags.push(t),await this.updateDisplay(),this.emit("tag:added",{tag:t,tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags}),!0):!1}async removeTag(e){if(this.readonly||this.disabled)return!1;if(e>=0&&e<this.tags.length){const t=this.tags[e];return this.tags.splice(e,1),await this.updateDisplay(),this.emit("tag:removed",{tag:t,tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags}),!0}return!1}async removeTagByValue(e){const t=this.tags.indexOf(e);return t>=0?await this.removeTag(t):!1}async clearTags(){if(this.readonly||this.disabled)return!1;const e=[...this.tags];return this.tags=[],await this.updateDisplay(),this.emit("tags:cleared",{oldTags:e}),this.emit("change",{value:"",tags:[]}),!0}async setTags(e){let t=[];Array.isArray(e)?t=e:typeof e=="string"&&(t=this.parseTagString(e)),t=t.filter(s=>this.isValidTag(s)).slice(0,this.maxTags),this.allowDuplicates||(t=[...new Set(t)]),this.tags=t,await this.updateDisplay(),this.emit("tags:set",{tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags})}isValidTag(e){return!(typeof e!="string"||e.length<this.minLength||e.length>this.maxLength||e.trim()==="")}parseTagString(e){return e?e.split(this.separator).map(t=>this.trimTags?t.trim():t).filter(t=>t.length>0):[]}getTagString(){return this.tags.join(this.separator)}getTags(){return[...this.tags]}focusTag(e){const t=this.element.querySelectorAll(".tag-item");t[e]&&(this.focusedTagIndex=e,console.log(`Focused tag index: ${e}`),t[e].focus())}async updateDisplay(){const e=this.element.querySelector(".tags-container");e&&(e.innerHTML=this.renderTags());const t=this.element.querySelector(".tag-input-hidden");t&&(t.value=this.getTagString()),this.updateTagCount()}updateTagCount(){const e=this.element.querySelector(".tag-count");e&&(e.textContent=this.tags.length)}showTagError(e){let t=this.element.querySelector(".tag-error");if(!t){t=document.createElement("div"),t.className="tag-error small text-danger mt-1";const s=this.element.querySelector(".tag-input-feedback");s&&s.parentNode.insertBefore(t,s.nextSibling)}t.textContent=e,setTimeout(()=>{t.parentNode&&t.remove()},3e3)}setEnabled(e){this.disabled=!e;const t=this.element.querySelector(".tag-input-field");t&&(t.disabled=this.disabled);const s=this.element.querySelector(".tag-input-wrapper");s&&s.classList.toggle("disabled",this.disabled)}setReadonly(e){this.readonly=e;const t=this.element.querySelector(".tag-input-field");t&&(t.style.display=e?"none":""),this.element.querySelectorAll(".tag-remove").forEach(i=>{i.style.display=e?"none":""})}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}getFormValue(){return this.getTagString()}async setFormValue(e){await this.setTags(e)}static create(e={}){return new Ve(e)}}class ts extends S{constructor(e={}){super({tagName:"div",className:"collection-dropdown-view dropdown-menu show w-100 position-absolute",style:"max-height: 250px; overflow-y: auto; z-index: 1000;",template:`
927
+ `){e.preventDefault();const r=s.slice(0,-1);r.trim()&&(await this.addTag(r),t.value="");return}}bindEvents(){this.__bnd_keydown||(this.__bnd_keydown=this.handleInputKeydown.bind(this)),this.element.addEventListener("keydown",this.__bnd_keydown),this.events.bind(this.element)}unbindEvents(){this.__bnd_keydown&&this.element.removeEventListener("keydown",this.__bnd_keydown),this.events.unbind()}handleInputKeydown(e){const t=e.target,s=t.value||"";switch(e.key){case"Enter":case"Tab":case",":s.trim()&&(e.preventDefault(),this.addTag(s),t.value="");break;case"Backspace":s===""&&this.tags.length>0&&(e.preventDefault(),this.focusedTagIndex>=0?(this.removeTag(this.focusedTagIndex),this.focusedTagIndex==0?this.focus():this.focusTag(this.focusedTagIndex-1)):this.removeTag(this.tags.length-1));break;case"ArrowLeft":if(s===""&&this.tags.length>0)if(e.preventDefault(),this.focusedTagIndex>=0){const i=this.focusedTagIndex-1;i>=0?this.focusTag(i):this.focus()}else this.focusTag(this.tags.length-1);break;case"ArrowRight":if(s===""&&this.tags.length>0)if(e.preventDefault(),this.focusedTagIndex>=0){const i=this.focusedTagIndex+1;i<this.tags.length?this.focusTag(i):this.focus()}else this.focusTag(0);break;case"Escape":t.value="",t.blur();break}}async addTag(e){if(this.readonly||this.disabled)return!1;const t=this.trimTags?e.trim():e;return this.isValidTag(t)?!this.allowDuplicates&&this.tags.includes(t)?(this.showTagError(`Tag "${t}" already exists`),!1):this.tags.length>=this.maxTags?(this.showTagError(`Maximum ${this.maxTags} tags allowed`),!1):(this.tags.push(t),await this.updateDisplay(),this.emit("tag:added",{tag:t,tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags}),!0):!1}async removeTag(e){if(this.readonly||this.disabled)return!1;if(e>=0&&e<this.tags.length){const t=this.tags[e];return this.tags.splice(e,1),await this.updateDisplay(),this.emit("tag:removed",{tag:t,tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags}),!0}return!1}async removeTagByValue(e){const t=this.tags.indexOf(e);return t>=0?await this.removeTag(t):!1}async clearTags(){if(this.readonly||this.disabled)return!1;const e=[...this.tags];return this.tags=[],await this.updateDisplay(),this.emit("tags:cleared",{oldTags:e}),this.emit("change",{value:"",tags:[]}),!0}async setTags(e){let t=[];Array.isArray(e)?t=e:typeof e=="string"&&(t=this.parseTagString(e)),t=t.filter(s=>this.isValidTag(s)).slice(0,this.maxTags),this.allowDuplicates||(t=[...new Set(t)]),this.tags=t,await this.updateDisplay(),this.emit("tags:set",{tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags})}isValidTag(e){return!(typeof e!="string"||e.length<this.minLength||e.length>this.maxLength||e.trim()==="")}parseTagString(e){return e?e.split(this.separator).map(t=>this.trimTags?t.trim():t).filter(t=>t.length>0):[]}getTagString(){return this.tags.join(this.separator)}getTags(){return[...this.tags]}focusTag(e){const t=this.element.querySelectorAll(".tag-item");t[e]&&(this.focusedTagIndex=e,console.log(`Focused tag index: ${e}`),t[e].focus())}async updateDisplay(){const e=this.element.querySelector(".tags-container");e&&(e.innerHTML=this.renderTags());const t=this.element.querySelector(".tag-input-hidden");t&&(t.value=this.getTagString()),this.updateTagCount()}updateTagCount(){const e=this.element.querySelector(".tag-count");e&&(e.textContent=this.tags.length)}showTagError(e){let t=this.element.querySelector(".tag-error");if(!t){t=document.createElement("div"),t.className="tag-error small text-danger mt-1";const s=this.element.querySelector(".tag-input-feedback");s&&s.parentNode.insertBefore(t,s.nextSibling)}t.textContent=e,setTimeout(()=>{t.parentNode&&t.remove()},3e3)}setEnabled(e){this.disabled=!e;const t=this.element.querySelector(".tag-input-field");t&&(t.disabled=this.disabled);const s=this.element.querySelector(".tag-input-wrapper");s&&s.classList.toggle("disabled",this.disabled)}setReadonly(e){this.readonly=e;const t=this.element.querySelector(".tag-input-field");t&&(t.style.display=e?"none":""),this.element.querySelectorAll(".tag-remove").forEach(i=>{i.style.display=e?"none":""})}escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}getFormValue(){return this.getTagString()}async setFormValue(e){await this.setTags(e)}static create(e={}){return new Ve(e)}}class ts extends C{constructor(e={}){super({tagName:"div",className:"collection-dropdown-view dropdown-menu show w-100 position-absolute",style:"max-height: 250px; overflow-y: auto; z-index: 1000;",template:`
928
928
  {{#data.loading}}
929
929
  <div class="dropdown-item text-center">
930
930
  <div class="spinner-border spinner-border-sm" role="status">
@@ -952,7 +952,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
952
952
  </div>
953
953
  {{/data.showNoResults}}
954
954
  {{/data.loading}}
955
- `,...e}),this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.selectedValue=e.selectedValue||"",this.loading=e.loading||!1,this.hasSearched=e.hasSearched||!1,this.focusedIndex=e.focusedIndex||-1}async getViewData(){const e=this.collection?this.collection.toJSON().map((t,s)=>{const i=$.getNestedValue(t,this.labelField),r=$.getNestedValue(t,this.valueField);return{...t,labelField:i,valueField:r,isSelected:r==this.selectedValue,isFocused:s===this.focusedIndex,index:s}}):[];return{loading:this.loading,hasSearched:this.hasSearched,showNoResults:!this.loading&&this.hasSearched&&e.length===0,items:e}}async handleActionSelectItem(e,t){e.preventDefault();const s=t.getAttribute("data-value"),i=t.getAttribute("data-label");this.emit("item-selected",{value:s,label:i})}updateState(e){Object.assign(this,e)}updateFocusedItem(e){this.focusedIndex=e,this.element?.querySelectorAll('.dropdown-item[data-action="select-item"]')?.forEach((s,i)=>{s.classList.toggle("bg-light",i===this.focusedIndex)})}getItemCount(){return this.collection?this.collection.length():0}getFocusedItem(){return this.focusedIndex>=0&&this.collection&&this.collection.toJSON()[this.focusedIndex]||null}}class ss extends S{constructor(e={}){super({className:"collection-select-view",template:`
955
+ `,...e}),this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.selectedValue=e.selectedValue||"",this.loading=e.loading||!1,this.hasSearched=e.hasSearched||!1,this.focusedIndex=e.focusedIndex||-1}async getViewData(){const e=this.collection?this.collection.toJSON().map((t,s)=>{const i=$.getNestedValue(t,this.labelField),r=$.getNestedValue(t,this.valueField);return{...t,labelField:i,valueField:r,isSelected:r==this.selectedValue,isFocused:s===this.focusedIndex,index:s}}):[];return{loading:this.loading,hasSearched:this.hasSearched,showNoResults:!this.loading&&this.hasSearched&&e.length===0,items:e}}async handleActionSelectItem(e,t){e.preventDefault();const s=t.getAttribute("data-value"),i=t.getAttribute("data-label");this.emit("item-selected",{value:s,label:i})}updateState(e){Object.assign(this,e)}updateFocusedItem(e){this.focusedIndex=e,this.element?.querySelectorAll('.dropdown-item[data-action="select-item"]')?.forEach((s,i)=>{s.classList.toggle("bg-light",i===this.focusedIndex)})}getItemCount(){return this.collection?this.collection.length():0}getFocusedItem(){return this.focusedIndex>=0&&this.collection&&this.collection.toJSON()[this.focusedIndex]||null}}class ss extends C{constructor(e={}){super({className:"collection-select-view",template:`
956
956
  <div class="position-relative">
957
957
  <input type="text"
958
958
  class="form-control {{#data.hasError}}is-invalid{{/data.hasError}} {{#data.showClear}}pe-5{{/data.showClear}}"
@@ -980,14 +980,14 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
980
980
  <div class="invalid-feedback">{{data.errorMessage}}</div>
981
981
  {{/data.hasError}}
982
982
  </div>
983
- `,...e}),this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.maxItems=e.maxItems||10,this.placeholder=e.placeholder||"Search...",this.debounceMs=e.debounceMs||400,this.name=e.name||"collection_select",this.emptyFetch=e.emptyFetch!==!1,this.requiresActiveGroup=e.requiresActiveGroup||!1,this.selectedValue=e.value||"0",this.selectedLabel="",this.searchValue="",this.showDropdown=!1,this.loading=!1,this.hasSearched=!1,this.focusedIndex=-1,this.hasError=!1,this.errorMessage="",this.selectedValue&&typeof this.selectedValue=="object"&&(this.selectedLabel=$.getNestedValue(this.selectedValue,this.labelField)||"",this.selectedValue=$.getNestedValue(this.selectedValue,this.valueField)||"0"),this.searchTimer=null,this.dropdownView=null,this.defaultParams={},this.defaultParamsOption=e.defaultParams||null,this.handleDocumentClick=this.handleDocumentClick.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleInputEvents=this.handleInputEvents.bind(this)}onInit(){this.collection&&this.setupCollection()}setupCollection(){if(this.defaultParams={...this.collection.params},this.collection.params.size=this.maxItems,this.defaultParams.size=this.maxItems,this.defaultParamsOption){const e=typeof this.defaultParamsOption=="function"?this.defaultParamsOption():this.defaultParamsOption;e&&typeof e=="object"&&(Object.assign(this.defaultParams,e),Object.assign(this.collection.params,e))}if(this.requiresActiveGroup){const e=this.getApp();e&&e.activeGroup&&e.activeGroup.id&&(this.collection.params.group=e.activeGroup.id,this.defaultParams.group=e.activeGroup.id)}this.collection.on("fetch:start",()=>{this.loading=!0,this.showDropdown=!0,this.updateDropdown()}),this.collection.on("fetch:end",()=>{this.loading=!1,this.showDropdown=!0,this.updateDropdown()}),this.selectedValue&&this.loadSelectedItem(),this.emptyFetch&&this.collection.isEmpty()&&this.performInitialFetch()}async performInitialFetch(){if(this.collection)try{const e={...this.defaultParams};delete e.search,await this.collection.updateParams(e,!0)}catch(e){console.error("Initial fetch error:",e)}}async loadSelectedItem(){try{if(!this.selectedValue||this.selectedValue=="0"||this.selectedLabel)return;const e=this.collection?.get(this.selectedValue);if(e){this.selectedLabel=this.getFieldValue(e,this.labelField),this.render(!1);return}let t=await this.collection.fetchOne(this.selectedValue);t&&(this.selectedLabel=this.getFieldValue(t,this.labelField)||`${t.constructor.name} #${t.id}`,this.render(!1))}catch(e){console.error("Error loading selected item:",e)}}async getViewData(){let e="";return this.showDropdown&&this.hasSearched?e=this.searchValue:this.selectedValue&&this.selectedLabel&&(e=this.selectedLabel),{name:this.name,placeholder:this.placeholder,displayValue:e,selectedValue:this.selectedValue,showClear:!!(this.selectedValue&&this.selectedValue!=="0"&&this.selectedLabel),hasError:this.hasError,errorMessage:this.errorMessage}}async onAfterRender(){await super.onAfterRender();const e=this.getInput();e&&(e.addEventListener("input",this.handleInputEvents),e.addEventListener("focus",this.handleInputEvents),e.addEventListener("keydown",this.handleKeyDown)),document.addEventListener("click",this.handleDocumentClick),this.createDropdownView()}async onBeforeDestroy(){await super.onBeforeDestroy();const e=this.getInput();e&&(e.removeEventListener("input",this.handleInputEvents),e.removeEventListener("focus",this.handleInputEvents),e.removeEventListener("keydown",this.handleKeyDown)),document.removeEventListener("click",this.handleDocumentClick),this.searchTimer&&clearTimeout(this.searchTimer),this.dropdownView&&this.dropdownView.destroy()}createDropdownView(){this.dropdownView&&this.dropdownView.destroy(),this.dropdownView=new ts({collection:this.collection,labelField:this.labelField,valueField:this.valueField,selectedValue:this.selectedValue,loading:this.loading,hasSearched:this.hasSearched,focusedIndex:this.focusedIndex}),this.dropdownView.on("item-selected",e=>{this.selectItem(e.value,e.label)})}async handleInputEvents(e){const t=e.target;e.type==="focus"?(this.showDropdown=!0,!this.hasSearched&&this.emptyFetch&&this.collection?.isEmpty()&&this.performInitialFetch(),this.updateDropdown()):e.type==="input"&&(this.searchValue=t.value,this.showDropdown=!0,this.hasSearched=!0,this.focusedIndex=-1,this.searchValue!==this.selectedLabel&&(this.selectedValue="0",this.selectedLabel="",this.emit("change",{value:"0",label:""})),this.searchTimer&&clearTimeout(this.searchTimer),this.searchTimer=setTimeout(()=>{this.performSearch()},this.debounceMs),this.updateDropdown())}async handleActionClearSelection(e,t){e.preventDefault(),e.stopPropagation(),this.clearSelection()}clearSelection(){this.selectedValue="0",this.selectedLabel="",this.searchValue="",this.showDropdown=!1,this.hasError=!1,this.focusedIndex=-1,this.hasSearched=!1;const e=this.getInput();e&&(e.value="",e.focus());const t=this.getHiddenInput();t&&(t.value="0"),this.updateDropdown(),this.render(),this.emit("change",{value:"0",label:""})}async performSearch(){if(this.collection)try{const e={...this.defaultParams};this.searchValue&&this.searchValue.trim()&&(e.search=this.searchValue.trim()),await this.collection.updateParams(e,!0)}catch(e){console.error("Search error:",e),this.loading=!1,this.updateDropdown()}}updateDropdown(){if(this.dropdownView)if(this.dropdownView.updateState({selectedValue:this.selectedValue,loading:this.loading,hasSearched:this.hasSearched,focusedIndex:this.focusedIndex}),this.showDropdown)if(this.dropdownView.isMounted())this.dropdownView.render();else{const e=this.element?.querySelector(".dropdown-container");e&&this.dropdownView.render(!0,e)}else this.dropdownView.isMounted()&&(this.dropdownView.destroy(),this.createDropdownView())}selectItem(e,t){this.selectedValue=e,this.selectedLabel=t,this.searchValue="",this.showDropdown=!1,this.hasError=!1,this.focusedIndex=-1,this.hasSearched=!1;const s=this.getInput();s&&(s.value=t);const i=this.getHiddenInput();i&&(i.value=e),this.updateDropdown(),this.emit("change",{value:e,label:t})}handleDocumentClick(e){this.element?.contains(e.target)||(this.showDropdown=!1,this.focusedIndex=-1,this.updateDropdown())}handleKeyDown(e){if(!this.showDropdown||!this.collection)return;const t=this.dropdownView?.getItemCount()||0;switch(e.key){case"ArrowDown":e.preventDefault(),this.focusedIndex=Math.min(this.focusedIndex+1,t-1),this.dropdownView?.updateFocusedItem(this.focusedIndex);break;case"ArrowUp":e.preventDefault(),this.focusedIndex=Math.max(this.focusedIndex-1,0),this.dropdownView?.updateFocusedItem(this.focusedIndex);break;case"Enter":{e.preventDefault();const s=this.dropdownView?.getFocusedItem();s&&this.selectItem(s[this.valueField],s[this.labelField]);break}case"Escape":e.preventDefault(),this.showDropdown=!1,this.focusedIndex=-1,this.updateDropdown();break}}getInput(){return this.element?.querySelector('input[type="text"]')}getHiddenInput(){return this.element?.querySelector('input[type="hidden"]')}setValue(e,t=""){this.selectedValue=e,this.selectedLabel=t,this.searchValue="",this.hasError=!1,this.hasSearched=!1;const s=this.getInput();s&&(s.value=t);const i=this.getHiddenInput();i&&(i.value=e)}getValue(){return this.selectedValue===0||this.selectedValue==="0"?null:this.selectedValue}getLabel(){return this.selectedLabel}setError(e){this.hasError=!0,this.errorMessage=e,this.render()}clearError(){this.hasError=!1,this.errorMessage="",this.render()}focus(){const e=this.getInput();e&&e.focus()}getFormValue(){return this.selectedValue===0||this.selectedValue==="0"?null:this.selectedValue}setFormValue(e){let t=e,s="";t&&typeof t=="object"&&(s=$.getNestedValue(t,this.labelField)||"",t=$.getNestedValue(t,this.valueField)),t=t||"0",t!=this.selectedValue&&(this.selectedValue=t,this.selectedLabel=s,this.searchValue="",this.hasSearched=!1,this.showDropdown=!1,this.hasError=!1,this.selectedValue&&this.selectedValue!=="0"?(this.selectedLabel||(this.selectedLabel=`${this.collection.getModelName()} #${this.selectedValue}`),this.loadSelectedItem()):this.render())}getFieldValue(e,t){if(!(!e||!t)){if(typeof e.get=="function"){const s=e.get(t);return s===void 0&&t.includes(".")?$.getNestedValue(e,t):s}return $.getNestedValue(e,t)}}}class is extends S{constructor(e={}){super({tagName:"div",className:"collection-multiselect-search",template:`
983
+ `,...e}),this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.maxItems=e.maxItems||10,this.placeholder=e.placeholder||"Search...",this.debounceMs=e.debounceMs||400,this.name=e.name||"collection_select",this.emptyFetch=e.emptyFetch!==!1,this.requiresActiveGroup=e.requiresActiveGroup||!1,this.selectedValue=e.value||"0",this.selectedLabel="",this.searchValue="",this.showDropdown=!1,this.loading=!1,this.hasSearched=!1,this.focusedIndex=-1,this.hasError=!1,this.errorMessage="",this.selectedValue&&typeof this.selectedValue=="object"&&(this.selectedLabel=$.getNestedValue(this.selectedValue,this.labelField)||"",this.selectedValue=$.getNestedValue(this.selectedValue,this.valueField)||"0"),this.searchTimer=null,this.dropdownView=null,this.defaultParams={},this.defaultParamsOption=e.defaultParams||null,this.handleDocumentClick=this.handleDocumentClick.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleInputEvents=this.handleInputEvents.bind(this)}onInit(){this.collection&&this.setupCollection()}setupCollection(){if(this.defaultParams={...this.collection.params},this.collection.params.size=this.maxItems,this.defaultParams.size=this.maxItems,this.defaultParamsOption){const e=typeof this.defaultParamsOption=="function"?this.defaultParamsOption():this.defaultParamsOption;e&&typeof e=="object"&&(Object.assign(this.defaultParams,e),Object.assign(this.collection.params,e))}if(this.requiresActiveGroup){const e=this.getApp();e&&e.activeGroup&&e.activeGroup.id&&(this.collection.params.group=e.activeGroup.id,this.defaultParams.group=e.activeGroup.id)}this.collection.on("fetch:start",()=>{this.loading=!0,this.showDropdown=!0,this.updateDropdown()}),this.collection.on("fetch:end",()=>{this.loading=!1,this.showDropdown=!0,this.updateDropdown()}),this.selectedValue&&this.loadSelectedItem(),this.emptyFetch&&this.collection.isEmpty()&&this.performInitialFetch()}async performInitialFetch(){if(this.collection)try{const e={...this.defaultParams};delete e.search,await this.collection.updateParams(e,!0)}catch(e){console.error("Initial fetch error:",e)}}async loadSelectedItem(){try{if(!this.selectedValue||this.selectedValue=="0"||this.selectedLabel)return;const e=this.collection?.get(this.selectedValue);if(e){this.selectedLabel=this.getFieldValue(e,this.labelField),this.render(!1);return}let t=await this.collection.fetchOne(this.selectedValue);t&&(this.selectedLabel=this.getFieldValue(t,this.labelField)||`${t.constructor.name} #${t.id}`,this.render(!1))}catch(e){console.error("Error loading selected item:",e)}}async getViewData(){let e="";return this.showDropdown&&this.hasSearched?e=this.searchValue:this.selectedValue&&this.selectedLabel&&(e=this.selectedLabel),{name:this.name,placeholder:this.placeholder,displayValue:e,selectedValue:this.selectedValue,showClear:!!(this.selectedValue&&this.selectedValue!=="0"&&this.selectedLabel),hasError:this.hasError,errorMessage:this.errorMessage}}async onAfterRender(){await super.onAfterRender();const e=this.getInput();e&&(e.addEventListener("input",this.handleInputEvents),e.addEventListener("focus",this.handleInputEvents),e.addEventListener("keydown",this.handleKeyDown)),document.addEventListener("click",this.handleDocumentClick),this.createDropdownView()}async onBeforeDestroy(){await super.onBeforeDestroy();const e=this.getInput();e&&(e.removeEventListener("input",this.handleInputEvents),e.removeEventListener("focus",this.handleInputEvents),e.removeEventListener("keydown",this.handleKeyDown)),document.removeEventListener("click",this.handleDocumentClick),this.searchTimer&&clearTimeout(this.searchTimer),this.dropdownView&&this.dropdownView.destroy()}createDropdownView(){this.dropdownView&&this.dropdownView.destroy(),this.dropdownView=new ts({collection:this.collection,labelField:this.labelField,valueField:this.valueField,selectedValue:this.selectedValue,loading:this.loading,hasSearched:this.hasSearched,focusedIndex:this.focusedIndex}),this.dropdownView.on("item-selected",e=>{this.selectItem(e.value,e.label)})}async handleInputEvents(e){const t=e.target;e.type==="focus"?(this.showDropdown=!0,!this.hasSearched&&this.emptyFetch&&this.collection?.isEmpty()&&this.performInitialFetch(),this.updateDropdown()):e.type==="input"&&(this.searchValue=t.value,this.showDropdown=!0,this.hasSearched=!0,this.focusedIndex=-1,this.searchValue!==this.selectedLabel&&(this.selectedValue="0",this.selectedLabel="",this.emit("change",{value:"0",label:""})),this.searchTimer&&clearTimeout(this.searchTimer),this.searchTimer=setTimeout(()=>{this.performSearch()},this.debounceMs),this.updateDropdown())}async handleActionClearSelection(e,t){e.preventDefault(),e.stopPropagation(),this.clearSelection()}clearSelection(){this.selectedValue="0",this.selectedLabel="",this.searchValue="",this.showDropdown=!1,this.hasError=!1,this.focusedIndex=-1,this.hasSearched=!1;const e=this.getInput();e&&(e.value="",e.focus());const t=this.getHiddenInput();t&&(t.value="0"),this.updateDropdown(),this.render(),this.emit("change",{value:"0",label:""})}async performSearch(){if(this.collection)try{const e={...this.defaultParams};this.searchValue&&this.searchValue.trim()&&(e.search=this.searchValue.trim()),await this.collection.updateParams(e,!0)}catch(e){console.error("Search error:",e),this.loading=!1,this.updateDropdown()}}updateDropdown(){if(this.dropdownView)if(this.dropdownView.updateState({selectedValue:this.selectedValue,loading:this.loading,hasSearched:this.hasSearched,focusedIndex:this.focusedIndex}),this.showDropdown)if(this.dropdownView.isMounted())this.dropdownView.render();else{const e=this.element?.querySelector(".dropdown-container");e&&this.dropdownView.render(!0,e)}else this.dropdownView.isMounted()&&(this.dropdownView.destroy(),this.createDropdownView())}selectItem(e,t){this.selectedValue=e,this.selectedLabel=t,this.searchValue="",this.showDropdown=!1,this.hasError=!1,this.focusedIndex=-1,this.hasSearched=!1;const s=this.getInput();s&&(s.value=t);const i=this.getHiddenInput();i&&(i.value=e),this.updateDropdown(),this.emit("change",{value:e,label:t})}handleDocumentClick(e){this.element?.contains(e.target)||(this.showDropdown=!1,this.focusedIndex=-1,this.updateDropdown())}handleKeyDown(e){if(!this.showDropdown||!this.collection)return;const t=this.dropdownView?.getItemCount()||0;switch(e.key){case"ArrowDown":e.preventDefault(),this.focusedIndex=Math.min(this.focusedIndex+1,t-1),this.dropdownView?.updateFocusedItem(this.focusedIndex);break;case"ArrowUp":e.preventDefault(),this.focusedIndex=Math.max(this.focusedIndex-1,0),this.dropdownView?.updateFocusedItem(this.focusedIndex);break;case"Enter":{e.preventDefault();const s=this.dropdownView?.getFocusedItem();s&&this.selectItem(s[this.valueField],s[this.labelField]);break}case"Escape":e.preventDefault(),this.showDropdown=!1,this.focusedIndex=-1,this.updateDropdown();break}}getInput(){return this.element?.querySelector('input[type="text"]')}getHiddenInput(){return this.element?.querySelector('input[type="hidden"]')}setValue(e,t=""){this.selectedValue=e,this.selectedLabel=t,this.searchValue="",this.hasError=!1,this.hasSearched=!1;const s=this.getInput();s&&(s.value=t);const i=this.getHiddenInput();i&&(i.value=e)}getValue(){return this.selectedValue===0||this.selectedValue==="0"?null:this.selectedValue}getLabel(){return this.selectedLabel}setError(e){this.hasError=!0,this.errorMessage=e,this.render()}clearError(){this.hasError=!1,this.errorMessage="",this.render()}focus(){const e=this.getInput();e&&e.focus()}getFormValue(){return this.selectedValue===0||this.selectedValue==="0"?null:this.selectedValue}setFormValue(e){let t=e,s="";t&&typeof t=="object"&&(s=$.getNestedValue(t,this.labelField)||"",t=$.getNestedValue(t,this.valueField)),t=t||"0",t!=this.selectedValue&&(this.selectedValue=t,this.selectedLabel=s,this.searchValue="",this.hasSearched=!1,this.showDropdown=!1,this.hasError=!1,this.selectedValue&&this.selectedValue!=="0"?(this.selectedLabel||(this.selectedLabel=`${this.collection.getModelName()} #${this.selectedValue}`),this.loadSelectedItem()):this.render())}getFieldValue(e,t){if(!(!e||!t)){if(typeof e.get=="function"){const s=e.get(t);return s===void 0&&t.includes(".")?$.getNestedValue(e,t):s}return $.getNestedValue(e,t)}}}class is extends C{constructor(e={}){super({tagName:"div",className:"collection-multiselect-search",template:`
984
984
  <input type="text"
985
985
  class="form-control form-control-sm mb-2"
986
986
  placeholder="{{placeholder}}"
987
987
  data-change-action="search"
988
988
  data-filter="live-search"
989
989
  data-filter-debounce="{{debounce}}" />
990
- `,...e}),this.placeholder=e.placeholder||"Search...",this.debounce=e.debounce||400}async onChangeSearch(e,t){const s=t.value.trim();this.emit("search",s)}getValue(){return this.element?.querySelector("input")?.value||""}clear(){const e=this.element?.querySelector("input");e&&(e.value="")}}class rs extends S{constructor(e={}){const s=!!e.customItemTemplate?"{{{customContent}}}":'<span {{#disabled}}class="text-muted"{{/disabled}}>{{label}}</span>';super({tagName:"div",className:"collection-multiselect-items",template:`
990
+ `,...e}),this.placeholder=e.placeholder||"Search...",this.debounce=e.debounce||400}async onChangeSearch(e,t){const s=t.value.trim();this.emit("search",s)}getValue(){return this.element?.querySelector("input")?.value||""}clear(){const e=this.element?.querySelector("input");e&&(e.value="")}}class rs extends C{constructor(e={}){const s=!!e.customItemTemplate?"{{{customContent}}}":'<span {{#disabled}}class="text-muted"{{/disabled}}>{{label}}</span>';super({tagName:"div",className:"collection-multiselect-items",template:`
991
991
  {{#loading}}
992
992
  <div class="text-center py-3">
993
993
  <div class="spinner-border spinner-border-sm" role="status">
@@ -1039,7 +1039,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1039
1039
  </div>
1040
1040
  {{/^items.length}}
1041
1041
  {{/loading}}
1042
- `,...e}),this.items=e.items||[],this.loading=e.loading||!1,this.maxHeight=e.maxHeight||336,this.showSelectAll=e.showSelectAll!==!1,this.selectedCount=e.selectedCount||0,this.totalCount=e.totalCount||0,this.unselectedCount=e.unselectedCount||0,this.allSelected=e.allSelected||!1,this.noneSelected=e.noneSelected||!0,this.customItemTemplate=e.customItemTemplate||null,this.lastClickedIndex=-1}handleActionToggle(e,t){const s=t.getAttribute("data-value"),i=parseInt(t.getAttribute("data-index"),10);this.emit("toggle",{value:s,index:i,shiftKey:e.shiftKey,element:t}),this.lastClickedIndex=i}updateItemCheckbox(e,t){const s=e.querySelector("i.bi");s&&(t?(s.classList.remove("bi-square"),s.classList.add("bi-check-square-fill","text-primary")):(s.classList.remove("bi-check-square-fill","text-primary"),s.classList.add("bi-square")))}updateActionButtons(){const e=this.element?.querySelector('[data-action="select-all"]'),t=this.element?.querySelector('[data-action="deselect-all"]');e&&(e.querySelector("span"),this.allSelected?(e.classList.add("text-muted"),e.disabled=!0):(e.classList.remove("text-muted"),e.disabled=!1)),t&&(this.noneSelected?(t.classList.add("text-muted"),t.disabled=!0):(t.classList.remove("text-muted"),t.disabled=!1))}async handleActionSelectAll(e){e.preventDefault(),this.emit("select-all")}async handleActionDeselectAll(e){e.preventDefault(),this.emit("deselect-all")}updateState(e){Object.assign(this,e)}}class ns extends S{constructor(e={}){super({tagName:"div",className:"collection-multiselect-view",template:`
1042
+ `,...e}),this.items=e.items||[],this.loading=e.loading||!1,this.maxHeight=e.maxHeight||336,this.showSelectAll=e.showSelectAll!==!1,this.selectedCount=e.selectedCount||0,this.totalCount=e.totalCount||0,this.unselectedCount=e.unselectedCount||0,this.allSelected=e.allSelected||!1,this.noneSelected=e.noneSelected||!0,this.customItemTemplate=e.customItemTemplate||null,this.lastClickedIndex=-1}handleActionToggle(e,t){const s=t.getAttribute("data-value"),i=parseInt(t.getAttribute("data-index"),10);this.emit("toggle",{value:s,index:i,shiftKey:e.shiftKey,element:t}),this.lastClickedIndex=i}updateItemCheckbox(e,t){const s=e.querySelector("i.bi");s&&(t?(s.classList.remove("bi-square"),s.classList.add("bi-check-square-fill","text-primary")):(s.classList.remove("bi-check-square-fill","text-primary"),s.classList.add("bi-square")))}updateActionButtons(){const e=this.element?.querySelector('[data-action="select-all"]'),t=this.element?.querySelector('[data-action="deselect-all"]');e&&(e.querySelector("span"),this.allSelected?(e.classList.add("text-muted"),e.disabled=!0):(e.classList.remove("text-muted"),e.disabled=!1)),t&&(this.noneSelected?(t.classList.add("text-muted"),t.disabled=!0):(t.classList.remove("text-muted"),t.disabled=!1))}async handleActionSelectAll(e){e.preventDefault(),this.emit("select-all")}async handleActionDeselectAll(e){e.preventDefault(),this.emit("deselect-all")}updateState(e){Object.assign(this,e)}}class ns extends C{constructor(e={}){super({tagName:"div",className:"collection-multiselect-view",template:`
1043
1043
  <div class="mojo-form-control">
1044
1044
  {{#label}}
1045
1045
  <label class="form-label">
@@ -1057,7 +1057,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1057
1057
  <div class="invalid-feedback d-block">{{error}}</div>
1058
1058
  {{/error}}
1059
1059
  </div>
1060
- `,...e}),this.name=e.name||"collection_multiselect",this.label=e.label||"",this.help=e.help||"",this.error=e.error||"",this.required=e.required||!1,this.disabled=e.disabled||!1,this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.excludeIds=e.excludeIds||[],this.ignoreIds=e.ignoreIds||[],this.itemTemplate=e.itemTemplate||null,this.collectionParams=e.collectionParams||{},this.defaultParamsOption=e.defaultParams||null,this.baseParams={},this.requiresActiveGroup=e.requiresActiveGroup||!1,this.size=e.size||8,this.maxHeight=e.maxHeight||this.size*42,this.showSelectAll=e.showSelectAll!==!1,this.enableSearch=e.enableSearch||!1,this.searchPlaceholder=e.searchPlaceholder||"Search...",this.searchDebounce=e.searchDebounce||400,this.selectedValues=Array.isArray(e.value)?e.value:[],this.loading=!1,this.items=[],this.searchView=null,this.listView=null}onInit(){this.collection&&this.setupCollection()}setupCollection(){if(this.baseParams={...this.collection.params},Object.keys(this.collectionParams).length>0&&(Object.assign(this.baseParams,this.collectionParams),Object.assign(this.collection.params,this.collectionParams)),this.defaultParamsOption){const e=typeof this.defaultParamsOption=="function"?this.defaultParamsOption():this.defaultParamsOption;e&&(Object.assign(this.baseParams,e),Object.assign(this.collection.params,e))}if(this.requiresActiveGroup){const e=this.getApp();e?.activeGroup?.id&&(this.baseParams.group=e.activeGroup.id,this.collection.params.group=e.activeGroup.id)}this.collection.on("fetch:start",()=>{this.loading=!0,this.updateListView()}),this.collection.on("fetch:end",()=>{this.loading=!1,this.buildItems(),this.updateListView()}),this.collection.isEmpty()||this.buildItems()}async onAfterRender(){await super.onAfterRender(),this.enableSearch&&this.createSearchView(),this.createListView(),this.collection?.isEmpty()&&this.collection.fetch()}createSearchView(){const e=this.element?.querySelector(".collection-multiselect-search-container");e&&(this.searchView=new is({placeholder:this.searchPlaceholder,debounce:this.searchDebounce}),this.searchView.on("search",t=>{this.handleSearch(t)}),this.searchView.render(!0,e))}createListView(){const e=this.element?.querySelector(".collection-multiselect-list-container");if(!e)return;const t=this.selectedValues.length,s=this.items.length,i=s-t;this.listView=new rs({items:this.items,loading:this.loading,maxHeight:this.maxHeight,showSelectAll:this.showSelectAll,selectedCount:t,totalCount:s,unselectedCount:i,allSelected:t===s&&s>0,noneSelected:t===0,customItemTemplate:this.itemTemplate}),this.listView.on("toggle",r=>{this.handleToggle(r)}),this.listView.on("select-all",()=>{this.selectAll()}),this.listView.on("deselect-all",()=>{this.deselectAll()}),this.listView.render(!0,e)}updateListView(){if(this.listView){const e=this.selectedValues.length,t=this.items.length,s=t-e;this.listView.updateState({items:this.items,loading:this.loading,selectedCount:e,totalCount:t,unselectedCount:s,allSelected:e===t&&t>0,noneSelected:e===0}),this.listView.render(!1)}}buildItems(){const e=this.collection.models.filter(t=>{const s=this.getFieldValue(t,this.valueField);return!(s==null||this.excludeIds.includes(s)||this.ignoreIds.some(i=>i==s))});this.items=e.map((t,s)=>{const i=t.toJSON?t.toJSON():t,r=this.getFieldValue(t,this.valueField),n={label:this.getFieldValue(t,this.labelField),value:r,index:s,selected:this.selectedValues.some(a=>a==r),disabled:this.disabled,model:i};return this.itemTemplate&&(n.customContent=this.renderItemTemplate(n)),n})}renderItemTemplate(e){if(!this.itemTemplate)return"";try{return this.renderTemplateString(this.itemTemplate,e)}catch(t){return console.error("Error rendering item template:",t),e.label}}getFieldValue(e,t){if(!(!e||!t))return typeof e.get=="function"?e.get(t)??$.getNestedValue(e,t):$.getNestedValue(e,t)}handleSearch(e){const t={...this.baseParams};e&&(t.search=e),this.collection.updateParams(t,!0)}handleToggle({value:e,index:t,shiftKey:s,element:i}){if(s&&this.listView.lastClickedIndex>=0){const r=Math.min(this.listView.lastClickedIndex,t),n=Math.max(this.listView.lastClickedIndex,t),a=!this.items[t].selected;for(let o=r;o<=n;o++){const l=this.items[o];l.disabled||(a?this.selectedValues.includes(l.value)||this.selectedValues.push(l.value):this.selectedValues=this.selectedValues.filter(d=>d!=l.value),l.selected=a)}this.updateListView()}else{const r=this.items[t];r.selected?(this.selectedValues=this.selectedValues.filter(n=>n!=e),r.selected=!1):(this.selectedValues.push(e),r.selected=!0),i&&this.listView&&(this.listView.updateItemCheckbox(i,r.selected),this.listView.selectedCount=this.selectedValues.length,this.listView.unselectedCount=this.items.length-this.selectedValues.length,this.listView.allSelected=this.selectedValues.length===this.items.length&&this.items.length>0,this.listView.noneSelected=this.selectedValues.length===0,this.listView.updateActionButtons())}this.emit("change",{value:this.selectedValues,name:this.name})}selectAll(){this.selectedValues=this.items.filter(e=>!e.disabled).map(e=>e.value),this.items.forEach(e=>{e.disabled||(e.selected=!0)}),this.updateListView(),this.emit("change",{value:this.selectedValues,name:this.name})}deselectAll(){this.selectedValues=[],this.items.forEach(e=>e.selected=!1),this.updateListView(),this.emit("change",{value:this.selectedValues,name:this.name})}async onBeforeDestroy(){await super.onBeforeDestroy(),this.searchView&&this.searchView.destroy(),this.listView&&this.listView.destroy()}getValue(){return this.selectedValues}setValue(e){this.selectedValues=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}setExcludeIds(e){this.excludeIds=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}setIgnoreIds(e){this.ignoreIds=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}async refresh(){await this.collection.fetch()}getFormValue(){return this.selectedValues}setFormValue(e){this.setValue(e)}}class as extends S{constructor(e={}){super({tagName:"div",className:"multiselect-items",template:`
1060
+ `,...e}),this.name=e.name||"collection_multiselect",this.label=e.label||"",this.help=e.help||"",this.error=e.error||"",this.required=e.required||!1,this.disabled=e.disabled||!1,this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.excludeIds=e.excludeIds||[],this.ignoreIds=e.ignoreIds||[],this.itemTemplate=e.itemTemplate||null,this.collectionParams=e.collectionParams||{},this.defaultParamsOption=e.defaultParams||null,this.baseParams={},this.requiresActiveGroup=e.requiresActiveGroup||!1,this.size=e.size||8,this.maxHeight=e.maxHeight||this.size*42,this.showSelectAll=e.showSelectAll!==!1,this.enableSearch=e.enableSearch||!1,this.searchPlaceholder=e.searchPlaceholder||"Search...",this.searchDebounce=e.searchDebounce||400,this.selectedValues=Array.isArray(e.value)?e.value:[],this.loading=!1,this.items=[],this.searchView=null,this.listView=null}onInit(){this.collection&&this.setupCollection()}setupCollection(){if(this.baseParams={...this.collection.params},Object.keys(this.collectionParams).length>0&&(Object.assign(this.baseParams,this.collectionParams),Object.assign(this.collection.params,this.collectionParams)),this.defaultParamsOption){const e=typeof this.defaultParamsOption=="function"?this.defaultParamsOption():this.defaultParamsOption;e&&(Object.assign(this.baseParams,e),Object.assign(this.collection.params,e))}if(this.requiresActiveGroup){const e=this.getApp();e?.activeGroup?.id&&(this.baseParams.group=e.activeGroup.id,this.collection.params.group=e.activeGroup.id)}this.collection.on("fetch:start",()=>{this.loading=!0,this.updateListView()}),this.collection.on("fetch:end",()=>{this.loading=!1,this.buildItems(),this.updateListView()}),this.collection.isEmpty()||this.buildItems()}async onAfterRender(){await super.onAfterRender(),this.enableSearch&&this.createSearchView(),this.createListView(),this.collection?.isEmpty()&&this.collection.fetch()}createSearchView(){const e=this.element?.querySelector(".collection-multiselect-search-container");e&&(this.searchView=new is({placeholder:this.searchPlaceholder,debounce:this.searchDebounce}),this.searchView.on("search",t=>{this.handleSearch(t)}),this.searchView.render(!0,e))}createListView(){const e=this.element?.querySelector(".collection-multiselect-list-container");if(!e)return;const t=this.selectedValues.length,s=this.items.length,i=s-t;this.listView=new rs({items:this.items,loading:this.loading,maxHeight:this.maxHeight,showSelectAll:this.showSelectAll,selectedCount:t,totalCount:s,unselectedCount:i,allSelected:t===s&&s>0,noneSelected:t===0,customItemTemplate:this.itemTemplate}),this.listView.on("toggle",r=>{this.handleToggle(r)}),this.listView.on("select-all",()=>{this.selectAll()}),this.listView.on("deselect-all",()=>{this.deselectAll()}),this.listView.render(!0,e)}updateListView(){if(this.listView){const e=this.selectedValues.length,t=this.items.length,s=t-e;this.listView.updateState({items:this.items,loading:this.loading,selectedCount:e,totalCount:t,unselectedCount:s,allSelected:e===t&&t>0,noneSelected:e===0}),this.listView.render(!1)}}buildItems(){const e=this.collection.models.filter(t=>{const s=this.getFieldValue(t,this.valueField);return!(s==null||this.excludeIds.includes(s)||this.ignoreIds.some(i=>i==s))});this.items=e.map((t,s)=>{const i=t.toJSON?t.toJSON():t,r=this.getFieldValue(t,this.valueField),n={label:this.getFieldValue(t,this.labelField),value:r,index:s,selected:this.selectedValues.some(a=>a==r),disabled:this.disabled,model:i};return this.itemTemplate&&(n.customContent=this.renderItemTemplate(n)),n})}renderItemTemplate(e){if(!this.itemTemplate)return"";try{return this.renderTemplateString(this.itemTemplate,e)}catch(t){return console.error("Error rendering item template:",t),e.label}}getFieldValue(e,t){if(!(!e||!t))return typeof e.get=="function"?e.get(t)??$.getNestedValue(e,t):$.getNestedValue(e,t)}handleSearch(e){const t={...this.baseParams};e&&(t.search=e),this.collection.updateParams(t,!0)}handleToggle({value:e,index:t,shiftKey:s,element:i}){if(s&&this.listView.lastClickedIndex>=0){const r=Math.min(this.listView.lastClickedIndex,t),n=Math.max(this.listView.lastClickedIndex,t),a=!this.items[t].selected;for(let o=r;o<=n;o++){const l=this.items[o];l.disabled||(a?this.selectedValues.includes(l.value)||this.selectedValues.push(l.value):this.selectedValues=this.selectedValues.filter(d=>d!=l.value),l.selected=a)}this.updateListView()}else{const r=this.items[t];r.selected?(this.selectedValues=this.selectedValues.filter(n=>n!=e),r.selected=!1):(this.selectedValues.push(e),r.selected=!0),i&&this.listView&&(this.listView.updateItemCheckbox(i,r.selected),this.listView.selectedCount=this.selectedValues.length,this.listView.unselectedCount=this.items.length-this.selectedValues.length,this.listView.allSelected=this.selectedValues.length===this.items.length&&this.items.length>0,this.listView.noneSelected=this.selectedValues.length===0,this.listView.updateActionButtons())}this.emit("change",{value:this.selectedValues,name:this.name})}selectAll(){this.selectedValues=this.items.filter(e=>!e.disabled).map(e=>e.value),this.items.forEach(e=>{e.disabled||(e.selected=!0)}),this.updateListView(),this.emit("change",{value:this.selectedValues,name:this.name})}deselectAll(){this.selectedValues=[],this.items.forEach(e=>e.selected=!1),this.updateListView(),this.emit("change",{value:this.selectedValues,name:this.name})}async onBeforeDestroy(){await super.onBeforeDestroy(),this.searchView&&this.searchView.destroy(),this.listView&&this.listView.destroy()}getValue(){return this.selectedValues}setValue(e){this.selectedValues=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}setExcludeIds(e){this.excludeIds=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}setIgnoreIds(e){this.ignoreIds=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}async refresh(){await this.collection.fetch()}getFormValue(){return this.selectedValues}setFormValue(e){this.setValue(e)}}class as extends C{constructor(e={}){super({tagName:"div",className:"multiselect-items",template:`
1061
1061
  {{#items.length}}
1062
1062
  <div class="multiselect-list" style="max-height: {{maxHeight}}px; overflow-y: auto;">
1063
1063
  {{#items}}
@@ -1088,7 +1088,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1088
1088
  <small>No options available</small>
1089
1089
  </div>
1090
1090
  {{/items.length}}
1091
- `,...e}),this.items=e.items||[],this.maxHeight=e.maxHeight||300}handleActionToggle(e,t){const s=t.getAttribute("data-value"),i=parseInt(t.getAttribute("data-index"),10),r=this.items[i];if(!r||r.disabled)return;r.selected=!r.selected;const n=t.querySelector('input[type="checkbox"]');n&&(n.checked=r.selected),this.emit("toggle",{value:s,index:i,selected:r.selected})}handleActionCloseDropdown(e,t){this.emit("close-dropdown")}getValue(){return this.items.filter(e=>e.selected).map(e=>e.value)}setValue(e){const t=new Set(Array.isArray(e)?e:[e]);this.items.forEach(s=>{s.selected=t.has(s.value)}),this.render(!1)}updateItems(e){this.items=e,this.render(!1)}}class os extends S{constructor(e={}){super({tagName:"div",className:"multiselect-dropdown",template:`
1091
+ `,...e}),this.items=e.items||[],this.maxHeight=e.maxHeight||300}handleActionToggle(e,t){const s=t.getAttribute("data-value"),i=parseInt(t.getAttribute("data-index"),10),r=this.items[i];if(!r||r.disabled)return;r.selected=!r.selected;const n=t.querySelector('input[type="checkbox"]');n&&(n.checked=r.selected),this.emit("toggle",{value:s,index:i,selected:r.selected})}handleActionCloseDropdown(e,t){this.emit("close-dropdown")}getValue(){return this.items.filter(e=>e.selected).map(e=>e.value)}setValue(e){const t=new Set(Array.isArray(e)?e:[e]);this.items.forEach(s=>{s.selected=t.has(s.value)}),this.render(!1)}updateItems(e){this.items=e,this.render(!1)}}class os extends C{constructor(e={}){super({tagName:"div",className:"multiselect-dropdown",template:`
1092
1092
  <div class="mojo-form-control">
1093
1093
  {{#label}}
1094
1094
  <label class="form-label">
@@ -1115,7 +1115,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1115
1115
  <div class="invalid-feedback d-block">{{error}}</div>
1116
1116
  {{/error}}
1117
1117
  </div>
1118
- `,...e}),this.name=e.name||"multiselect",this.label=e.label||"",this.help=e.help||"",this.error=e.error||"",this.required=e.required||!1,this.disabled=e.disabled||!1,this.placeholder=e.placeholder||e.placeHolder||"Select...",this.maxHeight=e.maxHeight||300,this.showSelectedLabels=e.showSelectedLabels!==!1,this.maxLabelsToShow=e.maxLabelsToShow||3,this.options=e.options||[],this.selectedValues=Array.isArray(e.value)?e.value:[],this.buttonText=this.computeButtonText(),this.listView=null}computeButtonText(){const e=this.selectedValues.length;return e===0?this.placeholder||"Select...":this.showSelectedLabels&&e<=this.maxLabelsToShow?this.selectedValues.map(s=>{const i=this.options.find(r=>(typeof r=="string"?r:r.value)===s);return typeof i=="string"?i:i?.label||i?.value||s}).join(", "):`${e} selected`}async onAfterRender(){await super.onAfterRender(),this.createListView()}createListView(){const e=this.element?.querySelector('[data-container="items"]');if(!e)return;const t=this.options.map((s,i)=>{const r=typeof s=="string"?s:s.value,n=typeof s=="string"?s:s.label||s.text||s.value,a=typeof s=="object"?s.disabled:!1;return{id:`${this.name}_${i}`,value:r,label:n,index:i,selected:this.selectedValues.includes(r),disabled:a}});this.listView=new as({items:t,maxHeight:this.maxHeight}),this.listView.on("toggle",s=>{this.handleToggle(s)}),this.listView.on("close-dropdown",()=>{this.closeDropdown()}),this.listView.render(!0,e)}closeDropdown(){const e=this.element?.querySelector(".dropdown-toggle");if(e&&window.bootstrap?.Dropdown){const t=window.bootstrap.Dropdown.getInstance(e);t&&t.hide()}}handleToggle(e){const{value:t,selected:s}=e;s?this.selectedValues.includes(t)||this.selectedValues.push(t):this.selectedValues=this.selectedValues.filter(i=>i!==t),this.updateButtonText(),this.emit("change",{value:this.selectedValues,name:this.name})}updateButtonText(){const e=this.element?.querySelector(".multiselect-button-text");if(!e)return;const t=this.selectedValues.length;this.buttonText=this.computeButtonText(),e.textContent=this.buttonText,t===0?e.classList.add("text-muted"):e.classList.remove("text-muted")}getValue(){return this.selectedValues}setValue(e){this.selectedValues=Array.isArray(e)?e:e?[e]:[],this.listView&&this.listView.setValue(this.selectedValues),this.updateButtonText()}setOptions(e){if(this.options=e,this.listView){const t=this.options.map((s,i)=>{const r=typeof s=="string"?s:s.value,n=typeof s=="string"?s:s.label||s.text||s.value,a=typeof s=="object"?s.disabled:!1;return{id:`${this.name}_${i}`,value:r,label:n,index:i,selected:this.selectedValues.includes(r),disabled:a}});this.listView.updateItems(t)}}clear(){this.setValue([])}getFormValue(){return this.getValue()}setFormValue(e){this.setValue(e)}async onBeforeDestroy(){await super.onBeforeDestroy(),this.listView&&this.listView.destroy()}}const Ne=["January","February","March","April","May","June","July","August","September","October","November","December"],Oe=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function ft(c){if(c==null||c==="")return null;const e=parseInt(String(c).slice(0,4),10);return Number.isFinite(e)?{y:e}:null}function Ce(c){if(c==null||c==="")return null;const e=String(c).split("-"),t=parseInt(e[0],10),s=parseInt(e[1],10);return!Number.isFinite(t)||!Number.isFinite(s)||s<1||s>12?null:{y:t,m:s}}function q(c){if(c==null||c==="")return null;if(c instanceof Date&&!isNaN(c.getTime()))return{y:c.getFullYear(),m:c.getMonth()+1,d:c.getDate()};const e=String(c).split("-"),t=parseInt(e[0],10),s=parseInt(e[1],10),i=parseInt(e[2],10);return!Number.isFinite(t)||!Number.isFinite(s)||!Number.isFinite(i)||s<1||s>12||i<1||i>31?null:{y:t,m:s,d:i}}function gt(c){const e=typeof c=="object"?c:ft(c);return e?String(e.y):""}function Re(c){const e=typeof c=="object"?c:Ce(c);return e?`${e.y}-${ee(e.m)}`:""}function B(c){const e=typeof c=="object"?c:q(c);return e?`${e.y}-${ee(e.m)}-${ee(e.d)}`:""}function U(c,e){return e==="year"?gt(c):e==="month"?Re(c):B(c)}function P(c,e){return e==="year"?ft(c):e==="month"?Ce(c):q(c)}const ls=/YYYY|YY|MMMM|MMM|MM|M|DD|D/g;function he(c,e){if(!c)return"";const t=c.y,s=c.m,i=c.d;return String(e).replace(ls,r=>{switch(r){case"YYYY":return String(t);case"YY":return String(t).slice(-2);case"MMMM":return s?Ne[s-1]:"";case"MMM":return s?Oe[s-1]:"";case"MM":return s?ee(s):"";case"M":return s?String(s):"";case"DD":return i?ee(i):"";case"D":return i?String(i):"";default:return r}})}function bt(c,e){return new Date(c,e,0).getDate()}function cs(c,e,t,s=1){return((new Date(c,e-1,t).getDay()-s)%7+7)%7}function ae(c,e){if(!c)return null;let t=c.y,s=c.m+e;for(;s>12;)s-=12,t+=1;for(;s<1;)s+=12,t-=1;if(c.d==null)return{y:t,m:s};const i=bt(t,s);return{y:t,m:s,d:Math.min(c.d,i)}}function yt(c,e){return!c||!e?0:c.y!==e.y?c.y<e.y?-1:1:(c.m||0)!==(e.m||0)?(c.m||0)<(e.m||0)?-1:1:(c.d||0)!==(e.d||0)?(c.d||0)<(e.d||0)?-1:1:0}function wt(c,e){return!c||!e?0:c.y!==e.y?c.y<e.y?-1:1:(c.m||0)!==(e.m||0)?(c.m||0)<(e.m||0)?-1:1:0}function ds(c,e){return!c||!e||c.y===e.y?0:c.y<e.y?-1:1}function W(c,e,t){return t==="year"?ds(c,e):t==="month"?wt(c,e):yt(c,e)}function J(c){if(c==null||c==="")return null;if(typeof c=="object"&&c!==null){const d=parseInt(c.hours??c.h,10),h=parseInt(c.minutes??c.m,10);return!Number.isFinite(d)||!Number.isFinite(h)||d<0||d>23||h<0||h>59?null:{hours:d,minutes:h}}const e=String(c).trim(),t=e.indexOf(" "),s=t>-1?e.slice(0,t):e,r=(t>-1?e.slice(t+1).trim():"").match(/^(am|pm)$/i)||s.match(/(am|pm)$/i),a=s.replace(/(am|pm)$/i,"").trim().split(":");if(a.length<2)return null;let o=parseInt(a[0],10);const l=parseInt(a[1],10);if(!Number.isFinite(o)||!Number.isFinite(l)||l<0||l>59)return null;if(r){const d=r[1].toLowerCase()==="pm";if(o<1||o>12)return null;o===12?o=d?12:0:d&&(o+=12)}return o<0||o>23?null:{hours:o,minutes:l}}function Z(c,e="24h"){if(!c)return"";const t=c.hours,s=c.minutes;if(!Number.isFinite(t)||!Number.isFinite(s))return"";if(e==="12h"){const i=t>=12?"PM":"AM";let r=t%12;return r===0&&(r=12),`${r}:${ee(s)} ${i}`}return`${ee(t)}:${ee(s)}`}function vt(c,e){return!c||!e?0:c.hours!==e.hours?c.hours<e.hours?-1:1:c.minutes!==e.minutes?c.minutes<e.minutes?-1:1:0}function hs(c,e){if(!c)return null;let t=c.hours*60+c.minutes+e;return t=(t%1440+1440)%1440,{hours:Math.floor(t/60),minutes:t%60}}function Ct(c,e){if(!c)return null;try{const t=e instanceof Date?e:new Date,r=new Intl.DateTimeFormat("en-US",{timeZone:c,timeZoneName:"shortOffset"}).formatToParts(t).find(h=>h.type==="timeZoneName");if(!r)return null;let n=r.value;if(n==="GMT"||n==="UTC")return"+00:00";n=n.replace(/^(GMT|UTC)/,"");const a=n.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!a)return null;const o=a[1],l=a[2].padStart(2,"0"),d=a[3]||"00";return`${o}${l}:${d}`}catch{return null}}function St(c){if(c==null||c==="")return null;if(typeof c=="object"&&!Array.isArray(c)&&!(c instanceof Date)){const h=c.date?q(c.date):null,u=c.time?J(c.time):null;return h?{date:h,time:u||{hours:0,minutes:0},timezone:c.timezone||null}:null}let e=String(c).trim();const t=e.match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::\d{2}(?:\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?$/);if(t){const[,h,u,m,p,f,g]=t;let b=null;return g&&(g==="Z"?b="+00:00":/^[+-]\d{4}$/.test(g)?b=`${g.slice(0,3)}:${g.slice(3)}`:b=g),{date:{y:+h,m:+u,d:+m},time:{hours:+p,minutes:+f},timezone:b}}let s,i;if(e.length>=11&&e.charAt(10)==="T")s=e.slice(0,10),i=e.slice(11);else{const h=e.indexOf(" ");if(h===-1){const u=q(e);return u?{date:u,time:{hours:0,minutes:0},timezone:null}:null}s=e.slice(0,h),i=e.slice(h+1)}const r=q(s);if(!r)return null;const n=i.trim();let a=null,o=n;const l=n.match(/\s+([A-Za-z][A-Za-z_+\-]*\/[A-Za-z][A-Za-z_+\-]*|UTC|GMT)$/);l&&(a=l[1],o=n.slice(0,l.index).trim());const d=J(o);return d?{date:r,time:d,timezone:a}:null}function E(){const c=new Date;return{y:c.getFullYear(),m:c.getMonth()+1,d:c.getDate()}}let Se=null,je=null,ze=null;function _t(c="en-US",e="short"){if((!c||c==="en-US"||c==="en")&&e==="short")return Oe.slice();if((!c||c==="en-US"||c==="en")&&e==="long")return Ne.slice();if(typeof Intl>"u"||!Intl.DateTimeFormat)return e==="long"?Ne.slice():Oe.slice();if(Se===c+"/"+e&&je)return je.slice();const t=new Intl.DateTimeFormat(c,{month:e}),s=[];for(let i=0;i<12;i++)s.push(t.format(new Date(2024,i,15)));return Se=c+"/"+e,je=s,s.slice()}function us(c="en-US",e=1,t="short"){if(typeof Intl>"u"||!Intl.DateTimeFormat)return xt(["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],e);const s=c+"/"+e+"/"+t;if(Se===s&&ze)return ze.slice();const i=new Intl.DateTimeFormat(c,{weekday:t}),r=[];for(let a=0;a<7;a++)r.push(i.format(new Date(2024,0,7+a)));const n=xt(r,e);return Se=s,ze=n,n.slice()}function ee(c){return c<10?"0"+c:String(c)}function xt(c,e){const t=(e%c.length+c.length)%c.length;return c.slice(t).concat(c.slice(0,t))}class He extends S{constructor(e={}){const{precision:t="day",mode:s="single",months:i=1,value:r=null,startValue:n=null,endValue:a=null,min:o=null,max:l=null,disabledDates:d=[],firstDay:h=1,locale:u="en-US",excludeDisabledFromRange:m=!1,year:p=null,month:f=null,class:g="",...b}=e;super({tagName:"div",className:`mojo-calendar mojo-calendar-${t} ${g}`.trim(),...b}),this.precision=t,this.mode=s,this.months=Math.max(1,Math.min(2,i|0)),this.firstDay=h,this.locale=u,this.excludeDisabledFromRange=m,this.min=P(o,t)||(o?q(o):null),this.max=P(l,t)||(l?q(l):null),this.disabledDates=(d||[]).map(_=>B(q(_)||null)).filter(Boolean),s==="single"?this.selected=P(r,t):(this.start=P(n,t),this.end=P(a,t),this._anchor=null),this._hover=null,this.view=t;const y=E(),C=(s==="single"?this.selected:this.start||this.end)||y;this.pageY=p!=null?Number(p):C.y??y.y,this.pageM=f!=null?Number(f):C.m??y.m,this._onCellMouseEnter=this._onCellMouseEnter.bind(this),this._onCellMouseLeave=this._onCellMouseLeave.bind(this)}setMin(e){this.min=P(e,this.precision),this._rerender()}setMax(e){this.max=P(e,this.precision),this._rerender()}setValue(e){this.selected=P(e,this.precision),this.selected&&(this.pageY=this.selected.y,this.pageM=this.selected.m||this.pageM),this._rerender()}setRange(e,t){this.start=P(e,this.precision),this.end=P(t,this.precision),this._anchor=null,this._rerender()}getValue(){return this.selected?U(this.selected,this.precision):""}getRange(){return{start:this.start?U(this.start,this.precision):"",end:this.end?U(this.end,this.precision):""}}async renderTemplate(){return""}async onAfterRender(){this._eventsWired||(this._wireEvents(this.element),this._eventsWired=!0),this._renderInto(this.element)}_rerender(){this.element&&this._renderInto(this.element)}_renderInto(e){e.innerHTML="";const t=document.createElement("div");if(t.className=this.months>1&&this.view==="day"?"mojo-calendar-multi":"mojo-calendar-single",this.view==="day"){const s=this.months;for(let i=0;i<s;i++){let r=this.pageY,n=this.pageM+i;for(;n>12;)n-=12,r+=1;t.appendChild(this._buildDayPane(r,n,i===0,i===s-1))}}else this.view==="month"?t.appendChild(this._buildMonthPane(this.pageY)):this.view==="year"&&t.appendChild(this._buildYearPane(this._decadeStart(this.pageY)));e.appendChild(t)}_decadeStart(e){return Math.floor(e/10)*10}_buildDayPane(e,t,s,i){const r=document.createElement("div");return r.className="mojo-calendar-pane",r.appendChild(this._buildHead(this._dayHeadLabel(e,t),"day",s,i,e,t)),r.appendChild(this._buildWeekdayHeader()),r.appendChild(this._buildDayGrid(e,t)),r}_dayHeadLabel(e,t){return{kind:"day",year:e,month:t}}_buildWeekdayHeader(){const e=document.createElement("div");return e.className="mojo-calendar-grid mojo-calendar-grid-day",us(this.locale,this.firstDay,"short").forEach(t=>{const s=document.createElement("div");s.className="mojo-calendar-weekday",s.textContent=t,e.appendChild(s)}),e}_buildDayGrid(e,t){const s=document.createElement("div");s.className="mojo-calendar-grid mojo-calendar-grid-day";const i=cs(e,t,1,this.firstDay),r=bt(e,t),n=E();for(let a=0;a<i;a++){const o=document.createElement("div");o.className="mojo-calendar-cell mojo-calendar-cell-blank",s.appendChild(o)}for(let a=1;a<=r;a++){const o={y:e,m:t,d:a},l=document.createElement("button");l.type="button",l.className="mojo-calendar-cell",l.dataset.ymd=B(o),o.y===n.y&&o.m===n.m&&o.d===n.d&&l.classList.add("mojo-calendar-cell-today"),this._isDisabledAt(o,"day")&&(l.classList.add("mojo-calendar-cell-disabled"),l.disabled=!0),this.mode==="range"?this._applyRangeClasses(l,o,"day"):this.selected&&yt(o,this.selected)===0&&l.classList.add("mojo-calendar-cell-selected");const d=document.createElement("span");d.className="mojo-calendar-cell-inner",d.textContent=String(a),l.appendChild(d),s.appendChild(l)}return s}_buildMonthPane(e){const t=document.createElement("div");return t.className="mojo-calendar-pane",t.appendChild(this._buildHead(String(e),"month",!0,!0,e,1)),t.appendChild(this._buildMonthGrid(e)),t}_buildMonthGrid(e){const t=document.createElement("div");t.className="mojo-calendar-grid mojo-calendar-grid-month";const s=_t(this.locale,"short");for(let i=1;i<=12;i++){const r={y:e,m:i},n=document.createElement("button");n.type="button",n.className="mojo-calendar-cell",n.dataset.ym=Re(r),this._isDisabledAt(r,"month")&&(n.classList.add("mojo-calendar-cell-disabled"),n.disabled=!0),this.precision==="month"&&this.mode==="range"?this._applyRangeClasses(n,r,"month"):this.precision==="month"&&this.mode==="single"&&this.selected&&wt(r,this.selected)===0&&n.classList.add("mojo-calendar-cell-selected");const a=document.createElement("span");a.className="mojo-calendar-cell-inner",a.textContent=s[i-1],n.appendChild(a),t.appendChild(n)}return t}_buildYearPane(e){const t=document.createElement("div");return t.className="mojo-calendar-pane",t.appendChild(this._buildHead(`${e} – ${e+11}`,"year",!0,!0,e,1)),t.appendChild(this._buildYearGrid(e)),t}_buildYearGrid(e){const t=document.createElement("div");t.className="mojo-calendar-grid mojo-calendar-grid-year";for(let s=0;s<12;s++){const i=e+s,r={y:i},n=document.createElement("button");n.type="button",n.className="mojo-calendar-cell",n.dataset.year=String(i),this._isDisabledAt(r,"year")&&(n.classList.add("mojo-calendar-cell-disabled"),n.disabled=!0),this.precision==="year"&&this.mode==="range"?this._applyRangeClasses(n,r,"year"):this.precision==="year"&&this.mode==="single"&&this.selected&&this.selected.y===i&&n.classList.add("mojo-calendar-cell-selected");const a=document.createElement("span");a.className="mojo-calendar-cell-inner",a.textContent=String(i),n.appendChild(a),t.appendChild(n)}return t}_applyRangeClasses(e,t,s){let i=this.start,r=this.end;if(this._anchor){const o=this._hover||this._anchor,l=W(this._anchor,o,s);i=l<=0?this._anchor:o,r=l<=0?o:this._anchor}if(!i||!r){this._anchor&&W(t,this._anchor,s)===0&&e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-solo");return}const n=W(t,i,s),a=W(t,r,s);n>0&&a<0&&e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range"),n===0&&(e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-start"),W(i,r,s)===0?e.classList.add("mojo-calendar-cell-anchor-solo"):e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range")),a===0&&W(i,r,s)!==0&&(e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-end"),e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range"))}_buildHead(e,t,s,i){const r=document.createElement("div");r.className="mojo-calendar-head";const n=document.createElement("button");if(n.type="button",n.className="mojo-calendar-head-label",n.dataset.level=t,n.dataset.action="zoom-out",typeof e=="string")n.textContent=e;else if(e&&e.kind==="day"){const o=_t(this.locale,"long");n.appendChild(document.createTextNode(`${o[e.month-1]} `));const l=document.createElement("span");l.className="mojo-calendar-year",l.textContent=String(e.year),n.appendChild(l)}r.appendChild(n);const a=document.createElement("div");return a.className="mojo-calendar-nav",s&&a.appendChild(this._navBtn("prev")),i&&a.appendChild(this._navBtn("next")),r.appendChild(a),r}_navBtn(e){const t=document.createElement("button");return t.type="button",t.className="mojo-calendar-nav-btn",t.dataset.action=`nav-${e}`,t.setAttribute("aria-label",e==="prev"?"Previous":"Next"),t.innerHTML=e==="prev"?"&#x2039;":"&#x203A;",t}_wireEvents(e){e.addEventListener("click",t=>this._onClick(t)),e.addEventListener("mouseover",this._onCellMouseEnter),e.addEventListener("mouseleave",this._onCellMouseLeave),e.addEventListener("keydown",t=>this._onKeyDown(t))}_onClick(e){const t=e.target.closest("[data-action], .mojo-calendar-cell");if(!t||t.classList.contains("mojo-calendar-cell-blank")||t.disabled)return;const s=t.dataset.action;if(s==="nav-prev")return this._navigate(-1);if(s==="nav-next")return this._navigate(1);if(s==="zoom-out")return this._zoomOut(t.dataset.level);t.classList.contains("mojo-calendar-cell")&&this._onCellClick(t)}_onCellClick(e){if(this.view==="year"){const t=parseInt(e.dataset.year,10);if(!Number.isFinite(t))return;if(this.precision==="year")return this._commitValue({y:t});this.pageY=t,this.view="month",this.emit("view:change",{view:this.view}),this._rerender();return}if(this.view==="month"){const t=Ce(e.dataset.ym);if(!t)return;if(this.precision==="month")return this._commitValue(t);this.pageY=t.y,this.pageM=t.m,this.view="day",this.emit("view:change",{view:this.view}),this._rerender();return}if(this.view==="day"){const t=q(e.dataset.ymd);if(!t)return;this._commitValue(t)}}_commitValue(e){if(this.mode==="single"){this.selected=e,this.emit("select",{value:U(e,this.precision),parsed:e}),this._rerender();return}if(!this._anchor){this._anchor=e,this.start=null,this.end=null,this._hover=null,this.emit("range:start",{anchor:U(e,this.precision)}),this._rerender();return}const t=this._anchor,s=e,i=W(t,s,this.precision);this.start=i<=0?t:s,this.end=i<=0?s:t,this._anchor=null,this._hover=null,this.emit("range:select",{start:U(this.start,this.precision),end:U(this.end,this.precision)}),this._rerender()}_onCellMouseEnter(e){if(this.mode!=="range"||!this._anchor)return;const t=e.target.closest(".mojo-calendar-cell");if(!t||t.classList.contains("mojo-calendar-cell-blank")||t.disabled)return;let s=null;this.view==="day"&&t.dataset.ymd?s=q(t.dataset.ymd):this.view==="month"&&t.dataset.ym?s=Ce(t.dataset.ym):this.view==="year"&&t.dataset.year&&(s={y:parseInt(t.dataset.year,10)}),s&&(this._hover&&W(this._hover,s,this.view)===0||(this._hover=s,this._rerender()))}_onCellMouseLeave(){this.mode!=="range"||!this._anchor||this._hover&&(this._hover=null,this._rerender())}_navigate(e){if(this.view==="day"){const t=ae({y:this.pageY,m:this.pageM},e);this.pageY=t.y,this.pageM=t.m}else this.view==="month"?this.pageY+=e:this.view==="year"&&(this.pageY=this._decadeStart(this.pageY)+e*10);this.emit("navigate",{delta:e}),this._rerender()}_zoomOut(e){if(e==="day"){this.view="month",this.emit("view:change",{view:this.view}),this._rerender();return}e==="month"&&(this.view="year",this.emit("view:change",{view:this.view}),this._rerender())}_onKeyDown(e){const t=e.key;if(t==="Escape"){this._anchor&&(this._anchor=null,this._hover=null,this.emit("range:cancel"),this._rerender(),e.preventDefault());return}if(t==="PageUp"){this._navigate(-1),e.preventDefault();return}if(t==="PageDown"){this._navigate(1),e.preventDefault();return}}_isDisabledAt(e,t){if(this.min&&W(e,this.min,t)<0||this.max&&W(e,this.max,t)>0)return!0;if(t==="day"&&this.disabledDates.length){const s=B(e);if(this.disabledDates.includes(s))return!0}return!1}async onBeforeDestroy(){this.element&&(this.element.removeEventListener("mouseover",this._onCellMouseEnter),this.element.removeEventListener("mouseleave",this._onCellMouseLeave)),await super.onBeforeDestroy()}}class _e{constructor(e={}){const{anchor:t=null,placement:s="bottom-start",gap:i=6,portal:r=!0,onOutsideClick:n=null,classNames:a=""}=e;this.anchor=t,this.placement=s,this.gap=i,this.portal=r,this.onOutsideClick=n,this.element=document.createElement("div"),this.element.className=`mojo-calendar-popover ${a}`.trim(),this.element.style.position="absolute",this.element.style.zIndex="10000",this.element.setAttribute("role","dialog"),this._open=!1,this._onDocClick=this._onDocClick.bind(this),this._onScroll=this._onScroll.bind(this),this._onResize=this._onResize.bind(this),this._onKey=this._onKey.bind(this)}setAnchor(e){this.anchor=e,this._open&&this._reposition()}setContent(e){this.element.innerHTML="",e&&this.element.appendChild(e)}open(){this._open||(this._open=!0,this.portal&&this.element.parentNode!==document.body&&document.body.appendChild(this.element),this.element.classList.add("is-open"),this._reposition(),setTimeout(()=>{document.addEventListener("mousedown",this._onDocClick,!0),document.addEventListener("keydown",this._onKey,!0),window.addEventListener("scroll",this._onScroll,!0),window.addEventListener("resize",this._onResize)},0))}close(){this._open&&(this._open=!1,this.element.classList.remove("is-open"),document.removeEventListener("mousedown",this._onDocClick,!0),document.removeEventListener("keydown",this._onKey,!0),window.removeEventListener("scroll",this._onScroll,!0),window.removeEventListener("resize",this._onResize),this.portal&&this.element.parentNode===document.body&&document.body.removeChild(this.element))}isOpen(){return this._open}destroy(){this.close(),this.element=null}_onDocClick(e){this.element.contains(e.target)||this.anchor&&this.anchor.contains(e.target)||(typeof this.onOutsideClick=="function"?this.onOutsideClick(e):this.close())}_onKey(e){e.key==="Escape"&&this.close()}_onScroll(){this._open&&this._reposition()}_onResize(){this._open&&this._reposition()}_reposition(){if(!this.anchor)return;const e=this.anchor.getBoundingClientRect(),t=this.element.getBoundingClientRect(),s=window.scrollX||window.pageXOffset||0,i=window.scrollY||window.pageYOffset||0;let r=e.bottom+i+this.gap,n=e.left+s;this.placement==="bottom-end"?n=e.right+s-t.width:this.placement==="top-start"?r=e.top+i-t.height-this.gap:this.placement==="top-end"&&(r=e.top+i-t.height-this.gap,n=e.right+s-t.width);const a=document.documentElement.clientWidth||window.innerWidth;n+t.width>s+a-8&&(n=s+a-t.width-8),n<s+8&&(n=s+8);const o=document.documentElement.clientHeight||window.innerHeight;r-i+t.height>o-8&&e.top-t.height-this.gap>8&&(r=e.top+i-t.height-this.gap),this.element.style.top=`${r}px`,this.element.style.left=`${n}px`}}const $t={day:"MMM DD, YYYY",month:"MMM YYYY",year:"YYYY"};class qe extends S{constructor(e={}){const{name:t,value:s="",precision:i="day",format:r=null,displayFormat:n=null,min:a=null,max:o=null,placeholder:l=null,disabled:d=!1,readonly:h=!1,required:u=!1,class:m="",inputClass:p="form-control",inline:f=!1,disabledDates:g=[],firstDay:b=1,lang:y="en-US",autoApply:C=!0,..._}=e;super({tagName:"div",className:`mojo-date-picker mojo-date-picker-${i} ${m}`.trim(),..._}),this.name=t,this.precision=i,this.format=r,this.displayFormat=n||$t[i]||$t.day,this.min=a,this.max=o,this.placeholder=l??this._defaultPlaceholder(i),this.disabled=d,this.readonly=h,this.required=u,this.inputClass=p,this.inline=f,this.disabledDates=g,this.firstDay=b,this.lang=y,this.autoApply=C,this.currentValue=s||"",this._calendar=null,this._popover=null}_defaultPlaceholder(e){return e==="year"?"Select year...":e==="month"?"Select month...":"Select date..."}async renderTemplate(){const e=this._inputId(),t=this._displayText(this.currentValue),s=!this.currentValue;return this.inline?`
1118
+ `,...e}),this.name=e.name||"multiselect",this.label=e.label||"",this.help=e.help||"",this.error=e.error||"",this.required=e.required||!1,this.disabled=e.disabled||!1,this.placeholder=e.placeholder||e.placeHolder||"Select...",this.maxHeight=e.maxHeight||300,this.showSelectedLabels=e.showSelectedLabels!==!1,this.maxLabelsToShow=e.maxLabelsToShow||3,this.options=e.options||[],this.selectedValues=Array.isArray(e.value)?e.value:[],this.buttonText=this.computeButtonText(),this.listView=null}computeButtonText(){const e=this.selectedValues.length;return e===0?this.placeholder||"Select...":this.showSelectedLabels&&e<=this.maxLabelsToShow?this.selectedValues.map(s=>{const i=this.options.find(r=>(typeof r=="string"?r:r.value)===s);return typeof i=="string"?i:i?.label||i?.value||s}).join(", "):`${e} selected`}async onAfterRender(){await super.onAfterRender(),this.createListView()}createListView(){const e=this.element?.querySelector('[data-container="items"]');if(!e)return;const t=this.options.map((s,i)=>{const r=typeof s=="string"?s:s.value,n=typeof s=="string"?s:s.label||s.text||s.value,a=typeof s=="object"?s.disabled:!1;return{id:`${this.name}_${i}`,value:r,label:n,index:i,selected:this.selectedValues.includes(r),disabled:a}});this.listView=new as({items:t,maxHeight:this.maxHeight}),this.listView.on("toggle",s=>{this.handleToggle(s)}),this.listView.on("close-dropdown",()=>{this.closeDropdown()}),this.listView.render(!0,e)}closeDropdown(){const e=this.element?.querySelector(".dropdown-toggle");if(e&&window.bootstrap?.Dropdown){const t=window.bootstrap.Dropdown.getInstance(e);t&&t.hide()}}handleToggle(e){const{value:t,selected:s}=e;s?this.selectedValues.includes(t)||this.selectedValues.push(t):this.selectedValues=this.selectedValues.filter(i=>i!==t),this.updateButtonText(),this.emit("change",{value:this.selectedValues,name:this.name})}updateButtonText(){const e=this.element?.querySelector(".multiselect-button-text");if(!e)return;const t=this.selectedValues.length;this.buttonText=this.computeButtonText(),e.textContent=this.buttonText,t===0?e.classList.add("text-muted"):e.classList.remove("text-muted")}getValue(){return this.selectedValues}setValue(e){this.selectedValues=Array.isArray(e)?e:e?[e]:[],this.listView&&this.listView.setValue(this.selectedValues),this.updateButtonText()}setOptions(e){if(this.options=e,this.listView){const t=this.options.map((s,i)=>{const r=typeof s=="string"?s:s.value,n=typeof s=="string"?s:s.label||s.text||s.value,a=typeof s=="object"?s.disabled:!1;return{id:`${this.name}_${i}`,value:r,label:n,index:i,selected:this.selectedValues.includes(r),disabled:a}});this.listView.updateItems(t)}}clear(){this.setValue([])}getFormValue(){return this.getValue()}setFormValue(e){this.setValue(e)}async onBeforeDestroy(){await super.onBeforeDestroy(),this.listView&&this.listView.destroy()}}const Re=["January","February","March","April","May","June","July","August","September","October","November","December"],Ne=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function ft(c){if(c==null||c==="")return null;const e=parseInt(String(c).slice(0,4),10);return Number.isFinite(e)?{y:e}:null}function _e(c){if(c==null||c==="")return null;const e=String(c).split("-"),t=parseInt(e[0],10),s=parseInt(e[1],10);return!Number.isFinite(t)||!Number.isFinite(s)||s<1||s>12?null:{y:t,m:s}}function q(c){if(c==null||c==="")return null;if(c instanceof Date&&!isNaN(c.getTime()))return{y:c.getFullYear(),m:c.getMonth()+1,d:c.getDate()};const e=String(c).split("-"),t=parseInt(e[0],10),s=parseInt(e[1],10),i=parseInt(e[2],10);return!Number.isFinite(t)||!Number.isFinite(s)||!Number.isFinite(i)||s<1||s>12||i<1||i>31?null:{y:t,m:s,d:i}}function gt(c){const e=typeof c=="object"?c:ft(c);return e?String(e.y):""}function Oe(c){const e=typeof c=="object"?c:_e(c);return e?`${e.y}-${ee(e.m)}`:""}function B(c){const e=typeof c=="object"?c:q(c);return e?`${e.y}-${ee(e.m)}-${ee(e.d)}`:""}function U(c,e){return e==="year"?gt(c):e==="month"?Oe(c):B(c)}function L(c,e){return e==="year"?ft(c):e==="month"?_e(c):q(c)}const ls=/YYYY|YY|MMMM|MMM|MM|M|DD|D/g;function he(c,e){if(!c)return"";const t=c.y,s=c.m,i=c.d;return String(e).replace(ls,r=>{switch(r){case"YYYY":return String(t);case"YY":return String(t).slice(-2);case"MMMM":return s?Re[s-1]:"";case"MMM":return s?Ne[s-1]:"";case"MM":return s?ee(s):"";case"M":return s?String(s):"";case"DD":return i?ee(i):"";case"D":return i?String(i):"";default:return r}})}function bt(c,e){return new Date(c,e,0).getDate()}function cs(c,e,t,s=1){return((new Date(c,e-1,t).getDay()-s)%7+7)%7}function ae(c,e){if(!c)return null;let t=c.y,s=c.m+e;for(;s>12;)s-=12,t+=1;for(;s<1;)s+=12,t-=1;if(c.d==null)return{y:t,m:s};const i=bt(t,s);return{y:t,m:s,d:Math.min(c.d,i)}}function yt(c,e){return!c||!e?0:c.y!==e.y?c.y<e.y?-1:1:(c.m||0)!==(e.m||0)?(c.m||0)<(e.m||0)?-1:1:(c.d||0)!==(e.d||0)?(c.d||0)<(e.d||0)?-1:1:0}function wt(c,e){return!c||!e?0:c.y!==e.y?c.y<e.y?-1:1:(c.m||0)!==(e.m||0)?(c.m||0)<(e.m||0)?-1:1:0}function ds(c,e){return!c||!e||c.y===e.y?0:c.y<e.y?-1:1}function W(c,e,t){return t==="year"?ds(c,e):t==="month"?wt(c,e):yt(c,e)}function J(c){if(c==null||c==="")return null;if(typeof c=="object"&&c!==null){const d=parseInt(c.hours??c.h,10),h=parseInt(c.minutes??c.m,10);return!Number.isFinite(d)||!Number.isFinite(h)||d<0||d>23||h<0||h>59?null:{hours:d,minutes:h}}const e=String(c).trim(),t=e.indexOf(" "),s=t>-1?e.slice(0,t):e,r=(t>-1?e.slice(t+1).trim():"").match(/^(am|pm)$/i)||s.match(/(am|pm)$/i),a=s.replace(/(am|pm)$/i,"").trim().split(":");if(a.length<2)return null;let o=parseInt(a[0],10);const l=parseInt(a[1],10);if(!Number.isFinite(o)||!Number.isFinite(l)||l<0||l>59)return null;if(r){const d=r[1].toLowerCase()==="pm";if(o<1||o>12)return null;o===12?o=d?12:0:d&&(o+=12)}return o<0||o>23?null:{hours:o,minutes:l}}function K(c,e="24h"){if(!c)return"";const t=c.hours,s=c.minutes;if(!Number.isFinite(t)||!Number.isFinite(s))return"";if(e==="12h"){const i=t>=12?"PM":"AM";let r=t%12;return r===0&&(r=12),`${r}:${ee(s)} ${i}`}return`${ee(t)}:${ee(s)}`}function vt(c,e){return!c||!e?0:c.hours!==e.hours?c.hours<e.hours?-1:1:c.minutes!==e.minutes?c.minutes<e.minutes?-1:1:0}function hs(c,e){if(!c)return null;let t=c.hours*60+c.minutes+e;return t=(t%1440+1440)%1440,{hours:Math.floor(t/60),minutes:t%60}}function _t(c,e){if(!c)return null;try{const t=e instanceof Date?e:new Date,r=new Intl.DateTimeFormat("en-US",{timeZone:c,timeZoneName:"shortOffset"}).formatToParts(t).find(h=>h.type==="timeZoneName");if(!r)return null;let n=r.value;if(n==="GMT"||n==="UTC")return"+00:00";n=n.replace(/^(GMT|UTC)/,"");const a=n.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!a)return null;const o=a[1],l=a[2].padStart(2,"0"),d=a[3]||"00";return`${o}${l}:${d}`}catch{return null}}function Ct(c){if(c==null||c==="")return null;if(typeof c=="object"&&!Array.isArray(c)&&!(c instanceof Date)){const h=c.date?q(c.date):null,u=c.time?J(c.time):null;return h?{date:h,time:u||{hours:0,minutes:0},timezone:c.timezone||null}:null}let e=String(c).trim();const t=e.match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::\d{2}(?:\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?$/);if(t){const[,h,u,m,p,f,g]=t;let b=null;return g&&(g==="Z"?b="+00:00":/^[+-]\d{4}$/.test(g)?b=`${g.slice(0,3)}:${g.slice(3)}`:b=g),{date:{y:+h,m:+u,d:+m},time:{hours:+p,minutes:+f},timezone:b}}let s,i;if(e.length>=11&&e.charAt(10)==="T")s=e.slice(0,10),i=e.slice(11);else{const h=e.indexOf(" ");if(h===-1){const u=q(e);return u?{date:u,time:{hours:0,minutes:0},timezone:null}:null}s=e.slice(0,h),i=e.slice(h+1)}const r=q(s);if(!r)return null;const n=i.trim();let a=null,o=n;const l=n.match(/\s+([A-Za-z][A-Za-z_+\-]*\/[A-Za-z][A-Za-z_+\-]*|UTC|GMT)$/);l&&(a=l[1],o=n.slice(0,l.index).trim());const d=J(o);return d?{date:r,time:d,timezone:a}:null}function E(){const c=new Date;return{y:c.getFullYear(),m:c.getMonth()+1,d:c.getDate()}}let Ce=null,je=null,He=null;function St(c="en-US",e="short"){if((!c||c==="en-US"||c==="en")&&e==="short")return Ne.slice();if((!c||c==="en-US"||c==="en")&&e==="long")return Re.slice();if(typeof Intl>"u"||!Intl.DateTimeFormat)return e==="long"?Re.slice():Ne.slice();if(Ce===c+"/"+e&&je)return je.slice();const t=new Intl.DateTimeFormat(c,{month:e}),s=[];for(let i=0;i<12;i++)s.push(t.format(new Date(2024,i,15)));return Ce=c+"/"+e,je=s,s.slice()}function us(c="en-US",e=1,t="short"){if(typeof Intl>"u"||!Intl.DateTimeFormat)return xt(["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],e);const s=c+"/"+e+"/"+t;if(Ce===s&&He)return He.slice();const i=new Intl.DateTimeFormat(c,{weekday:t}),r=[];for(let a=0;a<7;a++)r.push(i.format(new Date(2024,0,7+a)));const n=xt(r,e);return Ce=s,He=n,n.slice()}function ee(c){return c<10?"0"+c:String(c)}function xt(c,e){const t=(e%c.length+c.length)%c.length;return c.slice(t).concat(c.slice(0,t))}class ze extends C{constructor(e={}){const{precision:t="day",mode:s="single",months:i=1,value:r=null,startValue:n=null,endValue:a=null,min:o=null,max:l=null,disabledDates:d=[],firstDay:h=1,locale:u="en-US",excludeDisabledFromRange:m=!1,year:p=null,month:f=null,class:g="",...b}=e;super({tagName:"div",className:`mojo-calendar mojo-calendar-${t} ${g}`.trim(),...b}),this.precision=t,this.mode=s,this.months=Math.max(1,Math.min(2,i|0)),this.firstDay=h,this.locale=u,this.excludeDisabledFromRange=m,this.min=L(o,t)||(o?q(o):null),this.max=L(l,t)||(l?q(l):null),this.disabledDates=(d||[]).map(S=>B(q(S)||null)).filter(Boolean),s==="single"?this.selected=L(r,t):(this.start=L(n,t),this.end=L(a,t),this._anchor=null),this._hover=null,this.view=t;const y=E(),_=(s==="single"?this.selected:this.start||this.end)||y;this.pageY=p!=null?Number(p):_.y??y.y,this.pageM=f!=null?Number(f):_.m??y.m,this._onCellMouseEnter=this._onCellMouseEnter.bind(this),this._onCellMouseLeave=this._onCellMouseLeave.bind(this)}setMin(e){this.min=L(e,this.precision),this._rerender()}setMax(e){this.max=L(e,this.precision),this._rerender()}setValue(e){this.selected=L(e,this.precision),this.selected&&(this.pageY=this.selected.y,this.pageM=this.selected.m||this.pageM),this._rerender()}setRange(e,t){this.start=L(e,this.precision),this.end=L(t,this.precision),this._anchor=null,this._rerender()}getValue(){return this.selected?U(this.selected,this.precision):""}getRange(){return{start:this.start?U(this.start,this.precision):"",end:this.end?U(this.end,this.precision):""}}async renderTemplate(){return""}async onAfterRender(){this._eventsWired||(this._wireEvents(this.element),this._eventsWired=!0),this._renderInto(this.element)}_rerender(){this.element&&this._renderInto(this.element)}_renderInto(e){e.innerHTML="";const t=document.createElement("div");if(t.className=this.months>1&&this.view==="day"?"mojo-calendar-multi":"mojo-calendar-single",this.view==="day"){const s=this.months;for(let i=0;i<s;i++){let r=this.pageY,n=this.pageM+i;for(;n>12;)n-=12,r+=1;t.appendChild(this._buildDayPane(r,n,i===0,i===s-1))}}else this.view==="month"?t.appendChild(this._buildMonthPane(this.pageY)):this.view==="year"&&t.appendChild(this._buildYearPane(this._decadeStart(this.pageY)));e.appendChild(t)}_decadeStart(e){return Math.floor(e/10)*10}_buildDayPane(e,t,s,i){const r=document.createElement("div");return r.className="mojo-calendar-pane",r.appendChild(this._buildHead(this._dayHeadLabel(e,t),"day",s,i,e,t)),r.appendChild(this._buildWeekdayHeader()),r.appendChild(this._buildDayGrid(e,t)),r}_dayHeadLabel(e,t){return{kind:"day",year:e,month:t}}_buildWeekdayHeader(){const e=document.createElement("div");return e.className="mojo-calendar-grid mojo-calendar-grid-day",us(this.locale,this.firstDay,"short").forEach(t=>{const s=document.createElement("div");s.className="mojo-calendar-weekday",s.textContent=t,e.appendChild(s)}),e}_buildDayGrid(e,t){const s=document.createElement("div");s.className="mojo-calendar-grid mojo-calendar-grid-day";const i=cs(e,t,1,this.firstDay),r=bt(e,t),n=E();for(let a=0;a<i;a++){const o=document.createElement("div");o.className="mojo-calendar-cell mojo-calendar-cell-blank",s.appendChild(o)}for(let a=1;a<=r;a++){const o={y:e,m:t,d:a},l=document.createElement("button");l.type="button",l.className="mojo-calendar-cell",l.dataset.ymd=B(o),o.y===n.y&&o.m===n.m&&o.d===n.d&&l.classList.add("mojo-calendar-cell-today"),this._isDisabledAt(o,"day")&&(l.classList.add("mojo-calendar-cell-disabled"),l.disabled=!0),this.mode==="range"?this._applyRangeClasses(l,o,"day"):this.selected&&yt(o,this.selected)===0&&l.classList.add("mojo-calendar-cell-selected");const d=document.createElement("span");d.className="mojo-calendar-cell-inner",d.textContent=String(a),l.appendChild(d),s.appendChild(l)}return s}_buildMonthPane(e){const t=document.createElement("div");return t.className="mojo-calendar-pane",t.appendChild(this._buildHead(String(e),"month",!0,!0,e,1)),t.appendChild(this._buildMonthGrid(e)),t}_buildMonthGrid(e){const t=document.createElement("div");t.className="mojo-calendar-grid mojo-calendar-grid-month";const s=St(this.locale,"short");for(let i=1;i<=12;i++){const r={y:e,m:i},n=document.createElement("button");n.type="button",n.className="mojo-calendar-cell",n.dataset.ym=Oe(r),this._isDisabledAt(r,"month")&&(n.classList.add("mojo-calendar-cell-disabled"),n.disabled=!0),this.precision==="month"&&this.mode==="range"?this._applyRangeClasses(n,r,"month"):this.precision==="month"&&this.mode==="single"&&this.selected&&wt(r,this.selected)===0&&n.classList.add("mojo-calendar-cell-selected");const a=document.createElement("span");a.className="mojo-calendar-cell-inner",a.textContent=s[i-1],n.appendChild(a),t.appendChild(n)}return t}_buildYearPane(e){const t=document.createElement("div");return t.className="mojo-calendar-pane",t.appendChild(this._buildHead(`${e} – ${e+11}`,"year",!0,!0,e,1)),t.appendChild(this._buildYearGrid(e)),t}_buildYearGrid(e){const t=document.createElement("div");t.className="mojo-calendar-grid mojo-calendar-grid-year";for(let s=0;s<12;s++){const i=e+s,r={y:i},n=document.createElement("button");n.type="button",n.className="mojo-calendar-cell",n.dataset.year=String(i),this._isDisabledAt(r,"year")&&(n.classList.add("mojo-calendar-cell-disabled"),n.disabled=!0),this.precision==="year"&&this.mode==="range"?this._applyRangeClasses(n,r,"year"):this.precision==="year"&&this.mode==="single"&&this.selected&&this.selected.y===i&&n.classList.add("mojo-calendar-cell-selected");const a=document.createElement("span");a.className="mojo-calendar-cell-inner",a.textContent=String(i),n.appendChild(a),t.appendChild(n)}return t}_applyRangeClasses(e,t,s){let i=this.start,r=this.end;if(this._anchor){const o=this._hover||this._anchor,l=W(this._anchor,o,s);i=l<=0?this._anchor:o,r=l<=0?o:this._anchor}if(!i||!r){this._anchor&&W(t,this._anchor,s)===0&&e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-solo");return}const n=W(t,i,s),a=W(t,r,s);n>0&&a<0&&e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range"),n===0&&(e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-start"),W(i,r,s)===0?e.classList.add("mojo-calendar-cell-anchor-solo"):e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range")),a===0&&W(i,r,s)!==0&&(e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-end"),e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range"))}_buildHead(e,t,s,i){const r=document.createElement("div");r.className="mojo-calendar-head";const n=document.createElement("button");if(n.type="button",n.className="mojo-calendar-head-label",n.dataset.level=t,n.dataset.action="zoom-out",typeof e=="string")n.textContent=e;else if(e&&e.kind==="day"){const o=St(this.locale,"long");n.appendChild(document.createTextNode(`${o[e.month-1]} `));const l=document.createElement("span");l.className="mojo-calendar-year",l.textContent=String(e.year),n.appendChild(l)}r.appendChild(n);const a=document.createElement("div");return a.className="mojo-calendar-nav",s&&a.appendChild(this._navBtn("prev")),i&&a.appendChild(this._navBtn("next")),r.appendChild(a),r}_navBtn(e){const t=document.createElement("button");return t.type="button",t.className="mojo-calendar-nav-btn",t.dataset.action=`nav-${e}`,t.setAttribute("aria-label",e==="prev"?"Previous":"Next"),t.innerHTML=e==="prev"?"&#x2039;":"&#x203A;",t}_wireEvents(e){e.addEventListener("click",t=>this._onClick(t)),e.addEventListener("mouseover",this._onCellMouseEnter),e.addEventListener("mouseleave",this._onCellMouseLeave),e.addEventListener("keydown",t=>this._onKeyDown(t))}_onClick(e){const t=e.target.closest("[data-action], .mojo-calendar-cell");if(!t||t.classList.contains("mojo-calendar-cell-blank")||t.disabled)return;const s=t.dataset.action;if(s==="nav-prev")return this._navigate(-1);if(s==="nav-next")return this._navigate(1);if(s==="zoom-out")return this._zoomOut(t.dataset.level);t.classList.contains("mojo-calendar-cell")&&this._onCellClick(t)}_onCellClick(e){if(this.view==="year"){const t=parseInt(e.dataset.year,10);if(!Number.isFinite(t))return;if(this.precision==="year")return this._commitValue({y:t});this.pageY=t,this.view="month",this.emit("view:change",{view:this.view}),this._rerender();return}if(this.view==="month"){const t=_e(e.dataset.ym);if(!t)return;if(this.precision==="month")return this._commitValue(t);this.pageY=t.y,this.pageM=t.m,this.view="day",this.emit("view:change",{view:this.view}),this._rerender();return}if(this.view==="day"){const t=q(e.dataset.ymd);if(!t)return;this._commitValue(t)}}_commitValue(e){if(this.mode==="single"){this.selected=e,this.emit("select",{value:U(e,this.precision),parsed:e}),this._rerender();return}if(!this._anchor){this._anchor=e,this.start=null,this.end=null,this._hover=null,this.emit("range:start",{anchor:U(e,this.precision)}),this._rerender();return}const t=this._anchor,s=e,i=W(t,s,this.precision);this.start=i<=0?t:s,this.end=i<=0?s:t,this._anchor=null,this._hover=null,this.emit("range:select",{start:U(this.start,this.precision),end:U(this.end,this.precision)}),this._rerender()}_onCellMouseEnter(e){if(this.mode!=="range"||!this._anchor)return;const t=e.target.closest(".mojo-calendar-cell");if(!t||t.classList.contains("mojo-calendar-cell-blank")||t.disabled)return;let s=null;this.view==="day"&&t.dataset.ymd?s=q(t.dataset.ymd):this.view==="month"&&t.dataset.ym?s=_e(t.dataset.ym):this.view==="year"&&t.dataset.year&&(s={y:parseInt(t.dataset.year,10)}),s&&(this._hover&&W(this._hover,s,this.view)===0||(this._hover=s,this._rerender()))}_onCellMouseLeave(){this.mode!=="range"||!this._anchor||this._hover&&(this._hover=null,this._rerender())}_navigate(e){if(this.view==="day"){const t=ae({y:this.pageY,m:this.pageM},e);this.pageY=t.y,this.pageM=t.m}else this.view==="month"?this.pageY+=e:this.view==="year"&&(this.pageY=this._decadeStart(this.pageY)+e*10);this.emit("navigate",{delta:e}),this._rerender()}_zoomOut(e){if(e==="day"){this.view="month",this.emit("view:change",{view:this.view}),this._rerender();return}e==="month"&&(this.view="year",this.emit("view:change",{view:this.view}),this._rerender())}_onKeyDown(e){const t=e.key;if(t==="Escape"){this._anchor&&(this._anchor=null,this._hover=null,this.emit("range:cancel"),this._rerender(),e.preventDefault());return}if(t==="PageUp"){this._navigate(-1),e.preventDefault();return}if(t==="PageDown"){this._navigate(1),e.preventDefault();return}}_isDisabledAt(e,t){if(this.min&&W(e,this.min,t)<0||this.max&&W(e,this.max,t)>0)return!0;if(t==="day"&&this.disabledDates.length){const s=B(e);if(this.disabledDates.includes(s))return!0}return!1}async onBeforeDestroy(){this.element&&(this.element.removeEventListener("mouseover",this._onCellMouseEnter),this.element.removeEventListener("mouseleave",this._onCellMouseLeave)),await super.onBeforeDestroy()}}class Se{constructor(e={}){const{anchor:t=null,placement:s="bottom-start",gap:i=6,portal:r=!0,onOutsideClick:n=null,classNames:a=""}=e;this.anchor=t,this.placement=s,this.gap=i,this.portal=r,this.onOutsideClick=n,this.element=document.createElement("div"),this.element.className=`mojo-calendar-popover ${a}`.trim(),this.element.style.position="absolute",this.element.style.zIndex="10000",this.element.setAttribute("role","dialog"),this._open=!1,this._onDocClick=this._onDocClick.bind(this),this._onScroll=this._onScroll.bind(this),this._onResize=this._onResize.bind(this),this._onKey=this._onKey.bind(this)}setAnchor(e){this.anchor=e,this._open&&this._reposition()}setContent(e){this.element.innerHTML="",e&&this.element.appendChild(e)}open(){this._open||(this._open=!0,this.portal&&this.element.parentNode!==document.body&&document.body.appendChild(this.element),this.element.classList.add("is-open"),this._reposition(),setTimeout(()=>{document.addEventListener("mousedown",this._onDocClick,!0),document.addEventListener("keydown",this._onKey,!0),window.addEventListener("scroll",this._onScroll,!0),window.addEventListener("resize",this._onResize)},0))}close(){this._open&&(this._open=!1,this.element.classList.remove("is-open"),document.removeEventListener("mousedown",this._onDocClick,!0),document.removeEventListener("keydown",this._onKey,!0),window.removeEventListener("scroll",this._onScroll,!0),window.removeEventListener("resize",this._onResize),this.portal&&this.element.parentNode===document.body&&document.body.removeChild(this.element))}isOpen(){return this._open}destroy(){this.close(),this.element=null}_onDocClick(e){this.element.contains(e.target)||this.anchor&&this.anchor.contains(e.target)||(typeof this.onOutsideClick=="function"?this.onOutsideClick(e):this.close())}_onKey(e){e.key==="Escape"&&this.close()}_onScroll(){this._open&&this._reposition()}_onResize(){this._open&&this._reposition()}_reposition(){if(!this.anchor)return;const e=this.anchor.getBoundingClientRect(),t=this.element.getBoundingClientRect(),s=window.scrollX||window.pageXOffset||0,i=window.scrollY||window.pageYOffset||0;let r=e.bottom+i+this.gap,n=e.left+s;this.placement==="bottom-end"?n=e.right+s-t.width:this.placement==="top-start"?r=e.top+i-t.height-this.gap:this.placement==="top-end"&&(r=e.top+i-t.height-this.gap,n=e.right+s-t.width);const a=document.documentElement.clientWidth||window.innerWidth;n+t.width>s+a-8&&(n=s+a-t.width-8),n<s+8&&(n=s+8);const o=document.documentElement.clientHeight||window.innerHeight;r-i+t.height>o-8&&e.top-t.height-this.gap>8&&(r=e.top+i-t.height-this.gap),this.element.style.top=`${r}px`,this.element.style.left=`${n}px`}}const $t={day:"MMM DD, YYYY",month:"MMM YYYY",year:"YYYY"};class qe extends C{constructor(e={}){const{name:t,value:s="",precision:i="day",format:r=null,displayFormat:n=null,min:a=null,max:o=null,placeholder:l=null,disabled:d=!1,readonly:h=!1,required:u=!1,class:m="",inputClass:p="form-control",inline:f=!1,disabledDates:g=[],firstDay:b=1,lang:y="en-US",autoApply:_=!0,...S}=e;super({tagName:"div",className:`mojo-date-picker mojo-date-picker-${i} ${m}`.trim(),...S}),this.name=t,this.precision=i,this.format=r,this.displayFormat=n||$t[i]||$t.day,this.min=a,this.max=o,this.placeholder=l??this._defaultPlaceholder(i),this.disabled=d,this.readonly=h,this.required=u,this.inputClass=p,this.inline=f,this.disabledDates=g,this.firstDay=b,this.lang=y,this.autoApply=_,this.currentValue=s||"",this._calendar=null,this._popover=null}_defaultPlaceholder(e){return e==="year"?"Select year...":e==="month"?"Select month...":"Select date..."}async renderTemplate(){const e=this._inputId(),t=this._displayText(this.currentValue),s=!this.currentValue;return this.inline?`
1119
1119
  <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(this.currentValue)}" data-hidden-value />
1120
1120
  <div data-cal-host class="mojo-date-picker-inline${this.hasError()?" is-invalid":""}"></div>
1121
1121
  `:`
@@ -1127,7 +1127,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1127
1127
  ${!this.required&&!this.disabled&&!this.readonly?'<button type="button" class="mojo-date-trigger-clear" data-clear aria-label="Clear" tabindex="-1">&#x2715;</button>':""}
1128
1128
  </button>
1129
1129
  <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(this.currentValue)}" data-hidden-value />
1130
- `}async onAfterRender(){this.inline?this._mountCalendarInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this._setValue("")}))}_togglePopover(e){if(!(this.disabled||this.readonly)){if(this._popover?this._popover.setAnchor(e):this._popover=new _e({anchor:e}),this._popover.isOpen()){this._popover.close();return}this._calendar||(this._calendar=this._buildCalendar()),this._popover.setContent(this._calendar.element),this._popover.open(),this._calendar.render(!1)}}_mountCalendarInline(){const e=this.element.querySelector("[data-cal-host]");e&&(this._calendar||(this._calendar=this._buildCalendar()),e.appendChild(this._calendar.element),this._calendar.render(!1))}_buildCalendar(){const e=new He({precision:this.precision,mode:"single",months:1,value:this.currentValue||null,min:this.min,max:this.max,disabledDates:this.disabledDates,firstDay:this.firstDay,locale:this.lang});return e.on("select",({value:t})=>{this._setValue(t),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e}_setValue(e){const t=this.currentValue;let s="";if(e){const a=P(e,this.precision);a&&(s=U(a,this.precision))}this.currentValue=s;const i=this._displayText(s),r=this.element.querySelector("[data-trigger-text]");r&&(r.textContent=i||this.placeholder,r.classList.toggle("is-empty",!s));const n=this.element.querySelector("[data-hidden-value]");n&&(n.value=s),this._calendar&&this._calendar.setValue(s),t!==s&&(this.emit("change",{value:s,formatted:i,oldValue:t}),this.emit("date:changed",{value:s,oldValue:t}))}_displayText(e){if(!e)return"";const t=P(e,this.precision);return t?he(t,this._stripIncompatibleTokens(this.displayFormat)):""}_stripIncompatibleTokens(e){return this.precision==="day"?e:this.precision==="month"?e.replace(/\bDD\b|\bD\b/g,"").replace(/[\s\-\/]+$/,"").trim():this.precision==="year"?e.replace(/MMMM|MMM|MM|M|DD|D/g,"").replace(/[\s\-\/]+$/,"").trim()||"YYYY":e}setValue(e){this._setValue(e)}getValue(){return this.currentValue}getFormattedValue(){return this._displayText(this.currentValue)}clear(){this._setValue("")}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(e)}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(e)}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this._setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-date-${this.name}-${this.id}`:`mojo-date-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){this._popover&&(this._popover.destroy(),this._popover=null),this._calendar=null,await super.onBeforeDestroy()}static create(e={}){return new qe(e)}}function ms(){return[{label:"Today",range:()=>{const c=E();return{start:c,end:c}}},{label:"Yesterday",range:()=>{const c=E(),e=xe(c,-1);return{start:e,end:e}}},{label:"Last 7 days",range:()=>{const c=E();return{start:xe(c,-6),end:c}}},{label:"Last 30 days",range:()=>{const c=E();return{start:xe(c,-29),end:c}}},{label:"Last 90 days",range:()=>{const c=E();return{start:xe(c,-89),end:c}}},{divider:!0},{label:"This month",range:()=>{const c=E();return{start:{y:c.y,m:c.m,d:1},end:c}}},{label:"Last month",range:()=>{const c=E(),e=ae({y:c.y,m:c.m,d:1},-1),t=ae(e,1);t.d=0;const s=new Date(t.y,t.m,0).getDate();return{start:{...e,d:1},end:{...e,d:s}}}},{label:"This year",range:()=>{const c=E();return{start:{y:c.y,m:1,d:1},end:c}}}]}function ps(){return[{label:"This month",range:()=>{const c=E();return{start:{y:c.y,m:c.m},end:{y:c.y,m:c.m}}}},{label:"Last month",range:()=>{const c=E(),e=ae({y:c.y,m:c.m},-1);return{start:e,end:e}}},{label:"Last 3 months",range:()=>{const c=E();return{start:ae({y:c.y,m:c.m},-2),end:{y:c.y,m:c.m}}}},{label:"Last 6 months",range:()=>{const c=E();return{start:ae({y:c.y,m:c.m},-5),end:{y:c.y,m:c.m}}}},{label:"YTD",range:()=>{const c=E();return{start:{y:c.y,m:1},end:{y:c.y,m:c.m}}}},{label:"Last 12 months",range:()=>{const c=E();return{start:ae({y:c.y,m:c.m},-11),end:{y:c.y,m:c.m}}}}]}function fs(){return[{label:"This year",range:()=>{const c=E();return{start:{y:c.y},end:{y:c.y}}}},{label:"Last year",range:()=>{const c=E();return{start:{y:c.y-1},end:{y:c.y-1}}}},{label:"Last 3 years",range:()=>{const c=E();return{start:{y:c.y-2},end:{y:c.y}}}},{label:"Last 5 years",range:()=>{const c=E();return{start:{y:c.y-4},end:{y:c.y}}}},{label:"Last 10 years",range:()=>{const c=E();return{start:{y:c.y-9},end:{y:c.y}}}}]}function xe(c,e){if(!c)return null;const t=new Date(c.y,c.m-1,c.d+e);return{y:t.getFullYear(),m:t.getMonth()+1,d:t.getDate()}}function At(c){return c==="year"?fs():c==="month"?ps():ms()}class gs extends S{constructor(e={}){const{precision:t="day",presets:s="default",eyebrow:i="Quick range",...r}=e;super({tagName:"div",className:"mojo-calendar-presets",...r}),this.precision=t,this.eyebrow=i,this.activeIndex=-1,this.presets=s===!0||s==="default"?At(t):Array.isArray(s)?s:At(t)}setActive(e){this.activeIndex=e,this._highlight()}async renderTemplate(){return""}async onAfterRender(){this._renderInto(this.element)}_renderInto(e){if(e.innerHTML="",this.eyebrow){const t=document.createElement("div");t.className="mojo-calendar-presets-eyebrow",t.textContent=this.eyebrow,e.appendChild(t)}this.presets.forEach((t,s)=>{if(t.divider){const r=document.createElement("div");r.className="mojo-calendar-presets-divider",e.appendChild(r);return}const i=document.createElement("button");i.type="button",i.className="mojo-calendar-preset"+(this.activeIndex===s?" is-active":""),i.dataset.presetIndex=String(s),i.textContent=t.label,e.appendChild(i)}),e.addEventListener("click",t=>{const s=t.target.closest(".mojo-calendar-preset");if(!s)return;const i=parseInt(s.dataset.presetIndex,10),r=this.presets[i];if(!r||typeof r.range!="function")return;const n=r.range();this.activeIndex=i,this._highlight();const a=this.precision==="year"?gt:this.precision==="month"?Re:B;this.emit("preset:select",{index:i,label:r.label,start:a(n.start),end:a(n.end),parsed:n})})}_highlight(){this.element&&this.element.querySelectorAll(".mojo-calendar-preset").forEach(e=>{const t=parseInt(e.dataset.presetIndex,10);e.classList.toggle("is-active",t===this.activeIndex)})}}const Tt={day:"MMM DD, YYYY",month:"MMM YYYY",year:"YYYY"};class Be extends S{constructor(e={}){const{name:t,startName:s,endName:i,fieldName:r,startDate:n="",endDate:a="",precision:o="day",format:l=null,displayFormat:d=null,outputFormat:h="date",min:u=null,max:m=null,placeholder:p=null,disabled:f=!1,readonly:g=!1,required:b=!1,class:y="",inputClass:C="form-control",inline:_=!1,separator:A=" – ",autoApply:F=!0,months:j=null,presets:I=null,...R}=e;super({tagName:"div",className:`mojo-date-picker mojo-date-range-picker mojo-date-picker-${o} ${y}`.trim(),...R}),this.name=t,this.startName=s,this.endName=i,this.fieldName=r,this.precision=o,this.format=l,this.displayFormat=d||Tt[o]||Tt.day,this.outputFormat=h,this.min=u,this.max=m,this.placeholder=p??this._defaultPlaceholder(o),this.disabled=f,this.readonly=g,this.required=b,this.inputClass=C,this.inline=_,this.separator=A,this.autoApply=F,this.months=j??(o==="day"?2:1),this.presets=I,this.currentStartDate=n||"",this.currentEndDate=a||"",this._calendar=null,this._popover=null,this._presetSidebar=null}_defaultPlaceholder(e){return e==="year"?"Select year range...":e==="month"?"Select month range...":"Select date range..."}async renderTemplate(){const e=this._inputId(),t=this._displayText(),s=!this.currentStartDate,i=this.startName||(this.name?`${this.name}_start`:""),r=this.endName||(this.name?`${this.name}_end`:""),n=`
1130
+ `}async onAfterRender(){this.inline?this._mountCalendarInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this._setValue("")}))}_togglePopover(e){if(!(this.disabled||this.readonly)){if(this._popover?this._popover.setAnchor(e):this._popover=new Se({anchor:e}),this._popover.isOpen()){this._popover.close();return}this._calendar||(this._calendar=this._buildCalendar()),this._popover.setContent(this._calendar.element),this._popover.open(),this._calendar.render(!1)}}_mountCalendarInline(){const e=this.element.querySelector("[data-cal-host]");e&&(this._calendar||(this._calendar=this._buildCalendar()),e.appendChild(this._calendar.element),this._calendar.render(!1))}_buildCalendar(){const e=new ze({precision:this.precision,mode:"single",months:1,value:this.currentValue||null,min:this.min,max:this.max,disabledDates:this.disabledDates,firstDay:this.firstDay,locale:this.lang});return e.on("select",({value:t})=>{this._setValue(t),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e}_setValue(e){const t=this.currentValue;let s="";if(e){const a=L(e,this.precision);a&&(s=U(a,this.precision))}this.currentValue=s;const i=this._displayText(s),r=this.element.querySelector("[data-trigger-text]");r&&(r.textContent=i||this.placeholder,r.classList.toggle("is-empty",!s));const n=this.element.querySelector("[data-hidden-value]");n&&(n.value=s),this._calendar&&this._calendar.setValue(s),t!==s&&(this.emit("change",{value:s,formatted:i,oldValue:t}),this.emit("date:changed",{value:s,oldValue:t}))}_displayText(e){if(!e)return"";const t=L(e,this.precision);return t?he(t,this._stripIncompatibleTokens(this.displayFormat)):""}_stripIncompatibleTokens(e){return this.precision==="day"?e:this.precision==="month"?e.replace(/\bDD\b|\bD\b/g,"").replace(/[\s\-\/]+$/,"").trim():this.precision==="year"?e.replace(/MMMM|MMM|MM|M|DD|D/g,"").replace(/[\s\-\/]+$/,"").trim()||"YYYY":e}setValue(e){this._setValue(e)}getValue(){return this.currentValue}getFormattedValue(){return this._displayText(this.currentValue)}clear(){this._setValue("")}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(e)}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(e)}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this._setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-date-${this.name}-${this.id}`:`mojo-date-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){this._popover&&(this._popover.destroy(),this._popover=null),this._calendar=null,await super.onBeforeDestroy()}static create(e={}){return new qe(e)}}function ms(){return[{label:"Today",range:()=>{const c=E();return{start:c,end:c}}},{label:"Yesterday",range:()=>{const c=E(),e=xe(c,-1);return{start:e,end:e}}},{label:"Last 7 days",range:()=>{const c=E();return{start:xe(c,-6),end:c}}},{label:"Last 30 days",range:()=>{const c=E();return{start:xe(c,-29),end:c}}},{label:"Last 90 days",range:()=>{const c=E();return{start:xe(c,-89),end:c}}},{divider:!0},{label:"This month",range:()=>{const c=E();return{start:{y:c.y,m:c.m,d:1},end:c}}},{label:"Last month",range:()=>{const c=E(),e=ae({y:c.y,m:c.m,d:1},-1),t=ae(e,1);t.d=0;const s=new Date(t.y,t.m,0).getDate();return{start:{...e,d:1},end:{...e,d:s}}}},{label:"This year",range:()=>{const c=E();return{start:{y:c.y,m:1,d:1},end:c}}}]}function ps(){return[{label:"This month",range:()=>{const c=E();return{start:{y:c.y,m:c.m},end:{y:c.y,m:c.m}}}},{label:"Last month",range:()=>{const c=E(),e=ae({y:c.y,m:c.m},-1);return{start:e,end:e}}},{label:"Last 3 months",range:()=>{const c=E();return{start:ae({y:c.y,m:c.m},-2),end:{y:c.y,m:c.m}}}},{label:"Last 6 months",range:()=>{const c=E();return{start:ae({y:c.y,m:c.m},-5),end:{y:c.y,m:c.m}}}},{label:"YTD",range:()=>{const c=E();return{start:{y:c.y,m:1},end:{y:c.y,m:c.m}}}},{label:"Last 12 months",range:()=>{const c=E();return{start:ae({y:c.y,m:c.m},-11),end:{y:c.y,m:c.m}}}}]}function fs(){return[{label:"This year",range:()=>{const c=E();return{start:{y:c.y},end:{y:c.y}}}},{label:"Last year",range:()=>{const c=E();return{start:{y:c.y-1},end:{y:c.y-1}}}},{label:"Last 3 years",range:()=>{const c=E();return{start:{y:c.y-2},end:{y:c.y}}}},{label:"Last 5 years",range:()=>{const c=E();return{start:{y:c.y-4},end:{y:c.y}}}},{label:"Last 10 years",range:()=>{const c=E();return{start:{y:c.y-9},end:{y:c.y}}}}]}function xe(c,e){if(!c)return null;const t=new Date(c.y,c.m-1,c.d+e);return{y:t.getFullYear(),m:t.getMonth()+1,d:t.getDate()}}function At(c){return c==="year"?fs():c==="month"?ps():ms()}class gs extends C{constructor(e={}){const{precision:t="day",presets:s="default",eyebrow:i="Quick range",...r}=e;super({tagName:"div",className:"mojo-calendar-presets",...r}),this.precision=t,this.eyebrow=i,this.activeIndex=-1,this.presets=s===!0||s==="default"?At(t):Array.isArray(s)?s:At(t)}setActive(e){this.activeIndex=e,this._highlight()}async renderTemplate(){return""}async onAfterRender(){this._renderInto(this.element)}_renderInto(e){if(e.innerHTML="",this.eyebrow){const t=document.createElement("div");t.className="mojo-calendar-presets-eyebrow",t.textContent=this.eyebrow,e.appendChild(t)}this.presets.forEach((t,s)=>{if(t.divider){const r=document.createElement("div");r.className="mojo-calendar-presets-divider",e.appendChild(r);return}const i=document.createElement("button");i.type="button",i.className="mojo-calendar-preset"+(this.activeIndex===s?" is-active":""),i.dataset.presetIndex=String(s),i.textContent=t.label,e.appendChild(i)}),e.addEventListener("click",t=>{const s=t.target.closest(".mojo-calendar-preset");if(!s)return;const i=parseInt(s.dataset.presetIndex,10),r=this.presets[i];if(!r||typeof r.range!="function")return;const n=r.range();this.activeIndex=i,this._highlight();const a=this.precision==="year"?gt:this.precision==="month"?Oe:B;this.emit("preset:select",{index:i,label:r.label,start:a(n.start),end:a(n.end),parsed:n})})}_highlight(){this.element&&this.element.querySelectorAll(".mojo-calendar-preset").forEach(e=>{const t=parseInt(e.dataset.presetIndex,10);e.classList.toggle("is-active",t===this.activeIndex)})}}const Tt={day:"MMM DD, YYYY",month:"MMM YYYY",year:"YYYY"};class Be extends C{constructor(e={}){const{name:t,startName:s,endName:i,fieldName:r,startDate:n="",endDate:a="",precision:o="day",format:l=null,displayFormat:d=null,outputFormat:h="date",min:u=null,max:m=null,placeholder:p=null,disabled:f=!1,readonly:g=!1,required:b=!1,class:y="",inputClass:_="form-control",inline:S=!1,separator:A=" – ",autoApply:F=!0,months:j=null,presets:I=null,...O}=e;super({tagName:"div",className:`mojo-date-picker mojo-date-range-picker mojo-date-picker-${o} ${y}`.trim(),...O}),this.name=t,this.startName=s,this.endName=i,this.fieldName=r,this.precision=o,this.format=l,this.displayFormat=d||Tt[o]||Tt.day,this.outputFormat=h,this.min=u,this.max=m,this.placeholder=p??this._defaultPlaceholder(o),this.disabled=f,this.readonly=g,this.required=b,this.inputClass=_,this.inline=S,this.separator=A,this.autoApply=F,this.months=j??(o==="day"?2:1),this.presets=I,this.currentStartDate=n||"",this.currentEndDate=a||"",this._calendar=null,this._popover=null,this._presetSidebar=null}_defaultPlaceholder(e){return e==="year"?"Select year range...":e==="month"?"Select month range...":"Select date range..."}async renderTemplate(){const e=this._inputId(),t=this._displayText(),s=!this.currentStartDate,i=this.startName||(this.name?`${this.name}_start`:""),r=this.endName||(this.name?`${this.name}_end`:""),n=`
1131
1131
  ${this.name?`<input type="hidden" name="${this._attr(this.name)}" value="${this._attr(this.getCombinedValue())}" data-combined-value />`:""}
1132
1132
  ${i?`<input type="hidden" name="${this._attr(i)}" value="${this._attr(this.currentStartDate)}" data-start-value />`:""}
1133
1133
  ${r?`<input type="hidden" name="${this._attr(r)}" value="${this._attr(this.currentEndDate)}" data-end-value />`:""}
@@ -1143,7 +1143,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1143
1143
  ${!this.required&&!this.disabled&&!this.readonly?'<button type="button" class="mojo-date-trigger-clear" data-clear aria-label="Clear" tabindex="-1">&#x2715;</button>':""}
1144
1144
  </button>
1145
1145
  ${n}
1146
- `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this._setRange("","")}))}_togglePopover(e){if(this.disabled||this.readonly)return;if(this._popover)this._popover.setAnchor(e);else{const s=this._hasPresets();this._popover=new _e({anchor:e,classNames:s?"mojo-calendar-popover-with-presets":""})}if(this._popover.isOpen()){this._popover.close();return}this._calendar||(this._calendar=this._buildCalendar()),this._hasPresets()&&!this._presetSidebar&&(this._presetSidebar=this._buildPresetSidebar());const t=this._buildPopoverContent();this._popover.setContent(t),this._popover.open(),this._calendar.render(!1),this._presetSidebar&&this._presetSidebar.render(!1)}_mountInline(){const e=this.element.querySelector("[data-cal-host]");e&&(this._calendar||(this._calendar=this._buildCalendar()),this._hasPresets()&&!this._presetSidebar&&(this._presetSidebar=this._buildPresetSidebar()),e.appendChild(this._buildPopoverContent()),this._calendar.render(!1),this._presetSidebar&&this._presetSidebar.render(!1))}_buildPopoverContent(){const e=document.createElement("div");e.className="mojo-calendar-popover-inner",e.style.display="contents",this._presetSidebar&&e.appendChild(this._presetSidebar.element);const t=document.createElement("div");return t.className="mojo-calendar-cal-wrap",t.appendChild(this._calendar.element),e.appendChild(t),e}_buildCalendar(){const e=new He({precision:this.precision,mode:"range",months:this.months,startValue:this.currentStartDate||null,endValue:this.currentEndDate||null,min:this.min,max:this.max,firstDay:1,locale:"en-US"});return e.on("range:select",({start:t,end:s})=>{this._setRange(t,s),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e.on("range:start",()=>{this._presetSidebar&&this._presetSidebar.setActive(-1)}),e}_hasPresets(){return this.presets===!0||this.presets==="default"||Array.isArray(this.presets)&&this.presets.length>0}_buildPresetSidebar(){const e=new gs({precision:this.precision,presets:this.presets});return e.on("preset:select",({start:t,end:s})=>{this._setRange(t,s),this._calendar&&this._calendar.setRange(t,s),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e}_setRange(e,t){const s=this.currentStartDate,i=this.currentEndDate;let r="",n="";if(e){const o=P(e,this.precision);o&&(r=U(o,this.precision))}if(t){const o=P(t,this.precision);o&&(n=U(o,this.precision))}this.currentStartDate=r,this.currentEndDate=n;const a=this.element.querySelector("[data-trigger-text]");if(a){const o=this._displayText();a.textContent=o||this.placeholder,a.classList.toggle("is-empty",!r)}this._updateHidden(),(s!==r||i!==n)&&(this.emit("change",{startDate:r,endDate:n,combined:this.getCombinedValue(),formatted:this._displayText(),oldStartDate:s,oldEndDate:i}),this.emit("range:changed",{startDate:r,endDate:n,oldStartDate:s,oldEndDate:i}))}_updateHidden(){const e=this.element.querySelector("[data-start-value]"),t=this.element.querySelector("[data-end-value]"),s=this.element.querySelector("[data-combined-value]");e&&(e.value=this.currentStartDate),t&&(t.value=this.currentEndDate),s&&(s.value=this.getCombinedValue())}_displayText(){const e=this.currentStartDate?P(this.currentStartDate,this.precision):null,t=this.currentEndDate?P(this.currentEndDate,this.precision):null;if(!e&&!t)return"";const s=this._stripIncompatibleTokens(this.displayFormat);return e&&t?`${he(e,s)}${this.separator}${he(t,s)}`:he(e||t,s)}_stripIncompatibleTokens(e){return this.precision==="day"?e:this.precision==="month"?e.replace(/\bDD\b|\bD\b/g,"").replace(/[\s\-\/]+$/,"").trim():this.precision==="year"?e.replace(/MMMM|MMM|MM|M|DD|D/g,"").replace(/[\s\-\/]+$/,"").trim()||"YYYY":e}getCombinedValue(){return!this.currentStartDate&&!this.currentEndDate?"":this.outputFormat==="string"?`${this.currentStartDate}${this.separator}${this.currentEndDate}`:this.outputFormat==="object"?JSON.stringify({start:this.currentStartDate,end:this.currentEndDate}):`${this.currentStartDate}${this.separator}${this.currentEndDate}`}setRange(e,t){this._setRange(e,t),this._calendar&&this._calendar.setRange(e,t)}setStartDate(e){this._setRange(e,this.currentEndDate)}setEndDate(e){this._setRange(this.currentStartDate,e)}getStartDate(){return this.currentStartDate}getEndDate(){return this.currentEndDate}getRange(){return{start:this.currentStartDate,end:this.currentEndDate}}clear(){this._setRange("","")}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(e)}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(e)}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getCombinedValue()}async setFormValue(e){if(!e){this._setRange("","");return}if(typeof e=="object"&&e.start)this._setRange(e.start,e.end);else if(typeof e=="string"&&e.includes(this.separator.trim())){const[t,s]=e.split(this.separator.trim()).map(i=>i.trim());this._setRange(t,s)}else this._setRange(e,this.currentEndDate)}hasError(){return!1}_inputId(){return this.name?`mojo-daterange-${this.name}-${this.id}`:`mojo-daterange-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){this._popover&&(this._popover.destroy(),this._popover=null),this._calendar=null,this._presetSidebar=null,await super.onBeforeDestroy()}static create(e={}){return new Be(e)}}class Et extends S{constructor(e={}){super(e),this.name=e.name||"combo",this.placeholder=e.placeholder||e.placeHolder||"Type or select...",this.value=e.value||"",this.options=(e.options||[]).map(t=>typeof t=="string"?{label:t,value:t}:typeof t=="object"&&t!==null?t:{label:t,value:t}),this.allowCustom=e.allowCustom!==!1,this.disabled=e.disabled||!1,this.required=e.required||!1,this.maxHeight=e.maxHeight||300,this.filteredOptions=[...this.options],this.highlightedIndex=-1,this.isOpen=!1,this.template=`
1146
+ `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this._setRange("","")}))}_togglePopover(e){if(this.disabled||this.readonly)return;if(this._popover)this._popover.setAnchor(e);else{const s=this._hasPresets();this._popover=new Se({anchor:e,classNames:s?"mojo-calendar-popover-with-presets":""})}if(this._popover.isOpen()){this._popover.close();return}this._calendar||(this._calendar=this._buildCalendar()),this._hasPresets()&&!this._presetSidebar&&(this._presetSidebar=this._buildPresetSidebar());const t=this._buildPopoverContent();this._popover.setContent(t),this._popover.open(),this._calendar.render(!1),this._presetSidebar&&this._presetSidebar.render(!1)}_mountInline(){const e=this.element.querySelector("[data-cal-host]");e&&(this._calendar||(this._calendar=this._buildCalendar()),this._hasPresets()&&!this._presetSidebar&&(this._presetSidebar=this._buildPresetSidebar()),e.appendChild(this._buildPopoverContent()),this._calendar.render(!1),this._presetSidebar&&this._presetSidebar.render(!1))}_buildPopoverContent(){const e=document.createElement("div");e.className="mojo-calendar-popover-inner",e.style.display="contents",this._presetSidebar&&e.appendChild(this._presetSidebar.element);const t=document.createElement("div");return t.className="mojo-calendar-cal-wrap",t.appendChild(this._calendar.element),e.appendChild(t),e}_buildCalendar(){const e=new ze({precision:this.precision,mode:"range",months:this.months,startValue:this.currentStartDate||null,endValue:this.currentEndDate||null,min:this.min,max:this.max,firstDay:1,locale:"en-US"});return e.on("range:select",({start:t,end:s})=>{this._setRange(t,s),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e.on("range:start",()=>{this._presetSidebar&&this._presetSidebar.setActive(-1)}),e}_hasPresets(){return this.presets===!0||this.presets==="default"||Array.isArray(this.presets)&&this.presets.length>0}_buildPresetSidebar(){const e=new gs({precision:this.precision,presets:this.presets});return e.on("preset:select",({start:t,end:s})=>{this._setRange(t,s),this._calendar&&this._calendar.setRange(t,s),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e}_setRange(e,t){const s=this.currentStartDate,i=this.currentEndDate;let r="",n="";if(e){const o=L(e,this.precision);o&&(r=U(o,this.precision))}if(t){const o=L(t,this.precision);o&&(n=U(o,this.precision))}this.currentStartDate=r,this.currentEndDate=n;const a=this.element.querySelector("[data-trigger-text]");if(a){const o=this._displayText();a.textContent=o||this.placeholder,a.classList.toggle("is-empty",!r)}this._updateHidden(),(s!==r||i!==n)&&(this.emit("change",{startDate:r,endDate:n,combined:this.getCombinedValue(),formatted:this._displayText(),oldStartDate:s,oldEndDate:i}),this.emit("range:changed",{startDate:r,endDate:n,oldStartDate:s,oldEndDate:i}))}_updateHidden(){const e=this.element.querySelector("[data-start-value]"),t=this.element.querySelector("[data-end-value]"),s=this.element.querySelector("[data-combined-value]");e&&(e.value=this.currentStartDate),t&&(t.value=this.currentEndDate),s&&(s.value=this.getCombinedValue())}_displayText(){const e=this.currentStartDate?L(this.currentStartDate,this.precision):null,t=this.currentEndDate?L(this.currentEndDate,this.precision):null;if(!e&&!t)return"";const s=this._stripIncompatibleTokens(this.displayFormat);return e&&t?`${he(e,s)}${this.separator}${he(t,s)}`:he(e||t,s)}_stripIncompatibleTokens(e){return this.precision==="day"?e:this.precision==="month"?e.replace(/\bDD\b|\bD\b/g,"").replace(/[\s\-\/]+$/,"").trim():this.precision==="year"?e.replace(/MMMM|MMM|MM|M|DD|D/g,"").replace(/[\s\-\/]+$/,"").trim()||"YYYY":e}getCombinedValue(){return!this.currentStartDate&&!this.currentEndDate?"":this.outputFormat==="string"?`${this.currentStartDate}${this.separator}${this.currentEndDate}`:this.outputFormat==="object"?JSON.stringify({start:this.currentStartDate,end:this.currentEndDate}):`${this.currentStartDate}${this.separator}${this.currentEndDate}`}setRange(e,t){this._setRange(e,t),this._calendar&&this._calendar.setRange(e,t)}setStartDate(e){this._setRange(e,this.currentEndDate)}setEndDate(e){this._setRange(this.currentStartDate,e)}getStartDate(){return this.currentStartDate}getEndDate(){return this.currentEndDate}getRange(){return{start:this.currentStartDate,end:this.currentEndDate}}clear(){this._setRange("","")}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(e)}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(e)}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getCombinedValue()}async setFormValue(e){if(!e){this._setRange("","");return}if(typeof e=="object"&&e.start)this._setRange(e.start,e.end);else if(typeof e=="string"&&e.includes(this.separator.trim())){const[t,s]=e.split(this.separator.trim()).map(i=>i.trim());this._setRange(t,s)}else this._setRange(e,this.currentEndDate)}hasError(){return!1}_inputId(){return this.name?`mojo-daterange-${this.name}-${this.id}`:`mojo-daterange-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){this._popover&&(this._popover.destroy(),this._popover=null),this._calendar=null,this._presetSidebar=null,await super.onBeforeDestroy()}static create(e={}){return new Be(e)}}class Et extends C{constructor(e={}){super(e),this.name=e.name||"combo",this.placeholder=e.placeholder||e.placeHolder||"Type or select...",this.value=e.value||"",this.options=(e.options||[]).map(t=>typeof t=="string"?{label:t,value:t}:typeof t=="object"&&t!==null?t:{label:t,value:t}),this.allowCustom=e.allowCustom!==!1,this.disabled=e.disabled||!1,this.required=e.required||!1,this.maxHeight=e.maxHeight||300,this.filteredOptions=[...this.options],this.highlightedIndex=-1,this.isOpen=!1,this.template=`
1147
1147
  <div class="combobox-container">
1148
1148
  <div class="input-group">
1149
1149
  <input type="text"
@@ -1181,7 +1181,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1181
1181
  {{label}}
1182
1182
  </button>
1183
1183
  {{/items}}
1184
- `}async onInit(){await super.onInit()}async onAfterRender(){if(await super.onAfterRender(),this.input=this.element.querySelector(".combobox-input"),this.dropdown=this.element.querySelector(".combobox-dropdown"),this.dropdownItems=this.element.querySelector('[data-region="dropdown-items"]'),this.noMatchDiv=this.element.querySelector(".combobox-no-match"),this.value&&this.input){const e=this.options.find(t=>t.value===this.value);e?this.input.value=e.label||e.value:this.allowCustom&&(this.input.value=this.value)}this.renderItems(),this.setupEventListeners()}setupEventListeners(){this.input.addEventListener("focus",()=>this.openDropdown()),this.input.addEventListener("input",e=>this.handleInput(e)),this.input.addEventListener("keydown",e=>this.handleKeydown(e)),document.addEventListener("click",e=>{this.element.contains(e.target)||this.closeDropdown()})}handleInput(e){const t=e.target.value.toLowerCase();this.filteredOptions=this.options.filter(s=>(s.label||s.value).toLowerCase().includes(t)),this.highlightedIndex=-1,this.renderItems(),this.openDropdown(),!this.allowCustom&&this.noMatchDiv&&(this.noMatchDiv.style.display=this.filteredOptions.length===0?"block":"none"),this.value=e.target.value,this.emit("change",{value:this.value})}handleKeydown(e){if(!this.isOpen&&(e.key==="ArrowDown"||e.key==="ArrowUp")){this.openDropdown(),e.preventDefault();return}if(this.isOpen)switch(e.key){case"ArrowDown":e.preventDefault(),this.highlightedIndex=Math.min(this.highlightedIndex+1,this.filteredOptions.length-1),this.renderItems(),this.scrollToHighlighted();break;case"ArrowUp":e.preventDefault(),this.highlightedIndex=Math.max(this.highlightedIndex-1,-1),this.renderItems(),this.scrollToHighlighted();break;case"Enter":e.preventDefault(),this.highlightedIndex>=0&&this.selectItem(this.filteredOptions[this.highlightedIndex]);break;case"Escape":e.preventDefault(),this.closeDropdown();break;case"Tab":this.closeDropdown();break}}scrollToHighlighted(){if(this.highlightedIndex<0)return;const t=this.dropdownItems.querySelectorAll(".combobox-item")[this.highlightedIndex];t&&t.scrollIntoView({block:"nearest"})}openDropdown(){this.disabled||this.isOpen||(this.isOpen=!0,this.dropdown.classList.add("show"),this.input.value===""&&(this.filteredOptions=[...this.options],this.renderItems()))}closeDropdown(){this.isOpen&&(this.isOpen=!1,this.dropdown.classList.remove("show"),this.highlightedIndex=-1,this.allowCustom||!this.options.find(t=>t.value===this.input.value||t.label===this.input.value)&&this.input.value!==""&&(this.input.value=this.value))}selectItem(e){const t=e.value,s=e.label||e.value;this.input.value=s,this.value=t,this.closeDropdown(),this.filteredOptions=[...this.options],this.highlightedIndex=-1,this.emit("change",{value:this.value,label:s})}renderItems(){const e=this.filteredOptions.map((s,i)=>({value:s.value,label:s.label||s.value,index:i,highlighted:i===this.highlightedIndex})),t=D.render(this.itemTemplate,{items:e});this.dropdownItems.innerHTML=t}async onActionComboboxInput(e,t){}async onActionComboboxToggle(e,t){this.isOpen?this.closeDropdown():(this.input.focus(),this.openDropdown())}async onActionSelectItem(e,t){const s=t.getAttribute("data-value"),i=this.options.find(r=>r.value===s);i&&this.selectItem(i)}getValue(){return this.value}setValue(e){if(this.value=e,!this.input)return;const t=this.options.find(s=>s.value===e);t?this.input.value=t.label||t.value:this.allowCustom&&(this.input.value=e)}setFormValue(e){this.setValue(e)}getTemplateData(){return{placeholder:this.placeholder,value:this.input?this.input.value:this.value,disabled:this.disabled,required:this.required,maxHeight:this.maxHeight,allowCustom:this.allowCustom}}}const bs=["UTC","GMT","America/New_York","America/Chicago","America/Denver","America/Los_Angeles","America/Anchorage","America/Honolulu","America/Phoenix","America/Toronto","America/Vancouver","America/Mexico_City","America/Sao_Paulo","America/Buenos_Aires","America/Bogota","Europe/London","Europe/Dublin","Europe/Paris","Europe/Berlin","Europe/Madrid","Europe/Rome","Europe/Amsterdam","Europe/Stockholm","Europe/Athens","Europe/Moscow","Europe/Istanbul","Africa/Cairo","Africa/Johannesburg","Africa/Lagos","Africa/Nairobi","Asia/Dubai","Asia/Tehran","Asia/Karachi","Asia/Kolkata","Asia/Bangkok","Asia/Singapore","Asia/Hong_Kong","Asia/Shanghai","Asia/Tokyo","Asia/Seoul","Asia/Jakarta","Asia/Manila","Australia/Perth","Australia/Sydney","Australia/Melbourne","Pacific/Auckland","Pacific/Fiji","Pacific/Honolulu"];let Ft=!1;class Dt extends S{constructor(e={}){const{name:t="timezone",value:s=null,timezones:i=null,disabled:r=!1,required:n=!1,placeholder:a="Search timezone...",...o}=e;super({tagName:"div",className:"mojo-timezone-select",...o}),this.name=t,this.disabled=r,this.required=n,this.placeholder=a,this.timezones=i,this.currentValue=s||ys(),this._combo=null,this.template='<div data-region="combo-host"></div>'}async onAfterRender(){const e=this.element.querySelector('[data-region="combo-host"]');if(!e)return;const s=this._buildZoneList().map(i=>({value:i,label:this._labelFor(i)}));this._combo=new Et({name:this.name,value:this.currentValue,placeholder:this.placeholder,options:s,allowCustom:!1,disabled:this.disabled,required:this.required,maxHeight:280}),await this._combo.render(!0,e),this._combo.on("change",i=>{const r=i&&i.value?i.value:"";if(r!==this.currentValue){const n=this.currentValue;this.currentValue=r,this.emit("change",{value:r,oldValue:n})}})}_buildZoneList(){if(Array.isArray(this.timezones)&&this.timezones.length)return this.timezones.slice();try{if(typeof Intl<"u"&&typeof Intl.supportedValuesOf=="function"){const e=Intl.supportedValuesOf("timeZone");if(Array.isArray(e)&&e.length)return e.slice()}}catch{}return Ft||(Ft=!0,console.warn('[TimezoneSelect] Intl.supportedValuesOf("timeZone") unavailable; falling back to curated list.')),bs.slice()}_labelFor(e){const t=ws(e);return t?`${e} (UTC${t})`:e}getValue(){return this.currentValue}getFormValue(){return this.currentValue}setValue(e){if(e!==this.currentValue&&(this.currentValue=e||"",this._combo)){this._combo.value=this.currentValue;const t=this._combo.element&&this._combo.element.querySelector(".combobox-input");t&&(t.value=this.currentValue)}}setEnabled(e){this.disabled=!e;const t=this.element.querySelector(".combobox-input"),s=this.element.querySelector(".combobox-toggle");t&&(t.disabled=!e),s&&(s.disabled=!e)}async onBeforeDestroy(){if(this._combo&&typeof this._combo.destroy=="function")try{await this._combo.destroy()}catch{}this._combo=null,await super.onBeforeDestroy()}}function ys(){try{return new Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{return"UTC"}}function ws(c){try{const e=new Date,i=new Intl.DateTimeFormat("en-US",{timeZone:c,timeZoneName:"shortOffset"}).formatToParts(e).find(d=>d.type==="timeZoneName");if(!i)return null;let r=i.value;if(r==="GMT")return"+00:00";r=r.replace(/^GMT/,"");const n=r.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!n)return r||null;const a=n[1],o=n[2].padStart(2,"0"),l=n[3]||"00";return`${a==="-"?"−":"+"}${o}:${l}`}catch{return null}}class $e extends S{constructor(e={}){const{name:t,value:s="",format:i="24h",step:r=1,min:n=null,max:a=null,placeholder:o=null,disabled:l=!1,readonly:d=!1,required:h=!1,class:u="",inline:m=!1,autoApply:p=!1,timezone:f=!1,timezones:g=null,outputFormat:b="iso",showFooter:y=!0,...C}=e;super({tagName:"div",className:`mojo-time-picker ${u}`.trim(),...C}),this.name=t,this.format=i==="12h"?"12h":"24h",this.step=Math.max(1,parseInt(r,10)||1),this.min=n,this.max=a,this.placeholder=o??(this.format==="12h"?"h:mm AM/PM":"HH:MM"),this.disabled=l,this.readonly=d,this.required=h,this.inline=m,this.autoApply=p,this.showFooter=y!==!1,this.timezone=f===!0||Array.isArray(f),this.timezoneList=Array.isArray(f)?f:g,this.outputFormat=["object","iana","iso"].includes(b)?b:"iso";const _=this._parseInitial(s);this.currentTime=_.time,this.currentTimezone=_.timezone||(this.timezone?vs():null),this._popover=null,this._tzSelect=null,this._spinner=null}_parseInitial(e){if(e==null||e==="")return{time:null,timezone:null};if(typeof e=="object"&&!Array.isArray(e))return{time:e.time?J(e.time):null,timezone:e.timezone||null};const t=String(e).trim(),s=t.match(/^(\d{1,2}:\d{2})(Z|[+-]\d{2}:?\d{2})$/);if(s){const r=s[2];let n=null;return r==="Z"?n="+00:00":/^[+-]\d{4}$/.test(r)?n=`${r.slice(0,3)}:${r.slice(3)}`:n=r,{time:J(s[1]),timezone:n}}const i=t.indexOf(" ");if(i>-1){const r=t.slice(i+1).trim();return/^(am|pm)$/i.test(r)?{time:J(t),timezone:null}:{time:J(t.slice(0,i)),timezone:r||null}}return{time:J(t),timezone:null}}async renderTemplate(){const e=this._inputId(),t=this._displayText(),s=!this.currentTime,i=this._serialize();return this.inline?`
1184
+ `}async onInit(){await super.onInit()}async onAfterRender(){if(await super.onAfterRender(),this.input=this.element.querySelector(".combobox-input"),this.dropdown=this.element.querySelector(".combobox-dropdown"),this.dropdownItems=this.element.querySelector('[data-region="dropdown-items"]'),this.noMatchDiv=this.element.querySelector(".combobox-no-match"),this.value&&this.input){const e=this.options.find(t=>t.value===this.value);e?this.input.value=e.label||e.value:this.allowCustom&&(this.input.value=this.value)}this.renderItems(),this.setupEventListeners()}setupEventListeners(){this.input.addEventListener("focus",()=>this.openDropdown()),this.input.addEventListener("input",e=>this.handleInput(e)),this.input.addEventListener("keydown",e=>this.handleKeydown(e)),document.addEventListener("click",e=>{this.element.contains(e.target)||this.closeDropdown()})}handleInput(e){const t=e.target.value.toLowerCase();this.filteredOptions=this.options.filter(s=>(s.label||s.value).toLowerCase().includes(t)),this.highlightedIndex=-1,this.renderItems(),this.openDropdown(),!this.allowCustom&&this.noMatchDiv&&(this.noMatchDiv.style.display=this.filteredOptions.length===0?"block":"none"),this.value=e.target.value,this.emit("change",{value:this.value})}handleKeydown(e){if(!this.isOpen&&(e.key==="ArrowDown"||e.key==="ArrowUp")){this.openDropdown(),e.preventDefault();return}if(this.isOpen)switch(e.key){case"ArrowDown":e.preventDefault(),this.highlightedIndex=Math.min(this.highlightedIndex+1,this.filteredOptions.length-1),this.renderItems(),this.scrollToHighlighted();break;case"ArrowUp":e.preventDefault(),this.highlightedIndex=Math.max(this.highlightedIndex-1,-1),this.renderItems(),this.scrollToHighlighted();break;case"Enter":e.preventDefault(),this.highlightedIndex>=0&&this.selectItem(this.filteredOptions[this.highlightedIndex]);break;case"Escape":e.preventDefault(),this.closeDropdown();break;case"Tab":this.closeDropdown();break}}scrollToHighlighted(){if(this.highlightedIndex<0)return;const t=this.dropdownItems.querySelectorAll(".combobox-item")[this.highlightedIndex];t&&t.scrollIntoView({block:"nearest"})}openDropdown(){this.disabled||this.isOpen||(this.isOpen=!0,this.dropdown.classList.add("show"),this.input.value===""&&(this.filteredOptions=[...this.options],this.renderItems()))}closeDropdown(){this.isOpen&&(this.isOpen=!1,this.dropdown.classList.remove("show"),this.highlightedIndex=-1,this.allowCustom||!this.options.find(t=>t.value===this.input.value||t.label===this.input.value)&&this.input.value!==""&&(this.input.value=this.value))}selectItem(e){const t=e.value,s=e.label||e.value;this.input.value=s,this.value=t,this.closeDropdown(),this.filteredOptions=[...this.options],this.highlightedIndex=-1,this.emit("change",{value:this.value,label:s})}renderItems(){const e=this.filteredOptions.map((s,i)=>({value:s.value,label:s.label||s.value,index:i,highlighted:i===this.highlightedIndex})),t=D.render(this.itemTemplate,{items:e});this.dropdownItems.innerHTML=t}async onActionComboboxInput(e,t){}async onActionComboboxToggle(e,t){this.isOpen?this.closeDropdown():(this.input.focus(),this.openDropdown())}async onActionSelectItem(e,t){const s=t.getAttribute("data-value"),i=this.options.find(r=>r.value===s);i&&this.selectItem(i)}getValue(){return this.value}setValue(e){if(this.value=e,!this.input)return;const t=this.options.find(s=>s.value===e);t?this.input.value=t.label||t.value:this.allowCustom&&(this.input.value=e)}setFormValue(e){this.setValue(e)}getTemplateData(){return{placeholder:this.placeholder,value:this.input?this.input.value:this.value,disabled:this.disabled,required:this.required,maxHeight:this.maxHeight,allowCustom:this.allowCustom}}}const bs=["UTC","GMT","America/New_York","America/Chicago","America/Denver","America/Los_Angeles","America/Anchorage","America/Honolulu","America/Phoenix","America/Toronto","America/Vancouver","America/Mexico_City","America/Sao_Paulo","America/Buenos_Aires","America/Bogota","Europe/London","Europe/Dublin","Europe/Paris","Europe/Berlin","Europe/Madrid","Europe/Rome","Europe/Amsterdam","Europe/Stockholm","Europe/Athens","Europe/Moscow","Europe/Istanbul","Africa/Cairo","Africa/Johannesburg","Africa/Lagos","Africa/Nairobi","Asia/Dubai","Asia/Tehran","Asia/Karachi","Asia/Kolkata","Asia/Bangkok","Asia/Singapore","Asia/Hong_Kong","Asia/Shanghai","Asia/Tokyo","Asia/Seoul","Asia/Jakarta","Asia/Manila","Australia/Perth","Australia/Sydney","Australia/Melbourne","Pacific/Auckland","Pacific/Fiji","Pacific/Honolulu"];let Ft=!1;class Dt extends C{constructor(e={}){const{name:t="timezone",value:s=null,timezones:i=null,disabled:r=!1,required:n=!1,placeholder:a="Search timezone...",...o}=e;super({tagName:"div",className:"mojo-timezone-select",...o}),this.name=t,this.disabled=r,this.required=n,this.placeholder=a,this.timezones=i,this.currentValue=s||ys(),this._combo=null,this.template='<div data-region="combo-host"></div>'}async onAfterRender(){const e=this.element.querySelector('[data-region="combo-host"]');if(!e)return;const s=this._buildZoneList().map(i=>({value:i,label:this._labelFor(i)}));this._combo=new Et({name:this.name,value:this.currentValue,placeholder:this.placeholder,options:s,allowCustom:!1,disabled:this.disabled,required:this.required,maxHeight:280}),await this._combo.render(!0,e),this._combo.on("change",i=>{const r=i&&i.value?i.value:"";if(r!==this.currentValue){const n=this.currentValue;this.currentValue=r,this.emit("change",{value:r,oldValue:n})}})}_buildZoneList(){if(Array.isArray(this.timezones)&&this.timezones.length)return this.timezones.slice();try{if(typeof Intl<"u"&&typeof Intl.supportedValuesOf=="function"){const e=Intl.supportedValuesOf("timeZone");if(Array.isArray(e)&&e.length)return e.slice()}}catch{}return Ft||(Ft=!0,console.warn('[TimezoneSelect] Intl.supportedValuesOf("timeZone") unavailable; falling back to curated list.')),bs.slice()}_labelFor(e){const t=ws(e);return t?`${e} (UTC${t})`:e}getValue(){return this.currentValue}getFormValue(){return this.currentValue}setValue(e){if(e!==this.currentValue&&(this.currentValue=e||"",this._combo)){this._combo.value=this.currentValue;const t=this._combo.element&&this._combo.element.querySelector(".combobox-input");t&&(t.value=this.currentValue)}}setEnabled(e){this.disabled=!e;const t=this.element.querySelector(".combobox-input"),s=this.element.querySelector(".combobox-toggle");t&&(t.disabled=!e),s&&(s.disabled=!e)}async onBeforeDestroy(){if(this._combo&&typeof this._combo.destroy=="function")try{await this._combo.destroy()}catch{}this._combo=null,await super.onBeforeDestroy()}}function ys(){try{return new Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{return"UTC"}}function ws(c){try{const e=new Date,i=new Intl.DateTimeFormat("en-US",{timeZone:c,timeZoneName:"shortOffset"}).formatToParts(e).find(d=>d.type==="timeZoneName");if(!i)return null;let r=i.value;if(r==="GMT")return"+00:00";r=r.replace(/^GMT/,"");const n=r.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!n)return r||null;const a=n[1],o=n[2].padStart(2,"0"),l=n[3]||"00";return`${a==="-"?"−":"+"}${o}:${l}`}catch{return null}}class $e extends C{constructor(e={}){const{name:t,value:s="",format:i="24h",step:r=1,min:n=null,max:a=null,placeholder:o=null,disabled:l=!1,readonly:d=!1,required:h=!1,class:u="",inline:m=!1,autoApply:p=!1,timezone:f=!1,timezones:g=null,outputFormat:b="iso",showFooter:y=!0,..._}=e;super({tagName:"div",className:`mojo-time-picker ${u}`.trim(),..._}),this.name=t,this.format=i==="12h"?"12h":"24h",this.step=Math.max(1,parseInt(r,10)||1),this.min=n,this.max=a,this.placeholder=o??(this.format==="12h"?"h:mm AM/PM":"HH:MM"),this.disabled=l,this.readonly=d,this.required=h,this.inline=m,this.autoApply=p,this.showFooter=y!==!1,this.timezone=f===!0||Array.isArray(f),this.timezoneList=Array.isArray(f)?f:g,this.outputFormat=["object","iana","iso"].includes(b)?b:"iso";const S=this._parseInitial(s);this.currentTime=S.time,this.currentTimezone=S.timezone||(this.timezone?vs():null),this._popover=null,this._tzSelect=null,this._spinner=null}_parseInitial(e){if(e==null||e==="")return{time:null,timezone:null};if(typeof e=="object"&&!Array.isArray(e))return{time:e.time?J(e.time):null,timezone:e.timezone||null};const t=String(e).trim(),s=t.match(/^(\d{1,2}:\d{2})(Z|[+-]\d{2}:?\d{2})$/);if(s){const r=s[2];let n=null;return r==="Z"?n="+00:00":/^[+-]\d{4}$/.test(r)?n=`${r.slice(0,3)}:${r.slice(3)}`:n=r,{time:J(s[1]),timezone:n}}const i=t.indexOf(" ");if(i>-1){const r=t.slice(i+1).trim();return/^(am|pm)$/i.test(r)?{time:J(t),timezone:null}:{time:J(t.slice(0,i)),timezone:r||null}}return{time:J(t),timezone:null}}async renderTemplate(){const e=this._inputId(),t=this._displayText(),s=!this.currentTime,i=this._serialize();return this.inline?`
1185
1185
  <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(i)}" data-hidden-value />
1186
1186
  <div data-time-host class="mojo-time-picker-inline${this.hasError()?" is-invalid":""}"></div>
1187
1187
  `:`
@@ -1193,7 +1193,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1193
1193
  ${!this.required&&!this.disabled&&!this.readonly?'<button type="button" class="mojo-time-trigger-clear" data-clear aria-label="Clear" tabindex="-1">&#x2715;</button>':""}
1194
1194
  </button>
1195
1195
  <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(i)}" data-hidden-value />
1196
- `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this.clear()}))}_togglePopover(e){if(this.disabled||this.readonly)return;if(this._popover?this._popover.setAnchor(e):this._popover=new _e({anchor:e,classNames:"mojo-time-popover"}),this._popover.isOpen()){this._popover.close();return}const t=this._buildSpinnerContent();this._popover.setContent(t),this._popover.open(),this.timezone&&this._mountTimezoneSelect()}_mountInline(){const e=this.element.querySelector("[data-time-host]");if(!e)return;const t=this._buildSpinnerContent();e.appendChild(t),this.timezone&&this._mountTimezoneSelect()}_buildSpinnerContent(){const e=document.createElement("div");e.className="mojo-time-popover-inner";const t=document.createElement("div");t.className="mojo-time-stepper-row";const s=this.currentTime||{hours:0,minutes:0},i=this._hourDisplay(s.hours);t.appendChild(this._buildStepper("hour",i,"Hour"));const r=document.createElement("div");if(r.className="mojo-time-stepper-sep",r.textContent=":",t.appendChild(r),t.appendChild(this._buildStepper("minute",Ue(s.minutes),"Minute")),this.format==="12h"&&t.appendChild(this._buildAmPmToggle(s.hours)),e.appendChild(t),this.timezone){const n=document.createElement("div");n.className="mojo-time-tz-host",n.setAttribute("data-tz-host",""),e.appendChild(n)}if(this.showFooter){const n=document.createElement("div");n.className="mojo-time-foot";const a=document.createElement("button");a.type="button",a.className="btn btn-link btn-sm mojo-time-now",a.textContent="Now",a.addEventListener("click",l=>{l.preventDefault();const d=new Date;this._commitTime({hours:d.getHours(),minutes:d.getMinutes()}),this._refreshSpinnerDisplay()}),n.appendChild(a);const o=document.createElement("button");o.type="button",o.className="btn btn-primary btn-sm mojo-time-apply",o.textContent="Set",o.addEventListener("click",l=>{l.preventDefault(),this.currentTime||this._commitTime({hours:0,minutes:0}),this._popover&&this._popover.isOpen()&&this._popover.close()}),n.appendChild(o),e.appendChild(n)}return this._spinner=e,e}_buildStepper(e,t,s){const i=document.createElement("div");i.className=`mojo-time-stepper mojo-time-stepper-${e}`;const r=document.createElement("button");r.type="button",r.className="mojo-time-stepper-btn",r.setAttribute("aria-label",`Increase ${s.toLowerCase()}`),r.innerHTML='<i class="bi bi-chevron-up" aria-hidden="true"></i>',r.addEventListener("click",l=>{l.preventDefault(),this._step(e,1)});const n=document.createElement("input");n.type="text",n.className="mojo-time-stepper-value",n.value=t,n.setAttribute("inputmode","numeric"),n.setAttribute("aria-label",s),n.maxLength=2,n.addEventListener("focus",()=>n.select()),n.addEventListener("keydown",l=>this._onValueKey(e,n,l)),n.addEventListener("blur",()=>this._onValueBlur(e,n));const a=document.createElement("button");a.type="button",a.className="mojo-time-stepper-btn",a.setAttribute("aria-label",`Decrease ${s.toLowerCase()}`),a.innerHTML='<i class="bi bi-chevron-down" aria-hidden="true"></i>',a.addEventListener("click",l=>{l.preventDefault(),this._step(e,-1)});const o=document.createElement("div");return o.className="mojo-time-stepper-label",o.textContent=s,i.appendChild(r),i.appendChild(n),i.appendChild(a),i.appendChild(o),i}_buildAmPmToggle(e){const t=document.createElement("div");t.className="mojo-time-ampm";const s=e>=12,i=document.createElement("button");i.type="button",i.className=`mojo-time-ampm-btn${s?"":" is-active"}`,i.textContent="AM",i.addEventListener("click",n=>{n.preventDefault(),this._setAmPm("am")});const r=document.createElement("button");return r.type="button",r.className=`mojo-time-ampm-btn${s?" is-active":""}`,r.textContent="PM",r.addEventListener("click",n=>{n.preventDefault(),this._setAmPm("pm")}),t.appendChild(i),t.appendChild(r),t}_mountTimezoneSelect(){if(!this.timezone)return;const e=this.inline?this.element.querySelector("[data-time-host] [data-tz-host]"):this._spinner&&this._spinner.querySelector("[data-tz-host]");if(e){if(this._tzSelect)try{this._tzSelect.destroy&&this._tzSelect.destroy()}catch{}e.innerHTML="",this._tzSelect=new Dt({name:"timezone",value:this.currentTimezone,timezones:this.timezoneList}),this._tzSelect.render(!0,e),this._tzSelect.on("change",({value:t})=>{const s=this.currentTimezone;this.currentTimezone=t||null,s!==this.currentTimezone&&this._syncOutputs()})}}_step(e,t){const s=this.currentTime||{hours:0,minutes:0};let{hours:i,minutes:r}=s;if(e==="hour")i=((i+t)%24+24)%24;else{const a=i*60+r,o=t*this.step,l=((a+o)%1440+1440)%1440;i=Math.floor(l/60),r=l%60}const n=this._clampToBounds({hours:i,minutes:r});this._commitTime(n),this._refreshSpinnerDisplay()}_setAmPm(e){if(!this.currentTime)this._commitTime({hours:e==="pm"?12:0,minutes:0});else{const{hours:t,minutes:s}=this.currentTime;let i=t;e==="am"&&i>=12?i-=12:e==="pm"&&i<12&&(i+=12),this._commitTime(this._clampToBounds({hours:i,minutes:s}))}this._refreshSpinnerDisplay()}_onValueKey(e,t,s){s.key==="ArrowUp"?(s.preventDefault(),this._step(e,1),t.focus(),t.select()):s.key==="ArrowDown"?(s.preventDefault(),this._step(e,-1),t.focus(),t.select()):s.key==="Enter"?(s.preventDefault(),t.blur()):s.key==="Tab"||!/^[0-9]$/.test(s.key)&&!["Backspace","Delete","ArrowLeft","ArrowRight","Home","End"].includes(s.key)&&s.preventDefault()}_onValueBlur(e,t){const s=(t.value||"").replace(/\D/g,"");if(s===""){this._refreshSpinnerDisplay();return}let i=parseInt(s,10);const r=this.currentTime||{hours:0,minutes:0};let{hours:n,minutes:a}=r;if(e==="hour")if(this.format==="12h"){i<1&&(i=1),i>12&&(i=12);const o=r.hours>=12;i===12?n=o?12:0:n=o?i+12:i}else i<0&&(i=0),i>23&&(i=23),n=i;else i<0&&(i=0),i>59&&(i=59),a=i;this._commitTime(this._clampToBounds({hours:n,minutes:a})),this._refreshSpinnerDisplay()}_hourDisplay(e){if(this.format==="12h"){let t=e%12;return t===0&&(t=12),String(t)}return Ue(e)}_refreshSpinnerDisplay(){if(!this._spinner)return;const e=this.currentTime||{hours:0,minutes:0},t=this._spinner.querySelector(".mojo-time-stepper-hour .mojo-time-stepper-value"),s=this._spinner.querySelector(".mojo-time-stepper-minute .mojo-time-stepper-value");if(t&&(t.value=this._hourDisplay(e.hours)),s&&(s.value=Ue(e.minutes)),this.format==="12h"){const i=e.hours>=12,r=this._spinner.querySelector(".mojo-time-ampm-btn:nth-child(1)"),n=this._spinner.querySelector(".mojo-time-ampm-btn:nth-child(2)");r&&r.classList.toggle("is-active",!i),n&&n.classList.toggle("is-active",i)}}_clampToBounds(e){const t=this.min?J(this.min):null,s=this.max?J(this.max):null;return t&&vt(e,t)<0?t:s&&vt(e,s)>0?s:e}_commitTime(e){const t=this._serialize();this.currentTime=e?{hours:e.hours,minutes:e.minutes}:null,this._syncOutputs(t)}_syncOutputs(e){const t=this._serialize(),s=this._displayText(),i=this.element&&this.element.querySelector("[data-trigger-text]");i&&(i.textContent=s||this.placeholder,i.classList.toggle("is-empty",!this.currentTime));const r=this.element&&this.element.querySelector("[data-hidden-value]");r&&(r.value=t),e!==void 0&&e!==t&&(this.emit("change",{value:this.getValue(),formatted:s,oldValue:e}),this.emit("time:changed",{value:this.getValue()}))}_serialize(){if(!this.currentTime)return"";const e=Z(this.currentTime,"24h");if(!this.timezone||!this.currentTimezone)return e;if(this.outputFormat==="iana")return`${e} ${this.currentTimezone}`;const t=Ct(this.currentTimezone,new Date);return t?`${e}${t}`:e}_displayText(){if(!this.currentTime)return"";const e=Z(this.currentTime,this.format);return this.timezone&&this.currentTimezone?`${e} ${this.currentTimezone}`:e}getValue(){return this.currentTime?this.timezone&&this.outputFormat==="object"?{time:Z(this.currentTime,"24h"),timezone:this.currentTimezone||null}:this._serialize():this.outputFormat==="object"?null:""}setValue(e){const t=this._serialize(),s=this._parseInitial(e);this.currentTime=s.time,s.timezone&&(this.currentTimezone=s.timezone),this._refreshSpinnerDisplay(),this._syncOutputs(t)}getFormattedValue(){return this._displayText()}clear(){if(!this.currentTime&&!this.element.querySelector("[data-hidden-value]")?.value)return;const e=this._serialize();this.currentTime=null,this._syncOutputs(e)}setMin(e){this.min=e}setMax(e){this.max=e}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-time-${this.name}-${this.id}`:`mojo-time-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){if(this._popover){try{this._popover.destroy()}catch{}this._popover=null}if(this._tzSelect){try{await this._tzSelect.destroy()}catch{}this._tzSelect=null}this._spinner=null,await super.onBeforeDestroy()}static addMinutes(e,t){return hs(e,t)}static create(e={}){return new $e(e)}}function Ue(c){return c<10?"0"+c:String(c)}function vs(){try{return new Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{return"UTC"}}const Cs="MMM DD, YYYY";class We extends S{constructor(e={}){const{name:t,value:s="",format:i=null,displayFormat:r=null,timeFormat:n="24h",timeStep:a=1,min:o=null,max:l=null,placeholder:d=null,disabled:h=!1,readonly:u=!1,required:m=!1,class:p="",inline:f=!1,disabledDates:g=[],firstDay:b=1,lang:y="en-US",autoApply:C=!1,timezone:_=!1,timezones:A=null,outputFormat:F="iso",...j}=e;super({tagName:"div",className:`mojo-datetime-picker ${p}`.trim(),...j}),this.name=t,this.format=i,this.displayFormat=r||Cs,this.timeFormat=n==="12h"?"12h":"24h",this.timeStep=Math.max(1,parseInt(a,10)||1),this.min=o,this.max=l,this.placeholder=d??"Pick date & time...",this.disabled=h,this.readonly=u,this.required=m,this.inline=f,this.disabledDates=g,this.firstDay=b,this.lang=y,this.autoApply=C,this.timezone=_===!0||Array.isArray(_),this.timezoneList=Array.isArray(_)?_:A,this.outputFormat=["object","iana","iso"].includes(F)?F:"iso";const I=this._parseInitial(s);this.currentDate=I.date,this.currentTime=I.time,this.currentTimezone=I.timezone||(this.timezone?Mt():null),this._calendar=null,this._timePicker=null,this._tzSelect=null,this._popover=null,this._popoverContent=null}_parseInitial(e){return e==null||e===""?{date:null,time:null,timezone:null}:typeof e=="object"&&!Array.isArray(e)&&!(e instanceof Date)?St(e)||{date:null,time:null,timezone:null}:St(e)||{date:null,time:null,timezone:null}}async renderTemplate(){const e=this._inputId(),t=this._displayText(),s=!this.currentDate,i=this._serialize();return this.inline?`
1196
+ `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this.clear()}))}_togglePopover(e){if(this.disabled||this.readonly)return;if(this._popover?this._popover.setAnchor(e):this._popover=new Se({anchor:e,classNames:"mojo-time-popover"}),this._popover.isOpen()){this._popover.close();return}const t=this._buildSpinnerContent();this._popover.setContent(t),this._popover.open(),this.timezone&&this._mountTimezoneSelect()}_mountInline(){const e=this.element.querySelector("[data-time-host]");if(!e)return;const t=this._buildSpinnerContent();e.appendChild(t),this.timezone&&this._mountTimezoneSelect()}_buildSpinnerContent(){const e=document.createElement("div");e.className="mojo-time-popover-inner";const t=document.createElement("div");t.className="mojo-time-stepper-row";const s=this.currentTime||{hours:0,minutes:0},i=this._hourDisplay(s.hours);t.appendChild(this._buildStepper("hour",i,"Hour"));const r=document.createElement("div");if(r.className="mojo-time-stepper-sep",r.textContent=":",t.appendChild(r),t.appendChild(this._buildStepper("minute",Ue(s.minutes),"Minute")),this.format==="12h"&&t.appendChild(this._buildAmPmToggle(s.hours)),e.appendChild(t),this.timezone){const n=document.createElement("div");n.className="mojo-time-tz-host",n.setAttribute("data-tz-host",""),e.appendChild(n)}if(this.showFooter){const n=document.createElement("div");n.className="mojo-time-foot";const a=document.createElement("button");a.type="button",a.className="btn btn-link btn-sm mojo-time-now",a.textContent="Now",a.addEventListener("click",l=>{l.preventDefault();const d=new Date;this._commitTime({hours:d.getHours(),minutes:d.getMinutes()}),this._refreshSpinnerDisplay()}),n.appendChild(a);const o=document.createElement("button");o.type="button",o.className="btn btn-primary btn-sm mojo-time-apply",o.textContent="Set",o.addEventListener("click",l=>{l.preventDefault(),this.currentTime||this._commitTime({hours:0,minutes:0}),this._popover&&this._popover.isOpen()&&this._popover.close()}),n.appendChild(o),e.appendChild(n)}return this._spinner=e,e}_buildStepper(e,t,s){const i=document.createElement("div");i.className=`mojo-time-stepper mojo-time-stepper-${e}`;const r=document.createElement("button");r.type="button",r.className="mojo-time-stepper-btn",r.setAttribute("aria-label",`Increase ${s.toLowerCase()}`),r.innerHTML='<i class="bi bi-chevron-up" aria-hidden="true"></i>',r.addEventListener("click",l=>{l.preventDefault(),this._step(e,1)});const n=document.createElement("input");n.type="text",n.className="mojo-time-stepper-value",n.value=t,n.setAttribute("inputmode","numeric"),n.setAttribute("aria-label",s),n.maxLength=2,n.addEventListener("focus",()=>n.select()),n.addEventListener("keydown",l=>this._onValueKey(e,n,l)),n.addEventListener("blur",()=>this._onValueBlur(e,n));const a=document.createElement("button");a.type="button",a.className="mojo-time-stepper-btn",a.setAttribute("aria-label",`Decrease ${s.toLowerCase()}`),a.innerHTML='<i class="bi bi-chevron-down" aria-hidden="true"></i>',a.addEventListener("click",l=>{l.preventDefault(),this._step(e,-1)});const o=document.createElement("div");return o.className="mojo-time-stepper-label",o.textContent=s,i.appendChild(r),i.appendChild(n),i.appendChild(a),i.appendChild(o),i}_buildAmPmToggle(e){const t=document.createElement("div");t.className="mojo-time-ampm";const s=e>=12,i=document.createElement("button");i.type="button",i.className=`mojo-time-ampm-btn${s?"":" is-active"}`,i.textContent="AM",i.addEventListener("click",n=>{n.preventDefault(),this._setAmPm("am")});const r=document.createElement("button");return r.type="button",r.className=`mojo-time-ampm-btn${s?" is-active":""}`,r.textContent="PM",r.addEventListener("click",n=>{n.preventDefault(),this._setAmPm("pm")}),t.appendChild(i),t.appendChild(r),t}_mountTimezoneSelect(){if(!this.timezone)return;const e=this.inline?this.element.querySelector("[data-time-host] [data-tz-host]"):this._spinner&&this._spinner.querySelector("[data-tz-host]");if(e){if(this._tzSelect)try{this._tzSelect.destroy&&this._tzSelect.destroy()}catch{}e.innerHTML="",this._tzSelect=new Dt({name:"timezone",value:this.currentTimezone,timezones:this.timezoneList}),this._tzSelect.render(!0,e),this._tzSelect.on("change",({value:t})=>{const s=this.currentTimezone;this.currentTimezone=t||null,s!==this.currentTimezone&&this._syncOutputs()})}}_step(e,t){const s=this.currentTime||{hours:0,minutes:0};let{hours:i,minutes:r}=s;if(e==="hour")i=((i+t)%24+24)%24;else{const a=i*60+r,o=t*this.step,l=((a+o)%1440+1440)%1440;i=Math.floor(l/60),r=l%60}const n=this._clampToBounds({hours:i,minutes:r});this._commitTime(n),this._refreshSpinnerDisplay()}_setAmPm(e){if(!this.currentTime)this._commitTime({hours:e==="pm"?12:0,minutes:0});else{const{hours:t,minutes:s}=this.currentTime;let i=t;e==="am"&&i>=12?i-=12:e==="pm"&&i<12&&(i+=12),this._commitTime(this._clampToBounds({hours:i,minutes:s}))}this._refreshSpinnerDisplay()}_onValueKey(e,t,s){s.key==="ArrowUp"?(s.preventDefault(),this._step(e,1),t.focus(),t.select()):s.key==="ArrowDown"?(s.preventDefault(),this._step(e,-1),t.focus(),t.select()):s.key==="Enter"?(s.preventDefault(),t.blur()):s.key==="Tab"||!/^[0-9]$/.test(s.key)&&!["Backspace","Delete","ArrowLeft","ArrowRight","Home","End"].includes(s.key)&&s.preventDefault()}_onValueBlur(e,t){const s=(t.value||"").replace(/\D/g,"");if(s===""){this._refreshSpinnerDisplay();return}let i=parseInt(s,10);const r=this.currentTime||{hours:0,minutes:0};let{hours:n,minutes:a}=r;if(e==="hour")if(this.format==="12h"){i<1&&(i=1),i>12&&(i=12);const o=r.hours>=12;i===12?n=o?12:0:n=o?i+12:i}else i<0&&(i=0),i>23&&(i=23),n=i;else i<0&&(i=0),i>59&&(i=59),a=i;this._commitTime(this._clampToBounds({hours:n,minutes:a})),this._refreshSpinnerDisplay()}_hourDisplay(e){if(this.format==="12h"){let t=e%12;return t===0&&(t=12),String(t)}return Ue(e)}_refreshSpinnerDisplay(){if(!this._spinner)return;const e=this.currentTime||{hours:0,minutes:0},t=this._spinner.querySelector(".mojo-time-stepper-hour .mojo-time-stepper-value"),s=this._spinner.querySelector(".mojo-time-stepper-minute .mojo-time-stepper-value");if(t&&(t.value=this._hourDisplay(e.hours)),s&&(s.value=Ue(e.minutes)),this.format==="12h"){const i=e.hours>=12,r=this._spinner.querySelector(".mojo-time-ampm-btn:nth-child(1)"),n=this._spinner.querySelector(".mojo-time-ampm-btn:nth-child(2)");r&&r.classList.toggle("is-active",!i),n&&n.classList.toggle("is-active",i)}}_clampToBounds(e){const t=this.min?J(this.min):null,s=this.max?J(this.max):null;return t&&vt(e,t)<0?t:s&&vt(e,s)>0?s:e}_commitTime(e){const t=this._serialize();this.currentTime=e?{hours:e.hours,minutes:e.minutes}:null,this._syncOutputs(t)}_syncOutputs(e){const t=this._serialize(),s=this._displayText(),i=this.element&&this.element.querySelector("[data-trigger-text]");i&&(i.textContent=s||this.placeholder,i.classList.toggle("is-empty",!this.currentTime));const r=this.element&&this.element.querySelector("[data-hidden-value]");r&&(r.value=t),e!==void 0&&e!==t&&(this.emit("change",{value:this.getValue(),formatted:s,oldValue:e}),this.emit("time:changed",{value:this.getValue()}))}_serialize(){if(!this.currentTime)return"";const e=K(this.currentTime,"24h");if(!this.timezone||!this.currentTimezone)return e;if(this.outputFormat==="iana")return`${e} ${this.currentTimezone}`;const t=_t(this.currentTimezone,new Date);return t?`${e}${t}`:e}_displayText(){if(!this.currentTime)return"";const e=K(this.currentTime,this.format);return this.timezone&&this.currentTimezone?`${e} ${this.currentTimezone}`:e}getValue(){return this.currentTime?this.timezone&&this.outputFormat==="object"?{time:K(this.currentTime,"24h"),timezone:this.currentTimezone||null}:this._serialize():this.outputFormat==="object"?null:""}setValue(e){const t=this._serialize(),s=this._parseInitial(e);this.currentTime=s.time,s.timezone&&(this.currentTimezone=s.timezone),this._refreshSpinnerDisplay(),this._syncOutputs(t)}getFormattedValue(){return this._displayText()}clear(){if(!this.currentTime&&!this.element.querySelector("[data-hidden-value]")?.value)return;const e=this._serialize();this.currentTime=null,this._syncOutputs(e)}setMin(e){this.min=e}setMax(e){this.max=e}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-time-${this.name}-${this.id}`:`mojo-time-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){if(this._popover){try{this._popover.destroy()}catch{}this._popover=null}if(this._tzSelect){try{await this._tzSelect.destroy()}catch{}this._tzSelect=null}this._spinner=null,await super.onBeforeDestroy()}static addMinutes(e,t){return hs(e,t)}static create(e={}){return new $e(e)}}function Ue(c){return c<10?"0"+c:String(c)}function vs(){try{return new Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{return"UTC"}}const _s="MMM DD, YYYY";class We extends C{constructor(e={}){const{name:t,value:s="",format:i=null,displayFormat:r=null,timeFormat:n="24h",timeStep:a=1,min:o=null,max:l=null,placeholder:d=null,disabled:h=!1,readonly:u=!1,required:m=!1,class:p="",inline:f=!1,disabledDates:g=[],firstDay:b=1,lang:y="en-US",autoApply:_=!1,timezone:S=!1,timezones:A=null,outputFormat:F="iso",...j}=e;super({tagName:"div",className:`mojo-datetime-picker ${p}`.trim(),...j}),this.name=t,this.format=i,this.displayFormat=r||_s,this.timeFormat=n==="12h"?"12h":"24h",this.timeStep=Math.max(1,parseInt(a,10)||1),this.min=o,this.max=l,this.placeholder=d??"Pick date & time...",this.disabled=h,this.readonly=u,this.required=m,this.inline=f,this.disabledDates=g,this.firstDay=b,this.lang=y,this.autoApply=_,this.timezone=S===!0||Array.isArray(S),this.timezoneList=Array.isArray(S)?S:A,this.outputFormat=["object","iana","iso"].includes(F)?F:"iso";const I=this._parseInitial(s);this.currentDate=I.date,this.currentTime=I.time,this.currentTimezone=I.timezone||(this.timezone?kt():null),this._calendar=null,this._timePicker=null,this._tzSelect=null,this._popover=null,this._popoverContent=null}_parseInitial(e){return e==null||e===""?{date:null,time:null,timezone:null}:typeof e=="object"&&!Array.isArray(e)&&!(e instanceof Date)?Ct(e)||{date:null,time:null,timezone:null}:Ct(e)||{date:null,time:null,timezone:null}}async renderTemplate(){const e=this._inputId(),t=this._displayText(),s=!this.currentDate,i=this._serialize();return this.inline?`
1197
1197
  <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(i)}" data-hidden-value />
1198
1198
  <div data-dt-host class="mojo-datetime-picker-inline${this.hasError()?" is-invalid":""}"></div>
1199
1199
  `:`
@@ -1205,7 +1205,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1205
1205
  ${!this.required&&!this.disabled&&!this.readonly?'<button type="button" class="mojo-datetime-trigger-clear" data-clear aria-label="Clear" tabindex="-1">&#x2715;</button>':""}
1206
1206
  </button>
1207
1207
  <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(i)}" data-hidden-value />
1208
- `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this.clear()}))}_togglePopover(e){if(!(this.disabled||this.readonly)){if(this._popover?this._popover.setAnchor(e):this._popover=new _e({anchor:e,classNames:"mojo-datetime-popover"}),this._popover.isOpen()){this._popover.close();return}this._popoverContent||(this._popoverContent=this._buildContent()),this._popover.setContent(this._popoverContent),this._popover.open(),this._calendar&&this._calendar.render(!1)}}_mountInline(){const e=this.element.querySelector("[data-dt-host]");e&&(this._popoverContent||(this._popoverContent=this._buildContent()),e.appendChild(this._popoverContent),this._calendar&&this._calendar.render(!1))}_buildContent(){const e=document.createElement("div");e.className="mojo-datetime-popover-inner";const t=document.createElement("div");t.className="mojo-datetime-row";const s=document.createElement("div");s.className="mojo-datetime-cal-col",t.appendChild(s);const i=document.createElement("div");i.className="mojo-datetime-time-col",t.appendChild(i),e.appendChild(t),this._calendar=new He({precision:"day",mode:"single",months:1,value:this.currentDate?B(this.currentDate):null,min:this._dateBound(this.min),max:this._dateBound(this.max),disabledDates:this.disabledDates,firstDay:this.firstDay,locale:this.lang}),s.appendChild(this._calendar.element),this._calendar.on("select",({value:l})=>{const d=q(l);this.currentDate=d,this.currentTime||(this.currentTime={hours:0,minutes:0}),this._refreshTimezoneDefault(),this._syncOutputs()}),this._timePicker=new $e({name:null,value:this.currentTime?Z(this.currentTime,"24h"):"",format:this.timeFormat,step:this.timeStep,timezone:!1,inline:!0,autoApply:!1,showFooter:!1});const r=document.createElement("div");if(r.className="mojo-datetime-time-head",r.textContent="Time",i.appendChild(r),i.appendChild(this._timePicker.element),this._timePicker.on("change",()=>{const l=this._timePicker.currentTime;if(this.currentTime=l?{...l}:null,this.currentTime&&!this.currentDate){const d=new Date;this.currentDate={y:d.getFullYear(),m:d.getMonth()+1,d:d.getDate()},this._calendar&&this._calendar.setValue(B(this.currentDate))}this._syncOutputs()}),this._timePicker.render(!1),this.timezone){const l=document.createElement("div");l.className="mojo-datetime-tz-row";const d=document.createElement("div");d.className="mojo-datetime-tz-label",d.textContent="Timezone",l.appendChild(d);const h=document.createElement("div");h.className="mojo-datetime-tz-host",l.appendChild(h),e.appendChild(l),this._tzSelect=new Dt({name:"timezone",value:this.currentTimezone,timezones:Array.isArray(this.timezoneList)?this.timezoneList:null}),this._tzSelect.render(!0,h),this._tzSelect.on("change",({value:u})=>{const m=this.currentTimezone;this.currentTimezone=u||null,m!==this.currentTimezone&&this._syncOutputs()})}const n=document.createElement("div");n.className="mojo-datetime-foot";const a=document.createElement("button");a.type="button",a.className="btn btn-link btn-sm",a.textContent="Now",a.addEventListener("click",l=>{l.preventDefault();const d=new Date;this.currentDate={y:d.getFullYear(),m:d.getMonth()+1,d:d.getDate()},this.currentTime={hours:d.getHours(),minutes:d.getMinutes()},this._calendar&&this._calendar.setValue(B(this.currentDate)),this._timePicker&&this._timePicker.setValue(Z(this.currentTime,"24h")),this._syncOutputs()}),n.appendChild(a);const o=document.createElement("button");return o.type="button",o.className="btn btn-primary btn-sm",o.textContent="Done",o.addEventListener("click",l=>{l.preventDefault(),this._popover&&this._popover.isOpen()&&this._popover.close()}),n.appendChild(o),e.appendChild(n),e}_refreshTimezoneDefault(){this.timezone&&!this.currentTimezone&&this._timePicker&&(this.currentTimezone=this._timePicker.currentTimezone||Mt())}_timePickerValue(){if(!this.currentTime&&!this.currentTimezone)return"";const e=this.currentTime?Z(this.currentTime,"24h"):"00:00";return this.timezone&&this.currentTimezone?`${e} ${this.currentTimezone}`:e}_dateBound(e){return e?String(e).trim().split(/[ T]/)[0]:null}_syncOutputs(e){const t=this._serialize(),s=this._displayText(),i=this.element&&this.element.querySelector("[data-trigger-text]");i&&(i.textContent=s||this.placeholder,i.classList.toggle("is-empty",!this.currentDate));const r=this.element&&this.element.querySelector("[data-hidden-value]");r&&(r.value=t),e!==void 0&&e!==t?(this.emit("change",{value:this.getValue(),formatted:s,oldValue:e}),this.emit("datetime:changed",{value:this.getValue()})):e===void 0&&this.emit("change",{value:this.getValue(),formatted:s,oldValue:null})}_serialize(){if(!this.currentDate)return"";const e=B(this.currentDate),t=this.currentTime?Z(this.currentTime,"24h"):"00:00";if(this.outputFormat==="iana"){let i=`${e} ${t}`;return this.timezone&&this.currentTimezone&&(i+=` ${this.currentTimezone}`),i}let s=`${e}T${t}:00`;if(this.timezone&&this.currentTimezone){const i=new Date(this.currentDate.y,this.currentDate.m-1,this.currentDate.d,this.currentTime?.hours||0,this.currentTime?.minutes||0),r=Ct(this.currentTimezone,i);r&&(s+=r)}return s}_displayText(){if(!this.currentDate)return"";const e=he(this.currentDate,this.displayFormat),t=this.currentTime?Z(this.currentTime,this.timeFormat):this.timeFormat==="12h"?"12:00 AM":"00:00";let s=`${e} ${t}`;return this.timezone&&this.currentTimezone&&(s+=` ${this.currentTimezone}`),s}getValue(){if(!this.currentDate)return this.outputFormat==="object"?null:"";if(this.outputFormat==="object"){const e={date:B(this.currentDate),time:this.currentTime?Z(this.currentTime,"24h"):"00:00"};return this.timezone&&(e.timezone=this.currentTimezone||null),e}return this._serialize()}setValue(e){const t=this._parseInitial(e);this.currentDate=t.date,this.currentTime=t.time,t.timezone&&(this.currentTimezone=t.timezone),this._calendar&&this.currentDate&&this._calendar.setValue(B(this.currentDate)),this._timePicker&&this._timePicker.setValue(this._timePickerValue()),this._syncOutputs()}getFormattedValue(){return this._displayText()}clear(){const e=this._serialize();this.currentDate=null,this.currentTime=null,this._calendar&&this._calendar.setValue(null),this._timePicker&&this._timePicker.clear(),this._syncOutputs(e)}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(this._dateBound(e))}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(this._dateBound(e))}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-datetime-${this.name}-${this.id}`:`mojo-datetime-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){if(this._popover){try{this._popover.destroy()}catch{}this._popover=null}if(this._timePicker){try{await this._timePicker.destroy()}catch{}this._timePicker=null}if(this._tzSelect){try{await this._tzSelect.destroy()}catch{}this._tzSelect=null}this._calendar=null,this._popoverContent=null,await super.onBeforeDestroy()}static create(e={}){return new We(e)}}function Mt(){try{return new Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{return"UTC"}}class Ye extends S{constructor(e={}){const{name:t,value:s="",placeholder:i="Select or type...",options:r=[],allowCustom:n=!0,showDescription:a=!0,minChars:o=0,maxSuggestions:l=10,disabled:d=!1,readonly:h=!1,required:u=!1,class:m="",inputClass:p="form-control",onSelect:f=null,onChange:g=null,...b}=e;super({tagName:"div",className:`combo-input ${m}`,...b}),this.name=t,this.placeholder=i,this.options=this.normalizeOptions(r),this.allowCustom=n,this.showDescription=a,this.minChars=o,this.maxSuggestions=l,this.disabled=d,this.readonly=h,this.required=u,this.inputClass=p,this.onSelectCallback=f,this.onChangeCallback=g,this.currentValue=s,this.inputValue=this.getDisplayValue(s),this.filteredOptions=[],this.highlightedIndex=-1,this.isOpen=!1,this.selectedOption=this.findOptionByValue(s)}normalizeOptions(e){return Array.isArray(e)?e.map(t=>typeof t=="string"?{value:t,label:t}:typeof t=="object"&&t.value!==void 0?{value:t.value,label:t.label||String(t.value),description:t.description||t.label||"",meta:t.meta||{}}:null).filter(t=>t!==null):[]}findOptionByValue(e){return this.options.find(t=>t.value===e)||null}getDisplayValue(e){const t=this.findOptionByValue(e);return t?t.label:e}async renderTemplate(){return`
1208
+ `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",s=>{s.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",s=>{s.stopPropagation(),this.clear()}))}_togglePopover(e){if(!(this.disabled||this.readonly)){if(this._popover?this._popover.setAnchor(e):this._popover=new Se({anchor:e,classNames:"mojo-datetime-popover"}),this._popover.isOpen()){this._popover.close();return}this._popoverContent||(this._popoverContent=this._buildContent()),this._popover.setContent(this._popoverContent),this._popover.open(),this._calendar&&this._calendar.render(!1)}}_mountInline(){const e=this.element.querySelector("[data-dt-host]");e&&(this._popoverContent||(this._popoverContent=this._buildContent()),e.appendChild(this._popoverContent),this._calendar&&this._calendar.render(!1))}_buildContent(){const e=document.createElement("div");e.className="mojo-datetime-popover-inner";const t=document.createElement("div");t.className="mojo-datetime-row";const s=document.createElement("div");s.className="mojo-datetime-cal-col",t.appendChild(s);const i=document.createElement("div");i.className="mojo-datetime-time-col",t.appendChild(i),e.appendChild(t),this._calendar=new ze({precision:"day",mode:"single",months:1,value:this.currentDate?B(this.currentDate):null,min:this._dateBound(this.min),max:this._dateBound(this.max),disabledDates:this.disabledDates,firstDay:this.firstDay,locale:this.lang}),s.appendChild(this._calendar.element),this._calendar.on("select",({value:l})=>{const d=q(l);this.currentDate=d,this.currentTime||(this.currentTime={hours:0,minutes:0}),this._refreshTimezoneDefault(),this._syncOutputs()}),this._timePicker=new $e({name:null,value:this.currentTime?K(this.currentTime,"24h"):"",format:this.timeFormat,step:this.timeStep,timezone:!1,inline:!0,autoApply:!1,showFooter:!1});const r=document.createElement("div");if(r.className="mojo-datetime-time-head",r.textContent="Time",i.appendChild(r),i.appendChild(this._timePicker.element),this._timePicker.on("change",()=>{const l=this._timePicker.currentTime;if(this.currentTime=l?{...l}:null,this.currentTime&&!this.currentDate){const d=new Date;this.currentDate={y:d.getFullYear(),m:d.getMonth()+1,d:d.getDate()},this._calendar&&this._calendar.setValue(B(this.currentDate))}this._syncOutputs()}),this._timePicker.render(!1),this.timezone){const l=document.createElement("div");l.className="mojo-datetime-tz-row";const d=document.createElement("div");d.className="mojo-datetime-tz-label",d.textContent="Timezone",l.appendChild(d);const h=document.createElement("div");h.className="mojo-datetime-tz-host",l.appendChild(h),e.appendChild(l),this._tzSelect=new Dt({name:"timezone",value:this.currentTimezone,timezones:Array.isArray(this.timezoneList)?this.timezoneList:null}),this._tzSelect.render(!0,h),this._tzSelect.on("change",({value:u})=>{const m=this.currentTimezone;this.currentTimezone=u||null,m!==this.currentTimezone&&this._syncOutputs()})}const n=document.createElement("div");n.className="mojo-datetime-foot";const a=document.createElement("button");a.type="button",a.className="btn btn-link btn-sm",a.textContent="Now",a.addEventListener("click",l=>{l.preventDefault();const d=new Date;this.currentDate={y:d.getFullYear(),m:d.getMonth()+1,d:d.getDate()},this.currentTime={hours:d.getHours(),minutes:d.getMinutes()},this._calendar&&this._calendar.setValue(B(this.currentDate)),this._timePicker&&this._timePicker.setValue(K(this.currentTime,"24h")),this._syncOutputs()}),n.appendChild(a);const o=document.createElement("button");return o.type="button",o.className="btn btn-primary btn-sm",o.textContent="Done",o.addEventListener("click",l=>{l.preventDefault(),this._popover&&this._popover.isOpen()&&this._popover.close()}),n.appendChild(o),e.appendChild(n),e}_refreshTimezoneDefault(){this.timezone&&!this.currentTimezone&&this._timePicker&&(this.currentTimezone=this._timePicker.currentTimezone||kt())}_timePickerValue(){if(!this.currentTime&&!this.currentTimezone)return"";const e=this.currentTime?K(this.currentTime,"24h"):"00:00";return this.timezone&&this.currentTimezone?`${e} ${this.currentTimezone}`:e}_dateBound(e){return e?String(e).trim().split(/[ T]/)[0]:null}_syncOutputs(e){const t=this._serialize(),s=this._displayText(),i=this.element&&this.element.querySelector("[data-trigger-text]");i&&(i.textContent=s||this.placeholder,i.classList.toggle("is-empty",!this.currentDate));const r=this.element&&this.element.querySelector("[data-hidden-value]");r&&(r.value=t),e!==void 0&&e!==t?(this.emit("change",{value:this.getValue(),formatted:s,oldValue:e}),this.emit("datetime:changed",{value:this.getValue()})):e===void 0&&this.emit("change",{value:this.getValue(),formatted:s,oldValue:null})}_serialize(){if(!this.currentDate)return"";const e=B(this.currentDate),t=this.currentTime?K(this.currentTime,"24h"):"00:00";if(this.outputFormat==="iana"){let i=`${e} ${t}`;return this.timezone&&this.currentTimezone&&(i+=` ${this.currentTimezone}`),i}let s=`${e}T${t}:00`;if(this.timezone&&this.currentTimezone){const i=new Date(this.currentDate.y,this.currentDate.m-1,this.currentDate.d,this.currentTime?.hours||0,this.currentTime?.minutes||0),r=_t(this.currentTimezone,i);r&&(s+=r)}return s}_displayText(){if(!this.currentDate)return"";const e=he(this.currentDate,this.displayFormat),t=this.currentTime?K(this.currentTime,this.timeFormat):this.timeFormat==="12h"?"12:00 AM":"00:00";let s=`${e} ${t}`;return this.timezone&&this.currentTimezone&&(s+=` ${this.currentTimezone}`),s}getValue(){if(!this.currentDate)return this.outputFormat==="object"?null:"";if(this.outputFormat==="object"){const e={date:B(this.currentDate),time:this.currentTime?K(this.currentTime,"24h"):"00:00"};return this.timezone&&(e.timezone=this.currentTimezone||null),e}return this._serialize()}setValue(e){const t=this._parseInitial(e);this.currentDate=t.date,this.currentTime=t.time,t.timezone&&(this.currentTimezone=t.timezone),this._calendar&&this.currentDate&&this._calendar.setValue(B(this.currentDate)),this._timePicker&&this._timePicker.setValue(this._timePickerValue()),this._syncOutputs()}getFormattedValue(){return this._displayText()}clear(){const e=this._serialize();this.currentDate=null,this.currentTime=null,this._calendar&&this._calendar.setValue(null),this._timePicker&&this._timePicker.clear(),this._syncOutputs(e)}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(this._dateBound(e))}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(this._dateBound(e))}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-datetime-${this.name}-${this.id}`:`mojo-datetime-${this.id}`}_attr(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}async onBeforeDestroy(){if(this._popover){try{this._popover.destroy()}catch{}this._popover=null}if(this._timePicker){try{await this._timePicker.destroy()}catch{}this._timePicker=null}if(this._tzSelect){try{await this._tzSelect.destroy()}catch{}this._tzSelect=null}this._calendar=null,this._popoverContent=null,await super.onBeforeDestroy()}static create(e={}){return new We(e)}}function kt(){try{return new Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{return"UTC"}}class Ye extends C{constructor(e={}){const{name:t,value:s="",placeholder:i="Select or type...",options:r=[],allowCustom:n=!0,showDescription:a=!0,minChars:o=0,maxSuggestions:l=10,disabled:d=!1,readonly:h=!1,required:u=!1,class:m="",inputClass:p="form-control",onSelect:f=null,onChange:g=null,...b}=e;super({tagName:"div",className:`combo-input ${m}`,...b}),this.name=t,this.placeholder=i,this.options=this.normalizeOptions(r),this.allowCustom=n,this.showDescription=a,this.minChars=o,this.maxSuggestions=l,this.disabled=d,this.readonly=h,this.required=u,this.inputClass=p,this.onSelectCallback=f,this.onChangeCallback=g,this.currentValue=s,this.inputValue=this.getDisplayValue(s),this.filteredOptions=[],this.highlightedIndex=-1,this.isOpen=!1,this.selectedOption=this.findOptionByValue(s)}normalizeOptions(e){return Array.isArray(e)?e.map(t=>typeof t=="string"?{value:t,label:t}:typeof t=="object"&&t.value!==void 0?{value:t.value,label:t.label||String(t.value),description:t.description||t.label||"",meta:t.meta||{}}:null).filter(t=>t!==null):[]}findOptionByValue(e){return this.options.find(t=>t.value===e)||null}getDisplayValue(e){const t=this.findOptionByValue(e);return t?t.label:e}async renderTemplate(){return`
1209
1209
  <div class="combo-input-container position-relative">
1210
1210
  <div class="input-wrapper position-relative">
1211
1211
  ${this.renderInput()}
@@ -1277,10 +1277,10 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1277
1277
  <i class="bi bi-search me-1"></i>
1278
1278
  No matching options found.
1279
1279
  </div>
1280
- `}highlightMatch(e){if(!this.inputValue)return this.escapeHtml(e);const t=this.escapeHtml(e),s=new RegExp(`(${this.escapeRegex(this.inputValue)})`,"gi");return t.replace(s,'<mark class="bg-warning bg-opacity-25">$1</mark>')}async onAfterRender(){await super.onAfterRender(),this.updateFilteredOptions(),this.handleOutsideClick=e=>{this.element&&!this.element.contains(e.target)&&this.closeDropdown()},document.addEventListener("click",this.handleOutsideClick)}async onChangeInputChange(e,t){this.inputValue=t.value,this.updateFilteredOptions(),this.inputValue.length>=this.minChars?this.openDropdown():this.closeDropdown(),this.highlightedIndex=-1,await this.updateDropdownDisplay()}async onActionInputKeydown(e,t){switch(e.key){case"ArrowDown":e.preventDefault(),this.isOpen?this.highlightNext():this.openDropdown(),await this.updateDropdownDisplay();break;case"ArrowUp":e.preventDefault(),this.isOpen&&(this.highlightPrevious(),await this.updateDropdownDisplay());break;case"Enter":e.preventDefault(),this.isOpen&&this.highlightedIndex>=0?await this.selectHighlightedOption():this.allowCustom&&this.inputValue&&await this.selectCustomValue(this.inputValue);break;case"Escape":e.preventDefault(),this.closeDropdown();const s=this.element.querySelector(".combo-input-field");s&&(s.value=this.getDisplayValue(this.currentValue),this.inputValue=s.value);break;case"Tab":this.isOpen&&this.closeDropdown();break}}async onActionToggleDropdown(e,t){if(e.preventDefault(),e.stopPropagation(),this.isOpen)this.closeDropdown();else{this.inputValue="";const s=this.element.querySelector(".combo-input-field");s&&(s.value="",s.focus()),this.updateFilteredOptions(),this.openDropdown(),await this.updateDropdownDisplay()}}async onActionSelectOption(e,t){e.preventDefault(),e.stopPropagation();const s=parseInt(t.getAttribute("data-option-index"));s>=0&&s<this.filteredOptions.length&&await this.selectOption(this.filteredOptions[s])}openDropdown(){this.isOpen=!0;const e=this.element?.querySelector(".combo-dropdown");e&&e.classList.add("show");const t=this.element?.querySelector(".combo-input-field");t&&t.setAttribute("aria-expanded","true")}closeDropdown(){this.isOpen=!1,this.highlightedIndex=-1;const e=this.element?.querySelector(".combo-dropdown");e&&e.classList.remove("show");const t=this.element?.querySelector(".combo-input-field");t&&t.setAttribute("aria-expanded","false")}updateFilteredOptions(){const e=this.inputValue.toLowerCase().trim();if(!e){this.filteredOptions=[...this.options];return}this.filteredOptions=this.options.filter(t=>{const s=t.label.toLowerCase().includes(e),i=String(t.value).toLowerCase().includes(e),r=t.description?.toLowerCase().includes(e);return s||i||r}),this.filteredOptions.sort((t,s)=>{const i=t.label.toLowerCase()===e,r=s.label.toLowerCase()===e;if(i&&!r)return-1;if(!i&&r)return 1;const n=t.label.toLowerCase().startsWith(e),a=s.label.toLowerCase().startsWith(e);return n&&!a?-1:!n&&a?1:0})}async updateDropdownDisplay(){const e=this.element?.querySelector(".combo-dropdown");if(e&&(e.innerHTML=this.renderDropdownContent(),this.highlightedIndex>=0)){const t=e.querySelector(".combo-option.active");t&&t.scrollIntoView({block:"nearest"})}}highlightNext(){this.filteredOptions.length!==0&&(this.highlightedIndex=(this.highlightedIndex+1)%Math.min(this.filteredOptions.length,this.maxSuggestions))}highlightPrevious(){this.filteredOptions.length!==0&&(this.highlightedIndex=this.highlightedIndex<=0?Math.min(this.filteredOptions.length,this.maxSuggestions)-1:this.highlightedIndex-1)}async selectHighlightedOption(){this.highlightedIndex>=0&&this.highlightedIndex<this.filteredOptions.length&&await this.selectOption(this.filteredOptions[this.highlightedIndex])}async selectOption(e){this.currentValue=e.value,this.inputValue=e.label,this.selectedOption=e;const t=this.element?.querySelector(".combo-input-field");t&&(t.value=e.label);const s=this.element?.querySelector(".combo-input-hidden");s&&(s.value=e.value),this.closeDropdown(),this.emit("select",{option:e,value:e.value,meta:e.meta}),this.emit("change",{value:e.value,option:e,meta:e.meta}),typeof this.onSelectCallback=="function"&&this.onSelectCallback(e),typeof this.onChangeCallback=="function"&&this.onChangeCallback(e.value)}async selectCustomValue(e){if(!this.allowCustom)return;this.currentValue=e,this.inputValue=e,this.selectedOption=null;const t=this.element?.querySelector(".combo-input-hidden");t&&(t.value=e),this.closeDropdown(),this.emit("custom",{value:e}),this.emit("change",{value:e,custom:!0}),typeof this.onChangeCallback=="function"&&this.onChangeCallback(e)}getValue(){return this.currentValue}async setValue(e){this.currentValue=e,this.selectedOption=this.findOptionByValue(e),this.inputValue=this.getDisplayValue(e);const t=this.element?.querySelector(".combo-input-field");t&&(t.value=this.inputValue);const s=this.element?.querySelector(".combo-input-hidden");s&&(s.value=e),this.updateFilteredOptions()}getSelectedOption(){return this.selectedOption}async setOptions(e){this.options=this.normalizeOptions(e),this.updateFilteredOptions(),this.isOpen&&await this.updateDropdownDisplay()}setEnabled(e){this.disabled=!e;const t=this.element?.querySelector(".combo-input-field");t&&(t.disabled=this.disabled);const s=this.element?.querySelector(".combo-toggle");s&&(s.disabled=this.disabled)}setReadonly(e){this.readonly=e;const t=this.element?.querySelector(".combo-input-field");t&&(e?t.setAttribute("readonly",""):t.removeAttribute("readonly"))}focus(){const e=this.element?.querySelector(".combo-input-field");e&&e.focus()}async clear(){await this.setValue(""),this.inputValue="";const e=this.element?.querySelector(".combo-input-field");e&&(e.value=""),this.emit("clear")}getFormValue(){return this.allowCustom&&this.inputValue&&this.inputValue!==this.getDisplayValue(this.currentValue)?this.inputValue:this.currentValue}async setFormValue(e){await this.setValue(e)}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}async onBeforeDestroy(){this.handleOutsideClick&&document.removeEventListener("click",this.handleOutsideClick),await super.onBeforeDestroy()}static create(e={}){return new Ye(e)}}class te extends S{constructor(e={}){const{formConfig:t=e.config,fields:s,model:i=null,data:r={},defaults:n=null,errors:a={},fileHandling:o="base64",autosaveModelField:l=!1,...d}=e;super({tagName:"div",className:"form-view",enableTooltips:!0,...d}),X.onFormViewInit?.(this),this.model=i,this.defaults=n||r,this._originalData=r,this.errors=a,this.loading=!1,this.fileHandling=o,this.autosaveModelField=l,this.customComponents=new Map,this.fieldStatusManagers=new Map,this.saveTimeouts=new Map,this.pendingSaveFields=new Map,this.batchSaveTimeout=null,this.isSaving=!1,this.data=this.prepareFormData(),this.formConfig=t||{fields:s||[]},this.formBuilder=new fe({...this.getFormConfig(),data:this.data,errors:a})}prepareFormData(){const e={...this.defaults};if(this.model)if(this.model.attributes&&typeof this.model.attributes=="object")Object.assign(e,this.model.attributes);else if(typeof this.model.toJSON=="function"){const t=this.model.toJSON();Object.assign(e,t)}else typeof this.model=="object"&&this.model.constructor===Object&&Object.assign(e,this.model);return this._originalData&&Object.assign(e,this._originalData),e}getFormConfig(){const e={...this.formConfig},t=this.getApp();return this.formConfig.fields&&Array.isArray(this.formConfig.fields)?e.fields=this.formConfig.fields.filter(s=>s.permissions?t.activeUser?.hasPermission(s.permissions):!0):e.fields=[],e}async renderTemplate(){return this.formBuilder.buildFormHTML()}async onAfterRender(){await super.onAfterRender(),this.data=this.prepareFormData(),this.populateFormValues(),this.initializeFormComponents(),this.initializeChangeHandlers();const e=this.getFormElement();e&&e.addEventListener("submit",t=>(t.preventDefault(),!1)),this._initShowWhen(),X.onFormViewAfterRender?.(this)}populateFormValues(){if(!(!this.element||!this.formConfig?.fields)){this._isPopulating=!0;try{this.formConfig.fields.forEach(e=>{this.populateFieldRecursive(e)})}finally{this._isPopulating=!1}}}populateFieldRecursive(e){e.type==="group"&&e.fields?e.fields.forEach(t=>{this.populateFieldRecursive(t)}):e.type==="tabset"&&e.tabs?e.tabs.forEach(t=>{t.fields&&Array.isArray(t.fields)&&t.fields.forEach(s=>{this.populateFieldRecursive(s)})}):this.populateFieldValue(e)}populateFieldValue(e){if(!e.name||!this.element)return;const t=this.element.querySelector(`[name="${e.name}"]`);if(!t)return;const s=$.getContextData(this.data,e.name);s!=null&&this.setFieldValue(t,e,s)}initializeFormComponents(){this.initializeImageFields(),this.initializeCustomComponents(),this.initializeTagInputs(),this.initializeMultiSelectDropdowns(),this.initializeComboBoxes(),this.initializeCollectionSelects(),this.initializeCollectionMultiSelects(),this.initializeDatePickers(),this.initializeDateRangePickers(),this.initializeTimePickers(),this.initializeDateTimePickers(),this.initializePasswordFields()}initializeImageFields(){this.element.querySelectorAll(".image-drop-zone.droppable").length>0&&this.enableFileDrop({acceptedTypes:["image/*"],maxFileSize:10485760,multiple:!1,dropZoneSelector:".image-drop-zone.droppable",visualFeedback:!0,dragOverClass:"drag-over",dragActiveClass:"drag-active"})}initializeCustomComponents(){this.initializeTagInputs(),this.initializeCollectionSelects(),this.initializeCollectionMultiSelects(),this.initializeDatePickers(),this.initializeDateRangePickers(),this.initializeTimePickers(),this.initializeDateTimePickers(),this.initializeComboInputs();try{const t=(s=[])=>{s.forEach(i=>{if(i&&i.type==="group"&&Array.isArray(i.fields))t(i.fields);else if(i&&i.name){const r=this.element.querySelector(`[name="${i.name}"], #${i.id||i.name}`);r&&X.onFieldInit?.(this,r,i)}})};t(this.formConfig?.fields||[])}catch(t){console.warn("FormPlugins.onFieldInit error:",t)}this.element.querySelectorAll("[data-component]").forEach(t=>{t.getAttribute("data-component"),t.getAttribute("data-field")})}initializeChangeHandlers(){if(!this.element)return;const e=this.element.querySelectorAll("input:not([data-action]), select:not([data-action]), textarea:not([data-action])");console.log("FormView: initializeChangeHandlers - found",e.length,"inputs"),e.forEach(t=>{console.log("FormView: Processing input:",t.type,t.name,t.getAttribute("data-change-action")),!(t.hasAttribute("data-component")||t.hasAttribute("data-change-action")||t.classList.contains("form-check-input"))&&(t.addEventListener("change",s=>{if(this._isPopulating)return;const i=t.name;if(i){let r=t.value;if(t.type==="checkbox")r=t.checked;else if(t.type==="radio"){if(!t.checked)return}else if(t.multiple&&t.selectedOptions)r=Array.from(t.selectedOptions).map(n=>n.value);else if(t.type==="file"){const n=t.getAttribute("data-change-action");if(n==="image-selected"){this.onChangeImageSelected(s,t);return}else if(n==="file-selected"){this.onChangeFileSelected(s,t);return}}this.handleFieldChange(i,r)}}),(t.type==="text"||t.type==="email"||t.type==="url"||t.tagName==="TEXTAREA")&&t.addEventListener("input",s=>{if(this._isPopulating)return;const i=t.name;i&&this.handleFieldChange(i,t.value)}))})}initializeTagInputs(){this.element.querySelectorAll('[data-field-type="tag"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new Ve({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeMultiSelectDropdowns(){this.element.querySelectorAll('[data-field-type="multiselect"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n)return;const a=new os({...r,options:n.options||[],placeholder:n.placeholder||r.placeholder||"Select...",label:n.label,containerId:null});let o=r.value??$.getContextData(this.data,s);o&&a.setFormValue(o),a.render(!0,t),this.customComponents.set(s,a),a.on("change",l=>{this.handleFieldChange(s,l.value)})}catch(s){console.error("MultiSelectDropdown initialization failed:",s)}})}initializeComboBoxes(){this.element.querySelectorAll('[data-field-type="combobox"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n)return;const a=new Et({...r,options:n.options||[],placeholder:n.placeholder||r.placeholder||"Type or select...",containerId:null});let o=r.value??$.getContextData(this.data,s);o&&a.setFormValue(o),a.render(!0,t),this.customComponents.set(s,a),a.on("change",l=>{this.handleFieldChange(s,l.value)})}catch(s){console.error("ComboBox initialization failed:",s)}})}initializeCollectionSelects(){this.element.querySelectorAll('[data-field-type="collection"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n||!n.Collection)return;const a=new n.Collection;n.collectionParams&&(a.params={...a.params,...n.collectionParams});const o=new ss({...r,collection:a,defaultParams:n.defaultParams||null,containerId:null});let l=$.getContextData(this.data,s);l&&o.setFormValue(l),o.render(!0,t),this.customComponents.set(s,o),o.on("change",d=>{this.handleFieldChange(s,d.value)})}catch{}})}initializeCollectionMultiSelects(){this.element.querySelectorAll('[data-field-type="collectionmultiselect"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n||!n.Collection)return;const a=new n.Collection;n.collectionParams&&(a.params={...a.params,...n.collectionParams});const o=new ns({...r,collection:a,defaultParams:n.defaultParams||null,itemTemplate:n.itemTemplate||null,containerId:null});let l=$.getContextData(this.data,s);l&&o.setFormValue(l),o.render(!0,t),this.customComponents.set(s,o),o.on("change",d=>{this.handleFieldChange(s,d.value)})}catch(s){console.error("CollectionMultiSelect initialization failed:",s)}})}initializeDatePickers(){this.element.querySelectorAll('[data-field-type="datepicker"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new qe({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeDateRangePickers(){this.element.querySelectorAll('[data-field-type="daterange"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new Be({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.combined)})}catch{}})}initializeTimePickers(){this.element.querySelectorAll('[data-field-type="timepicker"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new $e({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeDateTimePickers(){this.element.querySelectorAll('[data-field-type="datetimepicker"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new We({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeComboInputs(){this.element.querySelectorAll('[data-field-type="combo"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new Ye({...r,containerId:null});let a=$.getContextData(this.data,s);a&&n.setValue(a),n.render(!0,t),this.customComponents.set(s,n),n.on("change",o=>{this.handleFieldChange(s,o.value)}),n.on("select",o=>{this.emit("field:select",{field:s,value:o.value,option:o.option,meta:o.meta})})}catch(s){console.error("ComboInput initialization failed:",s)}})}handleFieldChange(e,t){this._isPopulating||(this.data[e]=t,this.autosaveModelField&&this.model?this.handleFieldSave(e,t):this.model&&this.options.allowModelChange&&(this._isFormDrivenChange=!0,this.model.set(e,t)),this.emit("field:change",{field:e,value:t}),this._updateShowWhen(e,t),X.onFieldChange?.(this,e,t))}_initShowWhen(){if(this._showWhenMap={},!this.element)return;this.element.querySelectorAll("[data-show-when-field]").forEach(t=>{const s=t.getAttribute("data-show-when-field");this._showWhenMap[s]||(this._showWhenMap[s]=[]),this._showWhenMap[s].push(t),t.style.display==="none"?t.querySelectorAll("input, select, textarea").forEach(r=>{r.required&&(r.dataset.wasRequired="true",r.required=!1)}):t.querySelectorAll("input, select, textarea").forEach(r=>{r.required&&(r.dataset.wasRequired="true")})})}_updateShowWhen(e,t){const s=this._showWhenMap?.[e];if(!s)return;const i=String(t??"");s.forEach(r=>{const n=r.getAttribute("data-show-when-value").split(","),a=r.getAttribute("data-show-when-negate")==="true",o=n.includes(i),l=a?!o:o;r.style.display=l?"":"none",r.querySelectorAll("input, select, textarea").forEach(h=>{l?h.dataset.wasRequired==="true"&&(h.required=!0):(h.required&&(h.dataset.wasRequired="true"),h.required=!1)})})}async handleFieldSave(e,t){if(!this.model)return;this.pendingSaveFields.set(e,t),this.getFieldStatusManager(e).showStatus("saving"),this.batchSaveTimeout&&clearTimeout(this.batchSaveTimeout),this.batchSaveTimeout=setTimeout(async()=>{await this.executeBatchSave()},300)}async executeBatchSave(){if(this.isSaving||this.pendingSaveFields.size===0)return;const e=Object.fromEntries(this.pendingSaveFields),t=Array.from(this.pendingSaveFields.keys());try{if(this.isSaving=!0,this.pendingSaveFields.clear(),this.batchSaveTimeout=null,this._isFormDrivenChange=!0,typeof this.model.save=="function"){const s=await this.model.save(e,{skipRender:!0});if(!s||!s.success||s.data&&!s.data.status){const i=s?.data?.error||s?.error||s?.message||"Save failed";this.getApp()?.toast?.error(i),this.revertFields(t),t.forEach(r=>{this.getFieldStatusManager(r).showStatus("error",{message:i})});return}}else Object.entries(e).forEach(([s,i])=>{this.model.set(s,i,{skipRender:!0})});t.forEach(s=>{this.getFieldStatusManager(s).showStatus("saved")})}catch(s){console.error("Batch save error:",s),this.getApp()?.toast?.error(s.message||"An error occurred while saving"),this.revertFields(t),t.forEach(i=>{this.getFieldStatusManager(i).showStatus("error",{message:s.message})})}finally{this.isSaving=!1}}revertFields(e){if(!this.model)return;const t=this._isPopulating;this._isPopulating=!0;try{e.forEach(s=>{const i=this.model.get(s);this.data[s]=i;const r=this.element?.querySelector(`[name="${s}"]`);if(r){const n=this.getFormFieldConfig(s);n?this.setFieldValue(r,n,i):r.type==="checkbox"?r.checked=!!i:r.value=i??""}})}finally{this._isPopulating=t}}getFieldStatusManager(e){if(!this.fieldStatusManagers.has(e)){const t=this.element.querySelector(`[name="${e}"]`);if(t){const s=new Ss(t);this.fieldStatusManagers.set(e,s)}}return this.fieldStatusManagers.get(e)}refreshForm(){this.data=this.prepareFormData(),this.element&&this.populateFormValues()}getChangeReason(e,t){if(e instanceof File)return e.size===0||e.name===""||e.name==="blob"?"empty file, no change":`file upload: ${e.name}, ${e.size} bytes`;if(typeof e=="string"&&e.startsWith("data:image/"))return"base64 image upload";if(typeof e=="boolean"||typeof t=="boolean"){const s=!!e;return`boolean: ${t==null?!1:!!t} → ${s}`}return e==null||String(e).trim(),t==null||String(t).trim(),t==null?"was null/undefined, now has value":e==null?"was value, now null/undefined":"text content changed"}setFormData(e){this._originalData={...this._originalData,...e},this.refreshForm()}async onActionSubmitForm(e,t){e.preventDefault();const s=await this.handleSubmit();s.success?(this.data=s.data,this.emit("submit",{data:s.data,result:s.result,form:this,event:e}),!this.model&&this.formConfig.onSubmit&&typeof this.formConfig.onSubmit=="function"&&await this.formConfig.onSubmit(s.data,this)):this.emit("error",{error:s.error,result:s,form:this})}async onActionResetForm(e,t){const s=this.getFormElement();s&&(s.reset(),this.data={},this.clearAllErrors(),this.emit("reset",{form:this,event:e}))}async onActionClickImageUpload(e,t){console.log("FormView: onActionClickImageUpload called"),console.log("FormView: element:",t);const s=t.getAttribute("data-field-id");if(console.log("FormView: fieldId:",s),!s){console.error("FormView: No fieldId attribute found");return}const i=this.element.querySelector(`#${s}`);console.log("FormView: fileInput:",i),i&&!i.disabled?(i.click(),console.log("FormView: fileInput.click() called")):i?console.log("FormView: fileInput is disabled"):console.error("FormView: fileInput not found for fieldId:",s)}async onActionRemoveImage(e,t){const s=t.getAttribute("data-field");if(!s)return;const i=this.element.querySelector(`input[name="${s}"]`);i&&(i.value="",i.dispatchEvent(new Event("change",{bubbles:!0}))),delete this.data[s],this.emit("change",{field:s,value:null,form:this}),await this.updateField(s)}async onActionClearColor(e,t){const s=t.getAttribute("data-field");if(!s)return;const i=this.element.querySelector(`input[name="${s}"]`);i&&(i.value="",this.handleFieldChange(s,""),await this.updateField(s))}async onActionPreviewHtml(e,t){e.preventDefault();const s=t.getAttribute("data-target");if(!s)return;const i=this.element.querySelector(`#${s}`);if(!i)return;const r=i.value||"";(await Promise.resolve().then(()=>N)).default.htmlPreview({html:r,title:"HTML Preview"})}async onActionSelectButtonOption(e,t){const s=t.getAttribute("data-field"),i=t.getAttribute("data-value");if(!s||!i)return;this.data[s]=i;const r=t.closest(".btn-group");r&&(r.querySelectorAll("button").forEach(a=>{a.classList.remove("active"),a.classList.add("btn-outline-primary"),a.classList.remove("btn-primary")}),t.classList.add("active"),t.classList.remove("btn-outline-primary"),t.classList.add("btn-primary")),this.emit("field:changed",{field:s,value:i,form:this}),this.emit("change",{field:s,value:i,form:this}),this.emit("form:changed",await this.getFormData())}async onActionApplyFilter(e,t){const s=t.closest(".dropdown"),i=s?.querySelectorAll('input[type="checkbox"]');if(!i||i.length===0)return;const r=i[0].getAttribute("data-field");if(!r)return;const n=[];i.forEach(o=>{o.checked&&n.push(o.value)}),this.data[r]=n;const a=s.querySelector('[data-bs-toggle="dropdown"]');a&&window.bootstrap?.Dropdown&&window.bootstrap.Dropdown.getInstance(a)?.hide(),this.emit("field:changed",{field:r,value:n,form:this}),this.emit("change",{field:r,value:n,form:this}),this.emit("form:changed",await this.getFormData())}async onChangeValidateField(e,t){const s=t.name;if(s){const i=t.value;this.handleFieldChange(s,i),this.validateField(s)}}async onChangeToggleSwitch(e,t){const s=t.getAttribute("data-field");if(s){const i=t.checked;this.handleFieldChange(s,i),this.emit("switch:toggle",{field:s,checked:i,form:this})}}async onChangeImageSelected(e,t){console.log("FormView: onChangeImageSelected called"),console.log("FormView: element:",t),console.log("FormView: element.files:",t.files);const s=t.getAttribute("data-field"),i=t.files[0];if(console.log("FormView: fieldName:",s),console.log("FormView: file:",i),s&&i){console.log("FormView: fieldName and file exist, processing...");const r=this.findFieldConfig(s);console.log("FormView: fieldConfig:",r);const n=URL.createObjectURL(i);if(console.log("FormView: previewUrl created:",n),r&&r.imageSize){console.log("FormView: Image cropping is required, imageSize:",r.imageSize);try{const a=window.MOJO?.plugins?.ImageCropView;if(console.log("FormView: ImageCropView available?",!!a),!a){console.log("FormView: ImageCropView not available, falling back to normal handling"),this.data[s]=i,await this.updateImagePreview(s,n),this.emit("image:selected",{field:s,file:i,form:this});return}const o=await a.showDialog(n,{title:`Crop ${r.label||s}`,cropAndScale:r.imageSize,size:"lg"});if(o.action==="crop"&&o.data){const d=await(await fetch(o.data)).blob(),h=new File([d],i.name,{type:i.type||"image/png"});this.data[s]=h,await this.updateImagePreview(s,o.data),this.emit("image:selected",{field:s,file:h,originalFile:i,cropped:!0,cropData:o.cropData,form:this}),this.emit("change",{field:s,value:h,form:this})}else t.value=""}catch(a){console.error("FormView: Error during image cropping:",a),console.log("FormView: Falling back to normal image handling after error"),this.data[s]=i,await this.updateImagePreview(s,n),this.emit("image:selected",{field:s,file:i,form:this}),this.emit("change",{field:s,value:i,form:this})}}else console.log("FormView: Normal image handling (no cropping)"),this.data[s]=i,console.log("FormView: File stored in this.data["+s+"]"),await this.updateImagePreview(s,n),console.log("FormView: updateImagePreview completed"),this.emit("image:selected",{field:s,file:i,form:this}),console.log("FormView: image:selected event emitted")}else console.log("FormView: Missing fieldName or file - not processing")}async onChangeFileSelected(e,t){const s=Array.from(t.files);t.multiple?this.data[t.name]=t.files:this.data[t.name]=s[0]||null,this.emit("file:selected",{field:t.name,files:s,form:this}),this.emit("change",{field:t.name,value:s,form:this})}async onChangeRangeChanged(e,t){const s=t.name,i=t.value,r=t.getAttribute("data-target");if(r){const n=this.element.querySelector(`#${r}`);n&&(n.textContent=i)}s&&this.handleFieldChange(s,i),this.emit("range:changed",{field:s,value:i,form:this})}async onChangeFilterSearch(e,t){const s=t.value;this.emit("search",{query:s,field:t.name,form:this})}async onChangeFilterSelectOptions(e,t){const s=t.value.toLowerCase(),i=t.getAttribute("data-target"),r=i?this.element.querySelector(`#${i}`):null;r&&r.querySelectorAll("option").forEach(a=>{const o=a.textContent.toLowerCase();a.style.display=o.includes(s)?"":"none"})}async onFileDrop(e,t,s){const i=t.target.closest(".image-drop-zone");if(!i)return;const r=i.getAttribute("data-field");if(!r)return;const n=e[0],a=this.element.querySelector(`input[name="${r}"]`);if(a){const l=new DataTransfer;l.items.add(n),a.files=l.files,a.dispatchEvent(new Event("change",{bubbles:!0}))}this.data[r]=n;const o=URL.createObjectURL(n);await this.updateImagePreview(r,o),this.emit("image:dropped",{field:r,file:n,form:this})}async onFileDropError(e,t,s){this.showError(`File upload error: ${e.message}`),this.emit("file:error",{error:e,files:s,form:this})}getFormElement(){return this.element?this.element.querySelector("form"):null}getFormFieldConfig(e){const t=s=>{for(const i of s){if(i.name===e)return i;if(i.fields&&Array.isArray(i.fields)){const r=t(i.fields);if(r)return r}if(i.tabs&&Array.isArray(i.tabs)){for(const r of i.tabs)if(r.fields&&Array.isArray(r.fields)){const n=t(r.fields);if(n)return n}}}return null};return t(this.formConfig.fields||[])}async getFormData(){const e=this.getFormElement();if(!e)return this.fileHandling==="multipart"?new FormData:{};if(this.fileHandling==="multipart"){const t=new FormData(e);for(const[s,i]of Object.entries(this.data))if(i instanceof File)t.set(s,i);else if(i instanceof FileList)for(let r=0;r<i.length;r++)t.append(`${s}[${r}]`,i[r]);return t}else{const t=new FormData(e),s={};for(const[a,o]of t.entries())s[a]?(Array.isArray(s[a])||(s[a]=[s[a]]),s[a].push(o)):s[a]=o;e.querySelectorAll('input[type="checkbox"]').forEach(a=>{s[a.name]=a.checked}),e.querySelectorAll('input[type="number"]').forEach(a=>{if(a.name&&s[a.name]!==void 0&&s[a.name]!==""){const o=Number(s[a.name]);isNaN(o)||(s[a.name]=o)}}),this.formConfig.fields?.forEach(a=>{if(a.type==="select"&&a.name&&s[a.name]!==void 0){const o=this.getFormFieldConfig(a.name);if(o?.options&&Array.isArray(o.options)&&o.options.every(d=>{const h=typeof d=="object"?d.value:d;return h===""||!isNaN(Number(h))})&&s[a.name]!==""){const d=Number(s[a.name]);isNaN(d)||(s[a.name]=d)}}}),e.querySelectorAll('[data-field-type="json"]').forEach(a=>{try{s[a.name]=JSON.parse(a.value)}catch{s[a.name]=a.value}}),this.customComponents.forEach((a,o)=>{a.getFormValue?s[o]=a.getFormValue():a.getValue&&(s[o]=a.getValue())}),this.element&&this.element.querySelectorAll("[data-show-when-field]").forEach(o=>{o.style.display==="none"&&o.querySelectorAll("[name]").forEach(d=>{delete s[d.name]})});for(const[a,o]of Object.entries(this.data))if(o instanceof File)try{s[a]=await this.fileToBase64(o)}catch{s[a]=null}else if(o instanceof FileList){const l=[];for(let d=0;d<o.length;d++)try{l.push(await this.fileToBase64(o[d]))}catch{l.push(null)}s[a]=l}return s}}_onModelChange(){this.isSaving||(this.data=this.prepareFormData(),this.isMounted()&&(this._isFormDrivenChange||this.syncFormWithModel(),this._isFormDrivenChange=!1))}syncFormWithModel(){!this.model||!this.element||this.formDataMatchesModelData(this.data)||this.populateFormValues()}formDataMatchesModelData(e){if(!this.formConfig?.fields||!this.element)return!0;for(const t of this.formConfig.fields)if(t.type==="group"&&t.fields){for(const s of t.fields)if(!this.fieldValueMatchesModel(s,e))return!1}else if(!this.fieldValueMatchesModel(t,e))return!1;return!0}fieldValueMatchesModel(e,t){if(!e.name)return!0;const s=this.element.querySelector(`[name="${e.name}"]`);if(!s)return!0;const i=this.getFieldCurrentValue(s,e),r=$.getContextData(t,e.name);return this.valuesAreDifferent(i,r)===!1}getFieldCurrentValue(e,t){switch(t.type){case"checkbox":case"toggle":case"switch":return e.checked;case"radio":const s=this.element.querySelector(`[name="${t.name}"]:checked`);return s?s.value:"";case"select":return e.multiple?Array.from(e.selectedOptions).map(i=>i.value):e.value;case"file":case"image":return null;case"json":try{return e.value?JSON.parse(e.value):null}catch{return e.value}default:return e.value}}setFieldValue(e,t,s){switch(t.type){case"checkbox":case"toggle":case"switch":e.checked=!!s;break;case"radio":const i=this.element.querySelector(`[name="${t.name}"][value="${s}"]`);i&&(i.checked=!0);break;case"select":e.multiple&&Array.isArray(s)?Array.from(e.options).forEach(r=>{r.selected=s.includes(r.value)}):e.value=s??"";break;case"file":case"image":break;case"json":if(typeof s=="object"&&s!==null)try{e.value=JSON.stringify(s,null,2)}catch{e.value="{}"}else typeof s=="string"?e.value=s:e.value=String(s||"");break;default:e.value=s||"";break}e.dispatchEvent(new Event("change",{bubbles:!0}))}setDefaults(e){this.defaults={...this.defaults,...e},this.refreshForm()}async handleSubmit(){try{const e=await this.getFormData();if(this.formConfig.validateOnSubmit!==!1&&!this.validate())return this.focusFirstError(),{success:!1,data:e,error:"Form validation failed"};if(this.model&&typeof this.model.save=="function"){const t=await this.saveModel(e);if(t&&t.success!==!1)return{success:!0,data:e,result:t};{const s=t?.message||t?.error||"Save failed. Please try again.";return{success:!1,data:e,result:t,error:s}}}else return e}catch(e){return{success:!1,error:e.message||"An error occurred while submitting the form"}}}async saveModel(e=null){if(!this.model||typeof this.model.save!="function")throw new Error("No model available for saving");e||(e=await this.getFormData());const t=this.getChangedData(e);return!t||Object.keys(t).length===0?{success:!0,message:"No changes to save",data:e}:(this._isFormDrivenChange=!0,await this.model.save(t))}getChangedData(e){if(!this.model)return e;const t=this.getOriginalModelData();let s;return e instanceof FormData?s=this.getChangedFormData(e,t):s=this.getChangedObjectData(e,t),s}getOriginalModelData(){return this.model.attributes?this.model.attributes:typeof this.model.toJSON=="function"?this.model.toJSON():{}}getChangedFormData(e,t){const s=new FormData;let i=!1;for(const[r,n]of e.entries())if(n instanceof File)n.size===0||n.name===""||n.name==="blob"||(s.set(r,n),i=!0);else{const a=t[r];n!==a&&n!==String(a)&&(s.set(r,n),i=!0)}return i?s:null}getChangedObjectData(e,t){const s={};let i=!1;const r=new Set([...Object.keys(t),...Object.keys(e)]),n=(a,o)=>o.split(".").reduce((l,d)=>l&&typeof l=="object"?l[d]:void 0,a);for(const a of r){const o=this.findFieldConfig(a);if(!o)continue;const l=e[a],d=n(t,a),h=o.type||"text";this.valuesAreDifferent(l,d,h,o)&&(s[a]=l,i=!0)}return i?s:null}valuesAreDifferent(e,t,s="text",i={}){if(e instanceof File)return e.size>0&&e.name!==""&&e.name!=="blob";if(typeof e=="string"&&e.startsWith("data:image/"))return!0;if(s==="collection"&&typeof t=="object"&&t!==null&&t!==void 0&&typeof e=="string"){if(e==="0")return t!==null;const a=i.valueField||"id";if(t[a]==e)return!1}if(s==="switch"||s==="checkbox"||s==="toggle")return!!e!==!!t;const r=e==null?"":String(e).trim(),n=t==null?"":String(t).trim();return r!==n}validate(){const e=this.getFormElement();if(!e)return!1;const t=e.checkValidity();return t||e.classList.add("was-validated"),t}validateField(e){const t=this.getFormElement();if(!t)return!1;const s=t.elements[e];if(!s)return!1;const i=s.checkValidity();return i?(s.classList.remove("is-invalid"),s.classList.add("is-valid"),delete this.errors[e]):(s.classList.remove("is-valid"),s.classList.add("is-invalid"),this.errors[e]=s.validationMessage),i}focusFirstError(){const e=this.getFormElement();if(!e)return;const t=e.querySelector(":invalid");if(!t)return;const s=t.closest(".tab-pane");if(s&&!s.classList.contains("active")){const i=s.id,r=e.querySelector(`[role="tab"][aria-controls="${i}"], [data-bs-target="#${i}"]`);if(r){const n=window.bootstrap?.Tab?.getOrCreateInstance?window.bootstrap.Tab.getOrCreateInstance(r):null;n&&typeof n.show=="function"?n.show():(e.querySelectorAll('[role="tab"].nav-link').forEach(l=>{const d=l===r;l.classList.toggle("active",d),l.setAttribute("aria-selected",d?"true":"false")}),e.querySelectorAll(".tab-pane").forEach(l=>l.classList.remove("show","active")),s.classList.add("show","active"))}}t.focus(),t.scrollIntoView({behavior:"smooth",block:"center"})}clearAllErrors(){const e=this.getFormElement();if(!e)return;this.errors={},e.classList.remove("was-validated"),e.querySelectorAll(".is-invalid").forEach(i=>i.classList.remove("is-invalid")),e.querySelectorAll(".is-valid").forEach(i=>i.classList.remove("is-valid"))}setLoading(e){this.loading=e;const t=this.getFormElement();if(!t)return;const s=t.querySelectorAll("input, select, textarea, button"),i=t.querySelector('button[type="submit"]');if(e)s.forEach(r=>r.disabled=!0),i&&(i.innerHTML='<span class="spinner-border spinner-border-sm me-2"></span>Loading...');else if(s.forEach(r=>r.disabled=!1),i){const r=this.formConfig.options?.submitButton||"Submit";i.innerHTML=typeof r=="string"?r:"Submit"}}showError(e){if(this.emit("error",{message:e,form:this}),this.element){this.element.querySelectorAll(".alert").forEach(i=>i.remove());const s=document.createElement("div");s.className="alert alert-danger alert-dismissible fade show",s.innerHTML=`
1280
+ `}highlightMatch(e){if(!this.inputValue)return this.escapeHtml(e);const t=this.escapeHtml(e),s=new RegExp(`(${this.escapeRegex(this.inputValue)})`,"gi");return t.replace(s,'<mark class="bg-warning bg-opacity-25">$1</mark>')}async onAfterRender(){await super.onAfterRender(),this.updateFilteredOptions(),this.handleOutsideClick=e=>{this.element&&!this.element.contains(e.target)&&this.closeDropdown()},document.addEventListener("click",this.handleOutsideClick)}async onChangeInputChange(e,t){this.inputValue=t.value,this.updateFilteredOptions(),this.inputValue.length>=this.minChars?this.openDropdown():this.closeDropdown(),this.highlightedIndex=-1,await this.updateDropdownDisplay()}async onActionInputKeydown(e,t){switch(e.key){case"ArrowDown":e.preventDefault(),this.isOpen?this.highlightNext():this.openDropdown(),await this.updateDropdownDisplay();break;case"ArrowUp":e.preventDefault(),this.isOpen&&(this.highlightPrevious(),await this.updateDropdownDisplay());break;case"Enter":e.preventDefault(),this.isOpen&&this.highlightedIndex>=0?await this.selectHighlightedOption():this.allowCustom&&this.inputValue&&await this.selectCustomValue(this.inputValue);break;case"Escape":e.preventDefault(),this.closeDropdown();const s=this.element.querySelector(".combo-input-field");s&&(s.value=this.getDisplayValue(this.currentValue),this.inputValue=s.value);break;case"Tab":this.isOpen&&this.closeDropdown();break}}async onActionToggleDropdown(e,t){if(e.preventDefault(),e.stopPropagation(),this.isOpen)this.closeDropdown();else{this.inputValue="";const s=this.element.querySelector(".combo-input-field");s&&(s.value="",s.focus()),this.updateFilteredOptions(),this.openDropdown(),await this.updateDropdownDisplay()}}async onActionSelectOption(e,t){e.preventDefault(),e.stopPropagation();const s=parseInt(t.getAttribute("data-option-index"));s>=0&&s<this.filteredOptions.length&&await this.selectOption(this.filteredOptions[s])}openDropdown(){this.isOpen=!0;const e=this.element?.querySelector(".combo-dropdown");e&&e.classList.add("show");const t=this.element?.querySelector(".combo-input-field");t&&t.setAttribute("aria-expanded","true")}closeDropdown(){this.isOpen=!1,this.highlightedIndex=-1;const e=this.element?.querySelector(".combo-dropdown");e&&e.classList.remove("show");const t=this.element?.querySelector(".combo-input-field");t&&t.setAttribute("aria-expanded","false")}updateFilteredOptions(){const e=this.inputValue.toLowerCase().trim();if(!e){this.filteredOptions=[...this.options];return}this.filteredOptions=this.options.filter(t=>{const s=t.label.toLowerCase().includes(e),i=String(t.value).toLowerCase().includes(e),r=t.description?.toLowerCase().includes(e);return s||i||r}),this.filteredOptions.sort((t,s)=>{const i=t.label.toLowerCase()===e,r=s.label.toLowerCase()===e;if(i&&!r)return-1;if(!i&&r)return 1;const n=t.label.toLowerCase().startsWith(e),a=s.label.toLowerCase().startsWith(e);return n&&!a?-1:!n&&a?1:0})}async updateDropdownDisplay(){const e=this.element?.querySelector(".combo-dropdown");if(e&&(e.innerHTML=this.renderDropdownContent(),this.highlightedIndex>=0)){const t=e.querySelector(".combo-option.active");t&&t.scrollIntoView({block:"nearest"})}}highlightNext(){this.filteredOptions.length!==0&&(this.highlightedIndex=(this.highlightedIndex+1)%Math.min(this.filteredOptions.length,this.maxSuggestions))}highlightPrevious(){this.filteredOptions.length!==0&&(this.highlightedIndex=this.highlightedIndex<=0?Math.min(this.filteredOptions.length,this.maxSuggestions)-1:this.highlightedIndex-1)}async selectHighlightedOption(){this.highlightedIndex>=0&&this.highlightedIndex<this.filteredOptions.length&&await this.selectOption(this.filteredOptions[this.highlightedIndex])}async selectOption(e){this.currentValue=e.value,this.inputValue=e.label,this.selectedOption=e;const t=this.element?.querySelector(".combo-input-field");t&&(t.value=e.label);const s=this.element?.querySelector(".combo-input-hidden");s&&(s.value=e.value),this.closeDropdown(),this.emit("select",{option:e,value:e.value,meta:e.meta}),this.emit("change",{value:e.value,option:e,meta:e.meta}),typeof this.onSelectCallback=="function"&&this.onSelectCallback(e),typeof this.onChangeCallback=="function"&&this.onChangeCallback(e.value)}async selectCustomValue(e){if(!this.allowCustom)return;this.currentValue=e,this.inputValue=e,this.selectedOption=null;const t=this.element?.querySelector(".combo-input-hidden");t&&(t.value=e),this.closeDropdown(),this.emit("custom",{value:e}),this.emit("change",{value:e,custom:!0}),typeof this.onChangeCallback=="function"&&this.onChangeCallback(e)}getValue(){return this.currentValue}async setValue(e){this.currentValue=e,this.selectedOption=this.findOptionByValue(e),this.inputValue=this.getDisplayValue(e);const t=this.element?.querySelector(".combo-input-field");t&&(t.value=this.inputValue);const s=this.element?.querySelector(".combo-input-hidden");s&&(s.value=e),this.updateFilteredOptions()}getSelectedOption(){return this.selectedOption}async setOptions(e){this.options=this.normalizeOptions(e),this.updateFilteredOptions(),this.isOpen&&await this.updateDropdownDisplay()}setEnabled(e){this.disabled=!e;const t=this.element?.querySelector(".combo-input-field");t&&(t.disabled=this.disabled);const s=this.element?.querySelector(".combo-toggle");s&&(s.disabled=this.disabled)}setReadonly(e){this.readonly=e;const t=this.element?.querySelector(".combo-input-field");t&&(e?t.setAttribute("readonly",""):t.removeAttribute("readonly"))}focus(){const e=this.element?.querySelector(".combo-input-field");e&&e.focus()}async clear(){await this.setValue(""),this.inputValue="";const e=this.element?.querySelector(".combo-input-field");e&&(e.value=""),this.emit("clear")}getFormValue(){return this.allowCustom&&this.inputValue&&this.inputValue!==this.getDisplayValue(this.currentValue)?this.inputValue:this.currentValue}async setFormValue(e){await this.setValue(e)}escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}async onBeforeDestroy(){this.handleOutsideClick&&document.removeEventListener("click",this.handleOutsideClick),await super.onBeforeDestroy()}static create(e={}){return new Ye(e)}}class te extends C{constructor(e={}){const{formConfig:t=e.config,fields:s,model:i=null,data:r={},defaults:n=null,errors:a={},fileHandling:o="base64",autosaveModelField:l=!1,...d}=e;super({tagName:"div",className:"form-view",enableTooltips:!0,...d}),X.onFormViewInit?.(this),this.model=i,this.defaults=n||r,this._originalData=r,this.errors=a,this.loading=!1,this.fileHandling=o,this.autosaveModelField=l,this.customComponents=new Map,this.fieldStatusManagers=new Map,this.saveTimeouts=new Map,this.pendingSaveFields=new Map,this.batchSaveTimeout=null,this.isSaving=!1,this.data=this.prepareFormData(),this.formConfig=t||{fields:s||[]},this.formBuilder=new ge({...this.getFormConfig(),data:this.data,errors:a})}prepareFormData(){const e={...this.defaults};if(this.model)if(this.model.attributes&&typeof this.model.attributes=="object")Object.assign(e,this.model.attributes);else if(typeof this.model.toJSON=="function"){const t=this.model.toJSON();Object.assign(e,t)}else typeof this.model=="object"&&this.model.constructor===Object&&Object.assign(e,this.model);return this._originalData&&Object.assign(e,this._originalData),e}getFormConfig(){const e={...this.formConfig},t=this.getApp();return this.formConfig.fields&&Array.isArray(this.formConfig.fields)?e.fields=this.formConfig.fields.filter(s=>s.permissions?t.activeUser?.hasPermission(s.permissions):!0):e.fields=[],e}async renderTemplate(){return this.formBuilder.buildFormHTML()}async onAfterRender(){await super.onAfterRender(),this.data=this.prepareFormData(),this.populateFormValues(),this.initializeFormComponents(),this.initializeChangeHandlers();const e=this.getFormElement();e&&e.addEventListener("submit",t=>(t.preventDefault(),!1)),this._initShowWhen(),X.onFormViewAfterRender?.(this)}populateFormValues(){if(!(!this.element||!this.formConfig?.fields)){this._isPopulating=!0;try{this.formConfig.fields.forEach(e=>{this.populateFieldRecursive(e)})}finally{this._isPopulating=!1}}}populateFieldRecursive(e){e.type==="group"&&e.fields?e.fields.forEach(t=>{this.populateFieldRecursive(t)}):e.type==="tabset"&&e.tabs?e.tabs.forEach(t=>{t.fields&&Array.isArray(t.fields)&&t.fields.forEach(s=>{this.populateFieldRecursive(s)})}):this.populateFieldValue(e)}populateFieldValue(e){if(!e.name||!this.element)return;const t=this.element.querySelector(`[name="${e.name}"]`);if(!t)return;const s=$.getContextData(this.data,e.name);s!=null&&this.setFieldValue(t,e,s)}initializeFormComponents(){this.initializeImageFields(),this.initializeCustomComponents(),this.initializeTagInputs(),this.initializeMultiSelectDropdowns(),this.initializeComboBoxes(),this.initializeCollectionSelects(),this.initializeCollectionMultiSelects(),this.initializeDatePickers(),this.initializeDateRangePickers(),this.initializeTimePickers(),this.initializeDateTimePickers(),this.initializePasswordFields()}initializeImageFields(){this.element.querySelectorAll(".image-drop-zone.droppable").length>0&&this.enableFileDrop({acceptedTypes:["image/*"],maxFileSize:10485760,multiple:!1,dropZoneSelector:".image-drop-zone.droppable",visualFeedback:!0,dragOverClass:"drag-over",dragActiveClass:"drag-active"})}initializeCustomComponents(){this.initializeTagInputs(),this.initializeCollectionSelects(),this.initializeCollectionMultiSelects(),this.initializeDatePickers(),this.initializeDateRangePickers(),this.initializeTimePickers(),this.initializeDateTimePickers(),this.initializeComboInputs();try{const t=(s=[])=>{s.forEach(i=>{if(i&&i.type==="group"&&Array.isArray(i.fields))t(i.fields);else if(i&&i.name){const r=this.element.querySelector(`[name="${i.name}"], #${i.id||i.name}`);r&&X.onFieldInit?.(this,r,i)}})};t(this.formConfig?.fields||[])}catch(t){console.warn("FormPlugins.onFieldInit error:",t)}this.element.querySelectorAll("[data-component]").forEach(t=>{t.getAttribute("data-component"),t.getAttribute("data-field")})}initializeChangeHandlers(){if(!this.element)return;const e=this.element.querySelectorAll("input:not([data-action]), select:not([data-action]), textarea:not([data-action])");console.log("FormView: initializeChangeHandlers - found",e.length,"inputs"),e.forEach(t=>{console.log("FormView: Processing input:",t.type,t.name,t.getAttribute("data-change-action")),!(t.hasAttribute("data-component")||t.hasAttribute("data-change-action")||t.classList.contains("form-check-input"))&&(t.addEventListener("change",s=>{if(this._isPopulating)return;const i=t.name;if(i){let r=t.value;if(t.type==="checkbox")r=t.checked;else if(t.type==="radio"){if(!t.checked)return}else if(t.multiple&&t.selectedOptions)r=Array.from(t.selectedOptions).map(n=>n.value);else if(t.type==="file"){const n=t.getAttribute("data-change-action");if(n==="image-selected"){this.onChangeImageSelected(s,t);return}else if(n==="file-selected"){this.onChangeFileSelected(s,t);return}}this.handleFieldChange(i,r)}}),(t.type==="text"||t.type==="email"||t.type==="url"||t.tagName==="TEXTAREA")&&t.addEventListener("input",s=>{if(this._isPopulating)return;const i=t.name;i&&this.handleFieldChange(i,t.value)}))})}initializeTagInputs(){this.element.querySelectorAll('[data-field-type="tag"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new Ve({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeMultiSelectDropdowns(){this.element.querySelectorAll('[data-field-type="multiselect"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n)return;const a=new os({...r,options:n.options||[],placeholder:n.placeholder||r.placeholder||"Select...",label:n.label,containerId:null});let o=r.value??$.getContextData(this.data,s);o&&a.setFormValue(o),a.render(!0,t),this.customComponents.set(s,a),a.on("change",l=>{this.handleFieldChange(s,l.value)})}catch(s){console.error("MultiSelectDropdown initialization failed:",s)}})}initializeComboBoxes(){this.element.querySelectorAll('[data-field-type="combobox"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n)return;const a=new Et({...r,options:n.options||[],placeholder:n.placeholder||r.placeholder||"Type or select...",containerId:null});let o=r.value??$.getContextData(this.data,s);o&&a.setFormValue(o),a.render(!0,t),this.customComponents.set(s,a),a.on("change",l=>{this.handleFieldChange(s,l.value)})}catch(s){console.error("ComboBox initialization failed:",s)}})}initializeCollectionSelects(){this.element.querySelectorAll('[data-field-type="collection"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n||!n.Collection)return;const a=new n.Collection;n.collectionParams&&(a.params={...a.params,...n.collectionParams});const o=new ss({...r,collection:a,defaultParams:n.defaultParams||null,containerId:null});let l=$.getContextData(this.data,s);l&&o.setFormValue(l),o.render(!0,t),this.customComponents.set(s,o),o.on("change",d=>{this.handleFieldChange(s,d.value)})}catch{}})}initializeCollectionMultiSelects(){this.element.querySelectorAll('[data-field-type="collectionmultiselect"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=this.getFormFieldConfig(s);if(!n||!n.Collection)return;const a=new n.Collection;n.collectionParams&&(a.params={...a.params,...n.collectionParams});const o=new ns({...r,collection:a,defaultParams:n.defaultParams||null,itemTemplate:n.itemTemplate||null,containerId:null});let l=$.getContextData(this.data,s);l&&o.setFormValue(l),o.render(!0,t),this.customComponents.set(s,o),o.on("change",d=>{this.handleFieldChange(s,d.value)})}catch(s){console.error("CollectionMultiSelect initialization failed:",s)}})}initializeDatePickers(){this.element.querySelectorAll('[data-field-type="datepicker"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new qe({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeDateRangePickers(){this.element.querySelectorAll('[data-field-type="daterange"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new Be({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.combined)})}catch{}})}initializeTimePickers(){this.element.querySelectorAll('[data-field-type="timepicker"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new $e({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeDateTimePickers(){this.element.querySelectorAll('[data-field-type="datetimepicker"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new We({...r,containerId:null});n.render(!0,t),this.customComponents.set(s,n),n.on("change",a=>{this.handleFieldChange(s,a.value)})}catch{}})}initializeComboInputs(){this.element.querySelectorAll('[data-field-type="combo"]').forEach(t=>{try{const s=t.getAttribute("data-field-name"),i=t.getAttribute("data-field-config"),r=JSON.parse(i),n=new Ye({...r,containerId:null});let a=$.getContextData(this.data,s);a&&n.setValue(a),n.render(!0,t),this.customComponents.set(s,n),n.on("change",o=>{this.handleFieldChange(s,o.value)}),n.on("select",o=>{this.emit("field:select",{field:s,value:o.value,option:o.option,meta:o.meta})})}catch(s){console.error("ComboInput initialization failed:",s)}})}handleFieldChange(e,t){this._isPopulating||(this.data[e]=t,this.autosaveModelField&&this.model?this.handleFieldSave(e,t):this.model&&this.options.allowModelChange&&(this._isFormDrivenChange=!0,this.model.set(e,t)),this.emit("field:change",{field:e,value:t}),this._updateShowWhen(e,t),X.onFieldChange?.(this,e,t))}_initShowWhen(){if(this._showWhenMap={},!this.element)return;this.element.querySelectorAll("[data-show-when-field]").forEach(t=>{const s=t.getAttribute("data-show-when-field");this._showWhenMap[s]||(this._showWhenMap[s]=[]),this._showWhenMap[s].push(t),t.style.display==="none"?t.querySelectorAll("input, select, textarea").forEach(r=>{r.required&&(r.dataset.wasRequired="true",r.required=!1)}):t.querySelectorAll("input, select, textarea").forEach(r=>{r.required&&(r.dataset.wasRequired="true")})})}_updateShowWhen(e,t){const s=this._showWhenMap?.[e];if(!s)return;const i=String(t??"");s.forEach(r=>{const n=r.getAttribute("data-show-when-value").split(","),a=r.getAttribute("data-show-when-negate")==="true",o=n.includes(i),l=a?!o:o;r.style.display=l?"":"none",r.querySelectorAll("input, select, textarea").forEach(h=>{l?h.dataset.wasRequired==="true"&&(h.required=!0):(h.required&&(h.dataset.wasRequired="true"),h.required=!1)})})}async handleFieldSave(e,t){if(!this.model)return;this.pendingSaveFields.set(e,t),this.getFieldStatusManager(e).showStatus("saving"),this.batchSaveTimeout&&clearTimeout(this.batchSaveTimeout),this.batchSaveTimeout=setTimeout(async()=>{await this.executeBatchSave()},300)}async executeBatchSave(){if(this.isSaving||this.pendingSaveFields.size===0)return;const e=Object.fromEntries(this.pendingSaveFields),t=Array.from(this.pendingSaveFields.keys());try{if(this.isSaving=!0,this.pendingSaveFields.clear(),this.batchSaveTimeout=null,this._isFormDrivenChange=!0,typeof this.model.save=="function"){const s=await this.model.save(e,{skipRender:!0});if(!s||!s.success||s.data&&!s.data.status){const i=s?.data?.error||s?.error||s?.message||"Save failed";this.getApp()?.toast?.error(i),this.revertFields(t),t.forEach(r=>{this.getFieldStatusManager(r).showStatus("error",{message:i})});return}}else Object.entries(e).forEach(([s,i])=>{this.model.set(s,i,{skipRender:!0})});t.forEach(s=>{this.getFieldStatusManager(s).showStatus("saved")})}catch(s){console.error("Batch save error:",s),this.getApp()?.toast?.error(s.message||"An error occurred while saving"),this.revertFields(t),t.forEach(i=>{this.getFieldStatusManager(i).showStatus("error",{message:s.message})})}finally{this.isSaving=!1}}revertFields(e){if(!this.model)return;const t=this._isPopulating;this._isPopulating=!0;try{e.forEach(s=>{const i=this.model.get(s);this.data[s]=i;const r=this.element?.querySelector(`[name="${s}"]`);if(r){const n=this.getFormFieldConfig(s);n?this.setFieldValue(r,n,i):r.type==="checkbox"?r.checked=!!i:r.value=i??""}})}finally{this._isPopulating=t}}getFieldStatusManager(e){if(!this.fieldStatusManagers.has(e)){const t=this.element.querySelector(`[name="${e}"]`);if(t){const s=new Cs(t);this.fieldStatusManagers.set(e,s)}}return this.fieldStatusManagers.get(e)}refreshForm(){this.data=this.prepareFormData(),this.element&&this.populateFormValues()}getChangeReason(e,t){if(e instanceof File)return e.size===0||e.name===""||e.name==="blob"?"empty file, no change":`file upload: ${e.name}, ${e.size} bytes`;if(typeof e=="string"&&e.startsWith("data:image/"))return"base64 image upload";if(typeof e=="boolean"||typeof t=="boolean"){const s=!!e;return`boolean: ${t==null?!1:!!t} → ${s}`}return e==null||String(e).trim(),t==null||String(t).trim(),t==null?"was null/undefined, now has value":e==null?"was value, now null/undefined":"text content changed"}setFormData(e){this._originalData={...this._originalData,...e},this.refreshForm()}async onActionSubmitForm(e,t){e.preventDefault();const s=await this.handleSubmit();s.success?(this.data=s.data,this.emit("submit",{data:s.data,result:s.result,form:this,event:e}),!this.model&&this.formConfig.onSubmit&&typeof this.formConfig.onSubmit=="function"&&await this.formConfig.onSubmit(s.data,this)):this.emit("error",{error:s.error,result:s,form:this})}async onActionResetForm(e,t){const s=this.getFormElement();s&&(s.reset(),this.data={},this.clearAllErrors(),this.emit("reset",{form:this,event:e}))}async onActionClickImageUpload(e,t){console.log("FormView: onActionClickImageUpload called"),console.log("FormView: element:",t);const s=t.getAttribute("data-field-id");if(console.log("FormView: fieldId:",s),!s){console.error("FormView: No fieldId attribute found");return}const i=this.element.querySelector(`#${s}`);console.log("FormView: fileInput:",i),i&&!i.disabled?(i.click(),console.log("FormView: fileInput.click() called")):i?console.log("FormView: fileInput is disabled"):console.error("FormView: fileInput not found for fieldId:",s)}async onActionRemoveImage(e,t){const s=t.getAttribute("data-field");if(!s)return;const i=this.element.querySelector(`input[name="${s}"]`);i&&(i.value="",i.dispatchEvent(new Event("change",{bubbles:!0}))),delete this.data[s],this.emit("change",{field:s,value:null,form:this}),await this.updateField(s)}async onActionClearColor(e,t){const s=t.getAttribute("data-field");if(!s)return;const i=this.element.querySelector(`input[name="${s}"]`);i&&(i.value="",this.handleFieldChange(s,""),await this.updateField(s))}async onActionPreviewHtml(e,t){e.preventDefault();const s=t.getAttribute("data-target");if(!s)return;const i=this.element.querySelector(`#${s}`);if(!i)return;const r=i.value||"";(await Promise.resolve().then(()=>R)).default.htmlPreview({html:r,title:"HTML Preview"})}async onActionSelectButtonOption(e,t){const s=t.getAttribute("data-field"),i=t.getAttribute("data-value");if(!s||!i)return;this.data[s]=i;const r=t.closest(".btn-group");r&&(r.querySelectorAll("button").forEach(a=>{a.classList.remove("active"),a.classList.add("btn-outline-primary"),a.classList.remove("btn-primary")}),t.classList.add("active"),t.classList.remove("btn-outline-primary"),t.classList.add("btn-primary")),this.emit("field:changed",{field:s,value:i,form:this}),this.emit("change",{field:s,value:i,form:this}),this.emit("form:changed",await this.getFormData())}async onActionApplyFilter(e,t){const s=t.closest(".dropdown"),i=s?.querySelectorAll('input[type="checkbox"]');if(!i||i.length===0)return;const r=i[0].getAttribute("data-field");if(!r)return;const n=[];i.forEach(o=>{o.checked&&n.push(o.value)}),this.data[r]=n;const a=s.querySelector('[data-bs-toggle="dropdown"]');a&&window.bootstrap?.Dropdown&&window.bootstrap.Dropdown.getInstance(a)?.hide(),this.emit("field:changed",{field:r,value:n,form:this}),this.emit("change",{field:r,value:n,form:this}),this.emit("form:changed",await this.getFormData())}async onChangeValidateField(e,t){const s=t.name;if(s){const i=t.value;this.handleFieldChange(s,i),this.validateField(s)}}async onChangeToggleSwitch(e,t){const s=t.getAttribute("data-field");if(s){const i=t.checked;this.handleFieldChange(s,i),this.emit("switch:toggle",{field:s,checked:i,form:this})}}async onChangeImageSelected(e,t){console.log("FormView: onChangeImageSelected called"),console.log("FormView: element:",t),console.log("FormView: element.files:",t.files);const s=t.getAttribute("data-field"),i=t.files[0];if(console.log("FormView: fieldName:",s),console.log("FormView: file:",i),s&&i){console.log("FormView: fieldName and file exist, processing...");const r=this.findFieldConfig(s);console.log("FormView: fieldConfig:",r);const n=URL.createObjectURL(i);if(console.log("FormView: previewUrl created:",n),r&&r.imageSize){console.log("FormView: Image cropping is required, imageSize:",r.imageSize);try{const a=window.MOJO?.plugins?.ImageCropView;if(console.log("FormView: ImageCropView available?",!!a),!a){console.log("FormView: ImageCropView not available, falling back to normal handling"),this.data[s]=i,await this.updateImagePreview(s,n),this.emit("image:selected",{field:s,file:i,form:this});return}const o=await a.showDialog(n,{title:`Crop ${r.label||s}`,cropAndScale:r.imageSize,size:"lg"});if(o.action==="crop"&&o.data){const d=await(await fetch(o.data)).blob(),h=new File([d],i.name,{type:i.type||"image/png"});this.data[s]=h,await this.updateImagePreview(s,o.data),this.emit("image:selected",{field:s,file:h,originalFile:i,cropped:!0,cropData:o.cropData,form:this}),this.emit("change",{field:s,value:h,form:this})}else t.value=""}catch(a){console.error("FormView: Error during image cropping:",a),console.log("FormView: Falling back to normal image handling after error"),this.data[s]=i,await this.updateImagePreview(s,n),this.emit("image:selected",{field:s,file:i,form:this}),this.emit("change",{field:s,value:i,form:this})}}else console.log("FormView: Normal image handling (no cropping)"),this.data[s]=i,console.log("FormView: File stored in this.data["+s+"]"),await this.updateImagePreview(s,n),console.log("FormView: updateImagePreview completed"),this.emit("image:selected",{field:s,file:i,form:this}),console.log("FormView: image:selected event emitted")}else console.log("FormView: Missing fieldName or file - not processing")}async onChangeFileSelected(e,t){const s=Array.from(t.files);t.multiple?this.data[t.name]=t.files:this.data[t.name]=s[0]||null,this.emit("file:selected",{field:t.name,files:s,form:this}),this.emit("change",{field:t.name,value:s,form:this})}async onChangeRangeChanged(e,t){const s=t.name,i=t.value,r=t.getAttribute("data-target");if(r){const n=this.element.querySelector(`#${r}`);n&&(n.textContent=i)}s&&this.handleFieldChange(s,i),this.emit("range:changed",{field:s,value:i,form:this})}async onChangeFilterSearch(e,t){const s=t.value;this.emit("search",{query:s,field:t.name,form:this})}async onChangeFilterSelectOptions(e,t){const s=t.value.toLowerCase(),i=t.getAttribute("data-target"),r=i?this.element.querySelector(`#${i}`):null;r&&r.querySelectorAll("option").forEach(a=>{const o=a.textContent.toLowerCase();a.style.display=o.includes(s)?"":"none"})}async onFileDrop(e,t,s){const i=t.target.closest(".image-drop-zone");if(!i)return;const r=i.getAttribute("data-field");if(!r)return;const n=e[0],a=this.element.querySelector(`input[name="${r}"]`);if(a){const l=new DataTransfer;l.items.add(n),a.files=l.files,a.dispatchEvent(new Event("change",{bubbles:!0}))}this.data[r]=n;const o=URL.createObjectURL(n);await this.updateImagePreview(r,o),this.emit("image:dropped",{field:r,file:n,form:this})}async onFileDropError(e,t,s){this.showError(`File upload error: ${e.message}`),this.emit("file:error",{error:e,files:s,form:this})}getFormElement(){return this.element?this.element.querySelector("form"):null}getFormFieldConfig(e){const t=s=>{for(const i of s){if(i.name===e)return i;if(i.fields&&Array.isArray(i.fields)){const r=t(i.fields);if(r)return r}if(i.tabs&&Array.isArray(i.tabs)){for(const r of i.tabs)if(r.fields&&Array.isArray(r.fields)){const n=t(r.fields);if(n)return n}}}return null};return t(this.formConfig.fields||[])}async getFormData(){const e=this.getFormElement();if(!e)return this.fileHandling==="multipart"?new FormData:{};if(this.fileHandling==="multipart"){const t=new FormData(e);for(const[s,i]of Object.entries(this.data))if(i instanceof File)t.set(s,i);else if(i instanceof FileList)for(let r=0;r<i.length;r++)t.append(`${s}[${r}]`,i[r]);return t}else{const t=new FormData(e),s={};for(const[a,o]of t.entries())s[a]?(Array.isArray(s[a])||(s[a]=[s[a]]),s[a].push(o)):s[a]=o;e.querySelectorAll('input[type="checkbox"]').forEach(a=>{s[a.name]=a.checked}),e.querySelectorAll('input[type="number"]').forEach(a=>{if(a.name&&s[a.name]!==void 0&&s[a.name]!==""){const o=Number(s[a.name]);isNaN(o)||(s[a.name]=o)}}),this.formConfig.fields?.forEach(a=>{if(a.type==="select"&&a.name&&s[a.name]!==void 0){const o=this.getFormFieldConfig(a.name);if(o?.options&&Array.isArray(o.options)&&o.options.every(d=>{const h=typeof d=="object"?d.value:d;return h===""||!isNaN(Number(h))})&&s[a.name]!==""){const d=Number(s[a.name]);isNaN(d)||(s[a.name]=d)}}}),e.querySelectorAll('[data-field-type="json"]').forEach(a=>{try{s[a.name]=JSON.parse(a.value)}catch{s[a.name]=a.value}}),this.customComponents.forEach((a,o)=>{a.getFormValue?s[o]=a.getFormValue():a.getValue&&(s[o]=a.getValue())}),this.element&&this.element.querySelectorAll("[data-show-when-field]").forEach(o=>{o.style.display==="none"&&o.querySelectorAll("[name]").forEach(d=>{delete s[d.name]})});for(const[a,o]of Object.entries(this.data))if(o instanceof File)try{s[a]=await this.fileToBase64(o)}catch{s[a]=null}else if(o instanceof FileList){const l=[];for(let d=0;d<o.length;d++)try{l.push(await this.fileToBase64(o[d]))}catch{l.push(null)}s[a]=l}return s}}_onModelChange(){this.isSaving||(this.data=this.prepareFormData(),this.isMounted()&&(this._isFormDrivenChange||this.syncFormWithModel(),this._isFormDrivenChange=!1))}syncFormWithModel(){!this.model||!this.element||this.formDataMatchesModelData(this.data)||this.populateFormValues()}formDataMatchesModelData(e){if(!this.formConfig?.fields||!this.element)return!0;for(const t of this.formConfig.fields)if(t.type==="group"&&t.fields){for(const s of t.fields)if(!this.fieldValueMatchesModel(s,e))return!1}else if(!this.fieldValueMatchesModel(t,e))return!1;return!0}fieldValueMatchesModel(e,t){if(!e.name)return!0;const s=this.element.querySelector(`[name="${e.name}"]`);if(!s)return!0;const i=this.getFieldCurrentValue(s,e),r=$.getContextData(t,e.name);return this.valuesAreDifferent(i,r)===!1}getFieldCurrentValue(e,t){switch(t.type){case"checkbox":case"toggle":case"switch":return e.checked;case"radio":const s=this.element.querySelector(`[name="${t.name}"]:checked`);return s?s.value:"";case"select":return e.multiple?Array.from(e.selectedOptions).map(i=>i.value):e.value;case"file":case"image":return null;case"json":try{return e.value?JSON.parse(e.value):null}catch{return e.value}default:return e.value}}setFieldValue(e,t,s){switch(t.type){case"checkbox":case"toggle":case"switch":e.checked=!!s;break;case"radio":const i=this.element.querySelector(`[name="${t.name}"][value="${s}"]`);i&&(i.checked=!0);break;case"select":e.multiple&&Array.isArray(s)?Array.from(e.options).forEach(r=>{r.selected=s.includes(r.value)}):e.value=s??"";break;case"file":case"image":break;case"json":if(typeof s=="object"&&s!==null)try{e.value=JSON.stringify(s,null,2)}catch{e.value="{}"}else typeof s=="string"?e.value=s:e.value=String(s||"");break;default:e.value=s||"";break}e.dispatchEvent(new Event("change",{bubbles:!0}))}setDefaults(e){this.defaults={...this.defaults,...e},this.refreshForm()}async handleSubmit(){try{const e=await this.getFormData();if(this.formConfig.validateOnSubmit!==!1&&!this.validate())return this.focusFirstError(),{success:!1,data:e,error:"Form validation failed"};if(this.model&&typeof this.model.save=="function"){const t=await this.saveModel(e);if(t&&t.success!==!1)return{success:!0,data:e,result:t};{const s=t?.message||t?.error||"Save failed. Please try again.";return{success:!1,data:e,result:t,error:s}}}else return e}catch(e){return{success:!1,error:e.message||"An error occurred while submitting the form"}}}async saveModel(e=null){if(!this.model||typeof this.model.save!="function")throw new Error("No model available for saving");e||(e=await this.getFormData());const t=this.getChangedData(e);return!t||Object.keys(t).length===0?{success:!0,message:"No changes to save",data:e}:(this._isFormDrivenChange=!0,await this.model.save(t))}getChangedData(e){if(!this.model)return e;const t=this.getOriginalModelData();let s;return e instanceof FormData?s=this.getChangedFormData(e,t):s=this.getChangedObjectData(e,t),s}getOriginalModelData(){return this.model.attributes?this.model.attributes:typeof this.model.toJSON=="function"?this.model.toJSON():{}}getChangedFormData(e,t){const s=new FormData;let i=!1;for(const[r,n]of e.entries())if(n instanceof File)n.size===0||n.name===""||n.name==="blob"||(s.set(r,n),i=!0);else{const a=t[r];n!==a&&n!==String(a)&&(s.set(r,n),i=!0)}return i?s:null}getChangedObjectData(e,t){const s={};let i=!1;const r=new Set([...Object.keys(t),...Object.keys(e)]),n=(a,o)=>o.split(".").reduce((l,d)=>l&&typeof l=="object"?l[d]:void 0,a);for(const a of r){const o=this.findFieldConfig(a);if(!o)continue;const l=e[a],d=n(t,a),h=o.type||"text";this.valuesAreDifferent(l,d,h,o)&&(s[a]=l,i=!0)}return i?s:null}valuesAreDifferent(e,t,s="text",i={}){if(e instanceof File)return e.size>0&&e.name!==""&&e.name!=="blob";if(typeof e=="string"&&e.startsWith("data:image/"))return!0;if(s==="collection"&&typeof t=="object"&&t!==null&&t!==void 0&&typeof e=="string"){if(e==="0")return t!==null;const a=i.valueField||"id";if(t[a]==e)return!1}if(s==="switch"||s==="checkbox"||s==="toggle")return!!e!==!!t;const r=e==null?"":String(e).trim(),n=t==null?"":String(t).trim();return r!==n}validate(){const e=this.getFormElement();if(!e)return!1;const t=e.checkValidity();return t||e.classList.add("was-validated"),t}validateField(e){const t=this.getFormElement();if(!t)return!1;const s=t.elements[e];if(!s)return!1;const i=s.checkValidity();return i?(s.classList.remove("is-invalid"),s.classList.add("is-valid"),delete this.errors[e]):(s.classList.remove("is-valid"),s.classList.add("is-invalid"),this.errors[e]=s.validationMessage),i}focusFirstError(){const e=this.getFormElement();if(!e)return;const t=e.querySelector(":invalid");if(!t)return;const s=t.closest(".tab-pane");if(s&&!s.classList.contains("active")){const i=s.id,r=e.querySelector(`[role="tab"][aria-controls="${i}"], [data-bs-target="#${i}"]`);if(r){const n=window.bootstrap?.Tab?.getOrCreateInstance?window.bootstrap.Tab.getOrCreateInstance(r):null;n&&typeof n.show=="function"?n.show():(e.querySelectorAll('[role="tab"].nav-link').forEach(l=>{const d=l===r;l.classList.toggle("active",d),l.setAttribute("aria-selected",d?"true":"false")}),e.querySelectorAll(".tab-pane").forEach(l=>l.classList.remove("show","active")),s.classList.add("show","active"))}}t.focus(),t.scrollIntoView({behavior:"smooth",block:"center"})}clearAllErrors(){const e=this.getFormElement();if(!e)return;this.errors={},e.classList.remove("was-validated"),e.querySelectorAll(".is-invalid").forEach(i=>i.classList.remove("is-invalid")),e.querySelectorAll(".is-valid").forEach(i=>i.classList.remove("is-valid"))}setLoading(e){this.loading=e;const t=this.getFormElement();if(!t)return;const s=t.querySelectorAll("input, select, textarea, button"),i=t.querySelector('button[type="submit"]');if(e)s.forEach(r=>r.disabled=!0),i&&(i.innerHTML='<span class="spinner-border spinner-border-sm me-2"></span>Loading...');else if(s.forEach(r=>r.disabled=!1),i){const r=this.formConfig.options?.submitButton||"Submit";i.innerHTML=typeof r=="string"?r:"Submit"}}showError(e){if(this.emit("error",{message:e,form:this}),this.element){this.element.querySelectorAll(".alert").forEach(i=>i.remove());const s=document.createElement("div");s.className="alert alert-danger alert-dismissible fade show",s.innerHTML=`
1281
1281
  ${e}
1282
1282
  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
1283
- `,this.element.insertBefore(s,this.element.firstChild),setTimeout(()=>{s.parentNode&&s.remove()},5e3)}}async updateField(e){this.formBuilder=new fe({...this.getFormConfig(),data:this.data,errors:this.errors}),await this.render()}async updateImagePreview(e,t){const s=this.element.querySelector(`[data-field="${e}"].image-drop-zone`);if(!s)return;let i=s.querySelector("img");const r=s.querySelector(".bi-image")?.parentElement,n=s.getAttribute("data-field-id");if(t){if(i)i.src=t;else{const a=`${n}_preview`;s.innerHTML=`
1283
+ `,this.element.insertBefore(s,this.element.firstChild),setTimeout(()=>{s.parentNode&&s.remove()},5e3)}}async updateField(e){this.formBuilder=new ge({...this.getFormConfig(),data:this.data,errors:this.errors}),await this.render()}async updateImagePreview(e,t){const s=this.element.querySelector(`[data-field="${e}"].image-drop-zone`);if(!s)return;let i=s.querySelector("img");const r=s.querySelector(".bi-image")?.parentElement,n=s.getAttribute("data-field-id");if(t){if(i)i.src=t;else{const a=`${n}_preview`;s.innerHTML=`
1284
1284
  <img id="${a}"
1285
1285
  src="${t}"
1286
1286
  alt="Preview"
@@ -1294,7 +1294,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1294
1294
  style="opacity: 0.8;">
1295
1295
  <i class="bi bi-x"></i>
1296
1296
  </button>
1297
- `}r&&(r.style.display="none")}}findFieldConfig(e){const t=s=>{for(const i of s){if(i.name===e)return i;if(i.fields&&Array.isArray(i.fields)){const r=t(i.fields);if(r)return r}if(i.tabs&&Array.isArray(i.tabs)){for(const r of i.tabs)if(r.fields&&Array.isArray(r.fields)){const n=t(r.fields);if(n)return n}}}return null};return t(this.formConfig.fields||[])}async fileToBase64(e){return new Promise((t,s)=>{const i=new FileReader;i.onload=()=>t(i.result),i.onerror=s,i.readAsDataURL(e)})}hasFiles(e){if(e instanceof FormData){for(const[t,s]of e.entries())if(s instanceof File)return!0;return!1}else{for(const t of Object.values(e))if(t instanceof File||Array.isArray(t)&&t.some(s=>s instanceof File))return!0;return!1}}reset(){const e=this.getFormElement();e&&e.reset(),this.data={},this.errors={},this.clearAllErrors(),this.emit("reset",{form:this})}async updateConfig(e){this.formConfig={...this.formConfig,...e},this.formBuilder=new fe({...this.getFormConfig(),data:this.data,errors:this.errors}),await this.render()}async onBeforeDestroy(){const e=[];for(const t of this.customComponents.values())t.destroy&&e.push(t.destroy());await Promise.all(e),this.customComponents.clear(),Object.values(this.data).forEach(t=>{typeof t=="string"&&t.startsWith("blob:")&&URL.revokeObjectURL(t)}),await super.onBeforeDestroy()}initializePasswordFields(){if(!this.element)return;this.element.querySelectorAll('input[data-field-type="password"], input[type="password"]').forEach(t=>{this.updatePasswordStrengthUI(t);const s=r=>{this.updatePasswordStrengthUI(r.target)};t.addEventListener("input",s);const i=r=>{if(typeof r.getModifierState=="function"){const n=r.getModifierState("CapsLock");this.updateCapsLockWarning(t,!!n)}};t.addEventListener("keydown",i),t.addEventListener("keyup",i),this.updateCapsLockWarning(t,!1)})}async onActionTogglePassword(e,t){e.preventDefault();const s=t.getAttribute("data-target");let i=null;if(s&&(i=this.element.querySelector("#"+s)),!i){const a=t.closest(".input-group");a&&(i=a.querySelector('input[type="password"], input[data-field-type="password"], input[type="text"]'))}if(!i)return;const r=i.type==="password";i.type=r?"text":"password",t.setAttribute("aria-pressed",r?"true":"false"),t.setAttribute("aria-label",r?"Hide password":"Show password");const n=t.querySelector("i");n&&(n.classList.toggle("bi-eye",!r),n.classList.toggle("bi-eye-slash",r)),i.focus();try{const a=i.value?.length??0;i.setSelectionRange(a,a)}catch{}}async onActionCopyToClipboard(e,t){e.preventDefault();const s=t.getAttribute("data-target");if(!s)return;const i=this.element.querySelector("#"+s);if(i)try{await navigator.clipboard.writeText(i.value);const r=t.querySelector("i");if(r){const n=r.className;r.className="bi bi-check2",t.classList.add("btn-success"),t.classList.remove("btn-outline-secondary"),setTimeout(()=>{r.className=n,t.classList.remove("btn-success"),t.classList.add("btn-outline-secondary")},1500)}this.app&&this.app.toast&&this.app.toast.success("Copied to clipboard!")}catch(r){console.error("Failed to copy to clipboard:",r),this.app&&this.app.toast&&this.app.toast.error("Failed to copy to clipboard")}}computePasswordStrength(e=""){const t=e.length;let s=0;t>=6&&s++,t>=8&&s++,t>=12&&s++;const i=/[a-z]/.test(e),r=/[A-Z]/.test(e),n=/\d/.test(e),a=/[^A-Za-z0-9]/.test(e),o=[i,r,n,a].filter(Boolean).length;return o>=2&&s++,o>=3&&s++,s=Math.max(0,Math.min(4,s)),[{percent:0,label:"Too short",barClass:"bg-secondary"},{percent:25,label:"Weak",barClass:"bg-danger"},{percent:50,label:"Fair",barClass:"bg-warning"},{percent:75,label:"Good",barClass:"bg-info"},{percent:100,label:"Strong",barClass:"bg-success"}][s]}updatePasswordStrengthUI(e){if(!e||!e.id)return;const t=this.element.querySelector(`#${e.id}_strength_bar`),s=this.element.querySelector(`#${e.id}_strength_text`);if(!t&&!s)return;const{percent:i,label:r,barClass:n}=this.computePasswordStrength(e.value||"");t&&(t.className=`progress-bar ${n}`,t.style.width=`${i}%`,t.setAttribute("aria-valuenow",String(i))),s&&(s.textContent=r)}updateCapsLockWarning(e,t){if(!e||!e.id)return;const s=this.element.querySelector(`#${e.id}_caps_warning`);s&&(t?s.classList.remove("d-none"):s.classList.add("d-none"))}}class Ss{constructor(e){this.fieldElement=e,this.statusContainer=this.findOrCreateStatusContainer(),this.timeouts=new Map}findOrCreateStatusContainer(){let e=this.fieldElement.parentElement.querySelector(".field-status-label-inline");if(!e){const t=this.findFieldLabel();t&&(e=t.querySelector(".field-status-label-inline"))}return e||(e=this.createStatusContainer()),e}createStatusContainer(){const e=this.getFieldType();this.getPlacementStrategy(e);const t=document.createElement("div");return this.createLabelInlineContainer(t)}getFieldType(){const e=this.fieldElement.tagName.toLowerCase(),t=this.fieldElement.type?.toLowerCase(),s=this.fieldElement.className;return t==="checkbox"||s.includes("form-check-input")||s.includes("form-switch")?"toggle":e==="select"?"select":e==="textarea"?"textarea":"input"}getPlacementStrategy(e){return"label-inline"}createLabelInlineContainer(e){e.className="field-status-label-inline",e.innerHTML=this.getStatusHTML();const t=this.findFieldLabel();return t?t.appendChild(e):this.fieldElement.parentElement.appendChild(e),e}findFieldLabel(){if(this.fieldElement.id){const s=document.querySelector(`label[for="${this.fieldElement.id}"]`);if(s)return s}const e=this.fieldElement.parentElement.querySelector("label");if(e)return e;const t=this.fieldElement.closest("label");return t||null}createInputOverlayContainer(e){e.className="field-status-overlay",e.innerHTML=this.getStatusHTML();const t=this.fieldElement.parentElement;return getComputedStyle(t).position==="static"&&(t.style.position="relative"),t.appendChild(e),e}createFullOverlayContainer(e){e.className="field-status-full-overlay d-none",e.innerHTML=`
1297
+ `}r&&(r.style.display="none")}}findFieldConfig(e){const t=s=>{for(const i of s){if(i.name===e)return i;if(i.fields&&Array.isArray(i.fields)){const r=t(i.fields);if(r)return r}if(i.tabs&&Array.isArray(i.tabs)){for(const r of i.tabs)if(r.fields&&Array.isArray(r.fields)){const n=t(r.fields);if(n)return n}}}return null};return t(this.formConfig.fields||[])}async fileToBase64(e){return new Promise((t,s)=>{const i=new FileReader;i.onload=()=>t(i.result),i.onerror=s,i.readAsDataURL(e)})}hasFiles(e){if(e instanceof FormData){for(const[t,s]of e.entries())if(s instanceof File)return!0;return!1}else{for(const t of Object.values(e))if(t instanceof File||Array.isArray(t)&&t.some(s=>s instanceof File))return!0;return!1}}reset(){const e=this.getFormElement();e&&e.reset(),this.data={},this.errors={},this.clearAllErrors(),this.emit("reset",{form:this})}async updateConfig(e){this.formConfig={...this.formConfig,...e},this.formBuilder=new ge({...this.getFormConfig(),data:this.data,errors:this.errors}),await this.render()}async onBeforeDestroy(){const e=[];for(const t of this.customComponents.values())t.destroy&&e.push(t.destroy());await Promise.all(e),this.customComponents.clear(),Object.values(this.data).forEach(t=>{typeof t=="string"&&t.startsWith("blob:")&&URL.revokeObjectURL(t)}),await super.onBeforeDestroy()}initializePasswordFields(){if(!this.element)return;this.element.querySelectorAll('input[data-field-type="password"], input[type="password"]').forEach(t=>{this.updatePasswordStrengthUI(t);const s=r=>{this.updatePasswordStrengthUI(r.target)};t.addEventListener("input",s);const i=r=>{if(typeof r.getModifierState=="function"){const n=r.getModifierState("CapsLock");this.updateCapsLockWarning(t,!!n)}};t.addEventListener("keydown",i),t.addEventListener("keyup",i),this.updateCapsLockWarning(t,!1)})}async onActionTogglePassword(e,t){e.preventDefault();const s=t.getAttribute("data-target");let i=null;if(s&&(i=this.element.querySelector("#"+s)),!i){const a=t.closest(".input-group");a&&(i=a.querySelector('input[type="password"], input[data-field-type="password"], input[type="text"]'))}if(!i)return;const r=i.type==="password";i.type=r?"text":"password",t.setAttribute("aria-pressed",r?"true":"false"),t.setAttribute("aria-label",r?"Hide password":"Show password");const n=t.querySelector("i");n&&(n.classList.toggle("bi-eye",!r),n.classList.toggle("bi-eye-slash",r)),i.focus();try{const a=i.value?.length??0;i.setSelectionRange(a,a)}catch{}}async onActionCopyToClipboard(e,t){e.preventDefault();const s=t.getAttribute("data-target");if(!s)return;const i=this.element.querySelector("#"+s);if(i)try{await navigator.clipboard.writeText(i.value);const r=t.querySelector("i");if(r){const n=r.className;r.className="bi bi-check2",t.classList.add("btn-success"),t.classList.remove("btn-outline-secondary"),setTimeout(()=>{r.className=n,t.classList.remove("btn-success"),t.classList.add("btn-outline-secondary")},1500)}this.app&&this.app.toast&&this.app.toast.success("Copied to clipboard!")}catch(r){console.error("Failed to copy to clipboard:",r),this.app&&this.app.toast&&this.app.toast.error("Failed to copy to clipboard")}}computePasswordStrength(e=""){const t=e.length;let s=0;t>=6&&s++,t>=8&&s++,t>=12&&s++;const i=/[a-z]/.test(e),r=/[A-Z]/.test(e),n=/\d/.test(e),a=/[^A-Za-z0-9]/.test(e),o=[i,r,n,a].filter(Boolean).length;return o>=2&&s++,o>=3&&s++,s=Math.max(0,Math.min(4,s)),[{percent:0,label:"Too short",barClass:"bg-secondary"},{percent:25,label:"Weak",barClass:"bg-danger"},{percent:50,label:"Fair",barClass:"bg-warning"},{percent:75,label:"Good",barClass:"bg-info"},{percent:100,label:"Strong",barClass:"bg-success"}][s]}updatePasswordStrengthUI(e){if(!e||!e.id)return;const t=this.element.querySelector(`#${e.id}_strength_bar`),s=this.element.querySelector(`#${e.id}_strength_text`);if(!t&&!s)return;const{percent:i,label:r,barClass:n}=this.computePasswordStrength(e.value||"");t&&(t.className=`progress-bar ${n}`,t.style.width=`${i}%`,t.setAttribute("aria-valuenow",String(i))),s&&(s.textContent=r)}updateCapsLockWarning(e,t){if(!e||!e.id)return;const s=this.element.querySelector(`#${e.id}_caps_warning`);s&&(t?s.classList.remove("d-none"):s.classList.add("d-none"))}}class Cs{constructor(e){this.fieldElement=e,this.statusContainer=this.findOrCreateStatusContainer(),this.timeouts=new Map}findOrCreateStatusContainer(){let e=this.fieldElement.parentElement.querySelector(".field-status-label-inline");if(!e){const t=this.findFieldLabel();t&&(e=t.querySelector(".field-status-label-inline"))}return e||(e=this.createStatusContainer()),e}createStatusContainer(){const e=this.getFieldType();this.getPlacementStrategy(e);const t=document.createElement("div");return this.createLabelInlineContainer(t)}getFieldType(){const e=this.fieldElement.tagName.toLowerCase(),t=this.fieldElement.type?.toLowerCase(),s=this.fieldElement.className;return t==="checkbox"||s.includes("form-check-input")||s.includes("form-switch")?"toggle":e==="select"?"select":e==="textarea"?"textarea":"input"}getPlacementStrategy(e){return"label-inline"}createLabelInlineContainer(e){e.className="field-status-label-inline",e.innerHTML=this.getStatusHTML();const t=this.findFieldLabel();return t?t.appendChild(e):this.fieldElement.parentElement.appendChild(e),e}findFieldLabel(){if(this.fieldElement.id){const s=document.querySelector(`label[for="${this.fieldElement.id}"]`);if(s)return s}const e=this.fieldElement.parentElement.querySelector("label");if(e)return e;const t=this.fieldElement.closest("label");return t||null}createInputOverlayContainer(e){e.className="field-status-overlay",e.innerHTML=this.getStatusHTML();const t=this.fieldElement.parentElement;return getComputedStyle(t).position==="static"&&(t.style.position="relative"),t.appendChild(e),e}createFullOverlayContainer(e){e.className="field-status-full-overlay d-none",e.innerHTML=`
1298
1298
  <div class="saving-indicator">
1299
1299
  <div class="spinner-border spinner-border-sm text-primary" role="status">
1300
1300
  <span class="visually-hidden">Saving...</span>
@@ -1315,11 +1315,11 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1315
1315
  </div>
1316
1316
  <i class="bi bi-check-circle text-success d-none" data-status="saved"></i>
1317
1317
  <i class="bi bi-exclamation-circle text-danger d-none" data-status="error"></i>
1318
- `}showStatus(e,t={}){this.clearTimeout(e),this.showStandardStatus(e,t)}showStandardStatus(e,t={}){this.hideAllStatuses();const s=this.statusContainer.querySelector(`[data-status="${e}"]`);s&&(s.classList.remove("d-none"),s.classList.add("d-inline-block","show"),e==="saved"?this.setTimeout(e,()=>this.hideStatus(e),2500):e==="error"&&(t.message&&(s.title=t.message),this.setTimeout(e,()=>this.hideStatus(e),6e3)))}showFullOverlayStatus(e,t={}){this.statusContainer.querySelectorAll(".saving-indicator, .success-indicator, .error-indicator").forEach(r=>r.classList.add("d-none")),this.statusContainer.classList.remove("d-none");let i;switch(e){case"saving":i=".saving-indicator";break;case"saved":i=".success-indicator",this.setTimeout(e,()=>this.hideStatus(e),2500);break;case"error":if(i=".error-indicator",t.message){const r=this.statusContainer.querySelector(".error-indicator span");r&&(r.textContent=t.message)}this.setTimeout(e,()=>this.hideStatus(e),6e3);break}if(i){const r=this.statusContainer.querySelector(i);r&&r.classList.remove("d-none")}}hideStatus(e){const t=this.statusContainer.querySelector(`[data-status="${e}"]`);t&&(t.classList.remove("show"),t.classList.add("hide"),setTimeout(()=>{t.classList.add("d-none"),t.classList.remove("d-inline-block","hide"),t.title=""},300))}hideAllStatuses(){this.statusContainer.querySelectorAll("[data-status]").forEach(t=>{t.classList.add("d-none"),t.classList.remove("d-inline-block","show","hide"),t.title=""})}setTimeout(e,t,s){const i=setTimeout(t,s);this.timeouts.set(e,i)}clearTimeout(e){this.timeouts.has(e)&&(clearTimeout(this.timeouts.get(e)),this.timeouts.delete(e))}destroy(){this.timeouts.forEach(e=>clearTimeout(e)),this.timeouts.clear()}}es(te);const It=Object.freeze(Object.defineProperty({__proto__:null,FormView:te,default:te},Symbol.toStringTag,{value:"Module"}));class _s extends pe{constructor(e={}){super({title:"Form Page",description:"A page for submitting forms",icon:"form",fields:[],template:'<div data-container="form-view-container"></div>',className:"form-page container-sm",...e})}async onInit(){await super.onInit(),await this.recreateFormView()}async onEnter(){await super.onEnter(),this.formView&&await this.recreateFormView()}async onGroupChange(e){this.formView&&await this.recreateFormView()}async getModel(){return this.model?this.model:this.getApp().activeGroup?this.getApp().activeGroup:null}async recreateFormView(){this.formView&&(await this.formView.destroy(),this.removeChild(this.formView)),this.formView=new te({containerId:"form-view-container",fields:this.options.fields,autosaveModelField:!0}),this.addChild(this.formView);const e=await this.getModel();e&&this.formView.setModel(e)}}x.showDialog=(...c)=>v.dialog(...c),x.alert=(...c)=>v.alert(...c),x.confirm=(...c)=>v.confirm(...c),x.prompt=(...c)=>v.prompt(...c),x.showError=(...c)=>v.showError(...c),x.showForm=(...c)=>v.form(...c),x.showModelForm=(...c)=>v.modelForm(...c),x.showData=(...c)=>v.data(...c),x.showModelView=(...c)=>v.showModelView(...c),x.updateModelImage=(...c)=>v.updateModelImage(...c),x.showCode=(...c)=>v.code(...c),x.showHtmlPreview=(...c)=>v.htmlPreview(...c),x.formatCode=(...c)=>me.formatCode(...c),x.highlightCodeBlocks=(...c)=>me.highlightCodeBlocks(...c),x.showBusy=(...c)=>v.showBusy(...c),x.hideBusy=(...c)=>v.hideBusy(...c),x.showConfirm=x.confirm;class xs extends S{constructor(e={}){const{options:t=[],value:s,size:i="sm",ariaLabel:r="Segment control",...n}=e;super({tagName:"div",className:"segment-control",...n}),this.items=t,this.value=s!==void 0?s:t[0]&&t[0].value,this.size=i==="md"?"":"sm",this.ariaLabel=r,this.template=()=>this._buildTemplate()}_buildTemplate(){const e=this.size?`btn-group-${this.size}`:"",t=this.items.map(s=>{const i=s.value===this.value,r=i?"btn btn-primary":"btn btn-outline-secondary",n=s.icon?`<i class="bi ${this.escapeHtml(s.icon)} me-1"></i>`:"";return`<button type="button"
1318
+ `}showStatus(e,t={}){this.clearTimeout(e),this.showStandardStatus(e,t)}showStandardStatus(e,t={}){this.hideAllStatuses();const s=this.statusContainer.querySelector(`[data-status="${e}"]`);s&&(s.classList.remove("d-none"),s.classList.add("d-inline-block","show"),e==="saved"?this.setTimeout(e,()=>this.hideStatus(e),2500):e==="error"&&(t.message&&(s.title=t.message),this.setTimeout(e,()=>this.hideStatus(e),6e3)))}showFullOverlayStatus(e,t={}){this.statusContainer.querySelectorAll(".saving-indicator, .success-indicator, .error-indicator").forEach(r=>r.classList.add("d-none")),this.statusContainer.classList.remove("d-none");let i;switch(e){case"saving":i=".saving-indicator";break;case"saved":i=".success-indicator",this.setTimeout(e,()=>this.hideStatus(e),2500);break;case"error":if(i=".error-indicator",t.message){const r=this.statusContainer.querySelector(".error-indicator span");r&&(r.textContent=t.message)}this.setTimeout(e,()=>this.hideStatus(e),6e3);break}if(i){const r=this.statusContainer.querySelector(i);r&&r.classList.remove("d-none")}}hideStatus(e){const t=this.statusContainer.querySelector(`[data-status="${e}"]`);t&&(t.classList.remove("show"),t.classList.add("hide"),setTimeout(()=>{t.classList.add("d-none"),t.classList.remove("d-inline-block","hide"),t.title=""},300))}hideAllStatuses(){this.statusContainer.querySelectorAll("[data-status]").forEach(t=>{t.classList.add("d-none"),t.classList.remove("d-inline-block","show","hide"),t.title=""})}setTimeout(e,t,s){const i=setTimeout(t,s);this.timeouts.set(e,i)}clearTimeout(e){this.timeouts.has(e)&&(clearTimeout(this.timeouts.get(e)),this.timeouts.delete(e))}destroy(){this.timeouts.forEach(e=>clearTimeout(e)),this.timeouts.clear()}}es(te);const It=Object.freeze(Object.defineProperty({__proto__:null,FormView:te,default:te},Symbol.toStringTag,{value:"Module"}));class Ss extends fe{constructor(e={}){super({title:"Form Page",description:"A page for submitting forms",icon:"form",fields:[],template:'<div data-container="form-view-container"></div>',className:"form-page container-sm",...e})}async onInit(){await super.onInit(),await this.recreateFormView()}async onEnter(){await super.onEnter(),this.formView&&await this.recreateFormView()}async onGroupChange(e){this.formView&&await this.recreateFormView()}async getModel(){return this.model?this.model:this.getApp().activeGroup?this.getApp().activeGroup:null}async recreateFormView(){this.formView&&(await this.formView.destroy(),this.removeChild(this.formView)),this.formView=new te({containerId:"form-view-container",fields:this.options.fields,autosaveModelField:!0}),this.addChild(this.formView);const e=await this.getModel();e&&this.formView.setModel(e)}}x.showDialog=(...c)=>v.dialog(...c),x.alert=(...c)=>v.alert(...c),x.confirm=(...c)=>v.confirm(...c),x.prompt=(...c)=>v.prompt(...c),x.showError=(...c)=>v.showError(...c),x.showForm=(...c)=>v.form(...c),x.showModelForm=(...c)=>v.modelForm(...c),x.showData=(...c)=>v.data(...c),x.showModelView=(...c)=>v.showModelView(...c),x.updateModelImage=(...c)=>v.updateModelImage(...c),x.showCode=(...c)=>v.code(...c),x.showHtmlPreview=(...c)=>v.htmlPreview(...c),x.formatCode=(...c)=>pe.formatCode(...c),x.highlightCodeBlocks=(...c)=>pe.highlightCodeBlocks(...c),x.showBusy=(...c)=>v.showBusy(...c),x.hideBusy=(...c)=>v.hideBusy(...c),x.showConfirm=x.confirm;class xs extends C{constructor(e={}){const{options:t=[],value:s,size:i="sm",ariaLabel:r="Segment control",...n}=e;super({tagName:"div",className:"segment-control",...n}),this.items=t,this.value=s!==void 0?s:t[0]&&t[0].value,this.size=i==="md"?"":"sm",this.ariaLabel=r,this.template=()=>this._buildTemplate()}_buildTemplate(){const e=this.size?`btn-group-${this.size}`:"",t=this.items.map(s=>{const i=s.value===this.value,r=i?"btn btn-primary":"btn btn-outline-secondary",n=s.icon?`<i class="bi ${this.escapeHtml(s.icon)} me-1"></i>`:"";return`<button type="button"
1319
1319
  class="${r}"
1320
1320
  data-action="select"
1321
1321
  data-value="${this.escapeHtml(String(s.value))}"
1322
- ${i?'aria-pressed="true"':'aria-pressed="false"'}>${n}${this.escapeHtml(s.label)}</button>`}).join("");return`<div class="btn-group ${e}" role="group" aria-label="${this.escapeHtml(this.ariaLabel)}">${t}</div>`}async onActionSelect(e,t){const s=t.dataset.value;if(s===this.value)return;const i=this.value;this.value=s,this._paintActive(),this.emit("change",{value:s,previous:i})}_paintActive(){this.element&&this.element.querySelectorAll("button[data-value]").forEach(e=>{const t=e.dataset.value===String(this.value);e.classList.toggle("btn-primary",t),e.classList.toggle("btn-outline-secondary",!t),e.setAttribute("aria-pressed",t?"true":"false")})}setValue(e,{silent:t=!1}={}){const s=this.items.find(r=>String(r.value)===String(e));if(!s)return!1;const i=this.value;return s.value===i||(this.value=s.value,this._paintActive(),t||this.emit("change",{value:this.value,previous:i})),!0}getValue(){return this.value}}const kt={exact:{display:"is",description:"Exact match"},in:{display:"in",description:"Match any of the values (comma-separated)"},not:{display:"is not",description:"Does not match"},not_in:{display:"not in",description:"Does not match any of the values"},gt:{display:">",description:"Greater than"},gte:{display:">=",description:"Greater than or equal to"},lt:{display:"<",description:"Less than"},lte:{display:"<=",description:"Less than or equal to"},contains:{display:"contains",description:"Contains substring (case-sensitive)"},icontains:{display:"contains",description:"Contains substring (case-insensitive)"},startswith:{display:"starts with",description:"Starts with substring (case-sensitive)"},istartswith:{display:"starts with",description:"Starts with substring (case-insensitive)"},endswith:{display:"ends with",description:"Ends with substring (case-sensitive)"},iendswith:{display:"ends with",description:"Ends with substring (case-insensitive)"},isnull:{display:c=>c==="true"||c===!0?"is null":"is not null",description:"Check if value is null or not"},range:{display:"between",description:"Between two values (comma-separated)"}};function ge(c){if(!c||typeof c!="string")return{field:c,lookup:null};const e=c.split("__");if(e.length===1)return{field:c,lookup:null};const t=e[e.length-1];return kt[t]?{field:e.slice(0,-1).join("__"),lookup:t}:{field:c,lookup:null}}function $s(c,e,t){if(!c||e===null||e===void 0)return"";const{field:s,lookup:i}=ge(c),r=kt[i];if(e&&typeof e=="object"&&!Array.isArray(e)){const a=e.start!==void 0&&e.start!==null&&e.start!=="",o=e.end!==void 0&&e.end!==null&&e.end!=="";return a||o?a&&o?`${t} between '${e.start}' and '${e.end}'`:a?`${t} from '${e.start}'`:`${t} until '${e.end}'`:`${t} is '${JSON.stringify(e)}'`}const n=Array.isArray(e)?e.join(","):String(e);if(!i||i==="exact")return`${t} is '${n}'`;if(i==="in"||i==="not_in"){const a=n.split(",").map(l=>l.trim()).filter(l=>l);if(a.length===0)return`${t} ${r.display}`;const o=a.map(l=>`'${l}'`).join(", ");return`${t} ${r.display} ${o}`}if(i==="range"){const a=n.split(",").map(o=>o.trim()).filter(o=>o);return a.length===2?`${t} between '${a[0]}' and '${a[1]}'`:`${t} ${r.display} '${n}'`}if(i==="isnull"){const a=typeof r.display=="function"?r.display(n):r.display;return`${t} ${a}`}return r?`${t} ${r.display} '${n}'`:`${t} is '${n}'`}class Ae extends S{constructor(e={}){super({className:"list-view-item",...e}),this.selected=!1,this.index=e.index??0,this.listView=e.listView??null,this.clickable=e.clickable===!0,this.clickable&&this.element&&this.addClass("clickable"),this.template||(this.template=`
1322
+ ${i?'aria-pressed="true"':'aria-pressed="false"'}>${n}${this.escapeHtml(s.label)}</button>`}).join("");return`<div class="btn-group ${e}" role="group" aria-label="${this.escapeHtml(this.ariaLabel)}">${t}</div>`}async onActionSelect(e,t){const s=t.dataset.value;if(s===this.value)return;const i=this.value;this.value=s,this._paintActive(),this.emit("change",{value:s,previous:i})}_paintActive(){this.element&&this.element.querySelectorAll("button[data-value]").forEach(e=>{const t=e.dataset.value===String(this.value);e.classList.toggle("btn-primary",t),e.classList.toggle("btn-outline-secondary",!t),e.setAttribute("aria-pressed",t?"true":"false")})}setValue(e,{silent:t=!1}={}){const s=this.items.find(r=>String(r.value)===String(e));if(!s)return!1;const i=this.value;return s.value===i||(this.value=s.value,this._paintActive(),t||this.emit("change",{value:this.value,previous:i})),!0}getValue(){return this.value}}const Mt={exact:{display:"is",description:"Exact match"},in:{display:"in",description:"Match any of the values (comma-separated)"},not:{display:"is not",description:"Does not match"},not_in:{display:"not in",description:"Does not match any of the values"},gt:{display:">",description:"Greater than"},gte:{display:">=",description:"Greater than or equal to"},lt:{display:"<",description:"Less than"},lte:{display:"<=",description:"Less than or equal to"},contains:{display:"contains",description:"Contains substring (case-sensitive)"},icontains:{display:"contains",description:"Contains substring (case-insensitive)"},startswith:{display:"starts with",description:"Starts with substring (case-sensitive)"},istartswith:{display:"starts with",description:"Starts with substring (case-insensitive)"},endswith:{display:"ends with",description:"Ends with substring (case-sensitive)"},iendswith:{display:"ends with",description:"Ends with substring (case-insensitive)"},isnull:{display:c=>c==="true"||c===!0?"is null":"is not null",description:"Check if value is null or not"},range:{display:"between",description:"Between two values (comma-separated)"}};function ue(c){if(!c||typeof c!="string")return{field:c,lookup:null};const e=c.split("__");if(e.length===1)return{field:c,lookup:null};const t=e[e.length-1];return Mt[t]?{field:e.slice(0,-1).join("__"),lookup:t}:{field:c,lookup:null}}function $s(c,e,t){if(!c||e===null||e===void 0)return"";const{field:s,lookup:i}=ue(c),r=Mt[i];if(e&&typeof e=="object"&&!Array.isArray(e)){const a=e.start!==void 0&&e.start!==null&&e.start!=="",o=e.end!==void 0&&e.end!==null&&e.end!=="";return a||o?a&&o?`${t} between '${e.start}' and '${e.end}'`:a?`${t} from '${e.start}'`:`${t} until '${e.end}'`:`${t} is '${JSON.stringify(e)}'`}const n=Array.isArray(e)?e.join(","):String(e);if(!i||i==="exact")return`${t} is '${n}'`;if(i==="in"||i==="not_in"){const a=n.split(",").map(l=>l.trim()).filter(l=>l);if(a.length===0)return`${t} ${r.display}`;const o=a.map(l=>`'${l}'`).join(", ");return`${t} ${r.display} ${o}`}if(i==="range"){const a=n.split(",").map(o=>o.trim()).filter(o=>o);return a.length===2?`${t} between '${a[0]}' and '${a[1]}'`:`${t} ${r.display} '${n}'`}if(i==="isnull"){const a=typeof r.display=="function"?r.display(n):r.display;return`${t} ${a}`}return r?`${t} ${r.display} '${n}'`:`${t} is '${n}'`}class Ae extends C{constructor(e={}){super({className:"list-view-item",...e}),this.selected=!1,this.index=e.index??0,this.listView=e.listView??null,this.clickable=e.clickable===!0,this.clickable&&this.element&&this.addClass("clickable"),this.template||(this.template=`
1323
1323
  <div class="list-item-content" data-action="select">
1324
1324
  {{#model}}
1325
1325
  {{#id}}<span class="item-id">{{id}}</span>{{/id}}
@@ -1332,21 +1332,22 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1332
1332
  <span class="item-empty">No data</span>
1333
1333
  {{/model}}
1334
1334
  </div>
1335
- `)}async onActionSelect(e,t){e.stopPropagation(),this.selected?this.deselect():this.select()}async onActionView(e,t){e.stopPropagation(),this._emitRowEvent("row:view",e)}async onActionEdit(e,t){e.stopPropagation(),this._emitRowEvent("row:edit",e)}async onActionDelete(e,t){e.stopPropagation(),this._emitRowEvent("row:delete",e)}_emitRowEvent(e,t){const s={item:this,model:this.model,index:this.index,event:t,data:this.model?.toJSON?this.model.toJSON():this.model};this.emit(e,s),this.listView&&this.listView.emit(e,s)}select(){this.selected||(this.selected=!0,this.addClass("selected"),this.emit("item:select",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:select",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}))}deselect(){this.selected&&(this.selected=!1,this.removeClass("selected"),this.emit("item:deselect",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:deselect",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}))}async onAfterRender(){await super.onAfterRender(),this.clickable&&this.element&&(this.addClass("clickable"),this._wireClickableHandler()),this.listView?.rowStripe&&typeof this.listView._applyRowStripe=="function"&&this.listView._applyRowStripe(this)}_wireClickableHandler(){this._clickableHandler||!this.element||(this._clickableHandler=e=>{if(e.target?.closest?.("[data-action]"))return;const t=e.target?.tagName;t==="INPUT"||t==="TEXTAREA"||t==="SELECT"||(this.emit("item:click",{item:this,model:this.model,index:this.index,action:"row-click",event:e,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,action:"row-click",event:e,data:this.model?.toJSON?this.model.toJSON():this.model}))},this.element.addEventListener("click",this._clickableHandler))}async onActionDefault(e,t,s){this.emit("item:click",{item:this,model:this.model,index:this.index,action:e,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,action:e,data:this.model?.toJSON?this.model.toJSON():this.model})}setIndex(e){return this.index=e,this.element.setAttribute("data-index",e),this}setSelected(e){return e?this.select():this.deselect(),this}async destroy(){this._clickableHandler&&this.element&&(this.element.removeEventListener("click",this._clickableHandler),this._clickableHandler=null),this.listView=null,await super.destroy()}}class As extends S{constructor(e={}){super({tagName:e.tagName||"div",className:e.className||"list-group-header",...e}),this.key=e.key??"",this.index=e.index??0,this.colspan=e.colspan??1,this.template||(this.template="{{key}}")}}class se extends S{static GROUP_HEADER_STYLES=["banner","mark","band","rule"];static ROW_STRIPE_TOKENS=["danger","warning","success","info","primary","secondary"];static _warnedMinifiedClasses=new WeakSet;constructor(e={}){super({className:e.className||"list-view",...e}),this.collection=null,this.itemViews=new Map,this.selectedItems=new Set,this.itemTemplate=e.itemTemplate||null,this.itemClass=e.itemClass||Ae,this.selectionMode=e.selectionMode||"none",this.emptyMessage=e.emptyMessage||"No items to display",this.loading=!1,this.isEmpty=!0,this.searchable=e.searchable===!0,this.filterable=e.filterable===!0,this.paginated=e.paginated===!0;let t=e.paginationMode;t||(t=this.paginated?"more":"none"),this.paginationMode=t,this.searchPlacement=e.searchPlacement||"toolbar",this.searchPlaceholder=e.searchPlaceholder||"Search...",this.sortOptions=Array.isArray(e.sortOptions)?e.sortOptions:[],this.filters={},this.additionalFilters=e.filters||[],this.hideActivePills=e.hideActivePills===!0,this.hideActivePillNames=e.hideActivePillNames||[],this.title=e.title||null,this.eyebrow=e.eyebrow||null,this.showRefresh=e.showRefresh!==!1,this.toolbarButtons=e.toolbarButtons||[],this.toolbarRight=e.toolbarRight||null,this._toolbarRightMounted=!1,this.dayRangeFilter=this._normalizeDayRangeFilter(e.dayRangeFilter),this.dayRangeControl=null,this.exportOptions=e.exportOptions||null,this.exportSource=e.exportSource||"remote",this.persistSelection=e.persistSelection===void 0?this.paginationMode==="more":e.persistSelection===!0,this.onItemClick=typeof e.onItemClick=="function"?e.onItemClick:null,this.clickAction=e.clickAction||"none",this.itemView=e.itemView,this.addForm=e.addForm,this.editForm=e.editForm,this.deleteTemplate=e.deleteTemplate,this.formDialogConfig=e.formDialogConfig||{},this.viewDialogOptions=e.viewDialogOptions||{},this.fetchOnView=e.fetchOnView!==!1,this.clickable=e.clickable===!0||!!this.onItemClick||this.clickAction&&this.clickAction!=="none",this.rowStripe=typeof e.rowStripe=="function"?e.rowStripe:null,this.groupBy=typeof e.groupBy=="function"||typeof e.groupBy=="string"?e.groupBy:null,this.groupHeaderTemplate=e.groupHeaderTemplate||null,this.groupHeaderLabel=typeof e.groupHeaderLabel=="function"?e.groupHeaderLabel:null,this.groupHeaderClass=e.groupHeaderClass||As,this.groupHeaderStyle=se.GROUP_HEADER_STYLES.includes(e.groupHeaderStyle)?e.groupHeaderStyle:"banner",this.groupHeaderViews=new Map,this._renderOrder=[],this.loadingMore=!1,this._isToolbarEnabled()||this.paginationMode!=="none"?this.template=this.buildListTemplate():this.template||(this.template=this._defaultBareTemplate())}async onInit(){this._initCollection(this.options.collection||this.options.Collection),this.dayRangeFilter&&(this._seedDayRangeParams(),this.dayRangeControl=new xs({containerId:"toolbar-day-range",options:this.dayRangeFilter.options,value:this.dayRangeFilter.value,ariaLabel:this.dayRangeFilter.ariaLabel}),this.dayRangeControl.on("change",this._onDayRangeChange,this),this.addChild(this.dayRangeControl))}async onAfterMount(){await super.onAfterMount(),this.collection&&(this.options.fetchOnMount||!this.collection.lastFetchTime)&&this.collection.fetch()}async onBeforeRender(){this.searchValue=this.getActiveFilters().search||"",this.hasMore=this._computeHasMore()}async onAfterRender(){if(await super.onAfterRender(),this.toolbarRight&&!this._toolbarRightMounted&&(this.toolbarRight.containerId="toolbar-right",this.addChild(this.toolbarRight),await this.toolbarRight.render(),this._toolbarRightMounted=!0),this._toolbarRightMounted&&this.toolbarRight&&!this.element?.contains(this.toolbarRight.element)&&(this._toolbarRightMounted=!1),this.paginated&&this.paginationMode==="pages"&&this.collection){const e=this.collection.meta?.count||this.collection.length(),t=this.collection.params?.start||0,s=this.collection.params?.size||10,i=Math.min(t+s,e),r=this.element.querySelector('[data-value="start"]'),n=this.element.querySelector('[data-value="end"]'),a=this.element.querySelector('[data-value="total"]');r&&(r.textContent=e===0?0:t+1),n&&(n.textContent=i),a&&(a.textContent=e);const o=this.element.querySelector('[data-change-action="page-size"]');o&&(o.value=s),this.renderPagination()}this._isToolbarEnabled()&&(this.updateFilterPills(),this.setupSearchClearListener())}_defaultBareTemplate(){return`
1335
+ `)}async onActionSelect(e,t){e.stopPropagation(),this.selected?this.deselect():this.select()}async onActionView(e,t){e.stopPropagation(),this._emitRowEvent("row:view",e)}async onActionEdit(e,t){e.stopPropagation(),this._emitRowEvent("row:edit",e)}async onActionDelete(e,t){e.stopPropagation(),this._emitRowEvent("row:delete",e)}_emitRowEvent(e,t){const s={item:this,model:this.model,index:this.index,event:t,data:this.model?.toJSON?this.model.toJSON():this.model};this.emit(e,s),this.listView&&this.listView.emit(e,s)}select(){this.selected||(this.selected=!0,this.addClass("selected"),this.emit("item:select",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:select",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}))}deselect(){this.selected&&(this.selected=!1,this.removeClass("selected"),this.emit("item:deselect",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:deselect",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}))}async onAfterRender(){await super.onAfterRender(),this.clickable&&this.element&&(this.addClass("clickable"),this._wireClickableHandler()),this.listView?.rowStripe&&typeof this.listView._applyRowStripe=="function"&&this.listView._applyRowStripe(this)}_wireClickableHandler(){this._clickableHandler||!this.element||(this._clickableHandler=e=>{if(e.target?.closest?.("[data-action]"))return;const t=e.target?.tagName;t==="INPUT"||t==="TEXTAREA"||t==="SELECT"||(this.emit("item:click",{item:this,model:this.model,index:this.index,action:"row-click",event:e,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,action:"row-click",event:e,data:this.model?.toJSON?this.model.toJSON():this.model}))},this.element.addEventListener("click",this._clickableHandler))}async onActionDefault(e,t,s){this.emit("item:click",{item:this,model:this.model,index:this.index,action:e,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,action:e,data:this.model?.toJSON?this.model.toJSON():this.model})}setIndex(e){return this.index=e,this.element.setAttribute("data-index",e),this}setSelected(e){return e?this.select():this.deselect(),this}async destroy(){this._clickableHandler&&this.element&&(this.element.removeEventListener("click",this._clickableHandler),this._clickableHandler=null),this.listView=null,await super.destroy()}}class As extends C{constructor(e={}){super({tagName:e.tagName||"div",className:e.className||"list-group-header",...e}),this.key=e.key??"",this.index=e.index??0,this.colspan=e.colspan??1,this.template||(this.template="{{key}}")}}class se extends C{static GROUP_HEADER_STYLES=["banner","mark","band","rule"];static ROW_STRIPE_TOKENS=["danger","warning","success","info","primary","secondary"];static _warnedMinifiedClasses=new WeakSet;constructor(e={}){super({className:e.className||"list-view",...e}),this.collection=null,this.itemViews=new Map,this.selectedItems=new Set,this.itemTemplate=e.itemTemplate||null,this.itemClass=e.itemClass||Ae,this.selectionMode=e.selectionMode||"none",this.emptyMessage=e.emptyMessage||"No items to display",this.loading=!1,this.isEmpty=!0,this.searchable=e.searchable===!0,this.filterable=e.filterable===!0,this.paginated=e.paginated===!0;let t=e.paginationMode;t||(t=this.paginated?"more":"none"),this.paginationMode=t,this.searchPlacement=e.searchPlacement||"toolbar",this.searchPlaceholder=e.searchPlaceholder||"Search...",this.sortOptions=Array.isArray(e.sortOptions)?e.sortOptions:[],this.filters={},this.additionalFilters=e.filters||[],this.hideActivePills=e.hideActivePills===!0,this.hideActivePillNames=e.hideActivePillNames||[],this.title=e.title||null,this.eyebrow=e.eyebrow||null,this.showRefresh=e.showRefresh!==!1,this.toolbarButtons=e.toolbarButtons||[],this.toolbarRight=e.toolbarRight||null,this._toolbarRightMounted=!1,this.dayRangeFilter=this._normalizeDayRangeFilter(e.dayRangeFilter),this.dayRangeControl=null,this.filterPresets=this._normalizeFilterPresets(e.filterPresets),this.exportOptions=e.exportOptions||null,this.exportSource=e.exportSource||"remote",this.persistSelection=e.persistSelection===void 0?this.paginationMode==="more":e.persistSelection===!0,this.onItemClick=typeof e.onItemClick=="function"?e.onItemClick:null,this.clickAction=e.clickAction||"none",this.itemView=e.itemView,this.addForm=e.addForm,this.editForm=e.editForm,this.deleteTemplate=e.deleteTemplate,this.formDialogConfig=e.formDialogConfig||{},this.viewDialogOptions=e.viewDialogOptions||{},this.fetchOnView=e.fetchOnView!==!1,this.clickable=e.clickable===!0||!!this.onItemClick||this.clickAction&&this.clickAction!=="none",this.rowStripe=typeof e.rowStripe=="function"?e.rowStripe:null,this.groupBy=typeof e.groupBy=="function"||typeof e.groupBy=="string"?e.groupBy:null,this.groupHeaderTemplate=e.groupHeaderTemplate||null,this.groupHeaderLabel=typeof e.groupHeaderLabel=="function"?e.groupHeaderLabel:null,this.groupHeaderClass=e.groupHeaderClass||As,this.groupHeaderStyle=se.GROUP_HEADER_STYLES.includes(e.groupHeaderStyle)?e.groupHeaderStyle:"banner",this.groupHeaderViews=new Map,this._renderOrder=[],this.emptyState=this._normalizeEmptyState(e.emptyState),this.loadingStyle=e.loadingStyle==="spinner"||e.loadingStyle==="default"?"spinner":"skeleton",this.showResultCount=e.showResultCount===!0,this._autoRefreshMs=this._normalizeAutoRefresh(e.autoRefresh),this._autoRefreshTimer=null,this._autoRefreshPaused=!1,this._autoRefreshHandlers=null,this.autoRefreshIndicator=e.autoRefreshIndicator!==!1,this._autoRefreshPulseTimer=null,this.persistState=e.persistState===!0,this.persistKey=e.persistKey||null,this.loadingMore=!1,this._isToolbarEnabled()||this.paginationMode!=="none"?this.template=this.buildListTemplate():this.template||(this.template=this._defaultBareTemplate())}async onInit(){const e=this.persistState&&this.options.collection&&this.options.collection.params?Object.keys(this.options.collection.params):[];this._initCollection(this.options.collection||this.options.Collection),this.persistState&&(this._restorePersistedState(e),this.on("params-changed",()=>this._savePersistedState())),this.dayRangeFilter&&(this._seedDayRangeParams(),this.dayRangeControl=new xs({containerId:"toolbar-day-range",options:this.dayRangeFilter.options,value:this.dayRangeFilter.value,ariaLabel:this.dayRangeFilter.ariaLabel}),this.dayRangeControl.on("change",this._onDayRangeChange,this),this.addChild(this.dayRangeControl))}async onAfterMount(){await super.onAfterMount(),this.collection&&(this.options.fetchOnMount||!this.collection.lastFetchTime)&&this.collection.fetch(),this._startAutoRefresh()}async onBeforeUnmount(){await super.onBeforeUnmount(),this._stopAutoRefresh()}async onBeforeRender(){this.searchValue=this.getActiveFilters().search||"",this.hasMore=this._computeHasMore(),this.skeletonHtml=this.loadingStyle==="skeleton"&&this.loading?this._buildSkeletonHtml():"",this.emptyStateHtml=this.emptyState&&this.isEmpty&&!this.loading?this._buildEmptyStateHtml():""}async onAfterRender(){if(await super.onAfterRender(),this.toolbarRight&&!this._toolbarRightMounted&&(this.toolbarRight.containerId="toolbar-right",this.addChild(this.toolbarRight),await this.toolbarRight.render(),this._toolbarRightMounted=!0),this._toolbarRightMounted&&this.toolbarRight&&!this.element?.contains(this.toolbarRight.element)&&(this._toolbarRightMounted=!1),this.paginated&&this.paginationMode==="pages"&&this.collection){const e=this.collection.meta?.count||this.collection.length(),t=this.collection.params?.start||0,s=this.collection.params?.size||10,i=Math.min(t+s,e),r=this.element.querySelector('[data-value="start"]'),n=this.element.querySelector('[data-value="end"]'),a=this.element.querySelector('[data-value="total"]');r&&(r.textContent=e===0?0:t+1),n&&(n.textContent=i),a&&(a.textContent=e);const o=this.element.querySelector('[data-change-action="page-size"]');o&&(o.value=s),this.renderPagination()}this._isToolbarEnabled()&&(this.updateFilterPills(),this.renderFilterPresets(),this.setupSearchClearListener())}_defaultBareTemplate(){return`
1336
+ ${this._hasFeedbackFeature()?this._buildFeedbackStyles():""}
1336
1337
  <div class="list-view-container">
1337
1338
  {{#loading}}
1338
- <div class="list-loading">
1339
+ ${this._loadingContent(`<div class="list-loading">
1339
1340
  <div class="spinner-border spinner-border-sm" role="status">
1340
1341
  <span class="visually-hidden">Loading...</span>
1341
1342
  </div>
1342
1343
  Loading...
1343
- </div>
1344
+ </div>`)}
1344
1345
  {{/loading}}
1345
1346
  {{^loading}}
1346
1347
  {{#isEmpty}}
1347
- <div class="list-empty">
1348
+ ${this._emptyContent(`<div class="list-empty">
1348
1349
  {{emptyMessage}}
1349
- </div>
1350
+ </div>`)}
1350
1351
  {{/isEmpty}}
1351
1352
  {{^isEmpty}}
1352
1353
  <div class="list-items" data-container="items"></div>
@@ -1355,21 +1356,22 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1355
1356
  </div>
1356
1357
  `}buildListTemplate(){const e=this.buildToolbarTemplate(),t=this.paginationMode==="more"?this.buildShowMoreTemplate():"",s=this.paginationMode==="pages"?this.buildPaginationTemplate():"";return`
1357
1358
  <div class="list-view-wrapper">
1359
+ ${this._hasFeedbackFeature()?this._buildFeedbackStyles():""}
1358
1360
  ${e}
1359
1361
  <div class="list-view-container">
1360
1362
  {{#loading}}
1361
- <div class="list-loading text-center py-4">
1363
+ ${this._loadingContent(`<div class="list-loading text-center py-4">
1362
1364
  <div class="spinner-border spinner-border-sm" role="status">
1363
1365
  <span class="visually-hidden">Loading...</span>
1364
1366
  </div>
1365
1367
  Loading...
1366
- </div>
1368
+ </div>`)}
1367
1369
  {{/loading}}
1368
1370
  {{^loading}}
1369
1371
  {{#isEmpty}}
1370
- <div class="list-empty text-center py-4 text-muted">
1372
+ ${this._emptyContent(`<div class="list-empty text-center py-4 text-muted">
1371
1373
  {{emptyMessage}}
1372
- </div>
1374
+ </div>`)}
1373
1375
  {{/isEmpty}}
1374
1376
  {{^isEmpty}}
1375
1377
  <div class="list-items" data-container="items"></div>
@@ -1379,21 +1381,26 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1379
1381
  ${t}
1380
1382
  ${s}
1381
1383
  </div>
1382
- `}_isToolbarEnabled(){return!!(this.title||this.eyebrow||this.searchable||this.filterable&&this._hasAnyFilters()||this.sortOptions&&this.sortOptions.length>0||this.toolbarRight||this.dayRangeFilter||this.toolbarButtons&&this.toolbarButtons.length>0||this.options.showAdd||this.options.showExport)}_hasAnyFilters(){return this.filters&&Object.keys(this.filters).length>0||this.additionalFilters&&this.additionalFilters.length>0}buildToolbarTemplate(){if(!this._isToolbarEnabled())return"";const e=this._buildTitleBlockTemplate(),t=this.toolbarRight?'<div data-container="toolbar-right"></div>':"",s=this.dayRangeFilter?'<div data-container="toolbar-day-range"></div>':"",i=this.sortOptions&&this.sortOptions.length>0?this.buildSortDropdownTemplate():"",r=`
1384
+ `}_isToolbarEnabled(){return!!(this.title||this.eyebrow||this.searchable||this.filterable&&this._hasAnyFilters()||this.sortOptions&&this.sortOptions.length>0||this.toolbarRight||this.dayRangeFilter||this.filterPresets&&this.filterPresets.length>0||this.toolbarButtons&&this.toolbarButtons.length>0||this._autoRefreshIndicatorEnabled()||this.options.showAdd||this.options.showExport)}_autoRefreshIndicatorEnabled(){return this._autoRefreshMs>0&&this.autoRefreshIndicator!==!1}_hasAnyFilters(){return this.filters&&Object.keys(this.filters).length>0||this.additionalFilters&&this.additionalFilters.length>0}buildToolbarTemplate(){if(!this._isToolbarEnabled())return"";const e=this._buildTitleBlockTemplate(),t=this.toolbarRight?'<div data-container="toolbar-right"></div>':"",s=this.dayRangeFilter?'<div data-container="toolbar-day-range"></div>':"",i=this.sortOptions&&this.sortOptions.length>0?this.buildSortDropdownTemplate():"",r=this.filterPresets&&this.filterPresets.length>0,n=r&&this._presetsInline(),a=n?'<div data-container="filter-presets" class="preset-segment-slot"></div>':"",o=r&&!n?'<div data-container="filter-presets" class="preset-scroll mt-3"></div>':"",l=r?this._buildPresetStyle():"",d=this._autoRefreshIndicatorEnabled(),h=d?this._buildAutoRefreshIndicatorSlot():"",u=d?this._buildAutoRefreshIndicatorStyle():"",m=`
1383
1385
  <div class="d-flex align-items-center gap-2 flex-wrap ${e?"ms-auto":""}">
1384
1386
  ${this.buildActionButtonsTemplate()}
1387
+ ${h}
1385
1388
  ${i}
1386
1389
  ${this.filterable?this.buildFilterDropdownTemplate():""}
1387
1390
  ${this.searchable&&this.searchPlacement==="toolbar"?this.buildSearchTemplate():""}
1391
+ ${a}
1388
1392
  ${s}
1389
1393
  ${t}
1390
1394
  </div>
1391
1395
  `;return`
1392
1396
  <div class="table-action-buttons mb-3">
1397
+ ${l}
1398
+ ${u}
1393
1399
  <div class="d-flex align-items-center gap-3 flex-wrap">
1394
1400
  ${e}
1395
- ${r}
1401
+ ${m}
1396
1402
  </div>
1403
+ ${o}
1397
1404
  <div data-container="filter-pills"></div>
1398
1405
  </div>
1399
1406
  `}_buildTitleBlockTemplate(){return!this.title&&!this.eyebrow?"":'<div class="rs-table-title-block">{{#eyebrow}}<div class="text-body-secondary text-uppercase small fw-semibold rs-table-eyebrow" style="letter-spacing: 0.05em; line-height: 1.2;">{{eyebrow}}</div>{{/eyebrow}}{{#title}}<h5 class="mb-0 rs-table-title">{{title}}</h5>{{/title}}</div>'}buildActionButtonsTemplate(){const e=[];if(this.showRefresh&&e.push(`
@@ -1434,9 +1441,9 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1434
1441
  <i class="bi bi-download me-1"></i>
1435
1442
  <span class="d-none d-lg-inline">Export</span>
1436
1443
  </button>
1437
- `)}}return this.toolbarButtons&&this.toolbarButtons.length>0&&this.toolbarButtons.forEach((t,s)=>{const{label:i="Button",icon:r="",action:n="",handler:a=null,variant:o="outline-secondary",title:l=i,className:d="",permissions:h=null}=t;if(h&&!this.checkPermissions(h))return;const u=this.escapeHtml(r),m=this.escapeHtml(i),p=this.escapeHtml(l),f=this.escapeHtml(o),g=this.escapeHtml(d),b=this.escapeHtml(n),y=r?`<i class="${u} me-1"></i>`:"",C=`<span class="d-none d-lg-inline">${m}</span>`;let _="";a?_=`data-action="custom-toolbar-button" data-button-index="${s}"`:n&&(_=`data-action="${b}"`);const A=`btn btn-sm btn-${f} ${g}`.trim();e.push(`
1438
- <button class="${A}" ${_} title="${p}">
1439
- ${y}${C}
1444
+ `)}}return this.toolbarButtons&&this.toolbarButtons.length>0&&this.toolbarButtons.forEach((t,s)=>{const{label:i="Button",icon:r="",action:n="",handler:a=null,variant:o="outline-secondary",title:l=i,className:d="",permissions:h=null}=t;if(h&&!this.checkPermissions(h))return;const u=this.escapeHtml(r),m=this.escapeHtml(i),p=this.escapeHtml(l),f=this.escapeHtml(o),g=this.escapeHtml(d),b=this.escapeHtml(n),y=r?`<i class="${u} me-1"></i>`:"",_=`<span class="d-none d-lg-inline">${m}</span>`;let S="";a?S=`data-action="custom-toolbar-button" data-button-index="${s}"`:n&&(S=`data-action="${b}"`);const A=`btn btn-sm btn-${f} ${g}`.trim();e.push(`
1445
+ <button class="${A}" ${S} title="${p}">
1446
+ ${y}${_}
1440
1447
  </button>
1441
1448
  `)}),e.join("")}buildSearchTemplate(){return`
1442
1449
  <div class="flex-grow-1" style="max-width: 400px;">
@@ -1509,26 +1516,26 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1509
1516
  <i class="bi bi-x-circle me-2"></i>Clear All Filters
1510
1517
  </button>
1511
1518
  `:""}
1512
- `}buildActivePills(){if(this.hideActivePills)return"";const e=this.getActiveFilters(),t=e.search&&e.search.toString().trim()!=="";let s=Object.entries(e).filter(([a,o])=>o&&o.toString().trim()!==""&&a!=="search");if(this.hideActivePillNames&&this.hideActivePillNames.length>0&&(s=s.filter(([a])=>!this.hideActivePillNames.includes(a))),s.length===0&&!t)return"";const i=s.map(([a,o])=>{const{field:l}=ge(a),d=this.getFilterLabel(l),h=this.escapeHtml($s(a,o,d)),u=this.escapeHtml(a);return`
1519
+ `}buildActivePills(){const e=this.showResultCount?this._buildResultCountSummary():"";if(this.hideActivePills)return e?this._wrapPillRow(e):"";const t=this.getActiveFilters(),s=t.search&&t.search.toString().trim()!=="";let i=Object.entries(t).filter(([o,l])=>l&&l.toString().trim()!==""&&o!=="search");if(this.hideActivePillNames&&this.hideActivePillNames.length>0&&(i=i.filter(([o])=>!this.hideActivePillNames.includes(o))),i.length===0&&!s)return e?this._wrapPillRow(e):"";const r=i.map(([o,l])=>{const{field:d}=ue(o),h=this.getFilterLabel(d),u=this.escapeHtml($s(o,l,h)),m=this.escapeHtml(o);return`
1513
1520
  <span class="badge bg-primary me-1 mb-1 py-1 px-2 position-relative" style="font-size: 0.75rem;">
1514
1521
  <i class="bi bi-filter me-1" style="font-size: 0.65rem;"></i>
1515
1522
 
1516
1523
  <button type="button" class="btn btn-link p-0 ms-1 list-filter-pill-text"
1517
1524
  style="font-size: 0.65rem; line-height: 1; text-decoration: none;"
1518
1525
  data-action="edit-filter"
1519
- data-filter="${u}"
1526
+ data-filter="${m}"
1520
1527
  title="Edit filter">
1521
- ${h}
1528
+ ${u}
1522
1529
  </button>
1523
1530
 
1524
1531
  <button type="button" class="btn-close ms-1"
1525
1532
  style="font-size: 0.6rem; width: 0.5rem; height: 0.5rem;"
1526
1533
  data-action="remove-filter"
1527
- data-filter="${u}"
1534
+ data-filter="${m}"
1528
1535
  title="Remove filter">
1529
1536
  </button>
1530
1537
  </span>
1531
- `}).join(""),n=s.length>1||s.length>0&&t||s.length===0&&t?`
1538
+ `}).join(""),a=i.length>1||i.length>0&&s||i.length===0&&s?`
1532
1539
  <button class="btn btn-sm btn-outline-secondary mb-1 py-0 px-2" style="font-size: 0.75rem;" data-action="clear-all-filters">
1533
1540
  <i class="bi bi-x-circle me-1" style="font-size: 0.7rem;"></i>
1534
1541
  <small>Clear All</small>
@@ -1537,8 +1544,16 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1537
1544
  <div class="row mt-2">
1538
1545
  <div class="col-12">
1539
1546
  <div class="d-flex flex-wrap align-items-center">
1540
- ${i}
1541
- ${n}
1547
+ ${e}${r}
1548
+ ${a}
1549
+ </div>
1550
+ </div>
1551
+ </div>
1552
+ `}_wrapPillRow(e){return`
1553
+ <div class="row mt-2">
1554
+ <div class="col-12">
1555
+ <div class="d-flex flex-wrap align-items-center">
1556
+ ${e}
1542
1557
  </div>
1543
1558
  </div>
1544
1559
  </div>
@@ -1581,7 +1596,132 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1581
1596
  </button>
1582
1597
  </div>
1583
1598
  {{/hasMore}}
1584
- `}_initCollection(e){if(!e){console.log("Collection not provided");return}if(e instanceof de)this.setCollection(e);else if(typeof e=="function"){const t=new e;this.setCollection(t)}else if(Array.isArray(e)){const t=new de(e);this.setCollection(t)}}_normalizeDayRangeFilter(e){if(!e)return null;const t={field:"created",value:"7d",options:[{value:"1d",label:"1d"},{value:"7d",label:"7d"},{value:"30d",label:"30d"},{value:"90d",label:"90d"}],ariaLabel:"Time range"};return e===!0?t:{...t,...e}}_dayRangeDays(e){const t=/^(\d+)d$/.exec(String(e||""));return t?parseInt(t[1],10):null}_seedDayRangeParams(){if(!this.dayRangeFilter||!this.collection)return;const e=this._dayRangeDays(this.dayRangeFilter.value);if(e==null)return;const t=Math.floor(Date.now()/1e3)-e*86400;this.collection.params[`${this.dayRangeFilter.field}__gte`]=t}async _onDayRangeChange({value:e,previous:t}){const s=this.dayRangeFilter?.field||"created",i=this._dayRangeDays(e);let r={};if(i!=null&&this.collection){const n=Math.floor(Date.now()/1e3)-i*86400;this.collection.params[`${s}__gte`]=n,this.collection.params.start=0,r={[`${s}__gte`]:n}}if(this.emit("range:change",{field:s,value:e,previous:t,params:r}),this.emit("params-changed"),this.collection?.restEnabled)try{await this.collection.fetch()}catch(n){console.error("Failed to fetch day-range data:",n),await this.render()}else await this.render()}getRange(){return this.dayRangeControl?.getValue()??null}setRange(e,{silent:t=!1}={}){if(!this.dayRangeControl)return!1;const s=this.dayRangeControl.getValue();return this.dayRangeControl.setValue(e,{silent:!0})?(t||this._onDayRangeChange({value:e,previous:s}),!0):!1}setCollection(e){return this.collection===e?this:(this.collection&&(this.collection.off("add",this._onModelsAdded,this),this.collection.off("remove",this._onModelsRemoved,this),this.collection.off("reset",this._onCollectionReset,this),this.collection.off("fetch:start",this._onFetchStart,this),this.collection.off("fetch:end",this._onFetchEnd,this)),this.collection=e,this.options.defaultQuery&&!this.options.collectionParams&&(this.collection.params={...this.collection.params,...this.options.defaultQuery}),this.options.collectionParams&&(this.collection.params={...this.collection.params,...this.options.collectionParams}),this.options.pageSize&&this.collection&&(this.collection.params={...this.collection.params,size:this.options.pageSize}),this.collection&&(this.collection.on("add",this._onModelsAdded,this),this.collection.on("remove",this._onModelsRemoved,this),this.collection.on("reset",this._onCollectionReset,this),this.collection.on("fetch:start",this._onFetchStart,this),this.collection.on("fetch:end",this._onFetchEnd,this),this.collection.restEnabled&&!this.collection.lastFetchTime&&!this.collection.options?.preloaded?this.loading=!0:this._buildItems()),this)}async _renderChildren(){await super._renderChildren();const e=this.getChildElement("items");if(!e)return;const t=[];if(this._renderOrder.length>0)for(const s of this._renderOrder)e.appendChild(s.view.element),t.push(Promise.resolve(s.view.render(!1)).catch(()=>{}));else this.forEachItem(s=>{e.appendChild(s.element),t.push(Promise.resolve(s.render(!1)).catch(()=>{}))});await Promise.all(t)}_buildItems(){if(this._clearItems(),!this.collection||this.collection.isEmpty()){this.isEmpty=!0,this.emit("list:empty");return}this.isEmpty=!1,this.collection.forEach((e,t)=>{this._createItemView(e,t)}),this._applyPersistedSelections(),this._buildGroupHeaders(),this.emit("list:loaded",{count:this.collection.length()}),this.isMounted()&&this.render()}_buildGroupHeaders(){if(this.groupHeaderViews.forEach(i=>this.removeChild(i.id)),this.groupHeaderViews.clear(),this._renderOrder.length=0,!this.groupBy||!this.collection||this.collection.isEmpty())return;const e=typeof this.groupBy=="function"?this.groupBy:i=>i.get(this.groupBy);let t,s=!1;this.collection.forEach((i,r)=>{const n=this.itemViews.get(i.id);if(!n)return;let a;try{a=e(i)}catch(o){console.warn("ListView: groupBy resolver threw — treating as ungrouped tail",o),a=null}if(a&&(!s||a!==t)){const o=this._createGroupHeaderView(i,a,r);this._renderOrder.push({type:"header",view:o}),t=a,s=!0}this._renderOrder.push({type:"item",view:n})})}_rebuildGroupHeaders(){this._buildGroupHeaders()}_createGroupHeaderView(e,t,s){const i=this.groupHeaderLabel?this.groupHeaderLabel(t):t,r=new this.groupHeaderClass({template:this.groupHeaderTemplate||this._defaultGroupHeaderTemplate(),model:e,key:i,index:s,...this._groupHeaderViewOptions(e,t,s)});return this.groupHeaderViews.set(r.id,r),r}_groupHeaderViewOptions(e,t,s){return{className:`list-group-header list-group-header--${this.groupHeaderStyle}`}}_defaultGroupHeaderTemplate(){return"{{key}}"}_createItemView(e,t){if(this.itemViews.has(e.id))return this.itemViews.get(e.id);const s=new this.itemClass({model:e,index:t,listView:this,template:this.itemTemplate,clickable:this.clickable});return this.itemViews.set(e.id,s),this._wireItemViewListeners(s),s}_wireItemViewListeners(e){e.on("item:select",this._onItemSelect.bind(this)),e.on("item:deselect",this._onItemDeselect.bind(this)),e.on("item:click",t=>{t.action==="row-click"&&(this.emit("row:click",t),this._dispatchRowClick(t))}),e.on("row:click",t=>{this._dispatchRowClick(t)}),e.on("row:view",this._onRowView.bind(this)),e.on("row:edit",this._onRowEdit.bind(this)),e.on("row:delete",this._onRowDelete.bind(this))}_dispatchRowClick(e){if(typeof this.options.onRowClick=="function")return this.options.onRowClick(e.model,e.event);if(typeof this.clickAction=="function")return this.clickAction(e.model,e.event);if(this.onItemClick)return this.onItemClick(e.model,e.event);if(this.clickAction==="view")return this._onRowView(e);if(this.clickAction==="edit")return this._onRowEdit(e);this.clickAction==="select"&&(this.selectedItems.has(e.model.id)?this.deselectItem(e.model.id):this.selectItem(e.model.id))}_applyPersistedSelections(){!this.persistSelection||this.selectedItems.size===0||this.itemViews.forEach((e,t)=>{this.selectedItems.has(t)&&!e.selected&&(e.selected=!0,e.element&&e.addClass("selected"))})}_clearItems(){this.forEachItem(e=>{this.removeChild(e.id)}),this.itemViews.clear(),this.groupHeaderViews.forEach(e=>this.removeChild(e.id)),this.groupHeaderViews.clear(),this._renderOrder.length=0,this.persistSelection||this.selectedItems.clear()}_onModelsAdded(e){const{models:t}=e;t.forEach(s=>{const i=this.collection.models.indexOf(s);this._createItemView(s,i)}),this._applyPersistedSelections(),this.groupBy&&this._rebuildGroupHeaders(),this.isEmpty=this.collection.isEmpty(),!this.loading&&this.isMounted()&&this.render()}_onModelsRemoved(e){const{models:t}=e;t.forEach(s=>{const i=this.itemViews.get(s.id);i&&(this.removeChild(i.id),this.itemViews.delete(s.id),this.selectedItems.delete(s.id))}),this.isEmpty=this.collection.isEmpty(),!this.loading&&this.isMounted()&&this.render(),this.isEmpty&&this.emit("list:empty")}_onCollectionReset(e){this._buildItems()}_onFetchStart(){this.loading=!0,!this.loadingMore&&this.isMounted()&&this.render()}_onFetchEnd(){this.loading=!1,!this.loadingMore&&this.isMounted()&&this.render()}_onItemSelect(e){const{model:t,item:s}=e;if(this.selectionMode==="none"){s.deselect();return}this.selectionMode==="single"&&(this.itemViews.forEach((i,r)=>{r!==t.id&&i.selected&&i.deselect()}),this.selectedItems.clear()),this.selectedItems.add(t.id),this.emit("selection:change",{selected:Array.from(this.selectedItems),item:s,model:t})}_onItemDeselect(e){const{model:t}=e;this.selectedItems.delete(t.id),this.emit("selection:change",{selected:Array.from(this.selectedItems),item:e.item,model:t})}getSelectedItems(){const e=[];return this.selectedItems.forEach(t=>{const s=this.itemViews.get(t);s&&e.push({view:s,model:s.model,data:s.model?.toJSON?s.model.toJSON():s.model})}),e}forEachItem(e,t){if(typeof e!="function")throw new TypeError("Callback must be a function");let s=0;return this.itemViews.forEach(i=>{e.call(t,i,i.model,s++)}),this}clearSelection(){this.forEachItem(e=>{e.selected&&e.deselect()}),this.selectedItems.clear(),this.emit("selection:change",{selected:[]})}selectItem(e){const t=this.itemViews.get(e);return t&&t.select(),this}deselectItem(e){const t=this.itemViews.get(e);return t&&t.deselect(),this}setItemTemplate(e,t=!1){return this.itemTemplate=e,t&&this.itemViews.size>0&&this.forEachItem(s=>{s.setTemplate(e),s.isMounted()&&s.render()}),this}async refresh(){if(this.collection&&this.collection.restEnabled)return await this.collection.fetch();this._buildItems()}_stripeClassFor(e){if(!this.rowStripe||!e)return null;let t;try{t=this.rowStripe(e)}catch(s){return console.warn("ListView: rowStripe callback threw — treating as no stripe",s),null}return t==null||t===""||typeof t!="string"?null:se.ROW_STRIPE_TOKENS.includes(t)?`list-row-stripe-${t}`:t}_applyRowStripe(e){if(!e||!e.element)return;const t=e.element.classList;for(const i of Array.from(t))i.startsWith("list-row-stripe")&&t.remove(i);const s=this._stripeClassFor(e.model);if(s)try{t.add(s)}catch(i){console.warn("ListView: rowStripe returned an invalid class name, skipping",s,i)}}refreshStripes(){return this.rowStripe?(this.forEachItem(e=>this._applyRowStripe(e)),this):this}async _onRowView(e){if(this.emit("row:view",e),this.options.onItemView){await this.options.onItemView(e.model,e.event);return}if(this.fetchOnView)try{v.loading(),await e.model.fetch()}catch(s){v.hideLoading(!0),v.showError(s?.data?.error||s?.message||"Failed to load item details");return}finally{v.hideLoading(!0)}const t=this.getItemViewClass(e.model);if(t){const s=new t({model:e.model,collection:this.collection});await v.dialog({header:!1,body:s,size:"lg",centered:!1,...this.getFormDialogConfig(this.getModelClass(e.model)),...t.DIALOG_OPTIONS,...this.viewDialogOptions})}else await v.data({title:`View ${this.getModelName(e.model)} #${e.model.id}`,model:e.model})}async _onRowEdit(e){if(this.emit("row:edit",e),this.options.onItemEdit){await this.options.onItemEdit(e.model,e.event);return}const t=this.getModelClass(e.model);let s=this.getEditFormConfig(t);if(s){s.fields||(s={title:`Edit ${this.getModelName(e.model)}`,fields:s});const i=await v.modelForm({model:e.model,...s,...this.getFormDialogConfig(t)});if(!i)return;if(!i.success||!i?.result?.data.status){v.showError(i?.result?.data?.error||i?.result?.message||"An error occurred");return}}else{const i=await v.dialog({title:`Edit ${this.getModelName(e.model)} #${e.model.id}`,body:new te({model:e.model,fields:this.options.formFields||[]})});if(i){const r=await e.model.save(i);if(!r.data?.status){v.showError(r.data.error||"An error occurred");return}await this.refresh()}}}async _onRowDelete(e){if(this.emit("row:delete",e),this.options.onItemDelete){await this.options.onItemDelete(e.model,e.event);return}const t=this.getModelClass(e.model),s=this.deleteTemplate||t?.DELETE_TEMPLATE||'Are you sure you want to delete this {{name||"item"}}?',i=this.renderTemplateString(s,e.model);await v.confirm({message:i||"Are you sure you want to delete this item?",title:"Confirm Delete",confirmText:"Delete",confirmClass:"btn-danger"})&&(await e.model.destroy(),this.collection?.restEnabled?this.collection.fetch():this._buildItems())}async onActionAdd(e,t){if(this.options.onAdd){this.emit("list:add",{event:e}),await this.options.onAdd(e);return}this.emit("list:add",{event:e});const s=this.getModelClass();if(!s){console.warn("Cannot determine Model class for add operation");return}let i=this.getAddFormConfig(s);if(i){const r=new s;i.fields||(i={title:`Add ${this.getModelName()}`,fields:i});const n=await v.form({model:r,...i,...this.getFormDialogConfig(s)});if(n){this.options.addRequiresActiveGroup&&(n.group=this.getApp().activeGroup.id),this.options.addRequiresActiveUser&&(n.user=this.getApp().activeUser.id),this.options.addFormDefaults&&Object.assign(n,this.options.addFormDefaults);const a=await r.save(n);if(!a?.data.status){v.showError(a?.data.error||"An error occurred");return}this.collection&&this.collection.add(r),await this.refresh()}}else{const r=new s,n=await v.dialog({title:`Add ${this.getModelName()}`,body:new te({model:r,fields:this.options.formFields||[]})});if(n){const a=await r.save(n);if(!a?.data.status){v.showError(a.data.error||"An error occurred");return}this.collection&&this.collection.add(r),await this.refresh()}}}async onActionExport(e,t){const s=t.getAttribute("data-format")||"json";this.emit("list:export",{format:s,source:this.exportSource,event:e}),this.exportSource==="remote"?this.collection?await this.collection.download(s):console.warn("ListView: Cannot export from remote without a collection."):this.options.onExport?await this.options.onExport(this.collection?.toJSON()||[],s):console.warn("ListView: onExport handler not implemented for local export.")}getModelClass(e){return this.collection?.ModelClass?this.collection.ModelClass:this.collection?.model?this.collection.model:e?.constructor?e.constructor:null}getModelName(e){const t=this.getModelClass(e);if(!t)return"Item";if(t.MODEL_NAME)return t.MODEL_NAME;const s=(t.name||"").replace(/Model$/,"");return/^[A-Z][A-Za-z0-9]{2,}$/.test(s)?s:(se._warnedMinifiedClasses.has(t)||(se._warnedMinifiedClasses.add(t),console.warn(`ListView.getModelName: class name '${s}' looks minified — set a static MODEL_NAME on the model class for user-facing dialog titles. Falling back to 'Item'.`)),"Item")}getItemViewClass(e){if(this.itemView)return this.itemView;const t=this.getModelClass(e);return t?.VIEW_CLASS?t.VIEW_CLASS:null}getAddFormConfig(e){return this.addForm||e?.ADD_FORM||this.editForm||e?.EDIT_FORM}getEditFormConfig(e){return this.editForm||e?.EDIT_FORM||this.addForm||e?.ADD_FORM}getFormDialogConfig(e){return{...e?.FORM_DIALOG_CONFIG,...this.formDialogConfig}}renderTemplateString(e,t){return e?D.render(e,t):""}async onActionRefresh(e,t){await this.refresh()}async onActionApplySearch(e,t){const s=t.value.trim();this.collection&&(this.setFilter("search",s),this.collection.params.start=0,this.collection.restEnabled?await this.collection.fetch():await this.render()),this.updateFilterPills(),this.emit("list:search",{searchTerm:s}),this.emit("params-changed")}async onActionClearSearch(e,t){this.setFilter("search",null),this.collection&&(this.collection.params.start=0,this.collection.restEnabled&&await this.collection.fetch()),await this.render(),this.updateFilterPills(),this.emit("list:search",{searchTerm:""}),this.emit("params-changed")}setupSearchClearListener(){if(!this.element)return;this.element.querySelectorAll('input[type="search"][data-filter="search"]').forEach(t=>{t.addEventListener("input",s=>{s.target.value===""&&this.getActiveFilters().search&&this.onActionClearSearch(s,s.target)})})}updateFilterPills(){const e=this.element?.querySelector('[data-container="filter-pills"]');e&&(e.innerHTML=this.buildActivePills())}updateSearchInputs(e){const t=this.element?.querySelectorAll('[data-filter="search"]');t&&t.forEach(s=>{s.value=e||""})}renderPagination(){const e=this.element.querySelector('[data-container="pagination"]');if(!e||!this.collection)return;const t=this.collection.meta?.count||this.collection.length(),s=this.collection.params?.size||10,i=this.collection.params?.start||0,r=Math.floor(i/s)+1,n=Math.ceil(t/s);if(n<=1){e.innerHTML="";return}const a=r>1?r-1:n,o=r<n?r+1:1,l=[];l.push(`
1599
+ `}_normalizeEmptyState(e){if(!e||typeof e!="object")return null;let t=null;return e.action&&typeof e.action=="object"&&e.action.action&&(t={label:e.action.label||"Action",action:e.action.action,icon:e.action.icon||null}),{icon:e.icon||"inbox",title:e.title||null,message:e.message||null,action:t}}_hasFeedbackFeature(){return!!this.emptyState||this.loadingStyle==="skeleton"||this.showResultCount}_loadingContent(e){return this.loadingStyle==="skeleton"?"{{{skeletonHtml}}}":e}_emptyContent(e){return this.emptyState?"{{{emptyStateHtml}}}":e}_skeletonRowCount(){const e=this.collection?.params?.size,t=typeof e=="number"&&e>0?e:5;return Math.min(t,8)}_buildSkeletonHtml(){const e=this._skeletonRowCount();let t="";for(let s=0;s<e;s++)t+='<div class="list-skeleton-card"><span class="skeleton-line w-40"></span><span class="skeleton-line w-90"></span><span class="skeleton-line w-60"></span></div>';return`<div class="list-skeleton" aria-hidden="true">${t}</div>`}_buildEmptyStateHtml(){const e=this.emptyState;if(!e)return"";const t=Object.keys(this.getActiveFilters()).length,s=t>0;let i,r,n,a;if(s)i="funnel",r="No results match your filters",n=`No items match the ${t} active ${t===1?"filter":"filters"}. Try widening or removing a filter.`,a='<button class="btn btn-outline-primary" data-action="clear-all-filters"><i class="bi bi-x-circle me-1"></i>Clear filters</button>';else if(i=e.icon||"inbox",r=e.title||this.emptyMessage,n=e.message||"",e.action){const d=e.action.icon?`<i class="bi ${this.escapeHtml(e.action.icon)} me-1"></i>`:"";a=`<button class="btn btn-primary" data-action="${this.escapeHtml(e.action.action)}">${d}${this.escapeHtml(e.action.label)}</button>`}else a="";const o=r?`<div class="empty-state-title h6">${this.escapeHtml(r)}</div>`:"",l=n?`<p class="empty-state-message">${this.escapeHtml(n)}</p>`:"";return`
1600
+ <div class="table-empty-state">
1601
+ <span class="empty-state-icon"><i class="bi bi-${this.escapeHtml(i)}"></i></span>
1602
+ ${o}
1603
+ ${l}
1604
+ ${a}
1605
+ </div>
1606
+ `}_buildResultCountSummary(){if(!this.showResultCount||!this.collection)return"";const e=this.collection.meta||{},t=typeof e.count=="number"?e.count:null;if(t===null)return"";const s=this.collection.length(),i=Object.keys(this.getActiveFilters()).length>0,r=a=>Number(a).toLocaleString(),n=i?' <span class="count-filtered">· filtered</span>':"";return`<span class="result-count-summary me-2 mb-1">Showing <strong>${r(s)}</strong> of <strong>${r(t)}</strong>${n}</span>`}_buildFeedbackStyles(){return`
1607
+ <style>
1608
+ .table-empty-state { text-align: center; padding: 3rem 1.5rem; }
1609
+ .table-empty-state .empty-state-icon {
1610
+ display: inline-flex; align-items: center; justify-content: center;
1611
+ width: 4rem; height: 4rem; border-radius: 50%;
1612
+ margin-bottom: 1rem; font-size: 1.75rem;
1613
+ background: var(--bs-secondary-bg);
1614
+ color: var(--bs-secondary-color);
1615
+ border: 1px solid var(--bs-border-color);
1616
+ }
1617
+ .table-empty-state .empty-state-title {
1618
+ font-weight: 600; color: var(--bs-emphasis-color); margin-bottom: 0.35rem;
1619
+ }
1620
+ .table-empty-state .empty-state-message {
1621
+ color: var(--bs-secondary-color); max-width: 26rem; margin: 0 auto 1.25rem;
1622
+ }
1623
+
1624
+ .skeleton-line {
1625
+ display: block; height: 0.85rem; border-radius: 0.35rem;
1626
+ background-color: var(--bs-secondary-bg);
1627
+ background-image: linear-gradient(90deg,
1628
+ rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.06) 50%, rgba(0, 0, 0, 0) 100%);
1629
+ background-size: 200% 100%; background-repeat: no-repeat;
1630
+ animation: mojo-skeleton-shimmer 1.4s ease-in-out infinite;
1631
+ }
1632
+ [data-bs-theme="dark"] .skeleton-line {
1633
+ background-image: linear-gradient(90deg,
1634
+ rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.07) 50%, rgba(255, 255, 255, 0) 100%);
1635
+ }
1636
+ .skeleton-line.w-90 { width: 90%; }
1637
+ .skeleton-line.w-75 { width: 75%; }
1638
+ .skeleton-line.w-60 { width: 60%; }
1639
+ .skeleton-line.w-40 { width: 40%; }
1640
+ .skeleton-line.w-25 { width: 25%; }
1641
+ .skeleton-line.skeleton-pill { height: 1.35rem; width: 4rem; border-radius: 999px; }
1642
+ .list-skeleton-card {
1643
+ display: flex; flex-direction: column; gap: 0.5rem;
1644
+ padding: 0.85rem 1rem; margin-bottom: 0.5rem;
1645
+ border: 1px solid var(--bs-border-color-translucent);
1646
+ border-radius: 0.5rem;
1647
+ }
1648
+ @keyframes mojo-skeleton-shimmer {
1649
+ 0% { background-position: 150% 0; }
1650
+ 100% { background-position: -50% 0; }
1651
+ }
1652
+ @media (prefers-reduced-motion: reduce) {
1653
+ .skeleton-line { animation: none; }
1654
+ }
1655
+
1656
+ .result-count-summary { font-size: 0.8rem; color: var(--bs-secondary-color); }
1657
+ .result-count-summary strong { color: var(--bs-emphasis-color); font-weight: 600; }
1658
+ .result-count-summary .count-filtered { color: var(--bs-primary); }
1659
+ </style>
1660
+ `}_initCollection(e){if(!e){console.log("Collection not provided");return}if(e instanceof de)this.setCollection(e);else if(typeof e=="function"){const t=new e;this.setCollection(t)}else if(Array.isArray(e)){const t=new de(e);this.setCollection(t)}}_normalizeDayRangeFilter(e){if(!e)return null;const t={field:"created",value:"7d",options:[{value:"1d",label:"1d"},{value:"7d",label:"7d"},{value:"30d",label:"30d"},{value:"90d",label:"90d"}],ariaLabel:"Time range"};return e===!0?t:{...t,...e}}_dayRangeDays(e){const t=/^(\d+)d$/.exec(String(e||""));return t?parseInt(t[1],10):null}_seedDayRangeParams(){if(!this.dayRangeFilter||!this.collection)return;const e=this._dayRangeDays(this.dayRangeFilter.value);if(e==null)return;const t=Math.floor(Date.now()/1e3)-e*86400;this.collection.params[`${this.dayRangeFilter.field}__gte`]=t}async _onDayRangeChange({value:e,previous:t}){const s=this.dayRangeFilter?.field||"created",i=this._dayRangeDays(e);let r={};if(i!=null&&this.collection){const n=Math.floor(Date.now()/1e3)-i*86400;this.collection.params[`${s}__gte`]=n,this.collection.params.start=0,r={[`${s}__gte`]:n}}if(this.emit("range:change",{field:s,value:e,previous:t,params:r}),this.emit("params-changed"),this.collection?.restEnabled)try{await this.collection.fetch()}catch(n){console.error("Failed to fetch day-range data:",n),await this.render()}else await this.render()}getRange(){return this.dayRangeControl?.getValue()??null}setRange(e,{silent:t=!1}={}){if(!this.dayRangeControl)return!1;const s=this.dayRangeControl.getValue();return this.dayRangeControl.setValue(e,{silent:!0})?(t||this._onDayRangeChange({value:e,previous:s}),!0):!1}_normalizeFilterPresets(e){if(!Array.isArray(e)||e.length===0)return[];const t=new Set,s=[];return e.forEach(i=>{if(!(!i||!i.key)){if(t.has(i.key)){console.warn(`ListView: duplicate filterPresets key '${i.key}' — ignoring the later one.`);return}t.add(i.key),s.push({key:i.key,label:i.label||i.key,icon:i.icon||null,params:i.params&&typeof i.params=="object"?i.params:{},description:i.description||null})}}),s}_presetsInline(){return this.filterPresets.length<=4}_getPreset(e){return this.filterPresets.find(t=>t.key===e)||null}_resolvePresetParams(e){const t={},s=e?.params||{};return Object.keys(s).forEach(i=>{const r=s[i];if(r==="@me"){const n=this.getApp()?.activeUser?.id;if(n==null)return;t[i]=n}else t[i]=r}),t}_presetMatches(e){const t=this._resolvePresetParams(e),s=Object.keys(t);if(s.length===0)return!1;const i=this.getActiveFilters();return s.every(r=>{const n=t[r];if(Array.isArray(n)){if(n.length===0)return!0;const{field:a}=ue(r);if(n.length===1)return i[a]!==void 0&&String(i[a])===String(n[0]);const o=i[`${a}__in`];return o!==void 0&&String(o)===n.join(",")}return i[r]!==void 0&&String(i[r])===String(n)})}_clearPresetParams(e){const t=this._resolvePresetParams(e);Object.keys(t).forEach(s=>this.setFilter(s,null))}getActivePreset(){if(!this.filterPresets||this.filterPresets.length===0)return null;let e=null,t=-1;for(const s of this.filterPresets){if(!this._presetMatches(s))continue;const i=Object.keys(this._resolvePresetParams(s)).length;i>t&&(e=s,t=i)}return e}async applyPreset(e){const t=this._getPreset(e);if(!t)return!1;const s=this.getActivePreset();if(s&&s.key===t.key)return await this.clearPreset(),!0;s&&this._clearPresetParams(s);const i=this._resolvePresetParams(t);return Object.keys(i).forEach(r=>this.setFilter(r,i[r])),await this.applyFilters(),this.renderFilterPresets(),this.emit("preset:change",{key:t.key,params:i}),!0}async clearPreset(){const e=this.getActivePreset();e&&(this._clearPresetParams(e),await this.applyFilters()),this.renderFilterPresets(),this.emit("preset:change",null)}async onActionApplyPreset(e,t){e&&typeof e.preventDefault=="function"&&e.preventDefault();const s=t?.getAttribute("data-preset-key");s&&await this.applyPreset(s)}renderFilterPresets(){if(!this.filterPresets||this.filterPresets.length===0)return;const e=this.element?.querySelector('[data-container="filter-presets"]');e&&(e.innerHTML=this._buildPresetSegment())}_buildPresetSegment(){const e=this.getActivePreset(),t=e?e.key:null;return`<div class="btn-group btn-group-sm preset-segment" role="group" aria-label="Filter presets">${this.filterPresets.map(i=>{const r=i.key===t,n=r?"btn btn-primary":"btn btn-outline-secondary",a=i.icon?`<i class="bi ${this.escapeHtml(i.icon)}"></i> `:"",o=i.description?` title="${this.escapeHtml(i.description)}"`:"";return`<button type="button"
1661
+ class="${n}"
1662
+ data-action="apply-preset"
1663
+ data-preset-key="${this.escapeHtml(i.key)}"
1664
+ aria-pressed="${r?"true":"false"}"${o}>${a}${this.escapeHtml(i.label)}</button>`}).join("")}</div>`}_buildPresetStyle(){return`
1665
+ <style>
1666
+ .preset-segment .btn {
1667
+ --bs-btn-padding-y: 0.25rem;
1668
+ --bs-btn-padding-x: 0.6rem;
1669
+ font-size: 0.8125rem;
1670
+ font-weight: 500;
1671
+ }
1672
+ .preset-segment .btn .bi { font-size: 0.8rem; }
1673
+
1674
+ /* Touch: bump the tap target only on coarse pointers — desktop stays compact. */
1675
+ @media (pointer: coarse) {
1676
+ .preset-segment .btn {
1677
+ --bs-btn-padding-y: 0.5rem;
1678
+ --bs-btn-padding-x: 0.85rem;
1679
+ }
1680
+ }
1681
+
1682
+ /* 5+ presets: own row, scroll horizontally instead of wrapping. */
1683
+ .preset-scroll {
1684
+ overflow-x: auto;
1685
+ -webkit-overflow-scrolling: touch;
1686
+ scrollbar-width: thin;
1687
+ padding-bottom: 0.2rem;
1688
+ }
1689
+ .preset-scroll .btn-group { flex-wrap: nowrap; }
1690
+ .preset-scroll .btn { white-space: nowrap; }
1691
+ .preset-scroll::-webkit-scrollbar { height: 6px; }
1692
+ .preset-scroll::-webkit-scrollbar-thumb {
1693
+ background: rgba(0, 0, 0, 0.15);
1694
+ border-radius: 999px;
1695
+ }
1696
+ [data-bs-theme="dark"] .preset-scroll::-webkit-scrollbar-thumb {
1697
+ background: rgba(255, 255, 255, 0.12);
1698
+ }
1699
+ </style>
1700
+ `}_buildAutoRefreshIndicatorSlot(){const t=`Auto-refresh: ${Math.round(this._autoRefreshMs/1e3)}s`;return`<span class="mojo-autorefresh-indicator" data-autorefresh-indicator title="${this.escapeHtml(t)}">
1701
+ <i class="bi bi-arrow-repeat" aria-hidden="true"></i>
1702
+ <span class="visually-hidden">${this.escapeHtml(t)}</span>
1703
+ </span>`}_buildAutoRefreshIndicatorStyle(){return`
1704
+ <style>
1705
+ .mojo-autorefresh-indicator {
1706
+ display: inline-flex;
1707
+ align-items: center;
1708
+ color: var(--bs-secondary-color);
1709
+ font-size: 0.9rem;
1710
+ line-height: 1;
1711
+ }
1712
+ .mojo-autorefresh-indicator .bi { display: block; }
1713
+ .mojo-autorefresh-indicator.is-refreshing .bi {
1714
+ animation: mojo-autorefresh-spin 0.6s ease;
1715
+ }
1716
+ @keyframes mojo-autorefresh-spin {
1717
+ from { transform: rotate(0deg); }
1718
+ to { transform: rotate(360deg); }
1719
+ }
1720
+ @media (prefers-reduced-motion: reduce) {
1721
+ .mojo-autorefresh-indicator.is-refreshing .bi { animation: none; }
1722
+ }
1723
+ </style>
1724
+ `}_pulseAutoRefreshIndicator(){const e=this.element?.querySelector("[data-autorefresh-indicator]");e&&(e.classList.add("is-refreshing"),this._autoRefreshPulseTimer&&clearTimeout(this._autoRefreshPulseTimer),this._autoRefreshPulseTimer=setTimeout(()=>{e.classList.remove("is-refreshing"),this._autoRefreshPulseTimer=null},600))}setCollection(e){return this.collection===e?this:(this.collection&&(this.collection.off("add",this._onModelsAdded,this),this.collection.off("remove",this._onModelsRemoved,this),this.collection.off("reset",this._onCollectionReset,this),this.collection.off("fetch:start",this._onFetchStart,this),this.collection.off("fetch:end",this._onFetchEnd,this)),this.collection=e,this.options.defaultQuery&&!this.options.collectionParams&&(this.collection.params={...this.collection.params,...this.options.defaultQuery}),this.options.collectionParams&&(this.collection.params={...this.collection.params,...this.options.collectionParams}),this.options.pageSize&&this.collection&&(this.collection.params={...this.collection.params,size:this.options.pageSize}),this.collection&&(this.collection.on("add",this._onModelsAdded,this),this.collection.on("remove",this._onModelsRemoved,this),this.collection.on("reset",this._onCollectionReset,this),this.collection.on("fetch:start",this._onFetchStart,this),this.collection.on("fetch:end",this._onFetchEnd,this),this.collection.restEnabled&&!this.collection.lastFetchTime&&!this.collection.options?.preloaded?this.loading=!0:this._buildItems()),this)}async _renderChildren(){await super._renderChildren();const e=this.getChildElement("items");if(!e)return;const t=[];if(this._renderOrder.length>0)for(const s of this._renderOrder)e.appendChild(s.view.element),t.push(Promise.resolve(s.view.render(!1)).catch(()=>{}));else this.forEachItem(s=>{e.appendChild(s.element),t.push(Promise.resolve(s.render(!1)).catch(()=>{}))});await Promise.all(t)}_buildItems(){if(this._clearItems(),!this.collection||this.collection.isEmpty()){this.isEmpty=!0,this.emit("list:empty");return}this.isEmpty=!1,this.collection.forEach((e,t)=>{this._createItemView(e,t)}),this._applyPersistedSelections(),this._buildGroupHeaders(),this.emit("list:loaded",{count:this.collection.length()}),this.isMounted()&&this.render()}_buildGroupHeaders(){if(this.groupHeaderViews.forEach(i=>this.removeChild(i.id)),this.groupHeaderViews.clear(),this._renderOrder.length=0,!this.groupBy||!this.collection||this.collection.isEmpty())return;const e=typeof this.groupBy=="function"?this.groupBy:i=>i.get(this.groupBy);let t,s=!1;this.collection.forEach((i,r)=>{const n=this.itemViews.get(i.id);if(!n)return;let a;try{a=e(i)}catch(o){console.warn("ListView: groupBy resolver threw — treating as ungrouped tail",o),a=null}if(a&&(!s||a!==t)){const o=this._createGroupHeaderView(i,a,r);this._renderOrder.push({type:"header",view:o}),t=a,s=!0}this._renderOrder.push({type:"item",view:n})})}_rebuildGroupHeaders(){this._buildGroupHeaders()}_createGroupHeaderView(e,t,s){const i=this.groupHeaderLabel?this.groupHeaderLabel(t):t,r=new this.groupHeaderClass({template:this.groupHeaderTemplate||this._defaultGroupHeaderTemplate(),model:e,key:i,index:s,...this._groupHeaderViewOptions(e,t,s)});return this.groupHeaderViews.set(r.id,r),r}_groupHeaderViewOptions(e,t,s){return{className:`list-group-header list-group-header--${this.groupHeaderStyle}`}}_defaultGroupHeaderTemplate(){return"{{key}}"}_createItemView(e,t){if(this.itemViews.has(e.id))return this.itemViews.get(e.id);const s=new this.itemClass({model:e,index:t,listView:this,template:this.itemTemplate,clickable:this.clickable});return this.itemViews.set(e.id,s),this._wireItemViewListeners(s),s}_wireItemViewListeners(e){e.on("item:select",this._onItemSelect.bind(this)),e.on("item:deselect",this._onItemDeselect.bind(this)),e.on("item:click",t=>{t.action==="row-click"&&(this.emit("row:click",t),this._dispatchRowClick(t))}),e.on("row:click",t=>{this._dispatchRowClick(t)}),e.on("row:view",this._onRowView.bind(this)),e.on("row:edit",this._onRowEdit.bind(this)),e.on("row:delete",this._onRowDelete.bind(this))}_dispatchRowClick(e){if(typeof this.options.onRowClick=="function")return this.options.onRowClick(e.model,e.event);if(typeof this.clickAction=="function")return this.clickAction(e.model,e.event);if(this.onItemClick)return this.onItemClick(e.model,e.event);if(this.clickAction==="view")return this._onRowView(e);if(this.clickAction==="edit")return this._onRowEdit(e);this.clickAction==="select"&&(this.selectedItems.has(e.model.id)?this.deselectItem(e.model.id):this.selectItem(e.model.id))}_applyPersistedSelections(){!this.persistSelection||this.selectedItems.size===0||this.itemViews.forEach((e,t)=>{this.selectedItems.has(t)&&!e.selected&&(e.selected=!0,e.element&&e.addClass("selected"))})}_clearItems(){this.forEachItem(e=>{this.removeChild(e.id)}),this.itemViews.clear(),this.groupHeaderViews.forEach(e=>this.removeChild(e.id)),this.groupHeaderViews.clear(),this._renderOrder.length=0,this.persistSelection||this.selectedItems.clear()}_onModelsAdded(e){const{models:t}=e;t.forEach(s=>{const i=this.collection.models.indexOf(s);this._createItemView(s,i)}),this._applyPersistedSelections(),this.groupBy&&this._rebuildGroupHeaders(),this.isEmpty=this.collection.isEmpty(),!this.loading&&this.isMounted()&&this.render()}_onModelsRemoved(e){const{models:t}=e;t.forEach(s=>{const i=this.itemViews.get(s.id);i&&(this.removeChild(i.id),this.itemViews.delete(s.id),this.selectedItems.delete(s.id))}),this.isEmpty=this.collection.isEmpty(),!this.loading&&this.isMounted()&&this.render(),this.isEmpty&&this.emit("list:empty")}_onCollectionReset(e){this._buildItems()}_onFetchStart(){this.loading=!0,!this.loadingMore&&this.isMounted()&&this.render()}_onFetchEnd(){this.loading=!1,!this.loadingMore&&this.isMounted()&&this.render()}_onItemSelect(e){const{model:t,item:s}=e;if(this.selectionMode==="none"){s.deselect();return}this.selectionMode==="single"&&(this.itemViews.forEach((i,r)=>{r!==t.id&&i.selected&&i.deselect()}),this.selectedItems.clear()),this.selectedItems.add(t.id),this.emit("selection:change",{selected:Array.from(this.selectedItems),item:s,model:t})}_onItemDeselect(e){const{model:t}=e;this.selectedItems.delete(t.id),this.emit("selection:change",{selected:Array.from(this.selectedItems),item:e.item,model:t})}getSelectedItems(){const e=[];return this.selectedItems.forEach(t=>{const s=this.itemViews.get(t);s&&e.push({view:s,model:s.model,data:s.model?.toJSON?s.model.toJSON():s.model})}),e}forEachItem(e,t){if(typeof e!="function")throw new TypeError("Callback must be a function");let s=0;return this.itemViews.forEach(i=>{e.call(t,i,i.model,s++)}),this}clearSelection(){this.forEachItem(e=>{e.selected&&e.deselect()}),this.selectedItems.clear(),this.emit("selection:change",{selected:[]})}selectItem(e){const t=this.itemViews.get(e);return t&&t.select(),this}deselectItem(e){const t=this.itemViews.get(e);return t&&t.deselect(),this}setItemTemplate(e,t=!1){return this.itemTemplate=e,t&&this.itemViews.size>0&&this.forEachItem(s=>{s.setTemplate(e),s.isMounted()&&s.render()}),this}async refresh(){if(this.collection&&this.collection.restEnabled)return await this.collection.fetch();this._buildItems()}_stripeClassFor(e){if(!this.rowStripe||!e)return null;let t;try{t=this.rowStripe(e)}catch(s){return console.warn("ListView: rowStripe callback threw — treating as no stripe",s),null}return t==null||t===""||typeof t!="string"?null:se.ROW_STRIPE_TOKENS.includes(t)?`list-row-stripe-${t}`:t}_applyRowStripe(e){if(!e||!e.element)return;const t=e.element.classList;for(const i of Array.from(t))i.startsWith("list-row-stripe")&&t.remove(i);const s=this._stripeClassFor(e.model);if(s)try{t.add(s)}catch(i){console.warn("ListView: rowStripe returned an invalid class name, skipping",s,i)}}refreshStripes(){return this.rowStripe?(this.forEachItem(e=>this._applyRowStripe(e)),this):this}async _onRowView(e){if(this.emit("row:view",e),this.options.onItemView){await this.options.onItemView(e.model,e.event);return}if(this.fetchOnView)try{v.loading(),await e.model.fetch()}catch(s){v.hideLoading(!0),v.showError(s?.data?.error||s?.message||"Failed to load item details");return}finally{v.hideLoading(!0)}const t=this.getItemViewClass(e.model);if(t){const s=new t({model:e.model,collection:this.collection});await v.dialog({header:!1,body:s,size:"lg",centered:!1,...this.getFormDialogConfig(this.getModelClass(e.model)),...t.DIALOG_OPTIONS,...this.viewDialogOptions})}else await v.data({title:`View ${this.getModelName(e.model)} #${e.model.id}`,model:e.model})}async _onRowEdit(e){if(this.emit("row:edit",e),this.options.onItemEdit){await this.options.onItemEdit(e.model,e.event);return}const t=this.getModelClass(e.model);let s=this.getEditFormConfig(t);if(s){s.fields||(s={title:`Edit ${this.getModelName(e.model)}`,fields:s});const i=await v.modelForm({model:e.model,...s,...this.getFormDialogConfig(t)});if(!i)return;if(!i.success||!i?.result?.data.status){v.showError(i?.result?.data?.error||i?.result?.message||"An error occurred");return}}else{const i=await v.dialog({title:`Edit ${this.getModelName(e.model)} #${e.model.id}`,body:new te({model:e.model,fields:this.options.formFields||[]})});if(i){const r=await e.model.save(i);if(!r.data?.status){v.showError(r.data.error||"An error occurred");return}await this.refresh()}}}async _onRowDelete(e){if(this.emit("row:delete",e),this.options.onItemDelete){await this.options.onItemDelete(e.model,e.event);return}const t=this.getModelClass(e.model),s=this.deleteTemplate||t?.DELETE_TEMPLATE||'Are you sure you want to delete this {{name||"item"}}?',i=this.renderTemplateString(s,e.model);await v.confirm({message:i||"Are you sure you want to delete this item?",title:"Confirm Delete",confirmText:"Delete",confirmClass:"btn-danger"})&&(await e.model.destroy(),this.collection?.restEnabled?this.collection.fetch():this._buildItems())}async onActionAdd(e,t){if(this.options.onAdd){this.emit("list:add",{event:e}),await this.options.onAdd(e);return}this.emit("list:add",{event:e});const s=this.getModelClass();if(!s){console.warn("Cannot determine Model class for add operation");return}let i=this.getAddFormConfig(s);if(i){const r=new s;i.fields||(i={title:`Add ${this.getModelName()}`,fields:i});const n=await v.form({model:r,...i,...this.getFormDialogConfig(s)});if(n){this.options.addRequiresActiveGroup&&(n.group=this.getApp().activeGroup.id),this.options.addRequiresActiveUser&&(n.user=this.getApp().activeUser.id),this.options.addFormDefaults&&Object.assign(n,this.options.addFormDefaults);const a=await r.save(n);if(!a?.data.status){v.showError(a?.data.error||"An error occurred");return}this.collection&&this.collection.add(r),await this.refresh()}}else{const r=new s,n=await v.dialog({title:`Add ${this.getModelName()}`,body:new te({model:r,fields:this.options.formFields||[]})});if(n){const a=await r.save(n);if(!a?.data.status){v.showError(a.data.error||"An error occurred");return}this.collection&&this.collection.add(r),await this.refresh()}}}async onActionExport(e,t){const s=t.getAttribute("data-format")||"json";this.emit("list:export",{format:s,source:this.exportSource,event:e}),this.exportSource==="remote"?this.collection?await this.collection.download(s):console.warn("ListView: Cannot export from remote without a collection."):this.options.onExport?await this.options.onExport(this.collection?.toJSON()||[],s):console.warn("ListView: onExport handler not implemented for local export.")}getModelClass(e){return this.collection?.ModelClass?this.collection.ModelClass:this.collection?.model?this.collection.model:e?.constructor?e.constructor:null}getModelName(e){const t=this.getModelClass(e);if(!t)return"Item";if(t.MODEL_NAME)return t.MODEL_NAME;const s=(t.name||"").replace(/Model$/,"");return/^[A-Z][A-Za-z0-9]{2,}$/.test(s)?s:(se._warnedMinifiedClasses.has(t)||(se._warnedMinifiedClasses.add(t),console.warn(`ListView.getModelName: class name '${s}' looks minified — set a static MODEL_NAME on the model class for user-facing dialog titles. Falling back to 'Item'.`)),"Item")}getItemViewClass(e){if(this.itemView)return this.itemView;const t=this.getModelClass(e);return t?.VIEW_CLASS?t.VIEW_CLASS:null}getAddFormConfig(e){return this.addForm||e?.ADD_FORM||this.editForm||e?.EDIT_FORM}getEditFormConfig(e){return this.editForm||e?.EDIT_FORM||this.addForm||e?.ADD_FORM}getFormDialogConfig(e){return{...e?.FORM_DIALOG_CONFIG,...this.formDialogConfig}}renderTemplateString(e,t){return e?D.render(e,t):""}async onActionRefresh(e,t){await this.refresh()}async onActionApplySearch(e,t){const s=t.value.trim();this.collection&&(this.setFilter("search",s),this.collection.params.start=0,this.collection.restEnabled?await this.collection.fetch():await this.render()),this.updateFilterPills(),this.emit("list:search",{searchTerm:s}),this.emit("params-changed")}async onActionClearSearch(e,t){this.setFilter("search",null),this.collection&&(this.collection.params.start=0,this.collection.restEnabled&&await this.collection.fetch()),await this.render(),this.updateFilterPills(),this.emit("list:search",{searchTerm:""}),this.emit("params-changed")}setupSearchClearListener(){if(!this.element)return;this.element.querySelectorAll('input[type="search"][data-filter="search"]').forEach(t=>{t.addEventListener("input",s=>{s.target.value===""&&this.getActiveFilters().search&&this.onActionClearSearch(s,s.target)})})}updateFilterPills(){const e=this.element?.querySelector('[data-container="filter-pills"]');e&&(e.innerHTML=this.buildActivePills())}updateSearchInputs(e){const t=this.element?.querySelectorAll('[data-filter="search"]');t&&t.forEach(s=>{s.value=e||""})}renderPagination(){const e=this.element.querySelector('[data-container="pagination"]');if(!e||!this.collection)return;const t=this.collection.meta?.count||this.collection.length(),s=this.collection.params?.size||10,i=this.collection.params?.start||0,r=Math.floor(i/s)+1,n=Math.ceil(t/s);if(n<=1){e.innerHTML="";return}const a=r>1?r-1:n,o=r<n?r+1:1,l=[];l.push(`
1585
1725
  <li class="page-item">
1586
1726
  <a class="page-link" href="#" data-action="page" data-page="${a}">
1587
1727
  <i class="bi bi-chevron-left"></i>
@@ -1597,7 +1737,15 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1597
1737
  <i class="bi bi-chevron-right"></i>
1598
1738
  </a>
1599
1739
  </li>
1600
- `),e.innerHTML=l.join("")}async onActionPage(e,t){e.preventDefault();const s=parseInt(t.getAttribute("data-page"),10),i=this.collection.params?.size||10,r=this.collection.meta?.count||this.collection.length(),n=Math.max(1,Math.ceil(r/i));let a=isNaN(s)?1:s;a<1&&(a=n),a>n&&(a=1),this.collection.setParams({...this.collection.params,start:(a-1)*i}),this.collection.restEnabled?await this.collection.fetch():this.render(),this.emit("list:page",{page:a,event:e}),this.emit("params-changed")}async onChangePageSize(e,t){const s=parseInt(t.value,10);this.collection&&(this.collection.setParams({...this.collection.params,start:0,size:s}),this.collection.restEnabled&&await this.collection.fetch(),this.render()),this.emit("list:pagesize",{size:s}),this.emit("params-changed")}_computeHasMore(){if(this.paginationMode!=="more"||!this.collection)return!1;const e=this.collection.meta?.count;return typeof e!="number"?!1:this.collection.length()<e}async onActionShowMore(e,t){if(!this.loadingMore){if(!this.collection||typeof this.collection.fetchMore!="function"){console.warn("ListView: collection does not support fetchMore()");return}this.loadingMore=!0,this.isMounted()&&await this.render();try{const s=await this.collection.fetchMore();this.emit("list:show-more",{response:s})}catch(s){console.error("ListView: fetchMore failed",s)}finally{this.loadingMore=!1,this.isMounted()&&await this.render()}}}async onActionSortOption(e,t){e.preventDefault();const s=t.getAttribute("data-sort");this.collection&&(this.collection.setParams({...this.collection.params,sort:s||void 0,start:0}),this.collection.restEnabled?await this.collection.fetch():this.render()),this.emit("list:sort",{sort:s}),this.emit("params-changed")}async onActionCustomToolbarButton(e,t){const s=parseInt(t.getAttribute("data-button-index"),10),i=this.toolbarButtons[s];i&&typeof i.handler=="function"&&await i.handler.call(this,e,t)}async onActionAddFilter(e,t){const s=t.getAttribute("data-filter-key"),i=this.getFilterConfig(s),r=this.getActiveFilters()[s];if(!i){console.warn("No filter config found for key:",s);return}const n=await v.form({title:`${r!==void 0&&r!==""?"Edit":"Add"} ${this.getFilterLabel(s)} Filter`,size:"md",fields:[this.buildFilterDialogField(i,r,s)]});if(n){const a=this.extractFilterValue(i,n);this.setFilter(s,a),await this.applyFilters()}}async onActionEditFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=ge(s),r=this.getFilterConfig(i)||this.getFilterConfig(s),n=this.getActiveFilters(),a=n[s]||n[i];if(!r){console.warn("No filter config found for key:",s,"or field:",i);return}const o={filter_value:a};if(r.type==="daterange"&&a&&typeof a=="object"){const d=r.startName||"dr_start",h=r.endName||"dr_end";o[d]=a.start||"",o[h]=a.end||""}const l=await v.form({title:`Edit ${this.getFilterLabel(i)} Filter`,size:"md",data:o,fields:[this.buildFilterDialogField(r,a,i)]});if(l){const d=this.extractFilterValue(r,l);this.setFilter(s,d),await this.applyFilters()}}async onActionRemoveFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=ge(s);this.setFilter(s,null),s==="search"&&this.updateSearchInputs(""),this.collection?.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filter:remove",{key:s,field:i}),this.emit("params-changed")}async onActionClearAllFilters(e,t){if(!this.collection)return;const{start:s,size:i,sort:r}=this.collection.params,n={start:s,size:i};r&&(n.sort=r),Array.isArray(this.hideActivePillNames)&&this.hideActivePillNames.length>0&&this.hideActivePillNames.forEach(a=>{this.collection.params[a]!==void 0&&(n[a]=this.collection.params[a]);const o=this.getFilterConfig(a);if(o&&o.type==="daterange"){const l=o.startName||"dr_start",d=o.endName||"dr_end",h=o.fieldName||"dr_field";this.collection.params[l]!==void 0&&(n[l]=this.collection.params[l]),this.collection.params[d]!==void 0&&(n[d]=this.collection.params[d]),this.collection.params[h]!==void 0&&(n[h]=this.collection.params[h])}}),this.collection.params=n,this.updateSearchInputs(""),this.collection.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filters:clear"),this.emit("params-changed")}async applyFilters(){if(this.collection&&(this.collection.params.start=0),this.collection?.restEnabled)try{await this.collection.fetch(),await this.render()}catch(e){console.error("Failed to fetch filtered data:",e),await this.render()}else await this.render();this.updateFilterPills(),this.emit("params-changed")}getActiveFilters(){if(!this.collection?.params)return{};const{start:e,size:t,sort:s,...i}=this.collection.params,r={},n=new Set;return this.getAllAvailableFilters().forEach(o=>{if(o.config?.type==="daterange"){const l=o.key,d=o.config.startName||"dr_start",h=o.config.endName||"dr_end",u=o.config.fieldName||"dr_field";i[u]===l&&(i[d]||i[h])&&(r[l]={start:i[d]||"",end:i[h]||""},n.add(d),n.add(h),n.add(u))}}),Object.keys(i).forEach(o=>{n.has(o)||(r[o]=i[o])}),Object.keys(r).forEach(o=>{const l=`${o}__in`;Object.prototype.hasOwnProperty.call(r,l)&&delete r[o]}),r}setFilter(e,t){if(!this.collection)return;const s=this.getFilterConfig(e);if(s&&s.type==="daterange"){const i=s.startName||"dr_start",r=s.endName||"dr_end",n=s.fieldName||"dr_field";delete this.collection.params[i],delete this.collection.params[r],delete this.collection.params[n],t&&typeof t=="object"&&(t.start||t.end)&&(t.start&&(this.collection.params[i]=t.start),t.end&&(this.collection.params[r]=t.end),this.collection.params[n]=e)}else{const{field:i}=ge(e);if(delete this.collection.params[e],delete this.collection.params[i],delete this.collection.params[`${i}__in`],!t||Array.isArray(t)&&t.length===0)return;Array.isArray(t)?t.length===1?this.collection.params[i]=t[0]:this.collection.params[`${i}__in`]=t.join(","):this.collection.params[e]=t}}getAllAvailableFilters(){const e=[];return Object.entries(this.filters||{}).forEach(([t,s])=>{e.push({key:t,label:s.label||t,type:s.type,config:s})}),this.additionalFilters&&Array.isArray(this.additionalFilters)&&this.additionalFilters.forEach(t=>{e.push({key:t.name||t.key,label:t.label,type:t.type,config:t})}),e}getFilterConfig(e){if(this.filters&&this.filters[e])return this.filters[e];if(this.additionalFilters&&Array.isArray(this.additionalFilters)){const t=this.additionalFilters.find(s=>(s.name||s.key)===e);if(t)return t}return null}getFilterLabel(e){if(e==="search")return"Search";const t=this.filters?.[e];if(t&&t.label)return t.label;const s=this.additionalFilters?.find(i=>(i.name||i.key)===e);return s&&s.label?s.label:e.charAt(0).toUpperCase()+e.slice(1)}getFilterIcon(e){return{text:"search",select:"funnel",date:"calendar",daterange:"calendar-range",number:"123",boolean:"toggle-on"}[e]||"filter"}buildFilterDialogField(e,t,s){const{name:i,value:r,...n}=e,a={...n,name:"filter_value",label:n.label,value:t,placeholder:n.placeholder||n.placeHolder};if(e.type==="daterange"){if(a.startName=a.startName||"dr_start",a.endName=a.endName||"dr_end",a.fieldName=a.fieldName||"dr_field",a.format=a.format||"YYYY-MM-DD",a.displayFormat=a.displayFormat||"MMM DD, YYYY",a.separator=a.separator||" to ",a.label=a.label||"Date Range",t&&typeof t=="object"){const o=l=>{if(!l&&l!==0)return"";if(l instanceof Date&&!isNaN(l))return l.toISOString().slice(0,10);const d=String(l).trim();if(!d)return"";if(/^-?\d+$/.test(d)){const u=Number(d),m=d.length<=10?u*1e3:u,p=new Date(m);if(!isNaN(p))return p.toISOString().slice(0,10)}const h=new Date(d);return isNaN(h)?d:h.toISOString().slice(0,10)};a.startDate=o(t.start||t.from||t.begin||""),a.endDate=o(t.end||t.to||t.finish||"")}}else if(e.type==="multiselect"){let o=[];t&&(Array.isArray(t)?o=t:typeof t=="string"&&(o=t.split(",").map(l=>l.trim()).filter(l=>l))),a.value=o,!a.placeholder&&!a.placeHolder&&(e.placeholder||e.placeHolder?a.placeholder=e.placeholder||e.placeHolder:e.label&&(a.placeholder=`Select ${e.label}...`))}else if(e.type==="boolean"||e.type==="switch"||e.type==="toggle"){a.type="select";const o=t!=null&&t!==""?t:e.defaultValue,l=o===!0?"true":o===!1?"false":o==null?"":String(o);a.value=l;const d=e.trueLabel||"True",h=e.falseLabel||"False";a.options=[{value:"true",text:d},{value:"false",text:h}],!a.placeholder&&!a.placeHolder&&(a.placeholder=e.label?`Filter by ${e.label}…`:"Select…")}return a}extractFilterValue(e,t){if(e.type==="daterange"){const s=e.startName||"dr_start",i=e.endName||"dr_end";return{start:t[s],end:t[i]}}return e.type==="multiselect",t.filter_value}setTitle(e){this.title=e||null;const t=this.element?.querySelector(".rs-table-title");t&&(t.textContent=this.title||"")}setEyebrow(e){this.eyebrow=e||null;const t=this.element?.querySelector(".rs-table-eyebrow");t&&(t.textContent=this.eyebrow||"")}escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}async destroy(){this.collection&&(this.collection.off("add",this._onModelsAdded,this),this.collection.off("remove",this._onModelsRemoved,this),this.collection.off("reset",this._onCollectionReset,this),this.collection.off("fetch:start",this._onFetchStart,this),this.collection.off("fetch:end",this._onFetchEnd,this)),this._clearItems(),await super.destroy()}}class Ge extends Ae{constructor(e={}){super({tagName:"tr",className:"table-row",enableTooltips:!0,...e}),this.columns=e.columns||[],this.actions=e.actions||null,this.contextMenu=e.contextMenu||null,this.batchActions=e.batchActions||null,this.tableView=e.tableView||e.listView||null,this.editingCells=new Set,this.template=this.buildRowTemplate()}getResponsiveClasses(e){if(!e)return"";const t=["sm","md","lg","xl","xxl"];if(typeof e=="string")return t.includes(e)?`d-none d-${e}-table-cell`:(console.warn(`Invalid visibility breakpoint: ${e}. Valid options are: ${t.join(", ")}`),"");if(typeof e=="object"){const s=[];if(e.hide){if(!t.includes(e.hide))return console.warn(`Invalid hide breakpoint: ${e.hide}. Valid options are: ${t.join(", ")}`),"";s.push(`d-table-cell d-${e.hide}-none`)}if(e.show){if(!t.includes(e.show))return console.warn(`Invalid show breakpoint: ${e.show}. Valid options are: ${t.join(", ")}`),"";e.hide?s.push(`d-${e.show}-table-cell`):s.push(`d-none d-${e.show}-table-cell`)}return s.join(" ")}return""}buildRowTemplate(){let e="";return this.tableView&&this.tableView.isSelectable()&&(e+=`
1740
+ `),e.innerHTML=l.join("")}async onActionPage(e,t){e.preventDefault();const s=parseInt(t.getAttribute("data-page"),10),i=this.collection.params?.size||10,r=this.collection.meta?.count||this.collection.length(),n=Math.max(1,Math.ceil(r/i));let a=isNaN(s)?1:s;a<1&&(a=n),a>n&&(a=1),this.collection.setParams({...this.collection.params,start:(a-1)*i}),this.collection.restEnabled?await this.collection.fetch():this.render(),this.emit("list:page",{page:a,event:e}),this.emit("params-changed")}async onChangePageSize(e,t){const s=parseInt(t.value,10);this.collection&&(this.collection.setParams({...this.collection.params,start:0,size:s}),this.collection.restEnabled&&await this.collection.fetch(),this.render()),this.emit("list:pagesize",{size:s}),this.emit("params-changed")}_computeHasMore(){if(this.paginationMode!=="more"||!this.collection)return!1;const e=this.collection.meta?.count;return typeof e!="number"?!1:this.collection.length()<e}async onActionShowMore(e,t){if(!this.loadingMore){if(!this.collection||typeof this.collection.fetchMore!="function"){console.warn("ListView: collection does not support fetchMore()");return}this.loadingMore=!0,this.isMounted()&&await this.render();try{const s=await this.collection.fetchMore();this.emit("list:show-more",{response:s})}catch(s){console.error("ListView: fetchMore failed",s)}finally{this.loadingMore=!1,this.isMounted()&&await this.render()}}}async onActionSortOption(e,t){e.preventDefault();const s=t.getAttribute("data-sort");this.collection&&(this.collection.setParams({...this.collection.params,sort:s||void 0,start:0}),this.collection.restEnabled?await this.collection.fetch():this.render()),this.emit("list:sort",{sort:s}),this.emit("params-changed")}async onActionCustomToolbarButton(e,t){const s=parseInt(t.getAttribute("data-button-index"),10),i=this.toolbarButtons[s];i&&typeof i.handler=="function"&&await i.handler.call(this,e,t)}async onActionAddFilter(e,t){const s=t.getAttribute("data-filter-key"),i=this.getFilterConfig(s),r=this.getActiveFilters()[s];if(!i){console.warn("No filter config found for key:",s);return}const n=await v.form({title:`${r!==void 0&&r!==""?"Edit":"Add"} ${this.getFilterLabel(s)} Filter`,size:"md",fields:[this.buildFilterDialogField(i,r,s)]});if(n){const a=this.extractFilterValue(i,n);this.setFilter(s,a),await this.applyFilters()}}async onActionEditFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=ue(s),r=this.getFilterConfig(i)||this.getFilterConfig(s),n=this.getActiveFilters(),a=n[s]||n[i];if(!r){console.warn("No filter config found for key:",s,"or field:",i);return}const o={filter_value:a};if(r.type==="daterange"&&a&&typeof a=="object"){const d=r.startName||"dr_start",h=r.endName||"dr_end";o[d]=a.start||"",o[h]=a.end||""}const l=await v.form({title:`Edit ${this.getFilterLabel(i)} Filter`,size:"md",data:o,fields:[this.buildFilterDialogField(r,a,i)]});if(l){const d=this.extractFilterValue(r,l);this.setFilter(s,d),await this.applyFilters()}}async onActionRemoveFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=ue(s);this.setFilter(s,null),s==="search"&&this.updateSearchInputs(""),this.collection?.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filter:remove",{key:s,field:i}),this.emit("params-changed")}async onActionClearAllFilters(e,t){if(!this.collection)return;const{start:s,size:i,sort:r}=this.collection.params,n={start:s,size:i};r&&(n.sort=r),Array.isArray(this.hideActivePillNames)&&this.hideActivePillNames.length>0&&this.hideActivePillNames.forEach(a=>{this.collection.params[a]!==void 0&&(n[a]=this.collection.params[a]);const o=this.getFilterConfig(a);if(o&&o.type==="daterange"){const l=o.startName||"dr_start",d=o.endName||"dr_end",h=o.fieldName||"dr_field";this.collection.params[l]!==void 0&&(n[l]=this.collection.params[l]),this.collection.params[d]!==void 0&&(n[d]=this.collection.params[d]),this.collection.params[h]!==void 0&&(n[h]=this.collection.params[h])}}),this.collection.params=n,this.updateSearchInputs(""),this.collection.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filters:clear"),this.emit("params-changed")}async applyFilters(){if(this.collection&&(this.collection.params.start=0),this.collection?.restEnabled)try{await this.collection.fetch(),await this.render()}catch(e){console.error("Failed to fetch filtered data:",e),await this.render()}else await this.render();this.updateFilterPills(),this.emit("params-changed")}getActiveFilters(){if(!this.collection?.params)return{};const{start:e,size:t,sort:s,...i}=this.collection.params,r={},n=new Set;return this.getAllAvailableFilters().forEach(o=>{if(o.config?.type==="daterange"){const l=o.key,d=o.config.startName||"dr_start",h=o.config.endName||"dr_end",u=o.config.fieldName||"dr_field";i[u]===l&&(i[d]||i[h])&&(r[l]={start:i[d]||"",end:i[h]||""},n.add(d),n.add(h),n.add(u))}}),Object.keys(i).forEach(o=>{n.has(o)||(r[o]=i[o])}),Object.keys(r).forEach(o=>{const l=`${o}__in`;Object.prototype.hasOwnProperty.call(r,l)&&delete r[o]}),r}setFilter(e,t){if(!this.collection)return;const s=this.getFilterConfig(e);if(s&&s.type==="daterange"){const i=s.startName||"dr_start",r=s.endName||"dr_end",n=s.fieldName||"dr_field";delete this.collection.params[i],delete this.collection.params[r],delete this.collection.params[n],t&&typeof t=="object"&&(t.start||t.end)&&(t.start&&(this.collection.params[i]=t.start),t.end&&(this.collection.params[r]=t.end),this.collection.params[n]=e)}else{const{field:i}=ue(e);if(delete this.collection.params[e],delete this.collection.params[i],delete this.collection.params[`${i}__in`],!t||Array.isArray(t)&&t.length===0)return;Array.isArray(t)?t.length===1?this.collection.params[i]=t[0]:this.collection.params[`${i}__in`]=t.join(","):this.collection.params[e]=t}}getAllAvailableFilters(){const e=[];return Object.entries(this.filters||{}).forEach(([t,s])=>{e.push({key:t,label:s.label||t,type:s.type,config:s})}),this.additionalFilters&&Array.isArray(this.additionalFilters)&&this.additionalFilters.forEach(t=>{e.push({key:t.name||t.key,label:t.label,type:t.type,config:t})}),e}getFilterConfig(e){if(this.filters&&this.filters[e])return this.filters[e];if(this.additionalFilters&&Array.isArray(this.additionalFilters)){const t=this.additionalFilters.find(s=>(s.name||s.key)===e);if(t)return t}return null}getFilterLabel(e){if(e==="search")return"Search";const t=this.filters?.[e];if(t&&t.label)return t.label;const s=this.additionalFilters?.find(i=>(i.name||i.key)===e);return s&&s.label?s.label:e.charAt(0).toUpperCase()+e.slice(1)}getFilterIcon(e){return{text:"search",select:"funnel",date:"calendar",daterange:"calendar-range",number:"123",boolean:"toggle-on"}[e]||"filter"}buildFilterDialogField(e,t,s){const{name:i,value:r,...n}=e,a={...n,name:"filter_value",label:n.label,value:t,placeholder:n.placeholder||n.placeHolder};if(e.type==="daterange"){if(a.startName=a.startName||"dr_start",a.endName=a.endName||"dr_end",a.fieldName=a.fieldName||"dr_field",a.format=a.format||"YYYY-MM-DD",a.displayFormat=a.displayFormat||"MMM DD, YYYY",a.separator=a.separator||" to ",a.label=a.label||"Date Range",t&&typeof t=="object"){const o=l=>{if(!l&&l!==0)return"";if(l instanceof Date&&!isNaN(l))return l.toISOString().slice(0,10);const d=String(l).trim();if(!d)return"";if(/^-?\d+$/.test(d)){const u=Number(d),m=d.length<=10?u*1e3:u,p=new Date(m);if(!isNaN(p))return p.toISOString().slice(0,10)}const h=new Date(d);return isNaN(h)?d:h.toISOString().slice(0,10)};a.startDate=o(t.start||t.from||t.begin||""),a.endDate=o(t.end||t.to||t.finish||"")}}else if(e.type==="multiselect"){let o=[];t&&(Array.isArray(t)?o=t:typeof t=="string"&&(o=t.split(",").map(l=>l.trim()).filter(l=>l))),a.value=o,!a.placeholder&&!a.placeHolder&&(e.placeholder||e.placeHolder?a.placeholder=e.placeholder||e.placeHolder:e.label&&(a.placeholder=`Select ${e.label}...`))}else if(e.type==="boolean"||e.type==="switch"||e.type==="toggle"){a.type="select";const o=t!=null&&t!==""?t:e.defaultValue,l=o===!0?"true":o===!1?"false":o==null?"":String(o);a.value=l;const d=e.trueLabel||"True",h=e.falseLabel||"False";a.options=[{value:"true",text:d},{value:"false",text:h}],!a.placeholder&&!a.placeHolder&&(a.placeholder=e.label?`Filter by ${e.label}…`:"Select…")}return a}extractFilterValue(e,t){if(e.type==="daterange"){const s=e.startName||"dr_start",i=e.endName||"dr_end";return{start:t[s],end:t[i]}}return e.type==="multiselect",t.filter_value}setTitle(e){this.title=e||null;const t=this.element?.querySelector(".rs-table-title");t&&(t.textContent=this.title||"")}setEyebrow(e){this.eyebrow=e||null;const t=this.element?.querySelector(".rs-table-eyebrow");t&&(t.textContent=this.eyebrow||"")}escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}_normalizeAutoRefresh(e){return typeof e!="number"||!isFinite(e)||e<=0?0:Math.max(5,e)*1e3}_startAutoRefresh(){this._autoRefreshMs&&(this._autoRefreshTimer||(this._autoRefreshPaused=this._autoRefreshDocHidden(),this._bindAutoRefreshListeners(),this._autoRefreshTimer=setInterval(()=>this._autoRefreshTick(),this._autoRefreshMs)))}_stopAutoRefresh(){this._autoRefreshTimer&&(clearInterval(this._autoRefreshTimer),this._autoRefreshTimer=null),this._autoRefreshPulseTimer&&(clearTimeout(this._autoRefreshPulseTimer),this._autoRefreshPulseTimer=null),this._unbindAutoRefreshListeners(),this._autoRefreshPaused=!1}_bindAutoRefreshListeners(){if(this._autoRefreshHandlers)return;const e=()=>{this._autoRefreshPaused=!0},t=()=>{this._autoRefreshPaused=!1,this._autoRefreshResume()},s=()=>{const i=this._autoRefreshDocHidden();this._autoRefreshPaused=i,i||this._autoRefreshResume()};this._autoRefreshHandlers={onBlur:e,onFocus:t,onVisibility:s},typeof window<"u"&&(window.addEventListener("blur",e),window.addEventListener("focus",t)),typeof document<"u"&&document.addEventListener("visibilitychange",s)}_unbindAutoRefreshListeners(){const e=this._autoRefreshHandlers;e&&(typeof window<"u"&&(window.removeEventListener("blur",e.onBlur),window.removeEventListener("focus",e.onFocus)),typeof document<"u"&&document.removeEventListener("visibilitychange",e.onVisibility),this._autoRefreshHandlers=null)}_autoRefreshDocHidden(){return typeof document<"u"&&(document.visibilityState==="hidden"||document.hidden===!0)}_autoRefreshResume(){this._autoRefreshTimer&&this._autoRefreshTick()}_autoRefreshTick(){if(!this.isMounted()){this._stopAutoRefresh();return}this._autoRefreshShouldSkip()||!this.collection||!this.collection.restEnabled||Promise.resolve(this.collection.fetch()).then(()=>this._pulseAutoRefreshIndicator()).catch(e=>{console.warn("ListView autoRefresh: fetch failed",e)})}_autoRefreshShouldSkip(){return!!(this._autoRefreshPaused||this._autoRefreshDocHidden()||this.selectedItems&&this.selectedItems.size>0)}_persistStorageKey(){return`mojo:tableview:${this.persistKey||this._defaultPersistKey()}`}_defaultPersistKey(){const e=typeof window<"u"&&window.location&&window.location.pathname||"",t=this.collection&&this.collection.endpoint||"";return`${e}::${t}`}_persistStorage(){try{const e=typeof globalThis<"u"?globalThis.localStorage:null;if(e&&typeof e.getItem=="function")return e}catch{}return null}_readPersistedState(){const e=this._persistStorage();if(!e)return null;let t;try{t=e.getItem(this._persistStorageKey())}catch{return null}if(!t)return null;let s;try{s=JSON.parse(t)}catch{return this._clearPersistedStorage(),null}return!s||typeof s!="object"||s.v!==1?(this._clearPersistedStorage(),null):s}_writePersistedState(e){const t=this._persistStorage();if(t)try{t.setItem(this._persistStorageKey(),JSON.stringify(e))}catch{}}_clearPersistedStorage(){const e=this._persistStorage();if(e)try{e.removeItem(this._persistStorageKey())}catch{}}_restorePersistedState(e=[]){if(!this.persistState||!this.collection)return;const t=this._readPersistedState();if(!t)return;const s=this.collection.params||(this.collection.params={}),i=new Set(e);if(i.delete("start"),i.delete("size"),t.sort!==void 0&&!i.has("sort")&&(s.sort=t.sort),t.size!==void 0&&(s.size=t.size),t.dayRange!==void 0&&this.dayRangeFilter){const r=this.dayRangeFilter.field||"created";i.has(`${r}__gte`)||(this.dayRangeFilter.value=t.dayRange)}t.filters&&typeof t.filters=="object"&&Object.keys(t.filters).forEach(r=>{i.has(r)||(s[r]=t.filters[r])}),typeof this._restoreHiddenColumns=="function"&&this._restoreHiddenColumns(t.hidden)}_savePersistedState(){if(!this.persistState)return;const e=this.collection&&this.collection.params||{},t=this.dayRangeFilter?`${this.dayRangeFilter.field||"created"}__gte`:null,s={};Object.keys(e).forEach(r=>{if(r==="start"||r==="size"||r==="sort"||t&&r===t)return;const n=e[r];n==null||n===""||(s[r]=n)});const i={v:1};if(e.sort!==void 0&&(i.sort=e.sort),e.size!==void 0&&(i.size=e.size),this.dayRangeControl&&typeof this.dayRangeControl.getValue=="function"?i.dayRange=this.dayRangeControl.getValue():this.dayRangeFilter&&(i.dayRange=this.dayRangeFilter.value),Object.keys(s).length>0&&(i.filters=s),typeof this._getHiddenColumnKeys=="function"){const r=this._getHiddenColumnKeys();r&&r.length>0&&(i.hidden=r)}this._writePersistedState(i)}clearPersistedState(){this._clearPersistedStorage(),typeof this._onClearPersistedState=="function"&&this._onClearPersistedState()}async destroy(){this._stopAutoRefresh(),this.collection&&(this.collection.off("add",this._onModelsAdded,this),this.collection.off("remove",this._onModelsRemoved,this),this.collection.off("reset",this._onCollectionReset,this),this.collection.off("fetch:start",this._onFetchStart,this),this.collection.off("fetch:end",this._onFetchEnd,this)),this._clearItems(),await super.destroy()}}class Ge extends Ae{constructor(e={}){super({tagName:"tr",className:"table-row",enableTooltips:!0,...e}),this.columns=e.columns||[],this.actions=e.actions||null,this.contextMenu=e.contextMenu||null,this.batchActions=e.batchActions||null,this.tableView=e.tableView||e.listView||null,this.editingCells=new Set,this.template=this.buildRowTemplate()}getResponsiveClasses(e){if(!e)return"";const t=["sm","md","lg","xl","xxl"];if(typeof e=="string")return t.includes(e)?`d-none d-${e}-table-cell`:(console.warn(`Invalid visibility breakpoint: ${e}. Valid options are: ${t.join(", ")}`),"");if(typeof e=="object"){const s=[];if(e.hide){if(!t.includes(e.hide))return console.warn(`Invalid hide breakpoint: ${e.hide}. Valid options are: ${t.join(", ")}`),"";s.push(`d-table-cell d-${e.hide}-none`)}if(e.show){if(!t.includes(e.show))return console.warn(`Invalid show breakpoint: ${e.show}. Valid options are: ${t.join(", ")}`),"";e.hide?s.push(`d-${e.show}-table-cell`):s.push(`d-none d-${e.show}-table-cell`)}return s.join(" ")}return""}_isRowExpandEnabled(){return!!(this.tableView&&typeof this.tableView.isRowExpandEnabled=="function"&&this.tableView.isRowExpandEnabled())}buildRowTemplate(){let e="";return this._isRowExpandEnabled()&&(e+=`
1741
+ <td class="col-expand mojo-expand-cell">
1742
+ <button type="button" class="mojo-expand-toggle"
1743
+ data-action="toggle-expand"
1744
+ aria-label="Toggle details" aria-expanded="false">
1745
+ <i class="bi bi-chevron-right"></i>
1746
+ </button>
1747
+ </td>
1748
+ `),this.tableView&&this.tableView.isSelectable()&&(e+=`
1601
1749
  <td style="padding: 0;">
1602
1750
  <div class="mojo-select-cell {{#selected}}selected{{/selected}}"
1603
1751
  data-action="select">
@@ -1657,7 +1805,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1657
1805
  ${this.escapeHtml(t.label)}
1658
1806
  </a>
1659
1807
  </li>
1660
- `}).join(""):""}async onActionRowContextMenuItem(e,t){e.stopPropagation();const s=parseInt(t.getAttribute("data-menu-index"),10),i=this.contextMenu&&this.contextMenu[s];!i||typeof i.action!="function"||await i.action(this.model,this.getApp())}async onAfterRender(){await super.onAfterRender(),this.columns.forEach((t,s)=>{if(t.formatter&&typeof t.formatter=="function"){let i=this.element.querySelector(`[data-formatter-id="${s}"]`);if(i||(i=this.element.querySelector(`[data-formatter="${t.key}"]`)),i){const r=this.model.get?this.model.get(t.key):this.model[t.key],n={value:r,row:this.model,model:this.model,column:t,table:this.tableView,index:this.index};try{i.innerHTML=t.formatter(r,n)}catch(a){console.error(`Error formatting cell for column ${t.key}:`,a)}}}}),this.selected&&this.element.classList.add("selected");const e=this.model.get?this.model.get("id"):this.model.id;e&&this.element.setAttribute("data-id",e)}async onActionEditCell(e,t){e.stopPropagation();const s=t.getAttribute("data-column"),i=this.columns.find(r=>r.key===s);!i||!i.editable||this.editingCells.has(s)||await this.enterEditMode(s,i,t)}async onActionRowClick(e,t){e.target.closest(".btn-group")||e.target.closest(".dropdown")||e.target.closest(".cell-editor")||(this.emit("row:click",{row:this,model:this.model,column:t.getAttribute("data-column"),event:e}),this.tableView&&this.tableView.emit("row:click",{row:this,model:this.model,column:t.getAttribute("data-column"),event:e}))}async onActionView(e,t){e.stopPropagation(),this.emit("row:view",{row:this,model:this.model,event:e}),this.tableView&&this.tableView.emit("row:view",{row:this,model:this.model,event:e})}async onActionEdit(e,t){return e.stopPropagation(),this.emit("row:edit",{row:this,model:this.model,event:e}),this.tableView&&this.tableView.emit("row:edit",{row:this,model:this.model,event:e}),!0}async onActionDelete(e,t){e.stopPropagation(),this.emit("row:delete",{row:this,model:this.model,event:e}),this.tableView&&this.tableView.emit("row:delete",{row:this,model:this.model,event:e})}async enterEditMode(e,t,s){const i=s.querySelector(".cell-content");if(!i)return;this.editingCells.add(e);const r=this.model.get?this.model.get(e):this.model[e],n=this.createCellEditor(t,r),a=i.innerHTML;i.style.display="none";const o=document.createElement("div");o.className="cell-editor",o.innerHTML=n,s.appendChild(o);const l=o.querySelector("input, select, .form-check-input");l&&(l.focus(),(l.type==="text"||l.type==="textarea")&&l.select()),o.dataset.originalContent=a,o.dataset.columnKey=e,this.setupEditorEvents(o,e,t),this.emit("cell:edit",{row:this,model:this.model,column:e,originalValue:r})}createCellEditor(e,t){const s=e.editableOptions||{};switch(s.type){case"select":return this.createSelectEditor(s,t);case"switch":case"checkbox":return this.createSwitchEditor(s,t);case"textarea":return this.createTextareaEditor(s,t);default:return this.createTextEditor(s,t)}}createTextEditor(e,t){const s=e.placeholder||"";return`
1808
+ `}).join(""):""}async onActionRowContextMenuItem(e,t){e.stopPropagation();const s=parseInt(t.getAttribute("data-menu-index"),10),i=this.contextMenu&&this.contextMenu[s];!i||typeof i.action!="function"||await i.action(this.model,this.getApp())}async onAfterRender(){await super.onAfterRender(),this.columns.forEach((t,s)=>{if(t.formatter&&typeof t.formatter=="function"){let i=this.element.querySelector(`[data-formatter-id="${s}"]`);if(i||(i=this.element.querySelector(`[data-formatter="${t.key}"]`)),i){const r=this.model.get?this.model.get(t.key):this.model[t.key],n={value:r,row:this.model,model:this.model,column:t,table:this.tableView,index:this.index};try{i.innerHTML=t.formatter(r,n)}catch(a){console.error(`Error formatting cell for column ${t.key}:`,a)}}}}),this.selected&&this.element.classList.add("selected");const e=this.model.get?this.model.get("id"):this.model.id;if(e&&this.element.setAttribute("data-id",e),this._isRowExpandEnabled()){const t=!!(this.tableView.expandedRows&&this.tableView.expandedRows.has(e));this.element.classList.toggle("expanded",t);const s=this.element.querySelector(".mojo-expand-toggle");s&&s.setAttribute("aria-expanded",t?"true":"false")}}async onActionToggleExpand(e,t){e.stopPropagation(),this.tableView&&typeof this.tableView.toggleRowExpand=="function"&&await this.tableView.toggleRowExpand(this.model,this)}async onActionEditCell(e,t){e.stopPropagation();const s=t.getAttribute("data-column"),i=this.columns.find(r=>r.key===s);!i||!i.editable||this.editingCells.has(s)||await this.enterEditMode(s,i,t)}async onActionRowClick(e,t){e.target.closest(".btn-group")||e.target.closest(".dropdown")||e.target.closest(".cell-editor")||(this.emit("row:click",{row:this,model:this.model,column:t.getAttribute("data-column"),event:e}),this.tableView&&this.tableView.emit("row:click",{row:this,model:this.model,column:t.getAttribute("data-column"),event:e}))}async onActionView(e,t){e.stopPropagation(),this.emit("row:view",{row:this,model:this.model,event:e}),this.tableView&&this.tableView.emit("row:view",{row:this,model:this.model,event:e})}async onActionEdit(e,t){return e.stopPropagation(),this.emit("row:edit",{row:this,model:this.model,event:e}),this.tableView&&this.tableView.emit("row:edit",{row:this,model:this.model,event:e}),!0}async onActionDelete(e,t){e.stopPropagation(),this.emit("row:delete",{row:this,model:this.model,event:e}),this.tableView&&this.tableView.emit("row:delete",{row:this,model:this.model,event:e})}async enterEditMode(e,t,s){const i=s.querySelector(".cell-content");if(!i)return;this.editingCells.add(e);const r=this.model.get?this.model.get(e):this.model[e],n=this.createCellEditor(t,r),a=i.innerHTML;i.style.display="none";const o=document.createElement("div");o.className="cell-editor",o.innerHTML=n,s.appendChild(o);const l=o.querySelector("input, select, .form-check-input");l&&(l.focus(),(l.type==="text"||l.type==="textarea")&&l.select()),o.dataset.originalContent=a,o.dataset.columnKey=e,this.setupEditorEvents(o,e,t),this.emit("cell:edit",{row:this,model:this.model,column:e,originalValue:r})}createCellEditor(e,t){const s=e.editableOptions||{};switch(s.type){case"select":return this.createSelectEditor(s,t);case"switch":case"checkbox":return this.createSwitchEditor(s,t);case"textarea":return this.createTextareaEditor(s,t);default:return this.createTextEditor(s,t)}}createTextEditor(e,t){const s=e.placeholder||"";return`
1661
1809
  <div class="d-flex gap-1 align-items-center">
1662
1810
  <input type="${e.inputType||"text"}"
1663
1811
  class="form-control form-control-sm cell-input"
@@ -1710,24 +1858,117 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1710
1858
  </button>
1711
1859
  </div>
1712
1860
  </div>
1713
- `}setupEditorEvents(e,t,s){const i=e.querySelector(".cell-input"),r=e.querySelector(".cell-save"),n=e.querySelector(".cell-cancel");i&&(i.type==="text"||i.type==="email"||i.type==="number")&&i.addEventListener("keydown",a=>{a.key==="Enter"?(a.preventDefault(),this.saveCellEdit(e,t,s)):a.key==="Escape"&&(a.preventDefault(),this.cancelCellEdit(e,t))}),i&&(i.type==="checkbox"||i.tagName==="SELECT")&&s.autoSave!==!1&&i.addEventListener("change",()=>{this.saveCellEdit(e,t,s)}),r?.addEventListener("click",()=>{this.saveCellEdit(e,t,s)}),n?.addEventListener("click",()=>{this.cancelCellEdit(e,t)})}async saveCellEdit(e,t,s){const i=e.querySelector(".cell-input");if(!i)return;let r;i.type==="checkbox"?r=i.checked:(i.tagName,r=i.value);const n=this.model.get?this.model.get(t):this.model[t];try{this.model.save?await this.model.save({[t]:r}):this.model[t]=r,this.exitEditMode(e,t,r),this.emit("cell:save",{row:this,model:this.model,column:t,oldValue:n,newValue:r})}catch(a){console.error("Failed to save cell edit:",a),this.emit("cell:save:error",{row:this,model:this.model,column:t,oldValue:n,newValue:r,error:a}),e.classList.add("saving-error"),setTimeout(()=>e.classList.remove("saving-error"),3e3)}}cancelCellEdit(e,t){const s=e.dataset.originalContent;this.exitEditMode(e,t,null,s),this.emit("cell:cancel",{row:this,model:this.model,column:t})}exitEditMode(e,t,s=null,i=null){const n=e.closest("td").querySelector(".cell-content");if(n){if(s!==null){const a=this.columns.find(l=>l.key===t);let o=s;a&&a.formatter&&typeof a.formatter=="string"&&(o=V.pipe(s,a.formatter)),n.innerHTML=this.escapeHtml(o)}else i&&(n.innerHTML=i);n.style.display=""}e.remove(),this.editingCells.delete(t)}escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}select(){super.select(),this.addClass("selected");const e=this.element?.querySelector(".mojo-select-cell");e&&e.classList.add("selected")}deselect(){super.deselect(),this.removeClass("selected");const e=this.element?.querySelector(".mojo-select-cell");e&&e.classList.remove("selected")}}class Lt extends se{constructor(e={}){const t={className:"table-view-component",itemClass:e.itemClass||Ge,selectionMode:e.selectable?"multiple":"none",emptyMessage:e.emptyMessage||"No data available",addButtonIcon:e.addButtonIcon||"bi bi-plus-circle",...e};super(t),this.isFullscreen=!1,this.columns=e.columns||[],this.actions=e.actions||null,this.contextMenu=e.contextMenu||e.rowContextMenu||null,this.batchActions=e.batchActions||null,this.searchable=e.searchable!==!1,this.sortable=e.sortable!==!1,this.filterable=e.filterable!==!1,this.paginated=e.paginated!==!1,this.paginationMode=e.paginationMode||"pages",this.persistSelection=e.persistSelection===!0,this.clickAction=e.clickAction||"view",this.fetchOnView=e.fetchOnView!==!1,this.itemView=e.itemView,this.addForm=e.addForm,this.editForm=e.editForm,this.deleteTemplate=e.deleteTemplate,this.formDialogConfig=e.formDialogConfig||{},this.viewDialogOptions=e.viewDialogOptions||{},this.exportOptions=e.exportOptions||null,this.options.showExport&&!this.exportOptions&&(this.exportOptions=[{format:"csv",label:"Export as CSV",icon:"bi bi-file-earmark-spreadsheet"},{format:"json",label:"Export as JSON",icon:"bi bi-file-earmark-code"}]),this.exportSource=e.exportSource||"remote",this.filters={},this.additionalFilters=e.filters||[],this.hideActivePills=e.hideActivePills===!0,this.hideActivePillNames=e.hideActivePillNames||[],this.rowAction=e.rowAction||"row-click",this.batchBarLocation=e.batchBarLocation||"bottom",this.options.addButtonLabel=e.addButtonLabel||"Add",this.toolbarButtons=e.toolbarButtons||[],this.toolbarRight=e.toolbarRight||null,this.title=e.title||null,this.eyebrow=e.eyebrow||null,this.showRefresh=e.showRefresh!==!1,this.showFullscreen=e.showFullscreen!==!1,this.tableOptions={striped:!0,bordered:!1,hover:!0,responsive:!1,size:null,...e.tableOptions},this.searchPlacement=e.searchPlacement||"toolbar",this.searchPlaceholder=e.searchPlaceholder||"Search...",this.initializeColumns(),this.extractColumnFilters(),this.footerTotalColumns=this.columns.filter(s=>s.footer_total===!0),this.hasFooterTotals=this.footerTotalColumns.length>0,this.template=this.buildTableTemplate(),this.setupCollectionListeners()}setupCollectionListeners(){this.hasFooterTotals&&this.collection&&this.collection.on("reset add remove change",()=>{this.updateFooterTotals()})}initializeColumns(){this.columns.forEach(e=>{!e.key&&e.name&&(e.key=e.name),!e.label&&!e.title&&(e.label=e.key.charAt(0).toUpperCase()+e.key.slice(1))})}getResponsiveClasses(e){if(!e)return"";const t=["sm","md","lg","xl","xxl"];if(typeof e=="string")return t.includes(e)?`d-none d-${e}-table-cell`:(console.warn(`Invalid visibility breakpoint: ${e}. Valid options are: ${t.join(", ")}`),"");if(typeof e=="object"){const s=[];if(e.hide){if(!t.includes(e.hide))return console.warn(`Invalid hide breakpoint: ${e.hide}. Valid options are: ${t.join(", ")}`),"";s.push(`d-table-cell d-${e.hide}-none`)}if(e.show){if(!t.includes(e.show))return console.warn(`Invalid show breakpoint: ${e.show}. Valid options are: ${t.join(", ")}`),"";e.hide?s.push(`d-${e.show}-table-cell`):s.push(`d-none d-${e.show}-table-cell`)}return s.join(" ")}return""}getAlignClass(e){if(!e)return"";const s={left:"text-start",start:"text-start",center:"text-center",right:"text-end",end:"text-end"}[String(e).toLowerCase()];return s||(console.warn(`Invalid column align: ${e}. Valid options are: left, center, right`),"")}parseColumnKey(e){const t=e.split("|");return{fieldKey:t[0],formatter:t[1]||null}}updateFooterTotals(){if(!this.hasFooterTotals||!this.element)return;const e=this.calculateFooterTotals();let t=0;this.columns.forEach(s=>{if(s.footer_total){const i=`col_${t}`,r=this.element.querySelector(`[data-total-column="${i}"]`);if(r&&e[i]){const n=this.parseColumnKey(s.key).formatter||s.formatter;let a;n&&typeof n=="string"?a=this.formatValue(e[i].value,n):a=e[i].value,r.textContent=a}t++}})}formatValue(e,t){try{return V.pipe(e,t)}catch(s){return console.warn("Error formatting value:",s),e}}calculateFooterTotals(){if(!this.hasFooterTotals||!this.collection||this.collection.length===0)return{};const e={};return this.footerTotalColumns.forEach((t,s)=>{const{fieldKey:i,formatter:r}=this.parseColumnKey(t.key);let n=0;this.collection.forEach(o=>{const l=o.get?o.get(i):o[i],d=parseFloat(l)||0;n+=d});const a=`col_${s}`;e[a]={value:n,formatter:r||t.formatter,fieldKey:i,originalKey:t.key}}),e}extractColumnFilters(){this.filters={},this.columns.forEach(e=>{if(e.filter){const{fieldKey:t}=this.parseColumnKey(e.key);this.filters[t]={...e.filter,label:e.filter.label||e.label||t}}})}isSelectable(){return this.batchActions&&this.batchActions.length>0&&this.selectionMode==="multiple"}buildTableTemplate(){const e=this.batchBarLocation==="top"?this.buildBatchActionsPanel():"",t=this.batchBarLocation==="bottom"?this.buildBatchActionsPanel():"",s=(()=>{const i=this.tableOptions&&this.tableOptions.fontSize!=null?this.tableOptions.fontSize:this.options&&this.options.fontSize,r=i==="sm"?"0.9rem":i==="xs"?"0.8rem":i?String(i):null;return r?` style="font-size: ${r};"`:""})();return`
1861
+ `}setupEditorEvents(e,t,s){const i=e.querySelector(".cell-input"),r=e.querySelector(".cell-save"),n=e.querySelector(".cell-cancel");i&&(i.type==="text"||i.type==="email"||i.type==="number")&&i.addEventListener("keydown",a=>{a.key==="Enter"?(a.preventDefault(),this.saveCellEdit(e,t,s)):a.key==="Escape"&&(a.preventDefault(),this.cancelCellEdit(e,t))}),i&&(i.type==="checkbox"||i.tagName==="SELECT")&&s.autoSave!==!1&&i.addEventListener("change",()=>{this.saveCellEdit(e,t,s)}),r?.addEventListener("click",()=>{this.saveCellEdit(e,t,s)}),n?.addEventListener("click",()=>{this.cancelCellEdit(e,t)})}async saveCellEdit(e,t,s){const i=e.querySelector(".cell-input");if(!i)return;let r;i.type==="checkbox"?r=i.checked:(i.tagName,r=i.value);const n=this.model.get?this.model.get(t):this.model[t];try{this.model.save?await this.model.save({[t]:r}):this.model[t]=r,this.exitEditMode(e,t,r),this.emit("cell:save",{row:this,model:this.model,column:t,oldValue:n,newValue:r})}catch(a){console.error("Failed to save cell edit:",a),this.emit("cell:save:error",{row:this,model:this.model,column:t,oldValue:n,newValue:r,error:a}),e.classList.add("saving-error"),setTimeout(()=>e.classList.remove("saving-error"),3e3)}}cancelCellEdit(e,t){const s=e.dataset.originalContent;this.exitEditMode(e,t,null,s),this.emit("cell:cancel",{row:this,model:this.model,column:t})}exitEditMode(e,t,s=null,i=null){const n=e.closest("td").querySelector(".cell-content");if(n){if(s!==null){const a=this.columns.find(l=>l.key===t);let o=s;a&&a.formatter&&typeof a.formatter=="string"&&(o=V.pipe(s,a.formatter)),n.innerHTML=this.escapeHtml(o)}else i&&(n.innerHTML=i);n.style.display=""}e.remove(),this.editingCells.delete(t)}escapeHtml(e){return e==null?"":String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}select(){super.select(),this.addClass("selected");const e=this.element?.querySelector(".mojo-select-cell");e&&e.classList.add("selected")}deselect(){super.deselect(),this.removeClass("selected");const e=this.element?.querySelector(".mojo-select-cell");e&&e.classList.remove("selected")}}class Pt extends se{constructor(e={}){const t={className:"table-view-component",itemClass:e.itemClass||Ge,selectionMode:e.selectable?"multiple":"none",emptyMessage:e.emptyMessage||"No data available",addButtonIcon:e.addButtonIcon||"bi bi-plus-circle",...e};super(t),this.isFullscreen=!1,this.columns=e.columns||[],this.actions=e.actions||null,this.contextMenu=e.contextMenu||e.rowContextMenu||null,this.batchActions=e.batchActions||null,this.rowExpand=typeof e.rowExpand=="function"?e.rowExpand:null,this.rowExpandMultiple=e.rowExpandMultiple===!0,this.expandedRows=new Set,this.expandChildViews=new Map,this.columnChooser=e.columnChooser===!0,this._hiddenColumns=new Set,this.searchable=e.searchable!==!1,this.sortable=e.sortable!==!1,this.filterable=e.filterable!==!1,this.paginated=e.paginated!==!1,this.paginationMode=e.paginationMode||"pages",this.persistSelection=e.persistSelection===!0,this.clickAction=e.clickAction||"view",this.fetchOnView=e.fetchOnView!==!1,this.itemView=e.itemView,this.addForm=e.addForm,this.editForm=e.editForm,this.deleteTemplate=e.deleteTemplate,this.formDialogConfig=e.formDialogConfig||{},this.viewDialogOptions=e.viewDialogOptions||{},this.exportOptions=e.exportOptions||null,this.options.showExport&&!this.exportOptions&&(this.exportOptions=[{format:"csv",label:"Export as CSV",icon:"bi bi-file-earmark-spreadsheet"},{format:"json",label:"Export as JSON",icon:"bi bi-file-earmark-code"}]),this.exportSource=e.exportSource||"remote",this.filters={},this.additionalFilters=e.filters||[],this.hideActivePills=e.hideActivePills===!0,this.hideActivePillNames=e.hideActivePillNames||[],this.rowAction=e.rowAction||"row-click",this.batchBarLocation=e.batchBarLocation||"bottom",this.options.addButtonLabel=e.addButtonLabel||"Add",this.toolbarButtons=e.toolbarButtons||[],this.toolbarRight=e.toolbarRight||null,this.title=e.title||null,this.eyebrow=e.eyebrow||null,this.showRefresh=e.showRefresh!==!1,this.showFullscreen=e.showFullscreen!==!1,this.tableOptions={striped:!0,bordered:!1,hover:!0,responsive:!1,size:null,...e.tableOptions},this.searchPlacement=e.searchPlacement||"toolbar",this.searchPlaceholder=e.searchPlaceholder||"Search...",this.initializeColumns(),this.extractColumnFilters(),this.footerTotalColumns=this.columns.filter(s=>s.footer_total===!0),this.hasFooterTotals=this.footerTotalColumns.length>0,this.template=this.buildTableTemplate(),this.setupCollectionListeners()}setupCollectionListeners(){this.hasFooterTotals&&this.collection&&this.collection.on("reset add remove change",()=>{this.updateFooterTotals()})}initializeColumns(){this.columns.forEach(e=>{!e.key&&e.name&&(e.key=e.name),!e.label&&!e.title&&(e.label=e.key.charAt(0).toUpperCase()+e.key.slice(1))})}_isColumnHideable(e){return e&&e.hideable!==!1}_isColumnHidden(e){return!this.columnChooser||!this._isColumnHideable(e)?!1:this._hiddenColumns.has(e.key)}_getVisibleColumns(){return!this.columnChooser||this._hiddenColumns.size===0?this.columns:this.columns.filter(e=>!this._isColumnHidden(e))}_getHiddenColumnKeys(){return this.columnChooser?this.columns.filter(e=>this._isColumnHideable(e)&&this._hiddenColumns.has(e.key)).map(e=>e.key):[]}_restoreHiddenColumns(e){!this.columnChooser||!Array.isArray(e)||e.length===0||(e.forEach(t=>{const s=this.columns.find(i=>i.key===t);s&&this._isColumnHideable(s)&&this._hiddenColumns.add(t)}),this._hiddenColumns.size!==0&&(this.template=this.buildTableTemplate(),this._templateCache=null,this.itemViews.size>0&&this._buildItems()))}_onClearPersistedState(){this._hiddenColumns.size!==0&&(this._hiddenColumns.clear(),this._rebuildForColumnChange())}_rebuildForColumnChange(){return this.template=this.buildTableTemplate(),this._templateCache=null,this._clearItems(),this.collection&&!this.collection.isEmpty()?(this.isEmpty=!1,this.collection.forEach((e,t)=>this._createItemView(e,t)),this._applyPersistedSelections(),this._buildGroupHeaders()):this.isEmpty=!0,this.render()}async onActionToggleColumn(e,t){const s=t.getAttribute("data-column-key"),i=this.columns.find(r=>r.key===s);!i||!this._isColumnHideable(i)||(this._hiddenColumns.has(s)?this._hiddenColumns.delete(s):this._hiddenColumns.add(s),await this._rebuildForColumnChange(),this.persistState&&this._savePersistedState(),this.emit("columns:change",{hidden:this._getHiddenColumnKeys()}))}async onActionColumnChooserReset(e,t){e&&typeof e.preventDefault=="function"&&e.preventDefault();const s=this._hiddenColumns.size>0;this._hiddenColumns.clear(),this._clearPersistedStorage(),s&&await this._rebuildForColumnChange(),this.emit("columns:reset")}_buildColumnChooserTemplate(){if(!this.columnChooser)return"";const e=this.columns.map(s=>{const i=this.escapeHtml(s.label||s.title||s.key);return this._isColumnHideable(s)?`
1862
+ <label class="column-chooser-item">
1863
+ <input class="form-check-input" type="checkbox" ${this._isColumnHidden(s)?"":"checked"}
1864
+ data-action="toggle-column" data-column-key="${this.escapeHtml(s.key)}">
1865
+ <span class="form-check-label">${i}</span>
1866
+ </label>`:`
1867
+ <label class="column-chooser-item is-locked" title="Always shown">
1868
+ <input class="form-check-input" type="checkbox" checked disabled>
1869
+ <span class="form-check-label">${i}</span>
1870
+ <i class="bi bi-lock-fill column-chooser-lock" aria-hidden="true"></i>
1871
+ </label>`}).join(""),t=this.persistState?'<div class="column-chooser-persist"><i class="bi bi-check2-circle"></i>Saved for this table</div>':"";return`
1872
+ <div class="dropdown">
1873
+ <button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button"
1874
+ data-bs-toggle="dropdown" aria-expanded="false" title="Choose columns">
1875
+ <i class="bi bi-layout-three-columns"></i><span class="d-none d-xxl-inline ms-1">Columns</span>
1876
+ </button>
1877
+ <div class="dropdown-menu dropdown-menu-end column-chooser-menu" role="menu">
1878
+ <h6 class="dropdown-header">Show columns</h6>
1879
+ ${e}
1880
+ <li><hr class="dropdown-divider"></li>
1881
+ <a class="dropdown-item d-flex align-items-center" href="#" data-action="column-chooser-reset">
1882
+ <i class="bi bi-arrow-counterclockwise me-2"></i>Reset to defaults
1883
+ </a>
1884
+ ${t}
1885
+ </div>
1886
+ </div>
1887
+ `}_buildColumnChooserStyles(){return`
1888
+ <style>
1889
+ .column-chooser-menu { min-width: 268px; }
1890
+ .column-chooser-menu .dropdown-header {
1891
+ color: var(--bs-secondary-color);
1892
+ text-transform: uppercase;
1893
+ letter-spacing: 0.05em;
1894
+ font-size: 0.7rem;
1895
+ font-weight: 600;
1896
+ }
1897
+ .column-chooser-item {
1898
+ display: flex; align-items: center; gap: 0.5rem;
1899
+ margin: 0; padding: 0.35rem 1rem; cursor: pointer;
1900
+ }
1901
+ .column-chooser-item .form-check-input { margin-top: 0; flex: 0 0 auto; }
1902
+ .column-chooser-item .form-check-label { cursor: pointer; flex: 1 1 auto; color: var(--bs-body-color); }
1903
+ .column-chooser-item:hover { background: rgba(0, 0, 0, 0.04); }
1904
+ .column-chooser-item.is-locked { cursor: default; opacity: 0.72; }
1905
+ .column-chooser-item.is-locked:hover { background: transparent; }
1906
+ .column-chooser-item.is-locked .form-check-label { color: var(--bs-secondary-color); }
1907
+ .column-chooser-lock { color: var(--bs-secondary-color); font-size: 0.8rem; }
1908
+ .column-chooser-persist {
1909
+ padding: 0.4rem 1rem 0.15rem;
1910
+ color: var(--bs-secondary-color);
1911
+ font-size: 0.72rem;
1912
+ display: flex; align-items: center; gap: 0.35rem;
1913
+ }
1914
+
1915
+ [data-bs-theme="dark"] .column-chooser-item:hover { background: var(--bs-secondary-bg); }
1916
+ </style>
1917
+ `}getResponsiveClasses(e){if(!e)return"";const t=["sm","md","lg","xl","xxl"];if(typeof e=="string")return t.includes(e)?`d-none d-${e}-table-cell`:(console.warn(`Invalid visibility breakpoint: ${e}. Valid options are: ${t.join(", ")}`),"");if(typeof e=="object"){const s=[];if(e.hide){if(!t.includes(e.hide))return console.warn(`Invalid hide breakpoint: ${e.hide}. Valid options are: ${t.join(", ")}`),"";s.push(`d-table-cell d-${e.hide}-none`)}if(e.show){if(!t.includes(e.show))return console.warn(`Invalid show breakpoint: ${e.show}. Valid options are: ${t.join(", ")}`),"";e.hide?s.push(`d-${e.show}-table-cell`):s.push(`d-none d-${e.show}-table-cell`)}return s.join(" ")}return""}getAlignClass(e){if(!e)return"";const s={left:"text-start",start:"text-start",center:"text-center",right:"text-end",end:"text-end"}[String(e).toLowerCase()];return s||(console.warn(`Invalid column align: ${e}. Valid options are: left, center, right`),"")}parseColumnKey(e){const t=e.split("|");return{fieldKey:t[0],formatter:t[1]||null}}updateFooterTotals(){if(!this.hasFooterTotals||!this.element)return;const e=this.calculateFooterTotals();let t=0;this.columns.forEach(s=>{if(s.footer_total){const i=`col_${t}`,r=this.element.querySelector(`[data-total-column="${i}"]`);if(r&&e[i]){const n=this.parseColumnKey(s.key).formatter||s.formatter;let a;n&&typeof n=="string"?a=this.formatValue(e[i].value,n):a=e[i].value,r.textContent=a}t++}})}formatValue(e,t){try{return V.pipe(e,t)}catch(s){return console.warn("Error formatting value:",s),e}}calculateFooterTotals(){if(!this.hasFooterTotals||!this.collection||this.collection.length===0)return{};const e={};return this.footerTotalColumns.forEach((t,s)=>{const{fieldKey:i,formatter:r}=this.parseColumnKey(t.key);let n=0;this.collection.forEach(o=>{const l=o.get?o.get(i):o[i],d=parseFloat(l)||0;n+=d});const a=`col_${s}`;e[a]={value:n,formatter:r||t.formatter,fieldKey:i,originalKey:t.key}}),e}extractColumnFilters(){this.filters={},this.columns.forEach(e=>{if(e.filter){const{fieldKey:t}=this.parseColumnKey(e.key);this.filters[t]={...e.filter,label:e.filter.label||e.label||t}}})}isSelectable(){return this.batchActions&&this.batchActions.length>0&&this.selectionMode==="multiple"}isRowExpandEnabled(){return typeof this.rowExpand=="function"}_getRowExpandColspan(){const e=this._getVisibleColumns().length||0,t=this.isSelectable()?1:0,s=this.actions||this.contextMenu?1:0,i=this.isRowExpandEnabled()?1:0;return Math.max(1,i+t+e+s)}async toggleRowExpand(e,t){if(!this.isRowExpandEnabled()||!e)return;const s=e.id;if(this.expandedRows.has(s))this._collapseRow(s);else{this.rowExpandMultiple||Array.from(this.expandedRows).forEach(n=>this._collapseRow(n)),this.expandedRows.add(s);const r=t||this.itemViews.get(s);if(r&&r.element){r.element.classList.add("expanded");const n=r.element.querySelector(".mojo-expand-toggle");n&&n.setAttribute("aria-expanded","true")}await this._renderExpandedRow(s)}this.emit("row:expand:toggle",{model:e,expanded:this.expandedRows.has(s)})}_collapseRow(e){this.expandedRows.delete(e);const t=this.element?.querySelector(`tr.mojo-detail-row[data-detail-for="${e}"]`);t&&t.remove();const s=this.expandChildViews.get(e);s&&(this.removeChild(s),this.expandChildViews.delete(e));const i=this.itemViews.get(e);if(i&&i.element){i.element.classList.remove("expanded");const r=i.element.querySelector(".mojo-expand-toggle");r&&r.setAttribute("aria-expanded","false")}}async _renderExpandedRow(e){const t=this.itemViews.get(e);if(!t||!t.element||!t.element.parentNode)return;const s=this.element?.querySelector(`tr.mojo-detail-row[data-detail-for="${e}"]`);s&&s.remove();const i=t.model;let r;try{r=this.rowExpand(i)}catch(l){console.error("TableView rowExpand() threw for model",e,l);return}const n=this._getRowExpandColspan(),a=document.createElement("tr");if(a.className="mojo-detail-row",a.setAttribute("data-detail-for",e),r&&typeof r=="object"&&typeof r.render=="function"){const l=`row-expand-${e}`;a.innerHTML=`<td colspan="${n}"><div class="mojo-detail-panel"><div data-container="${l}"></div></div></td>`,t.element.after(a),this.addChild(r,{containerId:l}),this.expandChildViews.set(e,r),await r.render()}else{const l=r==null?"":String(r);a.innerHTML=`<td colspan="${n}"><div class="mojo-detail-panel">${l}</div></td>`,t.element.after(a)}}async _renderExpandedRows(){this.isRowExpandEnabled()&&(Array.from(this.expandedRows).forEach(e=>{this.itemViews.has(e)||this._collapseRow(e)}),this.expandedRows.size!==0&&(this.expandChildViews.forEach(e=>this.removeChild(e)),this.expandChildViews.clear(),await Promise.all(Array.from(this.expandedRows,e=>this._renderExpandedRow(e)))))}_buildRowExpandStyles(){return`
1918
+ <style>
1919
+ .table-view-component .col-expand { width: 2.4rem; padding: 0 !important; }
1920
+ .table-view-component .mojo-expand-toggle {
1921
+ display: flex; align-items: center; justify-content: center;
1922
+ width: 100%; height: 100%; padding: 0.4rem 0;
1923
+ cursor: pointer; color: var(--bs-secondary-color);
1924
+ background: transparent; border: 0;
1925
+ }
1926
+ .table-view-component .mojo-expand-toggle:hover { color: var(--bs-emphasis-color); }
1927
+ .table-view-component .mojo-expand-toggle .bi {
1928
+ transition: transform 0.18s ease; font-size: 0.95rem; line-height: 1;
1929
+ }
1930
+ .table-view-component .table-row.expanded .mojo-expand-toggle .bi { transform: rotate(90deg); }
1931
+ .table-view-component .table-row.expanded .mojo-expand-toggle { color: var(--bs-primary); }
1932
+
1933
+ .table-view-component tr.mojo-detail-row > td {
1934
+ padding: 0 !important;
1935
+ border-bottom: 1px solid var(--bs-border-color) !important;
1936
+ background: rgba(0, 0, 0, 0.02);
1937
+ }
1938
+ .table-view-component .mojo-detail-panel {
1939
+ margin: 0.6rem 0.85rem 0.9rem 3rem;
1940
+ background: var(--bs-tertiary-bg);
1941
+ border: 1px solid var(--bs-border-color);
1942
+ border-left: 3px solid var(--bs-primary);
1943
+ border-radius: 0.5rem;
1944
+ padding: 0.95rem 1.1rem;
1945
+ }
1946
+
1947
+ [data-bs-theme="dark"] .table-view-component tr.mojo-detail-row > td {
1948
+ background: rgba(255, 255, 255, 0.015);
1949
+ }
1950
+ </style>
1951
+ `}buildTableTemplate(){const e=this.batchBarLocation==="top"?this.buildBatchActionsPanel():"",t=this.batchBarLocation==="bottom"?this.buildBatchActionsPanel():"",s=(()=>{const i=this.tableOptions&&this.tableOptions.fontSize!=null?this.tableOptions.fontSize:this.options&&this.options.fontSize,r=i==="sm"?"0.9rem":i==="xs"?"0.8rem":i?String(i):null;return r?` style="font-size: ${r};"`:""})();return`
1714
1952
  <div class="mojo-table-wrapper">
1953
+ ${this.isRowExpandEnabled()?this._buildRowExpandStyles():""}
1954
+ ${this.columnChooser?this._buildColumnChooserStyles():""}
1955
+ ${this._hasFeedbackFeature()?this._buildFeedbackStyles():""}
1715
1956
  ${this.buildToolbarTemplate()}
1716
1957
  ${e}
1717
1958
  <div class="table-container"${s}>
1718
1959
  {{#loading}}
1719
- <div class="mojo-table-loading d-flex justify-content-center align-items-center py-5">
1960
+ ${this._loadingContent(`<div class="mojo-table-loading d-flex justify-content-center align-items-center py-5">
1720
1961
  <div class="spinner-border" role="status">
1721
1962
  <span class="visually-hidden">Loading...</span>
1722
1963
  </div>
1723
- </div>
1964
+ </div>`)}
1724
1965
  {{/loading}}
1725
1966
  {{^loading}}
1726
1967
  {{#isEmpty}}
1727
- <div class="table-empty text-center py-5">
1968
+ ${this._emptyContent(`<div class="table-empty text-center py-5">
1728
1969
  <i class="bi bi-inbox fa-2x mb-2 text-muted"></i>
1729
1970
  <p class="text-muted">{{emptyMessage}}</p>
1730
- </div>
1971
+ </div>`)}
1731
1972
  {{/isEmpty}}
1732
1973
  {{^isEmpty}}
1733
1974
  <table class="${this.buildTableClasses()}">
@@ -1741,13 +1982,13 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1741
1982
  ${t}
1742
1983
  ${this.paginated?this.buildPaginationTemplate():""}
1743
1984
  </div>
1744
- `}buildTableClasses(){let e=["table"];return this.tableOptions.striped&&e.push("table-striped"),this.tableOptions.bordered&&e.push("table-bordered"),this.tableOptions.hover&&e.push("table-hover"),this.tableOptions.responsive&&e.push("table-responsive"),this.tableOptions.background&&e.push(`table-${this.tableOptions.background}`),this.tableOptions.size==="sm"&&e.push("table-sm"),this.tableOptions.size==="lg"&&e.push("table-lg"),e.join(" ")}buildActionButtonsTemplate(){let e=super.buildActionButtonsTemplate();if(this.showFullscreen&&this.isFullscreenSupported()){const t=`
1985
+ `}_buildSkeletonHtml(){const e=this._skeletonRowCount(),t=["w-90","w-75","w-60","w-40","w-25"],s=(this.isRowExpandEnabled()?'<td class="col-expand"></td>':"")+(this.isSelectable()?"<td></td>":""),i=this.actions||this.contextMenu?'<td class="text-end"><span class="skeleton-line w-40 ms-auto"></span></td>':"",r=this._getVisibleColumns().map((a,o)=>{const l=this.getAlignClass(a.align),d=t[o%t.length];return`<td class="${l}"><span class="skeleton-line ${d}"></span></td>`}).join("");let n="";for(let a=0;a<e;a++)n+=`<tr class="mojo-skeleton-row" aria-hidden="true">${s}${r}${i}</tr>`;return`<table class="${this.buildTableClasses()}">${this.buildTableHeaderTemplate()}<tbody>${n}</tbody></table>`}buildTableClasses(){let e=["table"];return this.tableOptions.striped&&e.push("table-striped"),this.tableOptions.bordered&&e.push("table-bordered"),this.tableOptions.hover&&e.push("table-hover"),this.tableOptions.responsive&&e.push("table-responsive"),this.tableOptions.background&&e.push(`table-${this.tableOptions.background}`),this.tableOptions.size==="sm"&&e.push("table-sm"),this.tableOptions.size==="lg"&&e.push("table-lg"),e.join(" ")}buildActionButtonsTemplate(){let e=super.buildActionButtonsTemplate();if(this.showFullscreen&&this.isFullscreenSupported()){const t=`
1745
1986
  <button class="btn btn-sm btn-outline-secondary btn-fullscreen"
1746
1987
  data-action="toggle-fullscreen"
1747
1988
  title="Toggle Fullscreen">
1748
1989
  <i class="bi bi-fullscreen"></i>
1749
1990
  </button>
1750
- `,s=e.indexOf('data-action="refresh"');if(s!==-1){const i=e.indexOf("</button>",s)+9;e=e.slice(0,i)+t+e.slice(i)}else e=t+e}return e}buildTableHeaderTemplate(){let e="";return this.isSelectable()&&(e+=`
1991
+ `,s=e.indexOf('data-action="refresh"');if(s!==-1){const i=e.indexOf("</button>",s)+9;e=e.slice(0,i)+t+e.slice(i)}else e=t+e}return this.columnChooser&&(e+=this._buildColumnChooserTemplate()),e}buildTableHeaderTemplate(){let e="";return this.isRowExpandEnabled()&&(e+='<th class="col-expand mojo-expand-cell"></th>'),this.isSelectable()&&(e+=`
1751
1992
  <th style="width: 40px; padding: 0;">
1752
1993
  <div class="mojo-select-all-cell" data-action="select-all">
1753
1994
  <div class="mojo-checkbox">
@@ -1755,7 +1996,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1755
1996
  </div>
1756
1997
  </div>
1757
1998
  </th>
1758
- `),this.columns.forEach(t=>{const{fieldKey:s}=this.parseColumnKey(t.key),i=this.sortable&&t.sortable!==!1,r=this.getSortBy()===s?this.getSortDirection():null,n=this.getSortIcon(r),a=t.label||t.title||s,o=this.getResponsiveClasses(t.visibility),l=i?`
1999
+ `),this._getVisibleColumns().forEach(t=>{const{fieldKey:s}=this.parseColumnKey(t.key),i=this.sortable&&t.sortable!==!1,r=this.getSortBy()===s?this.getSortDirection():null,n=this.getSortIcon(r),a=t.label||t.title||s,o=this.getResponsiveClasses(t.visibility),l=i?`
1759
2000
  <div class="dropdown d-inline-block ms-2">
1760
2001
  <button class="btn btn-sm btn-link p-0 text-decoration-none" type="button"
1761
2002
  data-bs-toggle="dropdown" aria-expanded="false"
@@ -1790,7 +2031,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1790
2031
  ${e}
1791
2032
  </tr>
1792
2033
  </thead>
1793
- `}buildTableFooterTemplate(){let e="";this.isSelectable()&&(e+="<td></td>");let t=0;return this.columns.forEach((s,i)=>{const r=this.getResponsiveClasses(s.visibility),n=this.getAlignClass(s.align);if(s.footer_total){const a=`col_${t}`,o=this.parseColumnKey(s.key).formatter||s.formatter;let l;o&&typeof o=="string"?l=`{{{footerTotals.${a}.value|${o}}}}`:l=`{{footerTotals.${a}.value}}`,e+=`<td class="table-footer-total ${r} ${n}" data-total-column="${a}">${l}</td>`,t++}else i===0?e+=`<td class="table-footer-label ${r} ${n}"><strong>Totals</strong></td>`:e+=`<td class="${r} ${n}"></td>`}),(this.actions||this.contextMenu)&&(e+="<td></td>"),`
2034
+ `}buildTableFooterTemplate(){let e="";return this.isRowExpandEnabled()&&(e+="<td></td>"),this.isSelectable()&&(e+="<td></td>"),this._getVisibleColumns().forEach((t,s)=>{const i=this.getResponsiveClasses(t.visibility),r=this.getAlignClass(t.align);if(t.footer_total){const n=`col_${this.footerTotalColumns.indexOf(t)}`,a=this.parseColumnKey(t.key).formatter||t.formatter;let o;a&&typeof a=="string"?o=`{{{footerTotals.${n}.value|${a}}}}`:o=`{{footerTotals.${n}.value}}`,e+=`<td class="table-footer-total ${i} ${r}" data-total-column="${n}">${o}</td>`}else s===0?e+=`<td class="table-footer-label ${i} ${r}"><strong>Totals</strong></td>`:e+=`<td class="${i} ${r}"></td>`}),(this.actions||this.contextMenu)&&(e+="<td></td>"),`
1794
2035
  <tfoot>
1795
2036
  <tr class="table-totals-row">
1796
2037
  ${e}
@@ -1846,7 +2087,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1846
2087
  </div>
1847
2088
  </div>
1848
2089
  </div>
1849
- `}}_createItemView(e,t){if(this.itemViews.has(e.id))return this.itemViews.get(e.id);const s=new this.itemClass({model:e,index:t,listView:this,tableView:this,template:this.itemTemplate,columns:this.columns,actions:this.actions,contextMenu:this.contextMenu,batchActions:this.batchActions,containerId:"items"});return this.itemViews.set(e.id,s),this._wireItemViewListeners(s),s.on("item:select",()=>this.updateBatchActionsPanel()),s.on("item:deselect",()=>this.updateBatchActionsPanel()),s.on("cell:edit",this._onCellEdit.bind(this)),s.on("cell:save",this._onCellSave.bind(this)),s.on("cell:cancel",this._onCellCancel.bind(this)),s}async onBeforeRender(){await super.onBeforeRender(),this.footerTotals=this.calculateFooterTotals()}async onAfterRender(){await super.onAfterRender(),this.hasFooterTotals&&this.updateFooterTotals(),this.updateSortIcons()}_onCellEdit(e){this.emit("cell:edit",e)}async _onCellSave(e){this.emit("cell:save",e)}_onCellCancel(e){this.emit("cell:cancel",e)}_defaultGroupHeaderTemplate(){return'<th colspan="{{colspan}}" class="list-group-header-cell">{{key}}</th>'}_groupHeaderViewOptions(e,t,s){const i=this.columns?.length||0,r=this.isSelectable()?1:0,n=this.actions||this.contextMenu?1:0;return{tagName:"tr",className:`list-group-header-row list-group-header-row--${this.groupHeaderStyle}`,colspan:Math.max(1,i+r+n)}}isFullscreenSupported(){return!!(document.fullscreenEnabled||document.mozFullScreenEnabled||document.webkitFullscreenEnabled||document.msFullscreenEnabled)}async onActionToggleFullscreen(e,t){this.isFullscreen?await this.exitFullscreen():await this.enterFullscreen()}async enterFullscreen(){try{this.element.requestFullscreen?await this.element.requestFullscreen():this.element.mozRequestFullScreen?await this.element.mozRequestFullScreen():this.element.webkitRequestFullscreen?await this.element.webkitRequestFullscreen():this.element.msRequestFullscreen&&await this.element.msRequestFullscreen(),this.isFullscreen=!0,this.element.classList.add("table-fullscreen"),this.updateFullscreenButton(),this.setupFullscreenListeners(),this.emit("table:fullscreen:enter")}catch(e){console.warn("Could not enter fullscreen:",e)}}async exitFullscreen(){try{document.exitFullscreen?await document.exitFullscreen():document.mozCancelFullScreen?await document.mozCancelFullScreen():document.webkitExitFullscreen?await document.webkitExitFullscreen():document.msExitFullscreen&&await document.msExitFullscreen(),this.isFullscreen=!1,this.element.classList.remove("table-fullscreen"),this.updateFullscreenButton(),this.emit("table:fullscreen:exit")}catch(e){console.warn("Could not exit fullscreen:",e)}}updateFullscreenButton(){const e=this.element?.querySelector(".btn-fullscreen"),t=e?.querySelector("i");e&&t&&(this.isFullscreen?(t.className="bi bi-fullscreen-exit",e.title="Exit Fullscreen"):(t.className="bi bi-fullscreen",e.title="Enter Fullscreen"))}setupFullscreenListeners(){if(this._fullscreenHandler)return;const e=()=>{!(document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement)&&this.isFullscreen&&(this.isFullscreen=!1,this.element.classList.remove("table-fullscreen"),this.updateFullscreenButton(),this.emit("table:fullscreen:exit"))};document.addEventListener("fullscreenchange",e),document.addEventListener("mozfullscreenchange",e),document.addEventListener("webkitfullscreenchange",e),document.addEventListener("msfullscreenchange",e),this._fullscreenHandler=e}cleanupFullscreenListeners(){this._fullscreenHandler&&(document.removeEventListener("fullscreenchange",this._fullscreenHandler),document.removeEventListener("mozfullscreenchange",this._fullscreenHandler),document.removeEventListener("webkitfullscreenchange",this._fullscreenHandler),document.removeEventListener("msfullscreenchange",this._fullscreenHandler),this._fullscreenHandler=null)}destroy(){this.cleanupFullscreenListeners(),super.destroy()}async onActionAdd(e,t){return this.emit("table:add",{event:e}),super.onActionAdd(e,t)}async onActionExport(e,t){const s=t.getAttribute("data-format")||"json";return this.emit("table:export",{format:s,source:this.exportSource,event:e}),super.onActionExport(e,t)}getSortBy(){const e=this.collection?.params?.sort;return e?e.startsWith("-")?e.slice(1):e:null}getSortDirection(){const e=this.collection?.params?.sort;return e&&e.startsWith("-")?"desc":"asc"}getSortIcon(e){return e==="asc"?'<i class="bi bi-sort-alpha-down text-primary"></i>':e==="desc"?'<i class="bi bi-sort-alpha-down-alt text-primary"></i>':'<i class="bi bi-three-dots-vertical text-muted"></i>'}async onActionSort(e,t){e.preventDefault();const s=t.getAttribute("data-field"),i=t.getAttribute("data-direction");if(this.collection){let r;if(i==="none"?r=void 0:i==="desc"?r=`-${s}`:r=s,this.collection.setParams({...this.collection.params,sort:r,start:0}),this.collection.restEnabled)await this.collection.fetch();else{if(r){const n=r.startsWith("-"),a=n?r.slice(1):r;this.collection.sort((o,l)=>{const d=o.get(a),h=l.get(a);return d<h?n?1:-1:d>h?n?-1:1:0})}this.render()}}this.updateSortIcons(),this.emit("table:sort",{field:s,event:e}),this.emit("params-changed")}updateSortIcons(){if(!this.element)return;const e=this.getSortBy(),t=this.getSortDirection();this.columns.forEach(s=>{if(this.sortable&&s.sortable!==!1){const{fieldKey:i}=this.parseColumnKey(s.key),r=this.element.querySelector(`[data-bs-toggle="dropdown"][data-column="${i}"]`);if(r){const n=e===i,a=this.getSortIcon(n?t:null);r.innerHTML=a;const o=r.nextElementSibling;if(o){const l=o.querySelector(`[data-field="${i}"][data-direction="asc"]`),d=o.querySelector(`[data-field="${i}"][data-direction="desc"]`),h=o.querySelector(`[data-field="${i}"][data-direction="none"]`);l&&l.classList.toggle("active",n&&t==="asc"),d&&d.classList.toggle("active",n&&t==="desc"),h&&h.classList.toggle("active",!n||e!==i)}}}})}async onActionSelectAll(e,t){e.stopPropagation();const s=this.itemViews.size>0&&Array.from(this.itemViews.values()).every(r=>r.selected);s?this.clearSelection():this.forEachItem(r=>{r.selected||r.select()});const i=this.element?.querySelector(".mojo-select-all-cell");i&&i.classList.toggle("selected",!s),this.updateBatchActionsPanel()}updateBatchActionsPanel(){if(!this.batchActions||this.batchActions.length===0)return;const e=this.getSelectedItems().length;if(this.batchBarLocation==="top"){const s=this.element?.querySelector(".batch-actions-panel-top"),i=this.element?.querySelector(".batch-select-count");s&&i&&(i.textContent=e,e>0?s.classList.remove("d-none"):s.classList.add("d-none"))}else{const s=this.element?.querySelector(".batch-actions-panel"),i=this.element?.querySelector(".batch-select-count");s&&i&&(i.textContent=e,s.style.display=e>0?"block":"none")}const t=this.element?.querySelector(".mojo-select-all-cell");if(t){const s=this.itemViews.size>0&&Array.from(this.itemViews.values()).every(n=>n.selected),i=Array.from(this.itemViews.values()).some(n=>n.selected);t.classList.toggle("selected",s),t.classList.toggle("indeterminate",!s&&i);const r=t.querySelector("i");r&&(r.className=!s&&i?"bi bi-dash":"bi bi-check")}}async onActionBatch(e,t){const s=t.getAttribute("data-action").replace("batch-",""),i=this.getSelectedItems();this.emit("batch:action",{action:s,items:i,event:e})}async onActionClearSelection(e,t){this.clearSelection(),this.updateBatchActionsPanel()}getFilterDisplayValue(e,t){if(e==="search")return`"${t}"`;const s=this.filters[e]||this.additionalFilters.find(i=>(i.name||i.key)===e);if(s&&s.type==="daterange"&&typeof t=="object"){const i=t.start||"",r=t.end||"";return`${i} to ${r}`}if(s&&s.type==="select"&&s.options){if(typeof s.options[0]=="object"){const i=s.options.find(r=>r.value===t);return i?i.label:t}return t}return t}}function Ts(){return typeof window>"u"?null:((!window.MOJO||typeof window.MOJO!="object")&&(window.MOJO={}),window.MOJO)}function Es(c){return c.__lite&&c.__lite.version||(c.WebApp=ve,c.View=S,c.Page=pe,c.Router=Te,c.Model=Q,c.Collection=de,c.Rest=ne,c.FormBuilder=fe,c.FormView=te,c.Dialog=x,c.ModalView=x,c.ProgressView=Le,c.ListView=se,c.ListViewItem=Ae,c.TableView=Lt,c.TableRow=Ge,c.DataFormatter=V,c.MOJOUtils=$,c.__lite={version:"dev",build:"web-mojo.lite"},c.mount=async function(t,s){if(!t)throw new Error("MOJO.mount(view, container) requires a view");const i=typeof s=="string"?document.querySelector(s):s;if(!i)throw new Error("MOJO.mount(view, container) container not found");if(typeof t.render!="function"||typeof t.mount!="function")throw new Error("MOJO.mount expects a View instance with render() and mount() methods");return await t.render(),await t.mount(i),t}),c}const Je=Ts();Je&&Es(Je);class Ze extends S{constructor(e={}){const{data:t,model:s,fields:i,columns:r,responsive:n,showEmptyValues:a,emptyValueText:o,...l}=e;super({tagName:"div",className:"data-view",...l}),this.data=t||{},this.fields=i||[],this.model=s||null,this.model&&(this.data=this.model),this.dataViewOptions={columns:r||2,responsive:n!==!1,showEmptyValues:a||!1,emptyValueText:o||"—",rowClass:"row g-3",itemClass:"data-view-item",labelClass:"data-view-label fw-semibold text-muted small text-uppercase",valueClass:"data-view-value"}}async onBeforeRender(){this.fields.length===0&&this.getData()&&this.generateFieldsFromData()}async renderTemplate(){const e=this.buildItemsHTML();return`
2090
+ `}}_createItemView(e,t){if(this.itemViews.has(e.id))return this.itemViews.get(e.id);const s=new this.itemClass({model:e,index:t,listView:this,tableView:this,template:this.itemTemplate,columns:this._getVisibleColumns(),actions:this.actions,contextMenu:this.contextMenu,batchActions:this.batchActions,containerId:"items"});return this.itemViews.set(e.id,s),this._wireItemViewListeners(s),s.on("item:select",()=>this.updateBatchActionsPanel()),s.on("item:deselect",()=>this.updateBatchActionsPanel()),s.on("cell:edit",this._onCellEdit.bind(this)),s.on("cell:save",this._onCellSave.bind(this)),s.on("cell:cancel",this._onCellCancel.bind(this)),s}async onBeforeRender(){await super.onBeforeRender(),this.footerTotals=this.calculateFooterTotals()}async onAfterRender(){await super.onAfterRender(),this.hasFooterTotals&&this.updateFooterTotals(),this.updateSortIcons(),await this._renderExpandedRows()}_onCellEdit(e){this.emit("cell:edit",e)}async _onCellSave(e){this.emit("cell:save",e)}_onCellCancel(e){this.emit("cell:cancel",e)}_autoRefreshShouldSkip(){if(super._autoRefreshShouldSkip())return!0;for(const e of this.itemViews.values())if(e&&e.editingCells&&e.editingCells.size>0)return!0;return!!(this.element&&this.element.querySelector(".dropdown-menu.show"))}_defaultGroupHeaderTemplate(){return'<th colspan="{{colspan}}" class="list-group-header-cell">{{key}}</th>'}_groupHeaderViewOptions(e,t,s){const i=this._getVisibleColumns().length||0,r=this.isSelectable()?1:0,n=this.actions||this.contextMenu?1:0,a=this.isRowExpandEnabled()?1:0;return{tagName:"tr",className:`list-group-header-row list-group-header-row--${this.groupHeaderStyle}`,colspan:Math.max(1,a+i+r+n)}}isFullscreenSupported(){return!!(document.fullscreenEnabled||document.mozFullScreenEnabled||document.webkitFullscreenEnabled||document.msFullscreenEnabled)}async onActionToggleFullscreen(e,t){this.isFullscreen?await this.exitFullscreen():await this.enterFullscreen()}async enterFullscreen(){try{this.element.requestFullscreen?await this.element.requestFullscreen():this.element.mozRequestFullScreen?await this.element.mozRequestFullScreen():this.element.webkitRequestFullscreen?await this.element.webkitRequestFullscreen():this.element.msRequestFullscreen&&await this.element.msRequestFullscreen(),this.isFullscreen=!0,this.element.classList.add("table-fullscreen"),this.updateFullscreenButton(),this.setupFullscreenListeners(),this.emit("table:fullscreen:enter")}catch(e){console.warn("Could not enter fullscreen:",e)}}async exitFullscreen(){try{document.exitFullscreen?await document.exitFullscreen():document.mozCancelFullScreen?await document.mozCancelFullScreen():document.webkitExitFullscreen?await document.webkitExitFullscreen():document.msExitFullscreen&&await document.msExitFullscreen(),this.isFullscreen=!1,this.element.classList.remove("table-fullscreen"),this.updateFullscreenButton(),this.emit("table:fullscreen:exit")}catch(e){console.warn("Could not exit fullscreen:",e)}}updateFullscreenButton(){const e=this.element?.querySelector(".btn-fullscreen"),t=e?.querySelector("i");e&&t&&(this.isFullscreen?(t.className="bi bi-fullscreen-exit",e.title="Exit Fullscreen"):(t.className="bi bi-fullscreen",e.title="Enter Fullscreen"))}setupFullscreenListeners(){if(this._fullscreenHandler)return;const e=()=>{!(document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement)&&this.isFullscreen&&(this.isFullscreen=!1,this.element.classList.remove("table-fullscreen"),this.updateFullscreenButton(),this.emit("table:fullscreen:exit"))};document.addEventListener("fullscreenchange",e),document.addEventListener("mozfullscreenchange",e),document.addEventListener("webkitfullscreenchange",e),document.addEventListener("msfullscreenchange",e),this._fullscreenHandler=e}cleanupFullscreenListeners(){this._fullscreenHandler&&(document.removeEventListener("fullscreenchange",this._fullscreenHandler),document.removeEventListener("mozfullscreenchange",this._fullscreenHandler),document.removeEventListener("webkitfullscreenchange",this._fullscreenHandler),document.removeEventListener("msfullscreenchange",this._fullscreenHandler),this._fullscreenHandler=null)}destroy(){this.cleanupFullscreenListeners(),super.destroy()}async onActionAdd(e,t){return this.emit("table:add",{event:e}),super.onActionAdd(e,t)}async onActionExport(e,t){const s=t.getAttribute("data-format")||"json";return this.emit("table:export",{format:s,source:this.exportSource,event:e}),super.onActionExport(e,t)}getSortBy(){const e=this.collection?.params?.sort;return e?e.startsWith("-")?e.slice(1):e:null}getSortDirection(){const e=this.collection?.params?.sort;return e&&e.startsWith("-")?"desc":"asc"}getSortIcon(e){return e==="asc"?'<i class="bi bi-sort-alpha-down text-primary"></i>':e==="desc"?'<i class="bi bi-sort-alpha-down-alt text-primary"></i>':'<i class="bi bi-three-dots-vertical text-muted"></i>'}async onActionSort(e,t){e.preventDefault();const s=t.getAttribute("data-field"),i=t.getAttribute("data-direction");if(this.collection){let r;if(i==="none"?r=void 0:i==="desc"?r=`-${s}`:r=s,this.collection.setParams({...this.collection.params,sort:r,start:0}),this.collection.restEnabled)await this.collection.fetch();else{if(r){const n=r.startsWith("-"),a=n?r.slice(1):r;this.collection.sort((o,l)=>{const d=o.get(a),h=l.get(a);return d<h?n?1:-1:d>h?n?-1:1:0})}this.render()}}this.updateSortIcons(),this.emit("table:sort",{field:s,event:e}),this.emit("params-changed")}updateSortIcons(){if(!this.element)return;const e=this.getSortBy(),t=this.getSortDirection();this.columns.forEach(s=>{if(this.sortable&&s.sortable!==!1){const{fieldKey:i}=this.parseColumnKey(s.key),r=this.element.querySelector(`[data-bs-toggle="dropdown"][data-column="${i}"]`);if(r){const n=e===i,a=this.getSortIcon(n?t:null);r.innerHTML=a;const o=r.nextElementSibling;if(o){const l=o.querySelector(`[data-field="${i}"][data-direction="asc"]`),d=o.querySelector(`[data-field="${i}"][data-direction="desc"]`),h=o.querySelector(`[data-field="${i}"][data-direction="none"]`);l&&l.classList.toggle("active",n&&t==="asc"),d&&d.classList.toggle("active",n&&t==="desc"),h&&h.classList.toggle("active",!n||e!==i)}}}})}async onActionSelectAll(e,t){e.stopPropagation();const s=this.itemViews.size>0&&Array.from(this.itemViews.values()).every(r=>r.selected);s?this.clearSelection():this.forEachItem(r=>{r.selected||r.select()});const i=this.element?.querySelector(".mojo-select-all-cell");i&&i.classList.toggle("selected",!s),this.updateBatchActionsPanel()}updateBatchActionsPanel(){if(!this.batchActions||this.batchActions.length===0)return;const e=this.getSelectedItems().length;if(this.batchBarLocation==="top"){const s=this.element?.querySelector(".batch-actions-panel-top"),i=this.element?.querySelector(".batch-select-count");s&&i&&(i.textContent=e,e>0?s.classList.remove("d-none"):s.classList.add("d-none"))}else{const s=this.element?.querySelector(".batch-actions-panel"),i=this.element?.querySelector(".batch-select-count");s&&i&&(i.textContent=e,s.style.display=e>0?"block":"none")}const t=this.element?.querySelector(".mojo-select-all-cell");if(t){const s=this.itemViews.size>0&&Array.from(this.itemViews.values()).every(n=>n.selected),i=Array.from(this.itemViews.values()).some(n=>n.selected);t.classList.toggle("selected",s),t.classList.toggle("indeterminate",!s&&i);const r=t.querySelector("i");r&&(r.className=!s&&i?"bi bi-dash":"bi bi-check")}}async onActionBatch(e,t){const s=t.getAttribute("data-action").replace("batch-",""),i=this.getSelectedItems();this.emit("batch:action",{action:s,items:i,event:e})}async onActionClearSelection(e,t){this.clearSelection(),this.updateBatchActionsPanel()}getFilterDisplayValue(e,t){if(e==="search")return`"${t}"`;const s=this.filters[e]||this.additionalFilters.find(i=>(i.name||i.key)===e);if(s&&s.type==="daterange"&&typeof t=="object"){const i=t.start||"",r=t.end||"";return`${i} to ${r}`}if(s&&s.type==="select"&&s.options){if(typeof s.options[0]=="object"){const i=s.options.find(r=>r.value===t);return i?i.label:t}return t}return t}}function Ts(){return typeof window>"u"?null:((!window.MOJO||typeof window.MOJO!="object")&&(window.MOJO={}),window.MOJO)}function Es(c){return c.__lite&&c.__lite.version||(c.WebApp=ve,c.View=C,c.Page=fe,c.Router=Te,c.Model=Q,c.Collection=de,c.Rest=ne,c.FormBuilder=ge,c.FormView=te,c.Dialog=x,c.ModalView=x,c.ProgressView=Pe,c.ListView=se,c.ListViewItem=Ae,c.TableView=Pt,c.TableRow=Ge,c.DataFormatter=V,c.MOJOUtils=$,c.__lite={version:"dev",build:"web-mojo.lite"},c.mount=async function(t,s){if(!t)throw new Error("MOJO.mount(view, container) requires a view");const i=typeof s=="string"?document.querySelector(s):s;if(!i)throw new Error("MOJO.mount(view, container) container not found");if(typeof t.render!="function"||typeof t.mount!="function")throw new Error("MOJO.mount expects a View instance with render() and mount() methods");return await t.render(),await t.mount(i),t}),c}const Je=Ts();Je&&Es(Je);class Ke extends C{constructor(e={}){const{data:t,model:s,fields:i,columns:r,responsive:n,showEmptyValues:a,emptyValueText:o,...l}=e;super({tagName:"div",className:"data-view",...l}),this.data=t||{},this.fields=i||[],this.model=s||null,this.model&&(this.data=this.model),this.dataViewOptions={columns:r||2,responsive:n!==!1,showEmptyValues:a||!1,emptyValueText:o||"—",rowClass:"row g-3",itemClass:"data-view-item",labelClass:"data-view-label fw-semibold text-muted small text-uppercase",valueClass:"data-view-value"}}async onBeforeRender(){this.fields.length===0&&this.getData()&&this.generateFieldsFromData()}async renderTemplate(){const e=this.buildItemsHTML();return`
1850
2091
  <div class="${this.dataViewOptions.rowClass}">
1851
2092
  ${e}
1852
2093
  </div>
@@ -1894,5 +2135,5 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1894
2135
  ${i}
1895
2136
  </div>
1896
2137
  </div>
1897
- `}catch(s){return console.error("Error creating nested DataView:",s),'<span class="text-danger">Error displaying nested data</span>'}}async updateData(e){return this.data=e,this.model&&typeof this.model.set=="function"&&this.model.set(e),this.fields.length>0&&!this.options.fields&&(this.fields=[]),await this.render(),this.emit("data:updated",{data:e}),this}async updateFields(e){return this.fields=e,await this.render(),this.emit("fields:updated",{fields:e}),this}async updateConfig(e){return this.dataViewOptions={...this.dataViewOptions,...e},await this.render(),this.emit("config:updated",{options:this.dataViewOptions}),this}async refresh(){if(this.model&&typeof this.model.fetch=="function")try{await this.model.fetch(),this.emit("data:refreshed",{model:this.model})}catch(e){throw this.emit("error",{error:e,message:"Failed to refresh data"}),e}return this}getCurrentData(){return this.getData()}getField(e){return this.fields.find(t=>t.name===e)||null}setFieldFormat(e,t){const s=this.getField(e);return s?(s.format=t,s.formatter=t):this.fields.push({name:e,label:this.formatLabel(e),type:this.inferFieldType(this.getData()[e],e),format:t,formatter:t}),this}addFormatPipe(e,t){const s=this.getField(e);return s&&(s.format?(s.format+=`|${t}`,s.formatter=s.format):(s.format=t,s.formatter=t)),this}clearFieldFormat(e){const t=this.getField(e);if(t){const s=this.getData(),i=this.inferFormatter(s[e],e,t.type);t.format=i,t.formatter=i}return this}getFormattedValue(e,t=null){const s=this.getField(e);if(!s)return null;const i=t!==null?t:this.getData()[e],r=s.format||s.formatter;return r&&i!=null?V.pipe(i,r):i}setFieldFormats(e){return Object.entries(e).forEach(([t,s])=>{this.setFieldFormat(t,s)}),this}getFieldFormats(){const e={};return this.fields.forEach(t=>{const s=t.format||t.formatter;s&&(e[t.name]=s)}),e}onInit(){super.onInit(),this.model&&typeof this.model.on=="function"&&this.model.on("change",(e,t)=>{t&&t.skipRender||this.isMounted()&&this.render()})}static create(e={}){return new Ze(e)}}const Fs=Object.freeze(Object.defineProperty({__proto__:null,default:Ze},Symbol.toStringTag,{value:"Module"}));return T.Collection=de,T.DataFormatter=V,T.Dialog=x,T.FormBuilder=fe,T.FormPage=_s,T.FormView=te,T.ListView=se,T.ListViewItem=Ae,T.MOJOUtils=$,T.ModalView=x,T.Model=Q,T.Page=pe,T.ProgressView=Le,T.Rest=ne,T.Router=Te,T.TableRow=Ge,T.TableView=Lt,T.View=S,T.WebApp=ve,T.default=Je,Object.defineProperties(T,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),T})({});
2138
+ `}catch(s){return console.error("Error creating nested DataView:",s),'<span class="text-danger">Error displaying nested data</span>'}}async updateData(e){return this.data=e,this.model&&typeof this.model.set=="function"&&this.model.set(e),this.fields.length>0&&!this.options.fields&&(this.fields=[]),await this.render(),this.emit("data:updated",{data:e}),this}async updateFields(e){return this.fields=e,await this.render(),this.emit("fields:updated",{fields:e}),this}async updateConfig(e){return this.dataViewOptions={...this.dataViewOptions,...e},await this.render(),this.emit("config:updated",{options:this.dataViewOptions}),this}async refresh(){if(this.model&&typeof this.model.fetch=="function")try{await this.model.fetch(),this.emit("data:refreshed",{model:this.model})}catch(e){throw this.emit("error",{error:e,message:"Failed to refresh data"}),e}return this}getCurrentData(){return this.getData()}getField(e){return this.fields.find(t=>t.name===e)||null}setFieldFormat(e,t){const s=this.getField(e);return s?(s.format=t,s.formatter=t):this.fields.push({name:e,label:this.formatLabel(e),type:this.inferFieldType(this.getData()[e],e),format:t,formatter:t}),this}addFormatPipe(e,t){const s=this.getField(e);return s&&(s.format?(s.format+=`|${t}`,s.formatter=s.format):(s.format=t,s.formatter=t)),this}clearFieldFormat(e){const t=this.getField(e);if(t){const s=this.getData(),i=this.inferFormatter(s[e],e,t.type);t.format=i,t.formatter=i}return this}getFormattedValue(e,t=null){const s=this.getField(e);if(!s)return null;const i=t!==null?t:this.getData()[e],r=s.format||s.formatter;return r&&i!=null?V.pipe(i,r):i}setFieldFormats(e){return Object.entries(e).forEach(([t,s])=>{this.setFieldFormat(t,s)}),this}getFieldFormats(){const e={};return this.fields.forEach(t=>{const s=t.format||t.formatter;s&&(e[t.name]=s)}),e}onInit(){super.onInit(),this.model&&typeof this.model.on=="function"&&this.model.on("change",(e,t)=>{t&&t.skipRender||this.isMounted()&&this.render()})}static create(e={}){return new Ke(e)}}const Fs=Object.freeze(Object.defineProperty({__proto__:null,default:Ke},Symbol.toStringTag,{value:"Module"}));return T.Collection=de,T.DataFormatter=V,T.Dialog=x,T.FormBuilder=ge,T.FormPage=Ss,T.FormView=te,T.ListView=se,T.ListViewItem=Ae,T.MOJOUtils=$,T.ModalView=x,T.Model=Q,T.Page=fe,T.ProgressView=Pe,T.Rest=ne,T.Router=Te,T.TableRow=Ge,T.TableView=Pt,T.View=C,T.WebApp=ve,T.default=Je,Object.defineProperties(T,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),T})({});
1898
2139
  //# sourceMappingURL=web-mojo.lite.iife.min.js.map