web-mojo 2.5.16 → 2.5.17

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 (98) hide show
  1. package/CHANGELOG.md +5 -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-5Fkrr6EU.js → ChatView-CgmJ3Xz4.js} +2 -2
  11. package/dist/chunks/{ChatView-5Fkrr6EU.js.map → ChatView-CgmJ3Xz4.js.map} +1 -1
  12. package/dist/chunks/{ChatView-B2BqffEV.js → ChatView-D3OS7fhZ.js} +2 -2
  13. package/dist/chunks/{ChatView-B2BqffEV.js.map → ChatView-D3OS7fhZ.js.map} +1 -1
  14. package/dist/chunks/{ContextMenu-D9hPYdgP.js → ContextMenu-B_9nFUB7.js} +2 -2
  15. package/dist/chunks/{ContextMenu-D9hPYdgP.js.map → ContextMenu-B_9nFUB7.js.map} +1 -1
  16. package/dist/chunks/{ContextMenu-D4LNIfbH.js → ContextMenu-PlRWBjfr.js} +2 -2
  17. package/dist/chunks/{ContextMenu-D4LNIfbH.js.map → ContextMenu-PlRWBjfr.js.map} +1 -1
  18. package/dist/chunks/{DataView-DJkchA5W.js → DataView-CPoWgjcc.js} +2 -2
  19. package/dist/chunks/{DataView-DJkchA5W.js.map → DataView-CPoWgjcc.js.map} +1 -1
  20. package/dist/chunks/{DataView-DNiKWiXb.js → DataView-DGkg9oLi.js} +2 -2
  21. package/dist/chunks/{DataView-DNiKWiXb.js.map → DataView-DGkg9oLi.js.map} +1 -1
  22. package/dist/chunks/FormView-B6jVd903.js +2 -0
  23. package/dist/chunks/FormView-B6jVd903.js.map +1 -0
  24. package/dist/chunks/FormView-CAgltfRO.js +2 -0
  25. package/dist/chunks/FormView-CAgltfRO.js.map +1 -0
  26. package/dist/chunks/{ListView-ZyZEGyko.js → ListView-BptW0g4E.js} +2 -2
  27. package/dist/chunks/{ListView-ZyZEGyko.js.map → ListView-BptW0g4E.js.map} +1 -1
  28. package/dist/chunks/{ListView-B3hlgsdC.js → ListView-DybArz58.js} +2 -2
  29. package/dist/chunks/{ListView-B3hlgsdC.js.map → ListView-DybArz58.js.map} +1 -1
  30. package/dist/chunks/{MetricsCountryMapView-Bs6PNvws.js → MetricsCountryMapView-6FYDC-1E.js} +2 -2
  31. package/dist/chunks/{MetricsCountryMapView-Bs6PNvws.js.map → MetricsCountryMapView-6FYDC-1E.js.map} +1 -1
  32. package/dist/chunks/{MetricsCountryMapView-DNE3x_CQ.js → MetricsCountryMapView-BHE0m0JK.js} +2 -2
  33. package/dist/chunks/{MetricsCountryMapView-DNE3x_CQ.js.map → MetricsCountryMapView-BHE0m0JK.js.map} +1 -1
  34. package/dist/chunks/{Modal-CVqOVhfL.js → Modal-D0hcs-vA.js} +3 -3
  35. package/dist/chunks/{Modal-CVqOVhfL.js.map → Modal-D0hcs-vA.js.map} +1 -1
  36. package/dist/chunks/{Modal-m9_8tL1w.js → Modal-FuBSXLvN.js} +3 -3
  37. package/dist/chunks/{Modal-m9_8tL1w.js.map → Modal-FuBSXLvN.js.map} +1 -1
  38. package/dist/chunks/Passkeys-CjvKdlzH.js +2 -0
  39. package/dist/chunks/Passkeys-CjvKdlzH.js.map +1 -0
  40. package/dist/chunks/Passkeys-EG7YlSMs.js +2 -0
  41. package/dist/chunks/Passkeys-EG7YlSMs.js.map +1 -0
  42. package/dist/chunks/{TokenManager-D6DGDHN3.js → TokenManager-CBwgiqS8.js} +2 -2
  43. package/dist/chunks/{TokenManager-D6DGDHN3.js.map → TokenManager-CBwgiqS8.js.map} +1 -1
  44. package/dist/chunks/{TokenManager-BcY1Fj0K.js → TokenManager-CeYribH4.js} +2 -2
  45. package/dist/chunks/{TokenManager-BcY1Fj0K.js.map → TokenManager-CeYribH4.js.map} +1 -1
  46. package/dist/chunks/{User-BHZSj7Qq.js → User-BLVnk7mU.js} +2 -2
  47. package/dist/chunks/{User-qfXSd_AW.js.map → User-BLVnk7mU.js.map} +1 -1
  48. package/dist/chunks/{User-qfXSd_AW.js → User-CG5ID4Rh.js} +2 -2
  49. package/dist/chunks/{User-BHZSj7Qq.js.map → User-CG5ID4Rh.js.map} +1 -1
  50. package/dist/chunks/{UserProfileView-DIHp5p7t.js → UserProfileView-Bf2lkDfq.js} +2 -2
  51. package/dist/chunks/{UserProfileView-DIHp5p7t.js.map → UserProfileView-Bf2lkDfq.js.map} +1 -1
  52. package/dist/chunks/{UserProfileView-BQZ_Rk5P.js → UserProfileView-CnieZqTC.js} +2 -2
  53. package/dist/chunks/{UserProfileView-BQZ_Rk5P.js.map → UserProfileView-CnieZqTC.js.map} +1 -1
  54. package/dist/chunks/{WebApp-XQsYVh3-.js → WebApp-Dfqt3Elu.js} +2 -2
  55. package/dist/chunks/{WebApp-XQsYVh3-.js.map → WebApp-Dfqt3Elu.js.map} +1 -1
  56. package/dist/chunks/{WebApp-CfsvU5Eo.js → WebApp-xZyg6yDI.js} +2 -2
  57. package/dist/chunks/{WebApp-CfsvU5Eo.js.map → WebApp-xZyg6yDI.js.map} +1 -1
  58. package/dist/chunks/{admin-models-DZuzX9qA.js → admin-models-C7I47DbC.js} +2 -2
  59. package/dist/chunks/{admin-models-DZuzX9qA.js.map → admin-models-C7I47DbC.js.map} +1 -1
  60. package/dist/chunks/{admin-models-DOBTTiyR.js → admin-models-CI9bXwXg.js} +2 -2
  61. package/dist/chunks/{admin-models-DOBTTiyR.js.map → admin-models-CI9bXwXg.js.map} +1 -1
  62. package/dist/chunks/{exportChart--IHi-8qB.js → exportChart-1JhJxyMQ.js} +2 -2
  63. package/dist/chunks/{exportChart--IHi-8qB.js.map → exportChart-1JhJxyMQ.js.map} +1 -1
  64. package/dist/chunks/{exportChart-CsDl-pYc.js → exportChart-DNlfH7QN.js} +2 -2
  65. package/dist/chunks/{exportChart-CsDl-pYc.js.map → exportChart-DNlfH7QN.js.map} +1 -1
  66. package/dist/chunks/{index-C-rCHqyo.js → index-CUyzj6gq.js} +2 -2
  67. package/dist/chunks/{index-C-rCHqyo.js.map → index-CUyzj6gq.js.map} +1 -1
  68. package/dist/chunks/{index-DkoREh-Z.js → index-DcHktHmQ.js} +2 -2
  69. package/dist/chunks/{index-DkoREh-Z.js.map → index-DcHktHmQ.js.map} +1 -1
  70. package/dist/chunks/{version-j1iZ1PJ7.js → version-B5APgsRL.js} +2 -2
  71. package/dist/chunks/{version-j1iZ1PJ7.js.map → version-B5APgsRL.js.map} +1 -1
  72. package/dist/chunks/{version-3I3mx_ZJ.js → version-DQw2_GiY.js} +2 -2
  73. package/dist/chunks/{version-3I3mx_ZJ.js.map → version-DQw2_GiY.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 +57 -54
  87. package/dist/web-mojo.lite.iife.js.map +1 -1
  88. package/dist/web-mojo.lite.iife.min.js +108 -108
  89. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  90. package/package.json +1 -1
  91. package/dist/chunks/FormView-DCw6-3LL.js +0 -2
  92. package/dist/chunks/FormView-DCw6-3LL.js.map +0 -1
  93. package/dist/chunks/FormView-DJtpEn4i.js +0 -2
  94. package/dist/chunks/FormView-DJtpEn4i.js.map +0 -1
  95. package/dist/chunks/Passkeys-JmDAIwGA.js +0 -2
  96. package/dist/chunks/Passkeys-JmDAIwGA.js.map +0 -1
  97. package/dist/chunks/Passkeys-ax-A6pZk.js +0 -2
  98. package/dist/chunks/Passkeys-ax-A6pZk.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:a,queryParams:n}=this.parseInput(e);r&&await this.handleRouteChange(a,n)}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,a)=>{i[r]=s[a+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),a=new URLSearchParams(r);if(a.has("page")){t=a.get("page")||this.defaultRoute;for(const[n,o]of a)n!=="page"&&(s[n]=o)}else{i.startsWith("/")?t=i.substring(1)||this.defaultRoute:t=i||this.defaultRoute;for(const[n,o]of a)s[n]=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(([n,o])=>{o!=null&&o!==""&&r.searchParams.set(n,String(o))});const a=r.toString();s?window.history.replaceState(i,"",a):window.history.pushState(i,"",a)}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(a=>{try{const n=r(t,e);a(n)}catch(n){console.error(`Error in async event listener for '${e}':`,n),this.emitError(n,e,r),a()}}));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 a=r!==void 0?r:i;return t.call(this,s,a)}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 a=()=>{r&&clearTimeout(r)},n=o=>{a(),s(o)};this.once(e,n),t&&(r=setTimeout(()=>{this.off(e,n),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(a=>t.append(`${i}[]`,a)):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 a=this.categorizeError(new Error("HTTP Error"),e.status);s.errors=r.errors||{},s.message=r.message||a.message,s.reason=a.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 a={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{a=await this.processRequestInterceptors(a)}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")a.headers[this.config.duidHeader]=this.duid;else if(a.method==="GET"){const l=new URL(a.url);l.searchParams.append("duid",this.duid),a.url=l.toString()}else a.data&&typeof a.data=="object"&&!(a.data instanceof FormData)&&(a.data.duid=this.duid);const n={method:a.method,headers:a.headers},o=[];a.options.timeout&&o.push(AbortSignal.timeout(a.options.timeout)),a.options.signal&&o.push(a.options.signal),o.length>1?n.signal=AbortSignal.any?AbortSignal.any(o):o[0]:o.length===1&&(n.signal=o[0]),a.data&&["POST","PUT","PATCH"].includes(a.method)&&(a.data instanceof FormData?(n.body=a.data,delete n.headers["Content-Type"]):typeof a.data=="object"?n.body=JSON.stringify(a.data):n.body=a.data);try{const l=await fetch(a.url,n),d=await this.processResponseInterceptors(l,a);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,a),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 a=await fetch(r.url,{method:r.method,headers:r.headers,signal:r.options.signal});if(!a.ok)throw new Error(`Download failed: ${a.status} ${a.statusText}`);const n=a.headers.get("content-disposition");let o=s.filename||"download";if(n){const p=n.match(/filename="?(.+)"?/);p&&p.length>1&&(o=p[1])}const l=a.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(a){return console.error("Download error:",a),{success:!1,message:a.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 a=await fetch(r.url,{method:r.method,headers:r.headers,signal:r.options.signal});if(!a.ok)throw new Error(`Download failed: ${a.status} ${a.statusText}`);const n=await a.blob(),o=a.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(n),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(a){return console.error("Download error:",a),{success:!1,message:a.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 a=new XMLHttpRequest;s.onProgress&&typeof s.onProgress=="function"&&(a.upload.onprogress=s.onProgress),a.onload=function(){a.status>=200&&a.status<300?i({data:a.response,status:a.status,statusText:a.statusText,xhr:a}):r(new Error(`Upload failed: ${a.status} ${a.statusText}`))},a.onerror=function(){r(new Error("Upload failed: Network error"))},a.ontimeout=function(){r(new Error("Upload failed: Timeout"))},a.open("PUT",e),a.setRequestHeader("Content-Type",t.type),s.timeout&&(a.timeout=s.timeout),a.send(t)})}async uploadMultipart(e,t,s={},i={}){const r=new FormData;if(t instanceof FileList)Array.from(t).forEach((a,n)=>{r.append(`file_${n}`,a)});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(([a,n])=>{r.append(a,n)}),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 ae=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==="")return e;const t=parseFloat(e);return isNaN(t)?e:t*1e3}),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"},a=t&&typeof t=="object"?{...r,...t}:r;let n=i;if(a.urls!==!1){const o=/(^|\s)((?:https?:\/\/|www\.)[^\s<]+)/gi;n=n.replace(o,(l,d,h)=>{const u=h.startsWith("www.")?`https://${h}`:h;return`${d}<a href="${u}" target="${a.target}" rel="${a.rel}">${h}</a>`})}if(a.emails!==!1){const o=/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;n=n.replace(o,l=>`<a href="mailto:${l}">${l}</a>`)}return n}clipboard(e,t="text"){if(e==null)return"";const s=String(e),i=this.escapeHtml(s),r=t!=="icon-only",a=`
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==="")return e;const t=parseFloat(e);return isNaN(t)?e:t*1e3}),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"
@@ -9,10 +9,10 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
9
9
  </button>`.trim();return`
10
10
  <span class="mojo-clipboard d-inline-flex align-items-center">
11
11
  ${r?`<span class="font-monospace">${i}</span>`:""}
12
- ${a}
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.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,a)=>this.apply(a.name,r,...a.args),e):e}parsePipeString(e,t=null){const s=[],i=e.split("|").map(r=>r.trim());for(const r of i){const a=this.parseFormatter(r,t);a&&s.push(a)}return s}parseFormatter(e,t=null){const s=e.match(/^([a-zA-Z_]\w*)\s*\((.*)\)$/);if(s){const[,r,a]=s,n=a?this.parseArguments(a,t):[];return{name:r,args:n}}const i=e.match(/^([a-zA-Z_]\w*)(?::(.+))?$/);if(i){const[,r,a]=i,n=a?this.parseColonArguments(a,t):[];return{name:r,args:n}}return null}parseArguments(e,t=null){const s=[];let i="",r=!1,a=null,n=0;for(let o=0;o<e.length;o++){const l=e[o];!r&&(l==='"'||l==="'")?(r=!0,a=l,i+=l):r&&l===a&&e[o-1]!=="\\"?(r=!1,a=null,i+=l):!r&&l==="{"?(n++,i+=l):!r&&l==="}"?(n--,i+=l):!r&&n===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,a=null;for(let n=0;n<e.length;n++){const o=e[n];!r&&(o==='"'||o==="'")?(r=!0,a=o,i+=o):r&&o===a&&e[n-1]!=="\\"?(r=!1,a=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[n,o,l]=e.split("-").map(Number);s=new Date(n,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 a=new RegExp(`(${Object.keys(i).join("|")})`,"g");return r=r.replace(a,n=>i[n]||n),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 a=t;const n=Object.keys(r).sort((o,l)=>l.length-o.length);for(const o of n)a=a.replace(new RegExp(o,"g"),r[o]);return a}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 a=i&&i.locale||"en-US",n=i&&i.timeZone?i.timeZone:void 0,o=()=>{let k="";try{const ie=new Intl.DateTimeFormat(a,{hour:"2-digit",minute:"2-digit",timeZoneName:"short",...n?{timeZone:n}:{}}).formatToParts(r).find(z=>z.type==="timeZoneName");if(k=ie?ie.value:"",k&&/^GMT[+-]/i.test(k))try{const re=new Intl.DateTimeFormat(a,{timeStyle:"short",timeZoneName:"short",...n?{timeZone:n}:{}}).formatToParts(r).find(Is=>Is.type==="timeZoneName");re&&re.value&&!/^GMT[+-]/i.test(re.value)&&(k=re.value)}catch{}if(k&&/\s/.test(k)){const z=k.split(/\s+/).map(re=>re[0]).join("").toUpperCase();z.length>=2&&z.length<=4&&(k=z)}}catch{k=""}return k};if(!n){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(a,{timeZone:n,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(a,{timeZone:n,month:"long"}).format(r),M=new Intl.DateTimeFormat(a,{timeZone:n,month:"short"}).format(r),R=new Intl.DateTimeFormat(a,{timeZone:n,weekday:"long"}).format(r),oe=new Intl.DateTimeFormat(a,{timeZone:n,weekday:"short"}).format(r),be={YYYY:h,YY:h?h.slice(-2):"",MMMM:j,MMM:M,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},I=(k,Y)=>{if(!k)return"";const ie=new RegExp(`(${Object.keys(Y).sort((z,re)=>re.length-z.length).join("|")})`,"g");return k.replace(ie,z=>Y[z]??z)},H=I(t,be),Pt=I(s,ye),Ds=o();return H&&Pt?`${H} ${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),a=this.date(i,s);return!r||!a?"":`${r} - ${a}`}datetime_range(e,t=null,s="MM/DD/YYYY",i="HH:mm"){if(!e)return"";const r=t||new Date,a=this.datetime(e,s,i),n=this.datetime(r,s,i);return!a||!n?"":`${a} - ${n}`}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,a=Math.abs(r),n=Math.floor(a/1e3),o=Math.floor(n/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(n>30){const u=h?"in ":"",m=h?"":" ago";return u+n+" 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(),a=i<0?"-":"";let n,o;r.length<=2?(n="0",o=r.padStart(2,"0")):(n=r.slice(0,-2),o=r.slice(-2)),n=n.replace(/\B(?=(\d{3})+(?!\d))/g,",");let l;if(s===0)parseInt(o)>=50&&(n=(parseInt(n.replace(/,/g,""))+1).toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")),l=n;else if(s===2)l=`${n}.${o}`;else{const d=o.slice(0,s).padEnd(s,"0");l=`${n}.${d}`}return a+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"],a=t?1024:1e3;let n=i,o=0;for(;n>=a&&o<r.length-1;)n/=a,o++;const l=o===0?0:s;return`${n.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 a="th";return i===1&&r!==11?a="st":i===2&&r!==12?a="nd":i===3&&r!==13&&(a="rd"),t?a:s+a}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 a=String(t),n=a.match(/^\/(.+)\/([a-z]*)$/i);if(n){const[,o,l]=n;try{return r.replace(new RegExp(o,l),String(s))}catch{}}return String(i).includes("g")?r.split(a).join(String(s)):r.replace(a,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),a=i.substring(0,r),n=i.substring(i.length-r);return`${a}${s}${n}`}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)),a=i.slice(-s);return r+a}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)}`:"",a=t.class?` class="${t.class}"`:"";return`<a href="mailto:${s}${i}${r}"${a}>${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(a=>this.badge(a,t)).join(" ");const s=String(e);if(typeof t=="string"&&t.includes("=")){const a=Object.fromEntries(t.split(",").map(l=>l.split("=").map(d=>d.trim()))),n=a[s]||a[s.toLowerCase()]||this.inferBadgeType(s);return`<span class="badge ${n?`bg-${n}`:"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 a=String(e).toLowerCase(),n={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[a]||n[a]||"",d=s[a]||o[a]||"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,a={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;"},n=a[t]||a.md,l=`object-fit-cover ${s}`.trim();return`<img src="${r}" class="${l}" style="${n}" alt="${i}" />`}tooltip(e,t="",s="top",i=""){if(e==null)return"";const r=String(e),a=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="${a}">${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 a=Math.abs(r)===1?t:s||t+"s";return i?`${r} ${a}`:a}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 a=e.slice(),n=!1;if(i&&e.length>i&&(a=e.slice(0,i),n=!0),n){const o=e.length-i;return`${a.join(", ")}, ${s} ${o} ${r}`}return a.length===2?`${a[0]} ${s} ${a[1]}`:`${a.slice(0,-1).join(", ")}, ${s} ${a[a.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 a;switch(t){case"s":case"sec":case"seconds":a=r*1e3;break;case"m":case"min":case"minutes":a=r*6e4;break;case"h":case"hr":case"hours":a=r*36e5;break;case"d":case"day":case"days":a=r*864e5;break;default:a=r}const n=[{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(a===0)return s?"0s":"0 seconds";const o=Math.abs(a),l=a<0?"-":"",d=[];let h=o;for(const u of n)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=a=>Array.from(a).map(n=>n.toString(16).padStart(2,"0")).join("");if(typeof e=="number"){let a=Math.abs(Math.trunc(e)).toString(16);a.length%2&&(a="0"+a),i=a}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(a=>typeof a=="number"))i=r(Uint8Array.from(e.map(a=>a&255)));else{const n=new TextEncoder().encode(String(e));i=r(n)}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 a of s)r+=String.fromCharCode(a);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,a=-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){a=o;break}}a>-1&&(s=t.substring(0,a).trim(),i=t.substring(a+1).trim());const n=this.getNestedValue(e,s);return i?V.pipe(n,i,e):n}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 a=s[r];if(i==null)return;if(r===0)if(Xe(i,a)){const n=i[a];typeof n=="function"?i=n.call(e):i=n}else return;else{if(i&&typeof i.getContextValue=="function"){const n=s.slice(r).join(".");return i.getContextValue(n)}if(Array.isArray(i)&&!isNaN(a))i=i[parseInt(a)];else if(Xe(i,a))i=i[a];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 a=()=>{clearTimeout(s),e(...r)};clearTimeout(s),s=setTimeout(a,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 n;return i<2?n="very-weak":i<4?n="weak":i<6?n="fair":i<8?n="good":n="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:n,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",a="0123456789",n="!@#$%^&*()_+-=[]{}|;:,.<>?";s.excludeAmbiguous&&(i=i.replace(/[il]/g,""),r=r.replace(/[IOL]/g,""),a=a.replace(/[01]/g,""),n=n.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+=a,l.push(a[Math.floor(Math.random()*a.length)])),s.includeSpecialChars&&(o+=n,l.push(n[Math.floor(Math.random()*n.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 n=0;n<e.length;n++){const o=e[n];if(o==="(")i++;else if(o===")")i--;else if(o==="|"&&i===0){r=n;break}}r>-1&&(t=e.substring(0,r).trim(),s=e.substring(r+1).trim());let a;return t in this&&!Qe.has(t)&&t!=="_data"&&t!=="_rootContext"?a=this[t]:a=$.getNestedValue(this._data,t),s&&a!==void 0?V.pipe(a,s,this._rootContext||this._data):a}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]"},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=>Ht.has(r)))return;if(e&&e.startsWith(".")){let i=e.substring(1),r=!1,a=null;const n=i.indexOf("|");if(n!==-1&&(a=i.substring(n+1).trim(),i=i.substring(0,n).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)))),a&&o!==void 0)try{const l=qt();l&&typeof l.pipe=="function"&&(o=l.pipe(o,a,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,a,n,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,a=e.split("."),n=0;r!=null&&n<a.length;)if(r&&typeof r.getContextValue=="function"&&n<a.length)try{const l=a.slice(n).join(".");r=r.getContextValue(l),n=a.length,r!==void 0&&(o=!0)}catch{n===a.length-1&&(o=Fe(r,a[n])||it(r,a[n])),r=r[a[n++]]}else n===a.length-1&&(o=Fe(r,a[n])||it(r,a[n])),r=r[a[n++]];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),a=[];let n,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(n=r.pos,l=r.scanUntil(u),l)for(let f=0;f<l.length;++f)d=l.charAt(f),d===`
15
- `?a.push(["text",d]):a.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,n,r.pos],a.push(h);else if(o==="/"){let f;for(let g=a.length-1;g>=0;--g)if((a[g][0]==="#"||a[g][0]==="^")&&a[g][1]===l){f=a[g];break}f&&f.length===4&&f.push(r.pos),a.push([o,l,n,r.pos])}else a.push([o,l,n,r.pos])}return this.nestSections(this.squashTokens(a))}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 a=e[r];switch(a[0]){case"#":case"^":const n=[a[0],a[1],a[2],a[3],[],a[4]||null];s.push(n),i.push(n),s=n[4];break;case"/":const o=i.pop();o&&(o[5]=a[2],s=i.length>0?i[i.length-1][4]:t);break;default:s.push(a)}}return t}render(e,t,s,i){const r=this.getConfigTags(i)||["{{","}}"],a=this.parse(e,r),n=new Map;return this.renderTokens(a,new we(t),s,e,i,n)}renderTokens(e,t,s,i,r,a){a&&!t.renderCache&&(t.renderCache=a);let n="";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,a);n+=p}else if(typeof d=="object"||typeof d=="string"||typeof d=="number"){const u=t.push(d);t.renderCache&&(u.renderCache=t.renderCache),n+=this.renderTokens(h,u,s,i,r,a)}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&&(n+=d)}else d&&(n+=this.renderTokens(h,t,s,i,r,a));break;case"^":if(d=t.lookup(l[1]),!d||le(d)&&d.length===0){const u=l[4];u&&le(u)&&(n+=this.renderTokens(u,t,s,i,r,a))}break;case">":if(!s)continue;d=ue(s)?s(l[1]):s[l[1]],d!=null&&(n+=this.render(d,t.view,s,r));break;case"&":d=t.lookup(l[1]),d!=null&&(n+=d);break;case"name":d=t.lookup(l[1]),d!=null&&(n+=tt(d));break;case"text":n+=l[1];break}}return n}getConfigTags(e){return et(e)&&le(e.tags)?e.tags:null}}function De(c){return c.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}const Ie=new rt,D={name:"MOJO Mustache",version:"1.0.0",tags:["{{","}}"],Scanner:st,Context:we,Writer:rt,escape:tt,clearCache(){return Ie.clearCache()},parse(c,e){return Ie.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)),Ie.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 n=>{const{prior:o,done:l}=this._enterDispatchChain(n);try{o&&await o;const d=n.target.closest("[data-action]");if(d&&this.shouldHandle(d,n)){const u=d.getAttribute("data-action");if(d.tagName==="A"&&n.preventDefault(),this.hideTooltip(d),await this.dispatch(u,n,d)){n.preventDefault(),n.stopPropagation(),n.handledByChild=!0;return}}const h=n.target.closest("a[href], [data-page]");if(h&&!h.hasAttribute("data-action")&&this.shouldHandle(h,n)){if(n.ctrlKey||n.metaKey||n.shiftKey||n.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),n.preventDefault(),n.stopPropagation(),n.handledByChild=!0,h.hasAttribute("data-page")?await this.view.handlePageNavigation(h):await this.view.handleHrefNavigation(h)}}finally{l()}},s=async n=>{const{prior:o,done:l}=this._enterDispatchChain(n);try{o&&await o;const d=n.target.closest("[data-change-action]");if(d&&this.shouldHandle(d,n)){const u=d.getAttribute("data-change-action");await this.dispatchChange(u,n,d)&&(n.stopPropagation(),n.handledByChild=!0);return}const h=n.target.closest("[data-action]");if(h&&this.isFormControl(h)&&this.shouldHandle(h,n)){const u=h.getAttribute("data-action");await this.dispatch(u,n,h)&&(n.stopPropagation(),n.handledByChild=!0)}}finally{l()}},i=n=>{const o=n.target.closest("[data-change-action]");if(o&&this.shouldHandle(o,n)&&n.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,n,o).then(b=>{b&&(n.stopPropagation(),n.handledByChild=!0)})},p);this.debounceTimers.set(f,g);return}const l=n.target.closest("[data-action]");if(!l||!this.isFormControl(l)||l.hasAttribute("data-change-action")||!this.shouldHandle(l,n))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,n,l).then(f=>{f&&(n.stopPropagation(),n.handledByChild=!0)})},u);this.debounceTimers.set(m,p);return}this.dispatch(d,n,l).then(m=>{m&&(n.stopPropagation(),n.handledByChild=!0)})},r=async n=>{if(n.target.matches('[data-filter="search"]'))return;const o=n.target.closest("[data-keydown-action]")||n.target.closest("[data-change-action]");if(!o)return;const{prior:l,done:d}=this._enterDispatchChain(n);try{if(l&&await l,!this.shouldHandle(o,n))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(n.key)){const u=o.getAttribute("data-keydown-action")||o.getAttribute("data-change-action");await this.dispatch(u,n,o)&&(n.preventDefault(),n.stopPropagation(),n.handledByChild=!0)}}finally{d()}},a=n=>{const o=n.target.closest("form[data-action]");if(!o||!this.shouldHandle(o,n))return;n.preventDefault();const l=o.getAttribute("data-action");this.dispatch(l,n,o)};e.addEventListener("click",t),e.addEventListener("change",s),e.addEventListener("input",i),e.addEventListener("keydown",r),e.addEventListener("submit",a),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:a})}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),a=`handleAction${r(e)}`;if(typeof i[a]=="function")try{return t.preventDefault(),await i[a](t,s),!0}catch(l){return console.error(`Error in action ${e}:`,l),i.handleActionError(e,l,t,s),!0}const n=`onAction${r(e)}`;if(typeof i[n]=="function")try{return await i[n](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,a=`onChange${(n=>n.includes("-")?n.split("-").map(o=>o[0].toUpperCase()+o.slice(1)).join(""):n[0].toUpperCase()+n.slice(1))(e)}`;if(typeof i[a]=="function")try{return await i[a](t,s),!0}catch(n){return console.error(`Error in onChange ${e}:`,n),i.handleActionError?.(e,n,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 Me={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(){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(a=>S._warn(`Lazy child render error (${r.id})`,a)))}},{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,a=typeof window<"u"?window.innerWidth:0;i.top<r+120&&i.bottom>-120&&i.left<a&&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 a=this.findRouter();a&&typeof a.navigateToPage=="function"?await a.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}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 a={},n=r.trim();return n&&(a.customClass=n),new window.bootstrap.Tooltip(t,a)})}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 n=document.createElement("textarea");n.value=i,document.body.appendChild(n),n.select(),document.execCommand("copy"),document.body.removeChild(n)}const r=t.querySelector("i"),a=r&&r.className;return r&&(r.className="bi bi-check",setTimeout(()=>{r.className=a},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,Me);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((a,n)=>(a._dialogZIndex||0)-(n._dialogZIndex||0)),r=document.querySelector(".table-fullscreen")||document.body;e.forEach((a,n)=>{if(n>=s.length)return;const o=s[n];a.style.zIndex=o._dialogZIndex-5,a.parentNode!==r&&r.appendChild(a)})}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.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(Is=>Is.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),M=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:M,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},I=(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=I(t,be),Pt=I(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 Ie=new rt,D={name:"MOJO Mustache",version:"1.0.0",tags:["{{","}}"],Scanner:st,Context:we,Writer:rt,escape:tt,clearCache(){return Ie.clearCache()},parse(c,e){return Ie.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)),Ie.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 Me={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(){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}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,Me);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")),`
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 a=r.icon?`<i class="${r.icon} me-2"></i>`:"",n=r.label||"";if(r.href)return`<li><a class="dropdown-item" href="${r.href}"${r.target?` target="${r.target}"`:""}>${a}${n}</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}>${a}${n}</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.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`
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>
@@ -38,14 +38,14 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
38
38
  </div>
39
39
  `}async filterContextMenuItems(){if(!this.contextMenu||!this.contextMenu.items)return[];const e=[];for(const t of this.contextMenu.items){if(t.type==="divider"){e.push(t);continue}if(t.permissions)try{const s=this.getApp?.();let i=s?.activeUser||s?.getState?.("activeUser")||null;if(!i&&typeof window<"u"&&window.getApp)try{i=window.getApp()?.activeUser}catch{}if(i?.hasPermission){if(!i.hasPermission(t.permissions))continue}else continue}catch(s){console.warn("ModalView: error checking permissions for context menu item:",s);continue}e.push(t)}return e}async buildBody(){const e=`modal-body ${this.noBodyPadding?"modal-body-flush":""} ${this.bodyClass}`.replace(/\s+/g," ").trim();return this.bodyView?(this.bodyView.replaceById=!0,`<div class="${e}" data-view-container="body">
40
40
  <div id="${this.bodyView.id}"></div>
41
- </div>`):!this.body&&this.body!==""?"":`<div class="${e}">${this.body}</div>`}async buildFooter(){if(this.footerView)return`<div class="modal-footer ${this.footerClass}" data-view-container="footer"></div>`;if(this.footer!==null&&typeof this.footer=="string")return`<div class="modal-footer ${this.footerClass}">${this.footer}</div>`;if(this.buttons&&this.buttons.length>0){const e=this.buttons.map(t=>{const s=t.dismiss?'data-bs-dismiss="modal"':"",i=t.action?`data-action="${t.action}"`:"",r=t.id?`id="${t.id}"`:"",a=t.disabled?"disabled":"";return`
41
+ </div>`):!this.body&&this.body!==""?"":`<div class="${e}">${this.body}</div>`}async buildFooter(){if(this.footerView)return`<div class="modal-footer ${this.footerClass}" data-view-container="footer"></div>`;if(this.footer!==null&&typeof this.footer=="string")return`<div class="modal-footer ${this.footerClass}">${this.footer}</div>`;if(this.buttons&&this.buttons.length>0){const e=this.buttons.map(t=>{const s=t.dismiss?'data-bs-dismiss="modal"':"",i=t.action?`data-action="${t.action}"`:"",r=t.id?`id="${t.id}"`:"",n=t.disabled?"disabled":"";return`
42
42
  <button type="${t.type||"button"}"
43
43
  class="btn ${t.class||"btn-secondary"}"
44
- ${r} ${s} ${i} ${a}>
44
+ ${r} ${s} ${i} ${n}>
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(),a=40,n=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-a);let o=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-a),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,n);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 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=`
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>
@@ -139,21 +139,21 @@ 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=ae,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[a,n]of Object.entries(e))r=this._setNestedAttribute(a,n)||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),typeof e=="string")this.emit(`change:${e}`,t,this);else for(const[a,n]of Object.entries(e)){const o=this._getNestedValue(a);JSON.stringify(this._getNestedValue(a,i))!==JSON.stringify(o)&&this.emit(`change:${a}`,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 a=this.attributes[i],n=this[i];for(let l=1;l<s.length-1;l++){const d=s[l];(!a[d]||typeof a[d]!="object")&&(a[d]={}),(!n[d]||typeof n[d]!="object")&&(n[d]={}),a=a[d],n=n[d]}const o=s[s.length-1];return a[o]=t,n[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 a=e.id||this.getId();if(!a&&this.options.requiresId!==!1)throw new Error("Model: ID is required for fetching");t=this.buildUrl(a)}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(a){if(a.name==="AbortError")return console.info("Model: Request was cancelled"),this;throw a}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 a=await this.rest[i](r,e,t.params);return a.success?a.data.status?(this.originalAttributes={...this.attributes},this.set(a.data.data),this.errors={}):this.errors=a.data:this.errors=a.errors||{},a}catch(a){return{success:!1,error:a.message,status:a.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 a=r(s,this);if(a!==!0){this.errors[e]=a||`${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,Me);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=ae,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(a){return a.name==="AbortError"?(console.info("Collection: Request was cancelled"),{success:!1,error:"Request cancelled",status:0}):{success:!1,error:a.message,status:a.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 a=this.options.parse?this.parse(r):r.data;t.reset!==!1&&this.options.reset&&this.reset(),this.add(a,{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 a=await this.fetch();i(a)}catch(a){r(a)}},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()}`,a=this._buildDateRangeSuffix(i),n=`${r}${a}.${e}`,l={json:"application/json",csv:"text/csv"}[e]||"*/*";return i.filename=n,this.rest.download(s,i,{...t,filename:n,headers:{Accept:l}})}_buildDateRangeSuffix(e={}){const t=e.dr_start,s=e.dr_end;if(!t&&!s)return"";const i=n=>n?String(n).replace(/[^\dA-Za-z_-]/g,"-"):"",r=[],a=e.dr_field||"daterange";return r.push(i(a)),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 a;r instanceof this.ModelClass?(a=r,a.collection||(a.collection=this)):a=new this.ModelClass(r,{endpoint:this.endpoint,collection:this});const n=this.models.findIndex(o=>o.id===a.id);n!==-1?t.merge!==!1&&this.models[n].set(a.attributes):(this.models.push(a),i.push(a))}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 a=-1;if(typeof r=="string"||typeof r=="number"?a=this.models.findIndex(n=>n.id==r):a=this.models.indexOf(r),a!==-1){const n=this.models.splice(a,1)[0];n.collection===this&&(n.collection=null),i.push(n)}}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 a=i.get(s),n=r.get(s);return a<n?-1:a>n?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,Me);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},a=this.createToastElement(i,e,t,r);if(this.container.appendChild(a),typeof bootstrap>"u")throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const n=new bootstrap.Toast(a,{autohide:r.autohide,delay:r.delay});return this.toasts.set(i,{element:a,bootstrap:n,type:t,message:e}),a.addEventListener("hidden.bs.toast",()=>{this.cleanup(i)}),n.show(),{id:i,hide:()=>{try{n.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},a=this.createViewToastElement(i,e,t,r);if(this.container.appendChild(a),typeof bootstrap>"u")throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const n=new bootstrap.Toast(a,{autohide:r.autohide,delay:r.delay});this.toasts.set(i,{element:a,bootstrap:n,type:t,view:e,message:"View toast"}),a.addEventListener("hidden.bs.toast",()=>{this.cleanupView(i)});const o=a.querySelector(".toast-view-body");return o&&e&&e.render(!0,o),n.show(),{id:i,view:e,hide:()=>{try{n.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 a=i.title||i.icon?this.createToastHeader(i,s):"",n=this.createToastBody(t,i.icon&&!i.title);return r.innerHTML=`
143
- ${a}
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),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),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,Me);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,Me);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=`
144
143
  ${n}
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 a=i.title||i.icon?this.createToastHeader(i,s):"",n=this.createViewToastBody();return r.innerHTML=`
146
144
  ${a}
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=`
147
146
  ${n}
147
+ ${a}
148
148
  `,r}createViewToastBody(){return`
149
149
  <div class="toast-body p-0">
150
150
  <div class="toast-view-body p-3"></div>
151
151
  </div>
152
- `}createToastHeader(e,t){const s=e.icon?`<i class="${e.icon} toast-service-icon me-2"></i>`:"",i=e.title?`<strong class="me-auto">${s}${this.escapeHtml(e.title)}</strong>`:"",r=e.showTime?`<small class="text-muted">${this.getTimeString()}</small>`:"",a=e.dismissible?'<button type="button" class="btn-close toast-service-close" data-bs-dismiss="toast" aria-label="Close"></button>':"";return!i&&!r&&!a?"":`
152
+ `}createToastHeader(e,t){const s=e.icon?`<i class="${e.icon} toast-service-icon me-2"></i>`:"",i=e.title?`<strong class="me-auto">${s}${this.escapeHtml(e.title)}</strong>`:"",r=e.showTime?`<small class="text-muted">${this.getTimeString()}</small>`:"",n=e.dismissible?'<button type="button" class="btn-close toast-service-close" data-bs-dismiss="toast" aria-label="Close"></button>':"";return!i&&!r&&!n?"":`
153
153
  <div class="toast-header">
154
154
  ${i}
155
155
  ${r}
156
- ${a}
156
+ ${n}
157
157
  </div>
158
158
  `}createToastBody(e,t=!1){return`
159
159
  <div class="toast-body d-flex align-items-center">
@@ -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:a,headers:n}=e,o=r==="POST"&&a!==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(n||{}))m.toLowerCase()!=="content-type"&&l.setRequestHeader(m,p);const u=new FormData;for(const[m,p]of Object.entries(a))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(n||{}))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 at extends de{constructor(e={}){super({ModelClass:G,endpoint:"/api/group",size:10,...e})}}const nt={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(nt).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:at,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=nt,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)||!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:"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:"admin",label:"Log Admin"},{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"}]}],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 a of r)w.GRANULAR_TO_CATEGORY[a]=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:at,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 a=x.getMountTarget();return new Promise((n,o)=>{let l=!1;const d=u=>{l||(l=!0,n(u))},h=u=>{l||(l=!0,o(u))};(async()=>{try{await e.render(!0,a)}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:a,size:n="md",centered:o=!0,buttons:l=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:d=!1,...h}=e,u=i??r??a??s??"",m=new x({title:t,body:u,size:n,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:a,size:n="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 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:"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:"admin",label:"Log Admin"},{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"}]}],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?`
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">${a||""}</div>`;return v.dialog({header:!1,body:h,size:n,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:a="Alert",type:n="info",icon:o,className:l,...d}=i,h=n==="danger"?"error":n,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">${a}</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"}],a=new x({title:t,body:`<p>${i}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:r,...s});return await v._renderAndAwait(a,{buttons:r})==="confirm"}static async prompt(e,t="Input",s={}){const i=`prompt-input-${Date.now()}`,r=s.defaultValue||"",a=s.inputType||"text",n=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 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:`
212
212
  <p>${e}</p>
213
- <input type="${a}"
213
+ <input type="${n}"
214
214
  class="form-control"
215
215
  id="${i}"
216
216
  value="${r}"
217
- placeholder="${n}">
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:a="Submit",cancelText:n="Cancel",...o}=e,l=(await Promise.resolve().then(()=>Mt)).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:n,class:"btn-secondary",action:"cancel"},{text:a,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:a="Save",cancelText:n="Cancel",model:o,fields:l,...d}=e;if(!o)throw new Error("Modal.modelForm requires a model");const h=(await Promise.resolve().then(()=>Mt)).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:n,class:"btn-secondary",action:"cancel"},{text:a,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:a=2,responsive:n=!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:a,responsive:n,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",...a}=e,n=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:n,size:r,scrollable:!0,buttons:o,...a});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,...a}=e,n=new Gt({html:t,height:r}),o=[{text:"Close",class:"btn-secondary",dismiss:!0}],l=new x({title:s,body:n,size:i,scrollable:!1,buttons:o,...a});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},a=await v.form(r);if(!s||!a||!e.model)return a;const n=a[i];if(!n||!n.startsWith("data:"))return a;const o=n.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=ae,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:a}=s;await this.showPage(i,a,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},a=new s(r);return i.route&&(a.route=i.route),this.pageCache.set(e,a),console.log(`Created page: ${e} with route: ${a.route}`),a}catch(r){return console.error(`Failed to create page ${e}:`,r),null}}async showPage(e,t={},s={},i={}){const{fromRouter:r=!1,replace:a=!1,force:n=!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=ae,ae.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(n){console.warn(`[Page ${this.pageName}] scheduleRefresh handler error:`,n)}};s.immediate&&i();const r=setInterval(i,t),a={id:r,tier:s.tier||null,handler:i,intervalMs:t};return this._scheduledRefreshes.push(a),{cancel:()=>{clearInterval(r),this._scheduledRefreshes=(this._scheduledRefreshes||[]).filter(n=>n!==a)}}}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=`
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(()=>Mt)).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(()=>Mt)).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=`
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:a,minWidth:n,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=a||"tab-content",this.enableTransitions=h!==!1,this.transitionDuration=u||150,this.dropdownStyle=d||"select",this.minWidth=n||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 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`
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}`),a=i?this.element.querySelector(`#${i}`):null,n=this.tabs[e];if(this.enableTransitions){if(a&&a.classList.contains("show")&&(a.classList.remove("show"),await new Promise(o=>{const l=this._getTransitionDuration(a)||this.transitionDuration;setTimeout(o,l)}),a.classList.remove("active")),n){const o=this.element.querySelector(`[data-container="${s}-content"]`);o&&!n.isMounted()&&await n.render(!0,o)}r&&(r.classList.add("active"),r.offsetHeight,r.classList.add("show"))}else{if(a&&a.classList.remove("show","active"),n){const o=this.element.querySelector(`[data-container="${s}-content"]`);o&&!n.isMounted()&&await n.render(!0,o)}r&&r.classList.add("show","active")}n&&n.onTabActivated&&await n.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 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:`
316
316
  <div class="mojo-form-control">
317
317
  {{#label}}
318
318
  <label for="{{fieldId}}" class="{{labelClass}}">
@@ -651,38 +651,38 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
651
651
  ${e}
652
652
  ${t}
653
653
  </form>
654
- `}isAutoSizingField(e){return!e.columns||e.columns==="auto"||e.columns===""}buildFieldsHTML(){const e=[];let t=0;for(;t<this.fields.length;){const s=this.fields[t];if(s.columns=s.columns||s.cols,s.type==="group"){const i=[s];let r=s.columns||12;typeof r=="object"&&r!==null&&(r=r.md||r.sm||r.xs||12);let a=t+1;for(;a<this.fields.length&&this.fields[a].type==="group"&&r<12;){const o=this.fields[a];let l=o.columns||12;if(typeof l=="object"&&l!==null&&(l=l.md||l.sm||l.xs||12),r+l<=12)i.push(o),r+=l,a++;else break}let n=i.length>1;if(i.length===1&&s.columns){let o=s.columns;typeof o=="object"&&o!==null&&(o=o.md||o.sm||o.xs||12),n=n||o<12}if(n){const o=i.map(l=>this.buildGroupHTML(l)).join("");e.push(`<div class="row">${o}</div>`)}else e.push(this.buildGroupHTML(s));t=a}else if(s.columns&&s.columns<12){const i=[s];let r=s.columns||12;typeof r=="object"&&r!==null&&(r=r.md||r.sm||r.xs||12);let a=t+1;for(;a<this.fields.length&&this.fields[a].columns&&r<12;){const o=this.fields[a];let l=o.columns||12;if(typeof l=="object"&&l!==null&&(l=l.md||l.sm||l.xs||12),r+l<=12)i.push(o),r+=l,a++;else break}const n=i.map(o=>this.buildFieldHTML(o)).join("");e.push(`<div class="row">${n}</div>`),t=a}else if(this.isAutoSizingField(s)){const i=[s];let r=t+1;for(;r<this.fields.length;){const a=this.fields[r];if(this.isAutoSizingField(a))i.push(a),r++;else break}if(i.length>1){const a=i.map(n=>this.buildFieldHTML(n)).join("");e.push(`<div class="row">${a}</div>`)}else e.push(`<div class="row">${this.buildFieldHTML(s)}</div>`);t=r}else e.push(this.buildFieldHTML(s)),t++}return e.join("")}buildGroupHTML(e){const{columns:t=12,title:s,fields:i=[],class:r="",titleClass:a="h6 mb-3",responsive:n={}}=e;let o=[];if(typeof t=="object"&&t!==null){if(t.xs&&o.push(`col-${t.xs}`),t.sm&&o.push(`col-sm-${t.sm}`),t.md&&o.push(`col-md-${t.md}`),t.lg&&o.push(`col-lg-${t.lg}`),t.xl&&o.push(`col-xl-${t.xl}`),t.xxl&&o.push(`col-xxl-${t.xxl}`),!t.md&&(t.xs||t.sm)){const h=t.sm||t.xs;o.push(`col-md-${h}`)}o.length===0&&o.push("col-md-12")}else o.push(`col-md-${t}`);n.xs&&o.push(`col-${n.xs}`),n.sm&&o.push(`col-sm-${n.sm}`),n.lg&&o.push(`col-lg-${n.lg}`),n.xl&&o.push(`col-xl-${n.xl}`);const l=o.join(" "),d=i.map(h=>h.type==="group"?this.buildGroupHTML(h):this.buildFieldHTML(h)).join("");return`
654
+ `}isAutoSizingField(e){return!e.columns||e.columns==="auto"||e.columns===""}buildFieldsHTML(){const e=[];let t=0;for(;t<this.fields.length;){const s=this.fields[t];if(s.columns=s.columns||s.cols,s.type==="group"){const i=[s];let r=s.columns||12;typeof r=="object"&&r!==null&&(r=r.md||r.sm||r.xs||12);let n=t+1;for(;n<this.fields.length&&this.fields[n].type==="group"&&r<12;){const o=this.fields[n];let l=o.columns||12;if(typeof l=="object"&&l!==null&&(l=l.md||l.sm||l.xs||12),r+l<=12)i.push(o),r+=l,n++;else break}let a=i.length>1;if(i.length===1&&s.columns){let o=s.columns;typeof o=="object"&&o!==null&&(o=o.md||o.sm||o.xs||12),a=a||o<12}if(a){const o=i.map(l=>this.buildGroupHTML(l)).join("");e.push(`<div class="row">${o}</div>`)}else e.push(this.buildGroupHTML(s));t=n}else if(s.columns&&s.columns<12){const i=[s];let r=s.columns||12;typeof r=="object"&&r!==null&&(r=r.md||r.sm||r.xs||12);let n=t+1;for(;n<this.fields.length&&this.fields[n].columns&&r<12;){const o=this.fields[n];let l=o.columns||12;if(typeof l=="object"&&l!==null&&(l=l.md||l.sm||l.xs||12),r+l<=12)i.push(o),r+=l,n++;else break}const a=i.map(o=>this.buildFieldHTML(o)).join("");e.push(`<div class="row">${a}</div>`),t=n}else if(this.isAutoSizingField(s)){const i=[s];let r=t+1;for(;r<this.fields.length;){const n=this.fields[r];if(this.isAutoSizingField(n))i.push(n),r++;else break}if(i.length>1){const n=i.map(a=>this.buildFieldHTML(a)).join("");e.push(`<div class="row">${n}</div>`)}else e.push(`<div class="row">${this.buildFieldHTML(s)}</div>`);t=r}else e.push(this.buildFieldHTML(s)),t++}return e.join("")}buildGroupHTML(e){const{columns:t=12,title:s,fields:i=[],class:r="",titleClass:n="h6 mb-3",responsive:a={}}=e;let o=[];if(typeof t=="object"&&t!==null){if(t.xs&&o.push(`col-${t.xs}`),t.sm&&o.push(`col-sm-${t.sm}`),t.md&&o.push(`col-md-${t.md}`),t.lg&&o.push(`col-lg-${t.lg}`),t.xl&&o.push(`col-xl-${t.xl}`),t.xxl&&o.push(`col-xxl-${t.xxl}`),!t.md&&(t.xs||t.sm)){const h=t.sm||t.xs;o.push(`col-md-${h}`)}o.length===0&&o.push("col-md-12")}else o.push(`col-md-${t}`);a.xs&&o.push(`col-${a.xs}`),a.sm&&o.push(`col-sm-${a.sm}`),a.lg&&o.push(`col-lg-${a.lg}`),a.xl&&o.push(`col-xl-${a.xl}`);const l=o.join(" "),d=i.map(h=>h.type==="group"?this.buildGroupHTML(h):this.buildFieldHTML(h)).join("");return`
655
655
  <div class="${l}">
656
656
  <div class="mojo-form-group ${r}">
657
- ${s?`<div class="${a}">${this.escapeHtml(s)}</div>`:""}
657
+ ${s?`<div class="${n}">${this.escapeHtml(s)}</div>`:""}
658
658
  <div class="row">
659
659
  ${d}
660
660
  </div>
661
661
  </div>
662
662
  </div>
663
- `}buildFieldHTML(e){const{type:t,columns:s,class:i=""}=e;let r="";const a=X&&typeof X.getRenderer=="function"?X.getRenderer(t):null;if(typeof a=="function")try{const d=a(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 n;if(this.isAutoSizingField(e))n=`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),n=d.join(" ")}else n=`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="${n}"${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,a=[];return t!==void 0&&a.push(`min="${t}"`),s!==void 0&&a.push(`max="${s}"`),i!==void 0&&a.push(`step="${i}"`),this.renderInputField({...r,attributes:{...r.attributes,...a.reduce((n,o)=>{const[l,d]=o.split("=");return n[l]=d.replace(/"/g,""),n},{})}},"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,...a}=e;let n,o,l,d,h;switch(t){case"color":n=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":n=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":n="^[0-9A-Fa-f]+$",o=i||1,l=r||64,d="ABCDEF123456",h=h||"Only hexadecimal characters (0-9, A-F) allowed";break;default:n=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={...a,pattern:n,minLength:o,maxLength:l,placeholder:a.placeholder||d,help:a.help||h,attributes:{"data-hex-type":t,"data-allow-prefix":s,style:"text-transform: uppercase;",...a.attributes}};return this.renderInputField(u,"text")}renderInputField(e,t="text"){const{name:s,label:i,value:r="",placeholder:a="",required:n=!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:this.escapeHtml(f),label:i?this.escapeHtml(i):null,placeholder:a?this.escapeHtml(a):null,help:u?this.escapeHtml(u):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:p?this.escapeHtml(p):null,required:n,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:a=!1,disabled:n=!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?this.escapeHtml(s):null,placeholder:r?this.escapeHtml(r):null,help:m?this.escapeHtml(m):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:f?this.escapeHtml(f):null,rows:l||3,required:a,disabled:n,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:a=!1,disabled:n=!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?this.escapeHtml(s):null,placeholder:r?this.escapeHtml(r):null,help:u?this.escapeHtml(u):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:p?this.escapeHtml(p):null,rows:l||5,required:a,disabled:n,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:a=!1,readonly:n=!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?this.escapeHtml(s):null,placeholder:i?this.escapeHtml(i):null,help:h?this.escapeHtml(h):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:f?this.escapeHtml(f):null,rows:o||3,required:r,disabled:a,readonly:n,attrs:b};return D.render(this.templates.textarea,y)}renderSelectField(e){const{name:t,label:s,options:i=[],value:r="",required:a=!1,disabled:n=!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(([I,H])=>`${I}="${this.escapeHtml(H)}"`).join(" "),M=this.getFieldId(t);let R=[...i];if(m!==void 0&&p!==void 0){const I=f!==void 0?f:1,H=this.generateSelectOptions(m,p,I,{format:g,prefix:b,suffix:y});R=[...R,...H]}let oe="";Array.isArray(R)&&(oe=R.map(I=>{if(typeof I=="string"){const H=I===F?"selected":"";return`<option value="${this.escapeHtml(I)}" ${H}>${this.escapeHtml(I)}</option>`}else if(I&&typeof I=="object"){const H=I.value==F?"selected":"";return`<option value="${this.escapeHtml(I.value)}" ${H}>${this.escapeHtml(I.label||I.text||I.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(([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(([I,z])=>`${I}="${this.escapeHtml(z)}"`).join(" "),M=this.getFieldId(t);let R=[...i];if(m!==void 0&&p!==void 0){const I=f!==void 0?f:1,z=this.generateSelectOptions(m,p,I,{format:g,prefix:b,suffix:y});R=[...R,...z]}let oe="";Array.isArray(R)&&(oe=R.map(I=>{if(typeof I=="string"){const z=I===F?"selected":"";return`<option value="${this.escapeHtml(I)}" ${z}>${this.escapeHtml(I)}</option>`}else if(I&&typeof I=="object"){const z=I.value==F?"selected":"";return`<option value="${this.escapeHtml(I.value)}" ${z}>${this.escapeHtml(I.label||I.text||I.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="${M}">
670
- `:"",ye={labelClass:this.options.labelClass,inputClass:C,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:M,name:t,label:s?this.escapeHtml(s):null,help:u?this.escapeHtml(u):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:_?this.escapeHtml(_):null,searchInput:l?be:null,optionsHTML:oe,required:a,disabled:n,multiple:o,attrs:j};return D.render(this.templates.select,ye)}renderMultiSelectField(e){const{name:t,label:s,options:i=[],value:r=[],required:a=!1,disabled:n=!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:C,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:M,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`
671
671
  <div class="multiselect-placeholder"
672
672
  data-field-name="${t}"
673
673
  data-field-type="multiselect"
674
- data-field-config='${JSON.stringify({name:t,value:u,placeholder:d,maxHeight:o,disabled:n,required:a})}'>
674
+ data-field-config='${JSON.stringify({name:t,value:u,placeholder:d,maxHeight:o,disabled:a,required:n})}'>
675
675
  <input type="hidden" name="${t}" value="${this.escapeHtml(JSON.stringify(u))}">
676
676
  <select class="form-select${h?" is-invalid":""}"
677
677
  multiple
678
- ${n?"disabled":""}
679
- ${a?"required":""}>
678
+ ${a?"disabled":""}
679
+ ${n?"required":""}>
680
680
  ${i.map(m=>{const p=typeof m=="string"?m:m.value,f=typeof m=="string"?m:m.label||m.value,g=Array.isArray(u)&&u.includes(p)?"selected":"";return`<option value="${this.escapeHtml(p)}" ${g}>${this.escapeHtml(f)}</option>`}).join("")}
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:a=!1,class:n="",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:this.escapeHtml(s),help:l?this.escapeHtml(l):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:d?this.escapeHtml(d):null,value:this.escapeHtml(i),fieldClass:n,checked:u,required:r,disabled:a,attrs:m};return D.render(this.templates.checkbox,f)}renderSwitchField(e){const{name:t,label:s,value:i=!1,required:r=!1,disabled:a=!1,size:n="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=n!=="md"?`form-switch-${n}`:"",b={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:f,name:t,label:this.escapeHtml(s),help:d?this.escapeHtml(d):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:h?this.escapeHtml(h):null,value:this.escapeHtml(i),sizeClass:g,fieldClass:o,checked:m,required:r,disabled:a,attrs:p};return D.render(this.templates.switch,b)}renderRadioField(e){const{name:t,label:s,options:i=[],value:r="",disabled:a=!1,inline:n=!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`
685
- <div class="form-check ${n?"form-check-inline":""}">
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`
685
+ <div class="form-check ${a?"form-check-inline":""}">
686
686
  <input
687
687
  type="radio"
688
688
  id="${b}"
@@ -690,7 +690,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
690
690
  class="form-check-input ${h?"is-invalid":""}"
691
691
  value="${this.escapeHtml(y)}"
692
692
  ${_}
693
- ${a?"disabled":""}
693
+ ${n?"disabled":""}
694
694
 
695
695
  ${m}
696
696
  >
@@ -709,13 +709,13 @@ 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:a=!1,accept:n="*/*",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?this.escapeHtml(s):null,help:d?this.escapeHtml(d):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:u?this.escapeHtml(u):null,accept:n,required:i,disabled:r,multiple:a,attrs:m};return D.render(this.templates.file,f)}renderImageField(e){const{name:t,label:s,required:i=!1,disabled:r=!1,accept:a="image/*",class:n="",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} ${n}`.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(([M,R])=>`${M}="${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?this.escapeHtml(s):null,help:l?this.escapeHtml(l):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:p?this.escapeHtml(p):null,dropZoneId:g,previewId:b,containerClass:C.containerClass,width:C.width,height:C.height,accept:a,imageUrl:F,placeholderText:r?"No image":this.escapeHtml(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:a=!1,disabled:n=!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:this.escapeHtml(p),label:s?this.escapeHtml(s):null,placeholder:r?this.escapeHtml(r):null,help:h?this.escapeHtml(h):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:m?this.escapeHtml(m):null,required:a,disabled:n,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:a=1,value:n=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)??n,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?this.escapeHtml(s):null,help:h?this.escapeHtml(h):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:m?this.escapeHtml(m):null,min:i,max:r,step:a,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:a="btn-secondary",disabled:n=!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"}},C=y[d]||y.md,_=Object.entries(o).map(([M,R])=>`${M}="${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`
713
713
  <button
714
714
  type="button"
715
715
  ${t?`name="${t}"`:""}
716
- class="btn ${a}"
716
+ class="btn ${n}"
717
717
  ${l?`data-action="${l}"`:""}
718
- ${n?"disabled":""}
718
+ ${a?"disabled":""}
719
719
  ${d}
720
720
  >
721
721
  ${this.escapeHtml(s)}
@@ -729,23 +729,23 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
729
729
  <div class="form-html ${s}">
730
730
  ${t}
731
731
  </div>
732
- `}renderHeaderField(e){const{text:t="",level:s=3,class:i="",id:r=""}=e,a=Math.max(1,Math.min(6,parseInt(s))),n=r?` id="${this.escapeHtml(r)}"`:"",o=i?` class="${this.escapeHtml(i)}"`:"";return`<h${a}${n}${o}>${this.escapeHtml(t)}</h${a}>`}buildButtonsHTML(){if(!this.options.submitButton&&!this.options.resetButton&&!this.buttons.length)return"";let e="";if(this.buttons.forEach(t=>{e+=this.renderButton(t)+" "}),this.options.submitButton){let t="Submit";typeof this.options.submitButton=="string"?t=this.options.submitButton:this.options.submitButton===!0&&(t="Submit"),e+=`<button type="submit" class="btn btn-primary me-2" data-action="submit-form">${t}</button>`}if(this.options.resetButton){let t="Reset";typeof this.options.resetButton=="string"?t=this.options.resetButton:this.options.resetButton===!0&&(t="Reset"),e+=`<button type="button" class="btn btn-secondary" data-action="reset-form">${t}</button>`}return e?`
732
+ `}renderHeaderField(e){const{text:t="",level:s=3,class:i="",id:r=""}=e,n=Math.max(1,Math.min(6,parseInt(s))),a=r?` id="${this.escapeHtml(r)}"`:"",o=i?` class="${this.escapeHtml(i)}"`:"";return`<h${n}${a}${o}>${this.escapeHtml(t)}</h${n}>`}buildButtonsHTML(){if(!this.options.submitButton&&!this.options.resetButton&&!this.buttons.length)return"";let e="";if(this.buttons.forEach(t=>{e+=this.renderButton(t)+" "}),this.options.submitButton){let t="Submit";typeof this.options.submitButton=="string"?t=this.options.submitButton:this.options.submitButton===!0&&(t="Submit"),e+=`<button type="submit" class="btn btn-primary me-2" data-action="submit-form">${t}</button>`}if(this.options.resetButton){let t="Reset";typeof this.options.resetButton=="string"?t=this.options.resetButton:this.options.resetButton===!0&&(t="Reset"),e+=`<button type="button" class="btn btn-secondary" data-action="reset-form">${t}</button>`}return e?`
733
733
  <div class="form-actions mt-3">
734
734
  ${e}
735
735
  </div>
736
- `:""}getFieldValue(e){return this.structureOnly?"":$.getContextData(this.data,e)}renderTagField(e){const{name:t,label:s,value:i="",placeholder:r="Add tags...",required:a=!1,disabled:n=!1,readonly:o=!1,maxTags:l=50,allowDuplicates:d=!1,separator:h=",",help:u=e.helpText||e.help||""}=e,m=this.getFieldId(t),p=this.errors[t],f=this.getFieldValue(t)??i;return`
736
+ `:""}getFieldValue(e){return this.structureOnly?"":$.getContextData(this.data,e)}renderTagField(e){const{name:t,label:s,value:i="",placeholder:r="Add tags...",required:n=!1,disabled:a=!1,readonly:o=!1,maxTags:l=50,allowDuplicates:d=!1,separator:h=",",help:u=e.helpText||e.help||""}=e,m=this.getFieldId(t),p=this.errors[t],f=this.getFieldValue(t)??i;return`
737
737
  <div class="mojo-form-control">
738
- ${s?`<label for="${m}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
738
+ ${s?`<label for="${m}" class="${this.options.labelClass}">${this.escapeHtml(s)}${n?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
739
739
  <div class="tag-input-placeholder"
740
740
  data-field-name="${t}"
741
741
  data-field-type="tag"
742
- data-field-config='${JSON.stringify({name:t,value:f,placeholder:r,maxTags:l,allowDuplicates:d,separator:h,disabled:n,readonly:o,required:a})}'>
742
+ data-field-config='${JSON.stringify({name:t,value:f,placeholder:r,maxTags:l,allowDuplicates:d,separator:h,disabled:a,readonly:o,required:n})}'>
743
743
  <input type="text"
744
744
  id="${m}"
745
745
  name="${t}_display"
746
746
  class="${this.options.inputClass}${p?" is-invalid":""}"
747
747
  placeholder="${this.escapeHtml(r)}"
748
- ${n?"disabled":""}
748
+ ${a?"disabled":""}
749
749
  ${o?"readonly":""}
750
750
 
751
751
  <input type="hidden" name="${t}" value="${this.escapeHtml(f)}">
@@ -754,19 +754,19 @@ 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:a=!1,disabled:n=!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],C=this.getFieldValue(t)??i;return`
758
758
  <div class="mojo-form-control">
759
- ${s?`<label for="${b}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
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:n,readonly:o,required:a,requiresActiveGroup:f})}'>
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})}'>
764
764
  <input type="text"
765
765
  id="${b}"
766
766
  name="${t}_display"
767
767
  class="${this.options.inputClass}${y?" is-invalid":""}"
768
768
  placeholder="${this.escapeHtml(r)}"
769
- ${n?"disabled":""}
769
+ ${a?"disabled":""}
770
770
  ${o?"readonly":""}
771
771
 
772
772
  <input type="hidden" name="${t}" value="${this.escapeHtml(C)}">
@@ -775,78 +775,78 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
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:a=!1,Collection:n,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:C=!1,help:_=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:a,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:C})}'>
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
788
  ${_?`<div class="${this.options.helpClass}">${this.escapeHtml(_)}</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:a,required:n=!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:C=e.helpText||e.help||""}=e,_=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)}${n?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
793
+ ${s?`<label for="${_}" 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
- data-field-config='${JSON.stringify({name:t,value:F,precision:r,placeholder:a,min:d,max:h,format:u,displayFormat:m,disabledDates:p,firstDay:f,lang:g,autoApply:b,inline:y,disabled:o,readonly:l,required:n})}'></div>
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
798
  ${C?`<div class="${this.options.helpClass}">${this.escapeHtml(C)}</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:a,startDate:n="",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:M=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":""),I=this.getFieldValue(be)||n,H=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:C=" – ",months:_=null,presets:A=null,autoApply:F=!0,inline:j=!1,help:M=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":""),I=this.getFieldValue(be)||a,z=this.getFieldValue(ye)||o;return`
802
802
  <div class="mojo-form-control">
803
- ${a?`<label for="${R}" class="${this.options.labelClass}">${this.escapeHtml(a)}${h?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
803
+ ${n?`<label for="${R}" 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:I,endDate:H,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:I,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>
808
808
  ${M?`<div class="${this.options.helpClass}">${this.escapeHtml(M)}</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:a=1,min:n=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,C=this.getFieldId(t),_=this.errors[t],A=this.getFieldValue(t)??i;return`
812
812
  <div class="mojo-form-control">
813
813
  ${s?`<label for="${C}" 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
- data-field-config='${JSON.stringify({name:t,value:A,format:r,step:a,min:n,max:o,placeholder:l,timezone:m,timezones:p,outputFormat:f,autoApply:g,inline:b,disabled:h,readonly:u,required:d})}'></div>
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
819
  ${_?`<div class="${this.options.errorClass}">${this.escapeHtml(_)}</div>`:""}
820
820
  </div>
821
- `}renderDateTimePickerField(e){const{name:t,label:s,value:i="",displayFormat:r=null,timeFormat:a="24h",timeStep:n=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),M=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:C="string",autoApply:_=!1,inline:A=!1,help:F=e.helpText||e.help||""}=e,j=this.getFieldId(t),M=this.errors[t],R=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:a,timeStep:n,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: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>
828
828
  ${F?`<div class="${this.options.helpClass}">${this.escapeHtml(F)}</div>`:""}
829
829
  ${M?`<div class="${this.options.errorClass}">${this.escapeHtml(M)}</div>`:""}
830
830
  </div>
831
- `}renderChecklistDropdownField(e){const t=this.getFieldId(e.name),s=this.getFieldValue(e.name)??[],i={fieldId:t,fieldName:e.name,buttonText:e.buttonText||"Select Options",buttonIcon:e.buttonIcon||"bi-chevron-down",buttonClass:e.buttonClass||"btn btn-outline-secondary btn-sm dropdown-toggle",dropdownClass:e.dropdownClass||"dropdown-menu p-2",minWidth:e.minWidth||"200px",options:e.options.map(r=>({value:r.value,label:r.label,id:`${e.name}-${r.value}`,checked:s.includes(r.value)}))};return D.render(this.templates.checklistdropdown,i)}renderButtonGroupField(e){const t=this.getFieldId(e.name),s=this.getFieldValue(e.name)??e.value,i={fieldId:t,fieldName:e.name,size:e.size||"sm",variant:e.variant||"outline-primary",options:e.options.map(r=>({value:r.value,label:r.label,action:r.action,active:r.value===s,buttonClass:this.getButtonClass(r.value===s,e.variant)}))};return D.render(this.templates.buttongroup,i)}getButtonClass(e,t="outline-primary"){return e?`btn btn-${t.replace("outline-","")}`:`btn btn-${t}`}renderComboField(e){const{name:t,label:s,value:i="",required:r=!1,disabled:a=!1,maxHeight:n=300,help:o=e.helpText||e.help||""}=e,l=e.placeholder||e.placeHolder||"Type or select...",d=e.allowCustom!==!1;this.getFieldId(t);const h=this.errors[t],u=e.value??this.getFieldValue(t)??i;return`
831
+ `}renderChecklistDropdownField(e){const t=this.getFieldId(e.name),s=this.getFieldValue(e.name)??[],i={fieldId:t,fieldName:e.name,buttonText:e.buttonText||"Select Options",buttonIcon:e.buttonIcon||"bi-chevron-down",buttonClass:e.buttonClass||"btn btn-outline-secondary btn-sm dropdown-toggle",dropdownClass:e.dropdownClass||"dropdown-menu p-2",minWidth:e.minWidth||"200px",options:e.options.map(r=>({value:r.value,label:r.label,id:`${e.name}-${r.value}`,checked:s.includes(r.value)}))};return D.render(this.templates.checklistdropdown,i)}renderButtonGroupField(e){const t=this.getFieldId(e.name),s=this.getFieldValue(e.name)??e.value,i={fieldId:t,fieldName:e.name,size:e.size||"sm",variant:e.variant||"outline-primary",options:e.options.map(r=>({value:r.value,label:r.label,action:r.action,active:r.value===s,buttonClass:this.getButtonClass(r.value===s,e.variant)}))};return D.render(this.templates.buttongroup,i)}getButtonClass(e,t="outline-primary"){return e?`btn btn-${t.replace("outline-","")}`:`btn btn-${t}`}renderComboField(e){const{name:t,label:s,value:i="",required:r=!1,disabled:n=!1,maxHeight:a=300,help:o=e.helpText||e.help||""}=e,l=e.placeholder||e.placeHolder||"Type or select...",d=e.allowCustom!==!1;this.getFieldId(t);const h=this.errors[t],u=e.value??this.getFieldValue(t)??i;return`
832
832
  <div class="mojo-form-control">
833
833
  ${s?`<label class="${this.options.labelClass}">${this.escapeHtml(s)}${r?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
834
834
  <div class="combobox-placeholder"
835
835
  data-field-name="${t}"
836
836
  data-field-type="combobox"
837
- data-field-config='${JSON.stringify({name:t,value:u,placeholder:l,maxHeight:n,allowCustom:d,disabled:a,required:r})}'>
837
+ data-field-config='${JSON.stringify({name:t,value:u,placeholder:l,maxHeight:a,allowCustom:d,disabled:n,required:r})}'>
838
838
  <input type="text"
839
839
  class="form-control${h?" is-invalid":""}"
840
840
  value="${this.escapeHtml(u)}"
841
841
  placeholder="${this.escapeHtml(l)}"
842
- ${a?"disabled":""}
842
+ ${n?"disabled":""}
843
843
  ${r?"required":""}>
844
844
  <small class="form-text text-muted">This will be enhanced with ComboBox component</small>
845
845
  </div>
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:a="tab-content"}=e,n=i&&Object.prototype.hasOwnProperty.call(O.VARIANT_CLASSES,i)?i:O.DEFAULT_VARIANT,o=r||O.VARIANT_CLASSES[n],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(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`
850
850
  <li class="nav-item" role="presentation">
851
851
  <button class="nav-link ${f?"active":""}"
852
852
  id="${p}-tab"
@@ -874,11 +874,11 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
874
874
  <ul class="${o}" role="tablist">
875
875
  ${d}
876
876
  </ul>
877
- <div class="${a}">
877
+ <div class="${n}">
878
878
  ${h}
879
879
  </div>
880
880
  </div>
881
- `}generateSelectOptions(e,t,s=1,i={}){const{format:r,prefix:a="",suffix:n=""}=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=`${a}${h}${n}`,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()}},_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:a=!1,separator:n=",",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=a,this.separator=n,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){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()}},_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`
882
882
  <div class="tag-input-container">
883
883
  <div class="tag-input-wrapper border rounded p-2"
884
884
  data-action="focus-input"
@@ -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 as 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 S{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),a={label:this.getFieldValue(t,this.labelField),value:r,index:s,selected:this.selectedValues.some(n=>n==r),disabled:this.disabled,model:i};return this.itemTemplate&&(a.customContent=this.renderItemTemplate(a)),a})}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),a=Math.max(this.listView.lastClickedIndex,t),n=!this.items[t].selected;for(let o=r;o<=a;o++){const l=this.items[o];l.disabled||(n?this.selectedValues.includes(l.value)||this.selectedValues.push(l.value):this.selectedValues=this.selectedValues.filter(d=>d!=l.value),l.selected=n)}this.updateListView()}else{const r=this.items[t];r.selected?(this.selectedValues=this.selectedValues.filter(a=>a!=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 ns 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 S{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 a=t.querySelector('input[type="checkbox"]');a&&(a.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 S{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,a=typeof s=="string"?s:s.label||s.text||s.value,n=typeof s=="object"?s.disabled:!1;return{id:`${this.name}_${i}`,value:r,label:a,index:i,selected:this.selectedValues.includes(r),disabled:n}});this.listView=new ns({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,a=typeof s=="string"?s:s.label||s.text||s.value,n=typeof s=="object"?s.disabled:!1;return{id:`${this.name}_${i}`,value:r,label:a,index:i,selected:this.selectedValues.includes(r),disabled:n}});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 ne(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),n=s.replace(/(am|pm)$/i,"").trim().split(":");if(n.length<2)return null;let o=parseInt(n[0],10);const l=parseInt(n[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 a=r.value;if(a==="GMT"||a==="UTC")return"+00:00";a=a.replace(/^(GMT|UTC)/,"");const n=a.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!n)return null;const o=n[1],l=n[2].padStart(2,"0"),d=n[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 a=i.trim();let n=null,o=a;const l=a.match(/\s+([A-Za-z][A-Za-z_+\-]*\/[A-Za-z][A-Za-z_+\-]*|UTC|GMT)$/);l&&(n=l[1],o=a.slice(0,l.index).trim());const d=J(o);return d?{date:r,time:d,timezone:n}:null}function E(){const c=new Date;return{y:c.getFullYear(),m:c.getMonth()+1,d:c.getDate()}}let Se=null,je=null,He=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&&He)return He.slice();const i=new Intl.DateTimeFormat(c,{weekday:t}),r=[];for(let n=0;n<7;n++)r.push(i.format(new Date(2024,0,7+n)));const a=xt(r,e);return Se=s,He=a,a.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 S{constructor(e={}){const{precision:t="day",mode:s="single",months:i=1,value:r=null,startValue:a=null,endValue:n=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(a,t),this.end=P(n,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,a=this.pageM+i;for(;a>12;)a-=12,r+=1;t.appendChild(this._buildDayPane(r,a,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),a=E();for(let n=0;n<i;n++){const o=document.createElement("div");o.className="mojo-calendar-cell mojo-calendar-cell-blank",s.appendChild(o)}for(let n=1;n<=r;n++){const o={y:e,m:t,d:n},l=document.createElement("button");l.type="button",l.className="mojo-calendar-cell",l.dataset.ymd=B(o),o.y===a.y&&o.m===a.m&&o.d===a.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(n),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},a=document.createElement("button");a.type="button",a.className="mojo-calendar-cell",a.dataset.ym=Re(r),this._isDisabledAt(r,"month")&&(a.classList.add("mojo-calendar-cell-disabled"),a.disabled=!0),this.precision==="month"&&this.mode==="range"?this._applyRangeClasses(a,r,"month"):this.precision==="month"&&this.mode==="single"&&this.selected&&wt(r,this.selected)===0&&a.classList.add("mojo-calendar-cell-selected");const n=document.createElement("span");n.className="mojo-calendar-cell-inner",n.textContent=s[i-1],a.appendChild(n),t.appendChild(a)}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},a=document.createElement("button");a.type="button",a.className="mojo-calendar-cell",a.dataset.year=String(i),this._isDisabledAt(r,"year")&&(a.classList.add("mojo-calendar-cell-disabled"),a.disabled=!0),this.precision==="year"&&this.mode==="range"?this._applyRangeClasses(a,r,"year"):this.precision==="year"&&this.mode==="single"&&this.selected&&this.selected.y===i&&a.classList.add("mojo-calendar-cell-selected");const n=document.createElement("span");n.className="mojo-calendar-cell-inner",n.textContent=String(i),a.appendChild(n),t.appendChild(a)}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 a=W(t,i,s),n=W(t,r,s);a>0&&n<0&&e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range"),a===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")),n===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 a=document.createElement("button");if(a.type="button",a.className="mojo-calendar-head-label",a.dataset.level=t,a.dataset.action="zoom-out",typeof e=="string")a.textContent=e;else if(e&&e.kind==="day"){const o=_t(this.locale,"long");a.appendChild(document.createTextNode(`${o[e.month-1]} `));const l=document.createElement("span");l.className="mojo-calendar-year",l.textContent=String(e.year),a.appendChild(l)}r.appendChild(a);const n=document.createElement("div");return n.className="mojo-calendar-nav",s&&n.appendChild(this._navBtn("prev")),i&&n.appendChild(this._navBtn("next")),r.appendChild(n),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=ne({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:a=null,classNames:n=""}=e;this.anchor=t,this.placement=s,this.gap=i,this.portal=r,this.onOutsideClick=a,this.element=document.createElement("div"),this.element.className=`mojo-calendar-popover ${n}`.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,a=e.left+s;this.placement==="bottom-end"?a=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,a=e.right+s-t.width);const n=document.documentElement.clientWidth||window.innerWidth;a+t.width>s+n-8&&(a=s+n-t.width-8),a<s+8&&(a=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=`${a}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:a=null,min:n=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=a||$t[i]||$t.day,this.min=n,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 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?`
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,12 +1127,12 @@ 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 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 n=P(e,this.precision);n&&(s=U(n,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 a=this.element.querySelector("[data-hidden-value]");a&&(a.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=ne({y:c.y,m:c.m,d:1},-1),t=ne(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=ne({y:c.y,m:c.m},-1);return{start:e,end:e}}},{label:"Last 3 months",range:()=>{const c=E();return{start:ne({y:c.y,m:c.m},-2),end:{y:c.y,m:c.m}}}},{label:"Last 6 months",range:()=>{const c=E();return{start:ne({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:ne({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 a=r.range();this.activeIndex=i,this._highlight();const n=this.precision==="year"?gt:this.precision==="month"?Re:B;this.emit("preset:select",{index:i,label:r.label,start:n(a.start),end:n(a.end),parsed:a})})}_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:a="",endDate:n="",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:M=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=M,this.currentStartDate=a||"",this.currentEndDate=n||"",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`:""),a=`
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:M=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=M,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 />`:""}
1134
1134
  `;return this.inline?`
1135
- ${a}
1135
+ ${n}
1136
1136
  <div data-cal-host class="mojo-date-picker-inline${this.hasError()?" is-invalid":""}"></div>
1137
1137
  `:`
1138
1138
  <button type="button" id="${e}" class="mojo-date-trigger${this.hasError()?" is-invalid":""}"
@@ -1142,8 +1142,8 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1142
1142
  <span class="mojo-date-trigger-text${s?" is-empty":""}" data-trigger-text>${this._attr(t||this.placeholder)}</span>
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
- ${a}
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 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="",a="";if(e){const o=P(e,this.precision);o&&(r=U(o,this.precision))}if(t){const o=P(t,this.precision);o&&(a=U(o,this.precision))}this.currentStartDate=r,this.currentEndDate=a;const n=this.element.querySelector("[data-trigger-text]");if(n){const o=this._displayText();n.textContent=o||this.placeholder,n.classList.toggle("is-empty",!r)}this._updateHidden(),(s!==r||i!==a)&&(this.emit("change",{startDate:r,endDate:a,combined:this.getCombinedValue(),formatted:this._displayText(),oldStartDate:s,oldEndDate:i}),this.emit("range:changed",{startDate:r,endDate:a,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=`
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=`
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:a=!1,placeholder:n="Search timezone...",...o}=e;super({tagName:"div",className:"mojo-timezone-select",...o}),this.name=t,this.disabled=r,this.required=a,this.placeholder=n,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 a=this.currentValue;this.currentValue=r,this.emit("change",{value:r,oldValue:a})}})}_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 a=r.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!a)return r||null;const n=a[1],o=a[2].padStart(2,"0"),l=a[3]||"00";return`${n==="-"?"−":"+"}${o}:${l}`}catch{return null}}class $e extends S{constructor(e={}){const{name:t,value:s="",format:i="24h",step:r=1,min:a=null,max:n=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=a,this.max=n,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 a=null;return r==="Z"?a="+00:00":/^[+-]\d{4}$/.test(r)?a=`${r.slice(0,3)}:${r.slice(3)}`:a=r,{time:J(s[1]),timezone:a}}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 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?`
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 a=document.createElement("div");a.className="mojo-time-tz-host",a.setAttribute("data-tz-host",""),e.appendChild(a)}if(this.showFooter){const a=document.createElement("div");a.className="mojo-time-foot";const n=document.createElement("button");n.type="button",n.className="btn btn-link btn-sm mojo-time-now",n.textContent="Now",n.addEventListener("click",l=>{l.preventDefault();const d=new Date;this._commitTime({hours:d.getHours(),minutes:d.getMinutes()}),this._refreshSpinnerDisplay()}),a.appendChild(n);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()}),a.appendChild(o),e.appendChild(a)}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 a=document.createElement("input");a.type="text",a.className="mojo-time-stepper-value",a.value=t,a.setAttribute("inputmode","numeric"),a.setAttribute("aria-label",s),a.maxLength=2,a.addEventListener("focus",()=>a.select()),a.addEventListener("keydown",l=>this._onValueKey(e,a,l)),a.addEventListener("blur",()=>this._onValueBlur(e,a));const n=document.createElement("button");n.type="button",n.className="mojo-time-stepper-btn",n.setAttribute("aria-label",`Decrease ${s.toLowerCase()}`),n.innerHTML='<i class="bi bi-chevron-down" aria-hidden="true"></i>',n.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(a),i.appendChild(n),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",a=>{a.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",a=>{a.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 n=i*60+r,o=t*this.step,l=((n+o)%1440+1440)%1440;i=Math.floor(l/60),r=l%60}const a=this._clampToBounds({hours:i,minutes:r});this._commitTime(a),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:a,minutes:n}=r;if(e==="hour")if(this.format==="12h"){i<1&&(i=1),i>12&&(i=12);const o=r.hours>=12;i===12?a=o?12:0:a=o?i+12:i}else i<0&&(i=0),i>23&&(i=23),a=i;else i<0&&(i=0),i>59&&(i=59),n=i;this._commitTime(this._clampToBounds({hours:a,minutes:n})),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)"),a=this._spinner.querySelector(".mojo-time-ampm-btn:nth-child(2)");r&&r.classList.toggle("is-active",!i),a&&a.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:a="24h",timeStep:n=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=a==="12h"?"12h":"24h",this.timeStep=Math.max(1,parseInt(n,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 M=this._parseInitial(s);this.currentDate=M.date,this.currentTime=M.time,this.currentTimezone=M.timezone||(this.timezone?It():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 _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 M=this._parseInitial(s);this.currentDate=M.date,this.currentTime=M.time,this.currentTimezone=M.timezone||(this.timezone?It():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?`
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 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?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 a=document.createElement("div");a.className="mojo-datetime-foot";const n=document.createElement("button");n.type="button",n.className="btn btn-link btn-sm",n.textContent="Now",n.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()}),a.appendChild(n);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()}),a.appendChild(o),e.appendChild(a),e}_refreshTimezoneDefault(){this.timezone&&!this.currentTimezone&&this._timePicker&&(this.currentTimezone=this._timePicker.currentTimezone||It())}_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 It(){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:a=!0,showDescription:n=!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=a,this.showDescription=n,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 _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||It())}_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 It(){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`
1209
1209
  <div class="combo-input-container position-relative">
1210
1210
  <div class="input-wrapper position-relative">
1211
1211
  ${this.renderInput()}
@@ -1277,11 +1277,11 @@ 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 a=t.label.toLowerCase().startsWith(e),n=s.label.toLowerCase().startsWith(e);return a&&!n?-1:!a&&n?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:a=null,errors:n={},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=a||r,this._originalData=r,this.errors=n,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:n})}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(a=>a.value);else if(t.type==="file"){const a=t.getAttribute("data-change-action");if(a==="image-selected"){this.onChangeImageSelected(s,t);return}else if(a==="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),a=new Ve({...r,containerId:null});a.render(!0,t),this.customComponents.set(s,a),a.on("change",n=>{this.handleFieldChange(s,n.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),a=this.getFormFieldConfig(s);if(!a)return;const n=new os({...r,options:a.options||[],placeholder:a.placeholder||r.placeholder||"Select...",label:a.label,containerId:null});let o=r.value??$.getContextData(this.data,s);o&&n.setFormValue(o),n.render(!0,t),this.customComponents.set(s,n),n.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),a=this.getFormFieldConfig(s);if(!a)return;const n=new Et({...r,options:a.options||[],placeholder:a.placeholder||r.placeholder||"Type or select...",containerId:null});let o=r.value??$.getContextData(this.data,s);o&&n.setFormValue(o),n.render(!0,t),this.customComponents.set(s,n),n.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),a=this.getFormFieldConfig(s);if(!a||!a.Collection)return;const n=new a.Collection;a.collectionParams&&(n.params={...n.params,...a.collectionParams});const o=new ss({...r,collection:n,defaultParams:a.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),a=this.getFormFieldConfig(s);if(!a||!a.Collection)return;const n=new a.Collection;a.collectionParams&&(n.params={...n.params,...a.collectionParams});const o=new as({...r,collection:n,defaultParams:a.defaultParams||null,itemTemplate:a.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),a=new qe({...r,containerId:null});a.render(!0,t),this.customComponents.set(s,a),a.on("change",n=>{this.handleFieldChange(s,n.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),a=new Be({...r,containerId:null});a.render(!0,t),this.customComponents.set(s,a),a.on("change",n=>{this.handleFieldChange(s,n.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),a=new $e({...r,containerId:null});a.render(!0,t),this.customComponents.set(s,a),a.on("change",n=>{this.handleFieldChange(s,n.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),a=new We({...r,containerId:null});a.render(!0,t),this.customComponents.set(s,a),a.on("change",n=>{this.handleFieldChange(s,n.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),a=new Ye({...r,containerId:null});let n=$.getContextData(this.data,s);n&&a.setValue(n),a.render(!0,t),this.customComponents.set(s,a),a.on("change",o=>{this.handleFieldChange(s,o.value)}),a.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 a=r.getAttribute("data-show-when-value").split(","),n=r.getAttribute("data-show-when-negate")==="true",o=a.includes(i),l=n?!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);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)});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 a=this.getFormFieldConfig(s);a?this.setFieldValue(r,a,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(n=>{n.classList.remove("active"),n.classList.add("btn-outline-primary"),n.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 a=[];i.forEach(o=>{o.checked&&a.push(o.value)}),this.data[r]=a;const n=s.querySelector('[data-bs-toggle="dropdown"]');n&&window.bootstrap?.Dropdown&&window.bootstrap.Dropdown.getInstance(n)?.hide(),this.emit("field:changed",{field:r,value:a,form:this}),this.emit("change",{field:r,value:a,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 a=URL.createObjectURL(i);if(console.log("FormView: previewUrl created:",a),r&&r.imageSize){console.log("FormView: Image cropping is required, imageSize:",r.imageSize);try{const n=window.MOJO?.plugins?.ImageCropView;if(console.log("FormView: ImageCropView available?",!!n),!n){console.log("FormView: ImageCropView not available, falling back to normal handling"),this.data[s]=i,await this.updateImagePreview(s,a),this.emit("image:selected",{field:s,file:i,form:this});return}const o=await n.showDialog(a,{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(n){console.error("FormView: Error during image cropping:",n),console.log("FormView: Falling back to normal image handling after error"),this.data[s]=i,await this.updateImagePreview(s,a),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,a),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 a=this.element.querySelector(`#${r}`);a&&(a.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(n=>{const o=n.textContent.toLowerCase();n.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 a=e[0],n=this.element.querySelector(`input[name="${r}"]`);if(n){const l=new DataTransfer;l.items.add(a),n.files=l.files,n.dispatchEvent(new Event("change",{bubbles:!0}))}this.data[r]=a;const o=URL.createObjectURL(a);await this.updateImagePreview(r,o),this.emit("image:dropped",{field:r,file:a,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 a=t(r.fields);if(a)return a}}}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[n,o]of t.entries())s[n]?(Array.isArray(s[n])||(s[n]=[s[n]]),s[n].push(o)):s[n]=o;e.querySelectorAll('input[type="checkbox"]').forEach(n=>{s[n.name]=n.checked}),e.querySelectorAll('input[type="number"]').forEach(n=>{if(n.name&&s[n.name]!==void 0&&s[n.name]!==""){const o=Number(s[n.name]);isNaN(o)||(s[n.name]=o)}}),this.formConfig.fields?.forEach(n=>{if(n.type==="select"&&n.name&&s[n.name]!==void 0){const o=this.getFormFieldConfig(n.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[n.name]!==""){const d=Number(s[n.name]);isNaN(d)||(s[n.name]=d)}}}),e.querySelectorAll('[data-field-type="json"]').forEach(n=>{try{s[n.name]=JSON.parse(n.value)}catch{s[n.name]=n.value}}),this.customComponents.forEach((n,o)=>{n.getFormValue?s[o]=n.getFormValue():n.getValue&&(s[o]=n.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[n,o]of Object.entries(this.data))if(o instanceof File)try{s[n]=await this.fileToBase64(o)}catch{s[n]=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[n]=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);if(!t||Object.keys(t).length===0)return{success:!0,message:"No changes to save",data:e};try{return this._isFormDrivenChange=!0,await this.model.save(t)}catch(s){throw s}}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,a]of e.entries())if(a instanceof File)a.size===0||a.name===""||a.name==="blob"||(s.set(r,a),i=!0);else{const n=t[r];a!==n&&a!==String(n)&&(s.set(r,a),i=!0)}return i?s:null}getChangedObjectData(e,t){const s={};let i=!1;const r=new Set([...Object.keys(t),...Object.keys(e)]),a=(n,o)=>o.split(".").reduce((l,d)=>l&&typeof l=="object"?l[d]:void 0,n);for(const n of r){const o=this.findFieldConfig(n);if(!o)continue;const l=e[n],d=a(t,n),h=o.type||"text";this.valuesAreDifferent(l,d,h,o)&&(s[n]=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 n=i.valueField||"id";if(t[n]==e)return!1}if(s==="switch"||s==="checkbox"||s==="toggle")return!!e!==!!t;const r=e==null?"":String(e).trim(),a=t==null?"":String(t).trim();return r!==a}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 a=window.bootstrap?.Tab?.getOrCreateInstance?window.bootstrap.Tab.getOrCreateInstance(r):null;a&&typeof a.show=="function"?a.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){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);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)});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);if(!t||Object.keys(t).length===0)return{success:!0,message:"No changes to save",data:e};try{return this._isFormDrivenChange=!0,await this.model.save(t)}catch(s){throw s}}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,a=s.getAttribute("data-field-id");if(t){if(i)i.src=t;else{const n=`${a}_preview`;s.innerHTML=`
1284
- <img id="${n}"
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=`
1284
+ <img id="${a}"
1285
1285
  src="${t}"
1286
1286
  alt="Preview"
1287
1287
  class="img-thumbnail w-100 h-100"
@@ -1289,12 +1289,12 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1289
1289
  <button type="button"
1290
1290
  class="btn btn-sm btn-danger position-absolute top-0 end-0 m-1"
1291
1291
  data-action="remove-image"
1292
- data-field-id="${a}"
1292
+ data-field-id="${n}"
1293
1293
  data-field="${e}"
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 a=t(r.fields);if(a)return a}}}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 a=r.getModifierState("CapsLock");this.updateCapsLockWarning(t,!!a)}};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 n=t.closest(".input-group");n&&(i=n.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 a=t.querySelector("i");a&&(a.classList.toggle("bi-eye",!r),a.classList.toggle("bi-eye-slash",r)),i.focus();try{const n=i.value?.length??0;i.setSelectionRange(n,n)}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 a=r.className;r.className="bi bi-check2",t.classList.add("btn-success"),t.classList.remove("btn-outline-secondary"),setTimeout(()=>{r.className=a,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),a=/\d/.test(e),n=/[^A-Za-z0-9]/.test(e),o=[i,r,a,n].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:a}=this.computePasswordStrength(e.value||"");t&&(t.className=`progress-bar ${a}`,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 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=`
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 Mt=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",...a}=e;super({tagName:"div",className:"segment-control",...a}),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",a=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 Mt=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"
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"'}>${a}${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 n=e.start!==void 0&&e.start!==null&&e.start!=="",o=e.end!==void 0&&e.end!==null&&e.end!=="";return n||o?n&&o?`${t} between '${e.start}' and '${e.end}'`:n?`${t} from '${e.start}'`:`${t} until '${e.end}'`:`${t} is '${JSON.stringify(e)}'`}const a=Array.isArray(e)?e.join(","):String(e);if(!i||i==="exact")return`${t} is '${a}'`;if(i==="in"||i==="not_in"){const n=a.split(",").map(l=>l.trim()).filter(l=>l);if(n.length===0)return`${t} ${r.display}`;const o=n.map(l=>`'${l}'`).join(", ");return`${t} ${r.display} ${o}`}if(i==="range"){const n=a.split(",").map(o=>o.trim()).filter(o=>o);return n.length===2?`${t} between '${n[0]}' and '${n[1]}'`:`${t} ${r.display} '${a}'`}if(i==="isnull"){const n=typeof r.display=="function"?r.display(a):r.display;return`${t} ${n}`}return r?`${t} ${r.display} '${a}'`:`${t} is '${a}'`}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 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=`
1323
1323
  <div class="list-item-content" data-action="select">
1324
1324
  {{#model}}
1325
1325
  {{#id}}<span class="item-id">{{id}}</span>{{/id}}
@@ -1332,7 +1332,7 @@ 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"]'),a=this.element.querySelector('[data-value="end"]'),n=this.element.querySelector('[data-value="total"]');r&&(r.textContent=e===0?0:t+1),a&&(a.textContent=i),n&&(n.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 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`
1336
1336
  <div class="list-view-container">
1337
1337
  {{#loading}}
1338
1338
  <div class="list-loading">
@@ -1434,7 +1434,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1434
1434
  <i class="bi bi-download me-1"></i>
1435
1435
  <span class="d-none d-lg-inline">Export</span>
1436
1436
  </button>
1437
- `)}}return this.toolbarButtons&&this.toolbarButtons.length>0&&this.toolbarButtons.forEach((t,s)=>{const{label:i="Button",icon:r="",action:a="",handler:n=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(a),y=r?`<i class="${u} me-1"></i>`:"",C=`<span class="d-none d-lg-inline">${m}</span>`;let _="";n?_=`data-action="custom-toolbar-button" data-button-index="${s}"`:a&&(_=`data-action="${b}"`);const A=`btn btn-sm btn-${f} ${g}`.trim();e.push(`
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
1438
  <button class="${A}" ${_} title="${p}">
1439
1439
  ${y}${C}
1440
1440
  </button>
@@ -1468,9 +1468,9 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1468
1468
  <span class="d-none d-lg-inline">Sort</span>
1469
1469
  </button>
1470
1470
  <ul class="dropdown-menu dropdown-menu-end">
1471
- ${this.sortOptions.map(i=>{const a=`${i.dir==="desc"?"-":""}${i.key}`;return`
1472
- <li><a class="dropdown-item ${e===a?"active":""}" href="#"
1473
- data-action="sort-option" data-sort="${this.escapeHtml(a)}">
1471
+ ${this.sortOptions.map(i=>{const n=`${i.dir==="desc"?"-":""}${i.key}`;return`
1472
+ <li><a class="dropdown-item ${e===n?"active":""}" href="#"
1473
+ data-action="sort-option" data-sort="${this.escapeHtml(n)}">
1474
1474
  ${this.escapeHtml(i.label||i.key)}
1475
1475
  </a></li>
1476
1476
  `}).join("")}
@@ -1494,11 +1494,11 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1494
1494
  </div>
1495
1495
  </div>
1496
1496
  `:""}buildFilterList(){const e=this.getAllAvailableFilters(),t=this.getActiveFilters();return e.length===0?'<div class="dropdown-item-text text-muted">No filters available</div>':`
1497
- ${e.map(i=>{const r=Object.prototype.hasOwnProperty.call(t,i.key),a=r?"active":"",n=this.getFilterIcon(i.type||i.config?.type);return`
1498
- <button class="dropdown-item ${a}"
1497
+ ${e.map(i=>{const r=Object.prototype.hasOwnProperty.call(t,i.key),n=r?"active":"",a=this.getFilterIcon(i.type||i.config?.type);return`
1498
+ <button class="dropdown-item ${n}"
1499
1499
  data-action="add-filter"
1500
1500
  data-filter-key="${this.escapeHtml(i.key)}">
1501
- <i class="bi bi-${this.escapeHtml(n)} me-2"></i>
1501
+ <i class="bi bi-${this.escapeHtml(a)} me-2"></i>
1502
1502
  ${this.escapeHtml(i.label||i.key)}
1503
1503
  ${r?'<i class="bi bi-check-circle ms-auto"></i>':""}
1504
1504
  </button>
@@ -1509,7 +1509,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1509
1509
  <i class="bi bi-x-circle me-2"></i>Clear All Filters
1510
1510
  </button>
1511
1511
  `:""}
1512
- `}buildActivePills(){if(this.hideActivePills)return"";const e=this.getActiveFilters(),t=e.search&&e.search.toString().trim()!=="";let s=Object.entries(e).filter(([n,o])=>o&&o.toString().trim()!==""&&n!=="search");if(this.hideActivePillNames&&this.hideActivePillNames.length>0&&(s=s.filter(([n])=>!this.hideActivePillNames.includes(n))),s.length===0&&!t)return"";const i=s.map(([n,o])=>{const{field:l}=ge(n),d=this.getFilterLabel(l),h=this.escapeHtml($s(n,o,d)),u=this.escapeHtml(n);return`
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`
1513
1513
  <span class="badge bg-primary me-1 mb-1 py-1 px-2 position-relative" style="font-size: 0.75rem;">
1514
1514
  <i class="bi bi-filter me-1" style="font-size: 0.65rem;"></i>
1515
1515
 
@@ -1528,7 +1528,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1528
1528
  title="Remove filter">
1529
1529
  </button>
1530
1530
  </span>
1531
- `}).join(""),a=s.length>1||s.length>0&&t||s.length===0&&t?`
1531
+ `}).join(""),n=s.length>1||s.length>0&&t||s.length===0&&t?`
1532
1532
  <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
1533
  <i class="bi bi-x-circle me-1" style="font-size: 0.7rem;"></i>
1534
1534
  <small>Clear All</small>
@@ -1538,7 +1538,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1538
1538
  <div class="col-12">
1539
1539
  <div class="d-flex flex-wrap align-items-center">
1540
1540
  ${i}
1541
- ${a}
1541
+ ${n}
1542
1542
  </div>
1543
1543
  </div>
1544
1544
  </div>
@@ -1581,13 +1581,13 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1581
1581
  </button>
1582
1582
  </div>
1583
1583
  {{/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 a=Math.floor(Date.now()/1e3)-i*86400;this.collection.params[`${s}__gte`]=a,this.collection.params.start=0,r={[`${s}__gte`]:a}}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(a){console.error("Failed to fetch day-range data:",a),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 a=this.itemViews.get(i.id);if(!a)return;let n;try{n=e(i)}catch(o){console.warn("ListView: groupBy resolver threw — treating as ungrouped tail",o),n=null}if(n&&(!s||n!==t)){const o=this._createGroupHeaderView(i,n,r);this._renderOrder.push({type:"header",view:o}),t=n,s=!0}this._renderOrder.push({type:"item",view:a})})}_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 a=await v.form({model:r,...i,...this.getFormDialogConfig(s)});if(a){this.options.addRequiresActiveGroup&&(a.group=this.getApp().activeGroup.id),this.options.addRequiresActiveUser&&(a.user=this.getApp().activeUser.id),this.options.addFormDefaults&&Object.assign(a,this.options.addFormDefaults);const n=await r.save(a);if(!n?.data.status){v.showError(n?.data.error||"An error occurred");return}this.collection&&this.collection.add(r),await this.refresh()}}else{const r=new s,a=await v.dialog({title:`Add ${this.getModelName()}`,body:new te({model:r,fields:this.options.formFields||[]})});if(a){const n=await r.save(a);if(!n?.data.status){v.showError(n.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,a=Math.ceil(t/s);if(a<=1){e.innerHTML="";return}const n=r>1?r-1:a,o=r<a?r+1:1,l=[];l.push(`
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(`
1585
1585
  <li class="page-item">
1586
- <a class="page-link" href="#" data-action="page" data-page="${n}">
1586
+ <a class="page-link" href="#" data-action="page" data-page="${a}">
1587
1587
  <i class="bi bi-chevron-left"></i>
1588
1588
  </a>
1589
1589
  </li>
1590
- `);const d=1,h=new Set([1,a]);for(let p=r-d;p<=r+d;p++)p>=1&&p<=a&&h.add(p);const u=Array.from(h).sort((p,f)=>p-f);let m=0;for(const p of u)m&&p-m>1&&l.push('<li class="page-item disabled"><span class="page-link">…</span></li>'),l.push(`
1590
+ `);const d=1,h=new Set([1,n]);for(let p=r-d;p<=r+d;p++)p>=1&&p<=n&&h.add(p);const u=Array.from(h).sort((p,f)=>p-f);let m=0;for(const p of u)m&&p-m>1&&l.push('<li class="page-item disabled"><span class="page-link">…</span></li>'),l.push(`
1591
1591
  <li class="page-item ${p===r?"active":""}">
1592
1592
  <a class="page-link" href="#" data-action="page" data-page="${p}">${p}</a>
1593
1593
  </li>
@@ -1597,7 +1597,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1597
1597
  <i class="bi bi-chevron-right"></i>
1598
1598
  </a>
1599
1599
  </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(),a=Math.max(1,Math.ceil(r/i));let n=isNaN(s)?1:s;n<1&&(n=a),n>a&&(n=1),this.collection.setParams({...this.collection.params,start:(n-1)*i}),this.collection.restEnabled?await this.collection.fetch():this.render(),this.emit("list:page",{page:n,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 a=await v.form({title:`${r!==void 0&&r!==""?"Edit":"Add"} ${this.getFilterLabel(s)} Filter`,size:"md",fields:[this.buildFilterDialogField(i,r,s)]});if(a){const n=this.extractFilterValue(i,a);this.setFilter(s,n),await this.applyFilters()}}async onActionEditFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=ge(s),r=this.getFilterConfig(i)||this.getFilterConfig(s),a=this.getActiveFilters(),n=a[s]||a[i];if(!r){console.warn("No filter config found for key:",s,"or field:",i);return}const o={filter_value:n};if(r.type==="daterange"&&n&&typeof n=="object"){const d=r.startName||"dr_start",h=r.endName||"dr_end";o[d]=n.start||"",o[h]=n.end||""}const l=await v.form({title:`Edit ${this.getFilterLabel(i)} Filter`,size:"md",data:o,fields:[this.buildFilterDialogField(r,n,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,a={start:s,size:i};r&&(a.sort=r),Array.isArray(this.hideActivePillNames)&&this.hideActivePillNames.length>0&&this.hideActivePillNames.forEach(n=>{this.collection.params[n]!==void 0&&(a[n]=this.collection.params[n]);const o=this.getFilterConfig(n);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&&(a[l]=this.collection.params[l]),this.collection.params[d]!==void 0&&(a[d]=this.collection.params[d]),this.collection.params[h]!==void 0&&(a[h]=this.collection.params[h])}}),this.collection.params=a,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={},a=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]||""},a.add(d),a.add(h),a.add(u))}}),Object.keys(i).forEach(o=>{a.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",a=s.fieldName||"dr_field";delete this.collection.params[i],delete this.collection.params[r],delete this.collection.params[a],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[a]=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,...a}=e,n={...a,name:"filter_value",label:a.label,value:t,placeholder:a.placeholder||a.placeHolder};if(e.type==="daterange"){if(n.startName=n.startName||"dr_start",n.endName=n.endName||"dr_end",n.fieldName=n.fieldName||"dr_field",n.format=n.format||"YYYY-MM-DD",n.displayFormat=n.displayFormat||"MMM DD, YYYY",n.separator=n.separator||" to ",n.label=n.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)};n.startDate=o(t.start||t.from||t.begin||""),n.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))),n.value=o,!n.placeholder&&!n.placeHolder&&(e.placeholder||e.placeHolder?n.placeholder=e.placeholder||e.placeHolder:e.label&&(n.placeholder=`Select ${e.label}...`))}else if(e.type==="boolean"||e.type==="switch"||e.type==="toggle"){n.type="select";const o=t!=null&&t!==""?t:e.defaultValue,l=o===!0?"true":o===!1?"false":o==null?"":String(o);n.value=l;const d=e.trueLabel||"True",h=e.falseLabel||"False";n.options=[{value:"true",text:d},{value:"false",text:h}],!n.placeholder&&!n.placeHolder&&(n.placeholder=e.label?`Filter by ${e.label}…`:"Select…")}return n}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||"")}checkPermissions(e){return!0}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+=`
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||"")}checkPermissions(e){return!0}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+=`
1601
1601
  <td style="padding: 0;">
1602
1602
  <div class="mojo-select-cell {{#selected}}selected{{/selected}}"
1603
1603
  data-action="select">
@@ -1606,7 +1606,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1606
1606
  </div>
1607
1607
  </div>
1608
1608
  </td>
1609
- `),this.columns.forEach((t,s)=>{const i=t.class||t.className||"",r=this.getResponsiveClasses(t.visibility),a=t.editable?"editable-cell":"",n=this.tableView&&this.tableView.getAlignClass?this.tableView.getAlignClass(t.align):"",o=[i,r,a,n].filter(h=>h).join(" "),l=this.buildCellTemplate(t,s);let d=t.action;!d&&t.editable?d="edit-cell":!d&&this.tableView.rowAction&&(d=this.tableView.rowAction),d?e+=`<td class="${o}" data-action="${d}" data-column="${t.key}">${l}</td>`:e+=`<td class="${o}" data-column="${t.key}">${l}</td>`}),this.actions?e+=this.buildActionsTemplate():this.contextMenu&&(e+=this.buildContextMenuTemplate()),e}buildCellTemplate(e,t=0){const s=`model.${e.key}`,i=e.formatter||e.format,r=e.editable?` class="cell-content" data-field="${e.key}"`:"";if(i){if(typeof i=="string")return e.editable?`<span${r}>{{{${s}|${i}}}}</span>`:`{{{${s}|${i}}}}`;if(typeof i=="function"){const a=e.editable?"cell-content":"",n=e.editable?` data-field="${e.key}"`:"";return`<span class="${a}" data-formatter="${e.key}" data-formatter-id="${t}"${n}>{{${s}}}</span>`}}return e.template?e.editable?`<span${r}>${e.template}</span>`:e.template:e.editable?`<span${r}>{{{${s}}}}</span>`:`{{{${s}}}}`}buildActionsTemplate(){return!this.actions||this.actions.length===0?"":`<td><div class="btn-group btn-group-sm">${this.actions.map(t=>{if(typeof t=="string")switch(t){case"view":return`
1609
+ `),this.columns.forEach((t,s)=>{const i=t.class||t.className||"",r=this.getResponsiveClasses(t.visibility),n=t.editable?"editable-cell":"",a=this.tableView&&this.tableView.getAlignClass?this.tableView.getAlignClass(t.align):"",o=[i,r,n,a].filter(h=>h).join(" "),l=this.buildCellTemplate(t,s);let d=t.action;!d&&t.editable?d="edit-cell":!d&&this.tableView.rowAction&&(d=this.tableView.rowAction),d?e+=`<td class="${o}" data-action="${d}" data-column="${t.key}">${l}</td>`:e+=`<td class="${o}" data-column="${t.key}">${l}</td>`}),this.actions?e+=this.buildActionsTemplate():this.contextMenu&&(e+=this.buildContextMenuTemplate()),e}buildCellTemplate(e,t=0){const s=`model.${e.key}`,i=e.formatter||e.format,r=e.editable?` class="cell-content" data-field="${e.key}"`:"";if(i){if(typeof i=="string")return e.editable?`<span${r}>{{{${s}|${i}}}}</span>`:`{{{${s}|${i}}}}`;if(typeof i=="function"){const n=e.editable?"cell-content":"",a=e.editable?` data-field="${e.key}"`:"";return`<span class="${n}" data-formatter="${e.key}" data-formatter-id="${t}"${a}>{{${s}}}</span>`}}return e.template?e.editable?`<span${r}>${e.template}</span>`:e.template:e.editable?`<span${r}>{{{${s}}}}</span>`:`{{{${s}}}}`}buildActionsTemplate(){return!this.actions||this.actions.length===0?"":`<td><div class="btn-group btn-group-sm">${this.actions.map(t=>{if(typeof t=="string")switch(t){case"view":return`
1610
1610
  <button class="btn btn-sm btn-outline-primary"
1611
1611
  data-action="view"
1612
1612
  title="View">
@@ -1657,7 +1657,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1657
1657
  ${e.label}
1658
1658
  </a>
1659
1659
  </li>
1660
- `}).join("")}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],a={value:r,row:this.model,model:this.model,column:t,table:this.tableView,index:this.index};try{i.innerHTML=t.formatter(r,a)}catch(n){console.error(`Error formatting cell for column ${t.key}:`,n)}}}}),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],a=this.createCellEditor(t,r),n=i.innerHTML;i.style.display="none";const o=document.createElement("div");o.className="cell-editor",o.innerHTML=a,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=n,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`
1660
+ `}).join("")}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`
1661
1661
  <div class="d-flex gap-1 align-items-center">
1662
1662
  <input type="${e.inputType||"text"}"
1663
1663
  class="form-control form-control-sm cell-input"
@@ -1684,7 +1684,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1684
1684
  </button>
1685
1685
  </div>
1686
1686
  </div>
1687
- `}createSelectEditor(e,t){const s=e.options||[];let i="";return s.forEach(r=>{if(typeof r=="string")i+=`<option value="${r}" ${r===t?"selected":""}>${r}</option>`;else if(typeof r=="object"&&r.value!==void 0){const a=r.value===t?"selected":"";i+=`<option value="${r.value}" ${a}>${r.label||r.value}</option>`}}),`
1687
+ `}createSelectEditor(e,t){const s=e.options||[];let i="";return s.forEach(r=>{if(typeof r=="string")i+=`<option value="${r}" ${r===t?"selected":""}>${r}</option>`;else if(typeof r=="object"&&r.value!==void 0){const n=r.value===t?"selected":"";i+=`<option value="${r.value}" ${n}>${r.label||r.value}</option>`}}),`
1688
1688
  <div class="d-flex gap-1 align-items-center">
1689
1689
  <select class="form-select form-select-sm cell-input">
1690
1690
  ${i}
@@ -1710,7 +1710,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1710
1710
  </button>
1711
1711
  </div>
1712
1712
  </div>
1713
- `}setupEditorEvents(e,t,s){const i=e.querySelector(".cell-input"),r=e.querySelector(".cell-save"),a=e.querySelector(".cell-cancel");i&&(i.type==="text"||i.type==="email"||i.type==="number")&&i.addEventListener("keydown",n=>{n.key==="Enter"?(n.preventDefault(),this.saveCellEdit(e,t,s)):n.key==="Escape"&&(n.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)}),a?.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 a=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:a,newValue:r})}catch(n){console.error("Failed to save cell edit:",n),this.emit("cell:save:error",{row:this,model:this.model,column:t,oldValue:a,newValue:r,error:n}),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 a=e.closest("td").querySelector(".cell-content");if(a){if(s!==null){const n=this.columns.find(l=>l.key===t);let o=s;n&&n.formatter&&typeof n.formatter=="string"&&(o=V.pipe(s,n.formatter)),a.innerHTML=this.escapeHtml(o)}else i&&(a.innerHTML=i);a.style.display=""}e.remove(),this.editingCells.delete(t)}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=e,t.innerHTML}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||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 a=this.parseColumnKey(s.key).formatter||s.formatter;let n;a&&typeof a=="string"?n=this.formatValue(e[i].value,a):n=e[i].value,r.textContent=n}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 a=0;this.collection.forEach(o=>{const l=o.get?o.get(i):o[i],d=parseFloat(l)||0;a+=d});const n=`col_${s}`;e[n]={value:a,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`
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){if(e==null)return"";const t=document.createElement("div");return t.textContent=e,t.innerHTML}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||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`
1714
1714
  <div class="mojo-table-wrapper">
1715
1715
  ${this.buildToolbarTemplate()}
1716
1716
  ${e}
@@ -1755,12 +1755,12 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1755
1755
  </div>
1756
1756
  </div>
1757
1757
  </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,a=this.getSortIcon(r),n=t.label||t.title||s,o=this.getResponsiveClasses(t.visibility),l=i?`
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?`
1759
1759
  <div class="dropdown d-inline-block ms-2">
1760
1760
  <button class="btn btn-sm btn-link p-0 text-decoration-none" type="button"
1761
1761
  data-bs-toggle="dropdown" aria-expanded="false"
1762
1762
  data-column="${s}">
1763
- ${a}
1763
+ ${n}
1764
1764
  </button>
1765
1765
  <ul class="dropdown-menu dropdown-menu-end">
1766
1766
  <li><a class="dropdown-item ${r==="asc"?"active":""}"
@@ -1780,7 +1780,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1780
1780
  `:"",d=this.getAlignClass(t.align);e+=`
1781
1781
  <th class="${i?"sortable":""} ${o} ${d}">
1782
1782
  <div class="d-flex align-items-center ${d==="text-center"?"justify-content-center":d==="text-end"?"justify-content-end":""}">
1783
- <span>${n}</span>
1783
+ <span>${a}</span>
1784
1784
  ${l}
1785
1785
  </div>
1786
1786
  </th>
@@ -1790,7 +1790,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1790
1790
  ${e}
1791
1791
  </tr>
1792
1792
  </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),a=this.getAlignClass(s.align);if(s.footer_total){const n=`col_${t}`,o=this.parseColumnKey(s.key).formatter||s.formatter;let l;o&&typeof o=="string"?l=`{{{footerTotals.${n}.value|${o}}}}`:l=`{{footerTotals.${n}.value}}`,e+=`<td class="table-footer-total ${r} ${a}" data-total-column="${n}">${l}</td>`,t++}else i===0?e+=`<td class="table-footer-label ${r} ${a}"><strong>Totals</strong></td>`:e+=`<td class="${r} ${a}"></td>`}),(this.actions||this.contextMenu)&&(e+="<td></td>"),`
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>"),`
1794
1794
  <tfoot>
1795
1795
  <tr class="table-totals-row">
1796
1796
  ${e}
@@ -1846,24 +1846,24 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1846
1846
  </div>
1847
1847
  </div>
1848
1848
  </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,a=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+a)}}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 a=r.startsWith("-"),n=a?r.slice(1):r;this.collection.sort((o,l)=>{const d=o.get(n),h=l.get(n);return d<h?a?1:-1:d>h?a?-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 a=e===i,n=this.getSortIcon(a?t:null);r.innerHTML=n;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",a&&t==="asc"),d&&d.classList.toggle("active",a&&t==="desc"),h&&h.classList.toggle("active",!a||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(a=>a.selected),i=Array.from(this.itemViews.values()).some(a=>a.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=ae,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:a,showEmptyValues:n,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:a!==!1,showEmptyValues:n||!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`
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`
1850
1850
  <div class="${this.dataViewOptions.rowClass}">
1851
1851
  ${e}
1852
1852
  </div>
1853
- `}generateFieldsFromData(){const e=this.getData();e&&typeof e=="object"&&(this.fields=Object.keys(e).map(t=>{const s=e[t],i=this.inferFieldType(s,t),r=this.inferFormatter(s,t,i);return{name:t,label:this.formatLabel(t),type:i,format:r,formatter:r}}))}formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/[_-]/g," ").replace(/\b\w/g,t=>t.toUpperCase()).trim()}inferFieldType(e,t=""){if(e==null)return"text";const s=t.toLowerCase(),i=typeof e;if(s.includes("date")||s.includes("time")||s.includes("created")||s.includes("updated")||s.includes("modified")||s.includes("last_login")||s.includes("expires")||s.includes("last_activity"))return"datetime";if(s.includes("email")||s.includes("mail"))return"email";if(s.includes("url")||s.includes("link")||s.includes("website")||s.includes("homepage"))return"url";if(s.includes("phone")||s.includes("tel")||s.includes("mobile")||s.includes("cell"))return"phone";if(s.includes("price")||s.includes("cost")||s.includes("amount")||s.includes("fee")||s.includes("salary")||s.includes("revenue"))return"currency";if(s.includes("size")||s.includes("bytes"))return"filesize";if(s.includes("percent")||s.includes("rate")||s.includes("ratio")&&i==="number")return"percent";if(i==="boolean")return"boolean";if(i==="number")return"number";if(i==="object")return Array.isArray(e)?"array":e&&e.renditions?"file":this.shouldUseDataView(e,s)?"dataview":"object";if(i==="string"){if(e.includes("@")&&e.includes("."))return"email";if(e.match(/^\d{4}-\d{2}-\d{2}/))return"date";if(e.match(/^https?:\/\//))return"url";if(e.match(/^\+?[\d\s\-\(\)]+$/))return"phone"}return"text"}inferFormatter(e,t,s){const i=t.toLowerCase(),r=[];switch(s){case"datetime":i.includes("time")&&!i.includes("date")?r.push("time"):i.includes("relative")||i.includes("ago")||i.includes("last_")?r.push("relative"):i.includes("created")||i.includes("updated")||i.includes("modified")?r.push('date("MMM D, YYYY")'):r.push('date("MMMM D, YYYY")');break;case"date":i.includes("birth")||i.includes("dob")?r.push('date("MMMM D, YYYY")'):r.push('date("MMM D, YYYY")');break;case"email":break;case"url":break;case"phone":r.push("phone");break;case"currency":r.push("currency"),i.includes("eur")||i.includes("euro")?r[r.length-1]='currency("EUR")':(i.includes("gbp")||i.includes("pound"))&&(r[r.length-1]='currency("GBP")');break;case"filesize":r.push("filesize");break;case"percent":r.push("percent");break;case"number":if(typeof e=="number")if(i.includes("count")||i.includes("total")||i.includes("followers")||i.includes("views"))e>=1e3?r.push("compact"):r.push("number");else if(i.includes("score")||i.includes("rating"))r.push("number"),e%1!==0&&(r[r.length-1]="number(1)");else{if(i.includes("version")||i.includes("id"))return null;r.push("number")}break;case"boolean":break;case"text":typeof e=="string"&&(i.includes("description")||i.includes("content")||i.includes("body")?e.length>200?r.push("truncate(200)"):e.length>100&&r.push("truncate(100)"):i.includes("summary")||i.includes("excerpt")?e.length>150&&r.push("truncate(150)"):i.includes("name")||i.includes("title")||i.includes("label")?(r.push("capitalize"),e.length>50&&r.unshift("truncate(50)")):i.includes("slug")||i.includes("handle")||i.includes("username")?r.push("slug"):i.includes("code")||i.includes("token")||i.includes("key")?e.length>20&&r.push("mask"):e.length>100&&r.push("truncate(100)"));break;case"array":case"object":break;case"dataview":break;default:typeof e=="string"&&e.length>100&&r.push("truncate(100)");break}return r.length>0?r.join("|"):null}shouldUseDataView(e,t){if(!e||typeof e!="object"||Array.isArray(e))return!1;const s=["permissions","perms","access","rights","settings","config","configuration","options","profile","info","details","data","metadata","meta","attributes","props","preferences","prefs","user_data","contact","address","location","stats","statistics","metrics","counts"];if(window.utils&&window.utils.isObject(e)&&e.id)return!0;if(s.some(r=>t.includes(r))){const r=Object.keys(e);if(r.length>=2&&r.length<=20&&!r.some(n=>typeof e[n]=="object"&&e[n]!==null&&!Array.isArray(e[n])&&Object.keys(e[n]).length>3))return!0}return!1}getData(){return this.model&&this.model.attributes?{...this.model.attributes}:this.data||{}}getFieldValue(e){let t,s=e.name||e.key,i=e.format||e.formatter;if(!s)return null;if(s&&s.includes("|")){const r=s.split("|");s=r[0].trim(),i||(i=r.slice(1).join("|").trim())}if(this.model&&typeof this.model.get=="function"?t=this.model.get(s):t=this.getData()[s],i&&(t=V.pipe(t,i)),t==null||t==="")return this.dataViewOptions.showEmptyValues?this.dataViewOptions.emptyValueText:null;if(e.template){const r=this.model?this.model:this.data;return this.renderTemplateString(e.template,r)}return t}renderTemplateString(e,t){return!e||!t?"":e.replace(/\{\{([^}]+)\}\}/g,(s,i)=>{const r=i.trim();let a;const n=r.split("|"),o=n[0],l=n.slice(1).join("|");return this.model&&typeof this.model.get=="function"?a=this.model.get(o):a=o.split(".").reduce((d,h)=>d?d[h]:void 0,t),l&&(a=V.pipe(a,l)),a??""})}getColumnClasses(e){let t=this.getColumnSizeClasses(e);return e.justify=="right"?t+=" d-flex justify-content-end":e.justify=="center"&&(t+=" d-flex justify-content-center"),t}getColumnSizeClasses(e){if(e.type==="array"||e.type==="object"||e.type==="dataview")return"col-12";const t=e.columns||e.colSize||e.cols||Math.floor(12/this.dataViewOptions.columns);return this.dataViewOptions.responsive?`col-12 col-md-${t}`:`col-${t}`}buildItemsHTML(){return this.fields.map(e=>this.buildItemHTML(e)).filter(Boolean).join("")}buildItemHTML(e){const t=this.getFieldValue(e);if(t===null&&!this.dataViewOptions.showEmptyValues)return"";const s=e.label||this.formatLabel(e.name);return`
1853
+ `}generateFieldsFromData(){const e=this.getData();e&&typeof e=="object"&&(this.fields=Object.keys(e).map(t=>{const s=e[t],i=this.inferFieldType(s,t),r=this.inferFormatter(s,t,i);return{name:t,label:this.formatLabel(t),type:i,format:r,formatter:r}}))}formatLabel(e){return e.replace(/([A-Z])/g," $1").replace(/[_-]/g," ").replace(/\b\w/g,t=>t.toUpperCase()).trim()}inferFieldType(e,t=""){if(e==null)return"text";const s=t.toLowerCase(),i=typeof e;if(s.includes("date")||s.includes("time")||s.includes("created")||s.includes("updated")||s.includes("modified")||s.includes("last_login")||s.includes("expires")||s.includes("last_activity"))return"datetime";if(s.includes("email")||s.includes("mail"))return"email";if(s.includes("url")||s.includes("link")||s.includes("website")||s.includes("homepage"))return"url";if(s.includes("phone")||s.includes("tel")||s.includes("mobile")||s.includes("cell"))return"phone";if(s.includes("price")||s.includes("cost")||s.includes("amount")||s.includes("fee")||s.includes("salary")||s.includes("revenue"))return"currency";if(s.includes("size")||s.includes("bytes"))return"filesize";if(s.includes("percent")||s.includes("rate")||s.includes("ratio")&&i==="number")return"percent";if(i==="boolean")return"boolean";if(i==="number")return"number";if(i==="object")return Array.isArray(e)?"array":e&&e.renditions?"file":this.shouldUseDataView(e,s)?"dataview":"object";if(i==="string"){if(e.includes("@")&&e.includes("."))return"email";if(e.match(/^\d{4}-\d{2}-\d{2}/))return"date";if(e.match(/^https?:\/\//))return"url";if(e.match(/^\+?[\d\s\-\(\)]+$/))return"phone"}return"text"}inferFormatter(e,t,s){const i=t.toLowerCase(),r=[];switch(s){case"datetime":i.includes("time")&&!i.includes("date")?r.push("time"):i.includes("relative")||i.includes("ago")||i.includes("last_")?r.push("relative"):i.includes("created")||i.includes("updated")||i.includes("modified")?r.push('date("MMM D, YYYY")'):r.push('date("MMMM D, YYYY")');break;case"date":i.includes("birth")||i.includes("dob")?r.push('date("MMMM D, YYYY")'):r.push('date("MMM D, YYYY")');break;case"email":break;case"url":break;case"phone":r.push("phone");break;case"currency":r.push("currency"),i.includes("eur")||i.includes("euro")?r[r.length-1]='currency("EUR")':(i.includes("gbp")||i.includes("pound"))&&(r[r.length-1]='currency("GBP")');break;case"filesize":r.push("filesize");break;case"percent":r.push("percent");break;case"number":if(typeof e=="number")if(i.includes("count")||i.includes("total")||i.includes("followers")||i.includes("views"))e>=1e3?r.push("compact"):r.push("number");else if(i.includes("score")||i.includes("rating"))r.push("number"),e%1!==0&&(r[r.length-1]="number(1)");else{if(i.includes("version")||i.includes("id"))return null;r.push("number")}break;case"boolean":break;case"text":typeof e=="string"&&(i.includes("description")||i.includes("content")||i.includes("body")?e.length>200?r.push("truncate(200)"):e.length>100&&r.push("truncate(100)"):i.includes("summary")||i.includes("excerpt")?e.length>150&&r.push("truncate(150)"):i.includes("name")||i.includes("title")||i.includes("label")?(r.push("capitalize"),e.length>50&&r.unshift("truncate(50)")):i.includes("slug")||i.includes("handle")||i.includes("username")?r.push("slug"):i.includes("code")||i.includes("token")||i.includes("key")?e.length>20&&r.push("mask"):e.length>100&&r.push("truncate(100)"));break;case"array":case"object":break;case"dataview":break;default:typeof e=="string"&&e.length>100&&r.push("truncate(100)");break}return r.length>0?r.join("|"):null}shouldUseDataView(e,t){if(!e||typeof e!="object"||Array.isArray(e))return!1;const s=["permissions","perms","access","rights","settings","config","configuration","options","profile","info","details","data","metadata","meta","attributes","props","preferences","prefs","user_data","contact","address","location","stats","statistics","metrics","counts"];if(window.utils&&window.utils.isObject(e)&&e.id)return!0;if(s.some(r=>t.includes(r))){const r=Object.keys(e);if(r.length>=2&&r.length<=20&&!r.some(a=>typeof e[a]=="object"&&e[a]!==null&&!Array.isArray(e[a])&&Object.keys(e[a]).length>3))return!0}return!1}getData(){return this.model&&this.model.attributes?{...this.model.attributes}:this.data||{}}getFieldValue(e){let t,s=e.name||e.key,i=e.format||e.formatter;if(!s)return null;if(s&&s.includes("|")){const r=s.split("|");s=r[0].trim(),i||(i=r.slice(1).join("|").trim())}if(this.model&&typeof this.model.get=="function"?t=this.model.get(s):t=this.getData()[s],i&&(t=V.pipe(t,i)),t==null||t==="")return this.dataViewOptions.showEmptyValues?this.dataViewOptions.emptyValueText:null;if(e.template){const r=this.model?this.model:this.data;return this.renderTemplateString(e.template,r)}return t}renderTemplateString(e,t){return!e||!t?"":e.replace(/\{\{([^}]+)\}\}/g,(s,i)=>{const r=i.trim();let n;const a=r.split("|"),o=a[0],l=a.slice(1).join("|");return this.model&&typeof this.model.get=="function"?n=this.model.get(o):n=o.split(".").reduce((d,h)=>d?d[h]:void 0,t),l&&(n=V.pipe(n,l)),n??""})}getColumnClasses(e){let t=this.getColumnSizeClasses(e);return e.justify=="right"?t+=" d-flex justify-content-end":e.justify=="center"&&(t+=" d-flex justify-content-center"),t}getColumnSizeClasses(e){if(e.type==="array"||e.type==="object"||e.type==="dataview")return"col-12";const t=e.columns||e.colSize||e.cols||Math.floor(12/this.dataViewOptions.columns);return this.dataViewOptions.responsive?`col-12 col-md-${t}`:`col-${t}`}buildItemsHTML(){return this.fields.map(e=>this.buildItemHTML(e)).filter(Boolean).join("")}buildItemHTML(e){const t=this.getFieldValue(e);if(t===null&&!this.dataViewOptions.showEmptyValues)return"";const s=e.label||this.formatLabel(e.name);return`
1854
1854
  <div class="${this.getColumnClasses(e)}">
1855
1855
  <div class="${this.dataViewOptions.itemClass} ${e.className}" data-field="${e.name}">
1856
1856
  ${this.buildLabelHTML(s,e)}
1857
1857
  ${this.buildValueHTML(t,e)}
1858
1858
  </div>
1859
1859
  </div>
1860
- `}buildLabelHTML(e,t){return`<div class="${t.labelClass||this.dataViewOptions.labelClass}">${this.escapeHtml(e)}:</div>`}buildValueHTML(e,t){const s=t.valueClass||this.dataViewOptions.valueClass,i=this.formatDisplayValue(e,t);return`<div class="${s}">${i}</div>`}formatDisplayValue(e,t){if(e==null)return this.dataViewOptions.emptyValueText;if(t.template||t.format||t.formatter)return String(e);const i=this.getData()[t.name];switch(t.type){case"boolean":return i?'<span class="badge bg-success">Yes</span>':'<span class="badge bg-secondary">No</span>';case"email":const r=String(e);return`<a href="mailto:${this.escapeHtml(r)}" class="text-decoration-none">${this.escapeHtml(r)}</a>`;case"url":const a=String(e);return`<a href="${this.escapeHtml(a)}" target="_blank" rel="noopener" class="text-decoration-none">${this.escapeHtml(a)} <i class="bi bi-box-arrow-up-right"></i></a>`;case"array":case"object":return this.formatAsJson(i);case"dataview":return this.formatAsDataView(i,t);case"phone":const n=String(e);return`<a href="tel:${n.replace(/[^\d\+]/g,"")}" class="text-decoration-none">${this.escapeHtml(n)}</a>`;default:return this.escapeHtml(String(e))}}formatAsJson(e){try{const t=JSON.stringify(e,null,2),s=this.escapeHtml(t),i=t.split(`
1861
- `).length,r=i>10||t.length>500,a=`json-${Math.random().toString(36).substr(2,9)}`;if(r){const n=JSON.stringify(e).substring(0,100)+(JSON.stringify(e).length>100?"...":""),o=this.escapeHtml(n);return`
1860
+ `}buildLabelHTML(e,t){return`<div class="${t.labelClass||this.dataViewOptions.labelClass}">${this.escapeHtml(e)}:</div>`}buildValueHTML(e,t){const s=t.valueClass||this.dataViewOptions.valueClass,i=this.formatDisplayValue(e,t);return`<div class="${s}">${i}</div>`}formatDisplayValue(e,t){if(e==null)return this.dataViewOptions.emptyValueText;if(t.template||t.format||t.formatter)return String(e);const i=this.getData()[t.name];switch(t.type){case"boolean":return i?'<span class="badge bg-success">Yes</span>':'<span class="badge bg-secondary">No</span>';case"email":const r=String(e);return`<a href="mailto:${this.escapeHtml(r)}" class="text-decoration-none">${this.escapeHtml(r)}</a>`;case"url":const n=String(e);return`<a href="${this.escapeHtml(n)}" target="_blank" rel="noopener" class="text-decoration-none">${this.escapeHtml(n)} <i class="bi bi-box-arrow-up-right"></i></a>`;case"array":case"object":return this.formatAsJson(i);case"dataview":return this.formatAsDataView(i,t);case"phone":const a=String(e);return`<a href="tel:${a.replace(/[^\d\+]/g,"")}" class="text-decoration-none">${this.escapeHtml(a)}</a>`;default:return this.escapeHtml(String(e))}}formatAsJson(e){try{const t=JSON.stringify(e,null,2),s=this.escapeHtml(t),i=t.split(`
1861
+ `).length,r=i>10||t.length>500,n=`json-${Math.random().toString(36).substr(2,9)}`;if(r){const a=JSON.stringify(e).substring(0,100)+(JSON.stringify(e).length>100?"...":""),o=this.escapeHtml(a);return`
1862
1862
  <div class="json-container">
1863
1863
  <div class="d-flex align-items-center justify-content-between mb-1">
1864
1864
  <small class="text-muted">${Array.isArray(e)?"Array":"Object"} (${i} lines)</small>
1865
1865
  <div class="btn-group btn-group-sm" role="group">
1866
- <button type="button" class="btn btn-outline-secondary btn-sm json-toggle" data-bs-toggle="collapse" data-bs-target="#${a}" aria-expanded="false">
1866
+ <button type="button" class="btn btn-outline-secondary btn-sm json-toggle" data-bs-toggle="collapse" data-bs-target="#${n}" aria-expanded="false">
1867
1867
  <i class="bi bi-eye"></i> Show
1868
1868
  </button>
1869
1869
  <button type="button" class="btn btn-outline-secondary btn-sm json-copy" data-json='${this.escapeHtml(t)}' title="Copy JSON">
@@ -1874,7 +1874,7 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1874
1874
  <div class="json-preview bg-light p-2 rounded small border" style="font-family: 'Courier New', monospace;">
1875
1875
  <code class="text-muted">${o}</code>
1876
1876
  </div>
1877
- <div class="collapse mt-2" id="${a}">
1877
+ <div class="collapse mt-2" id="${n}">
1878
1878
  <pre class="json-display p-3 rounded small mb-0" style="max-height: 400px; overflow-y: auto; white-space: pre-wrap; font-family: 'Courier New', monospace;"><code>${this.syntaxHighlightJson(s)}</code></pre>
1879
1879
  </div>
1880
1880
  </div>
@@ -1894,5 +1894,5 @@ var MOJO=(function(T){"use strict";class Te{constructor(e={}){this.defaultRoute=
1894
1894
  ${i}
1895
1895
  </div>
1896
1896
  </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",()=>{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=ae,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})({});
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",()=>{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})({});
1898
1898
  //# sourceMappingURL=web-mojo.lite.iife.min.js.map