web-mojo 2.3.5 → 2.3.7

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 (62) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/dist/admin.cjs.js +1 -1
  3. package/dist/admin.es.js +1 -1
  4. package/dist/auth.cjs.js +1 -1
  5. package/dist/auth.es.js +1 -1
  6. package/dist/charts.cjs.js +1 -1
  7. package/dist/charts.es.js +1 -1
  8. package/dist/chunks/{AssistantPanelView-D3WCWj5q.js → AssistantPanelView-B5tMna_t.js} +2 -2
  9. package/dist/chunks/{AssistantPanelView-D3WCWj5q.js.map → AssistantPanelView-B5tMna_t.js.map} +1 -1
  10. package/dist/chunks/{AssistantPanelView-CvjzGGS8.js → AssistantPanelView-BOdIQuqK.js} +2 -2
  11. package/dist/chunks/{AssistantPanelView-CvjzGGS8.js.map → AssistantPanelView-BOdIQuqK.js.map} +1 -1
  12. package/dist/chunks/{ChatView-B-2JVhM3.js → ChatView-BquP2SP_.js} +2 -2
  13. package/dist/chunks/{ChatView-B-2JVhM3.js.map → ChatView-BquP2SP_.js.map} +1 -1
  14. package/dist/chunks/{ChatView-oZ9FggEo.js → ChatView-rWg4ZSJy.js} +2 -2
  15. package/dist/chunks/{ChatView-oZ9FggEo.js.map → ChatView-rWg4ZSJy.js.map} +1 -1
  16. package/dist/chunks/Passkeys-C1m6avHh.js +2 -0
  17. package/dist/chunks/Passkeys-C1m6avHh.js.map +1 -0
  18. package/dist/chunks/Passkeys-Dx5bduZJ.js +2 -0
  19. package/dist/chunks/Passkeys-Dx5bduZJ.js.map +1 -0
  20. package/dist/chunks/UserProfileView-AhUCUowp.js +2 -0
  21. package/dist/chunks/UserProfileView-AhUCUowp.js.map +1 -0
  22. package/dist/chunks/UserProfileView-CJKQNzSj.js +2 -0
  23. package/dist/chunks/UserProfileView-CJKQNzSj.js.map +1 -0
  24. package/dist/chunks/{admin-CXA-Vkhf.js → admin-Beq0Eckn.js} +2 -2
  25. package/dist/chunks/admin-Beq0Eckn.js.map +1 -0
  26. package/dist/chunks/{admin-DcLy2QC2.js → admin-D2CqCMaa.js} +2 -2
  27. package/dist/chunks/{admin-CXA-Vkhf.js.map → admin-D2CqCMaa.js.map} +1 -1
  28. package/dist/chunks/{exportChart-BQXkqsxe.js → exportChart-Cn6owWxP.js} +2 -2
  29. package/dist/chunks/{exportChart-BQXkqsxe.js.map → exportChart-Cn6owWxP.js.map} +1 -1
  30. package/dist/chunks/{exportChart-UQ5nq_mR.js → exportChart-DqydcfXz.js} +2 -2
  31. package/dist/chunks/{exportChart-UQ5nq_mR.js.map → exportChart-DqydcfXz.js.map} +1 -1
  32. package/dist/chunks/{index-TqW1pAMX.js → index-BKR6vFMH.js} +2 -2
  33. package/dist/chunks/{index-TqW1pAMX.js.map → index-BKR6vFMH.js.map} +1 -1
  34. package/dist/chunks/{index-C9wf7N-j.js → index-CMKYMKaH.js} +2 -2
  35. package/dist/chunks/{index-C9wf7N-j.js.map → index-CMKYMKaH.js.map} +1 -1
  36. package/dist/chunks/{version-xpJSWoyH.js → version-CBjwNXEK.js} +2 -2
  37. package/dist/chunks/{version-xpJSWoyH.js.map → version-CBjwNXEK.js.map} +1 -1
  38. package/dist/chunks/{version-Bdrq2emC.js → version-DQwtLRjN.js} +2 -2
  39. package/dist/chunks/{version-Bdrq2emC.js.map → version-DQwtLRjN.js.map} +1 -1
  40. package/dist/css/web-mojo.css +1 -1
  41. package/dist/docit.cjs.js +1 -1
  42. package/dist/docit.es.js +1 -1
  43. package/dist/index.cjs.js +1 -1
  44. package/dist/index.es.js +1 -1
  45. package/dist/lightbox.cjs.js +1 -1
  46. package/dist/lightbox.es.js +1 -1
  47. package/dist/user-profile.cjs.js +1 -1
  48. package/dist/user-profile.es.js +1 -1
  49. package/dist/web-mojo.lite.iife.js +31 -6
  50. package/dist/web-mojo.lite.iife.js.map +1 -1
  51. package/dist/web-mojo.lite.iife.min.js +58 -58
  52. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  53. package/package.json +1 -1
  54. package/dist/chunks/Passkeys-8ko7Rg8G.js +0 -2
  55. package/dist/chunks/Passkeys-8ko7Rg8G.js.map +0 -1
  56. package/dist/chunks/Passkeys-CD8RKUl8.js +0 -2
  57. package/dist/chunks/Passkeys-CD8RKUl8.js.map +0 -1
  58. package/dist/chunks/UserProfileView-DC70hRer.js +0 -2
  59. package/dist/chunks/UserProfileView-DC70hRer.js.map +0 -1
  60. package/dist/chunks/UserProfileView-TQ9BqUE2.js +0 -2
  61. package/dist/chunks/UserProfileView-TQ9BqUE2.js.map +0 -1
  62. package/dist/chunks/admin-DcLy2QC2.js.map +0 -1
@@ -1,4 +1,4 @@
1
- var MOJO=(function(A){"use strict";class oe{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 He{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 De=["light","dark","system"];class qe{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=De.includes(e)?e:"system",this._apply(!1),this.preference==="system"&&this._attachSystemListener(),this}getPreference(){return this.preference}getResolved(){return this.resolved}set(e){if(!De.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 je{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),c=await this.processResponseInterceptors(l,a);return r.dataOnly&&c.data&&typeof c.data=="object"&&"data"in c.data&&(c.message=c.message||c.data.message,c.data=c.data.data),c}catch(l){if(l.name==="AbortError")throw l;const c=this.categorizeError(l),d={success:!1,status:0,statusText:"Network Error",headers:{},data:null,errors:{network:l.message},message:c.message,reason:c.reason},u={ok:!1,status:0,statusText:"Network Error",headers:new Headers,json:async()=>({}),text:async()=>""};return await this.processResponseInterceptors(u,a),d}}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(),c=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()}}),d=await new Response(c).blob(),u=window.URL.createObjectURL(d),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 c=window.URL.createObjectURL(n),d=document.createElement("a");return d.style.display="none",d.href=c,d.download=l,document.body.appendChild(d),d.click(),window.URL.revokeObjectURL(c),d.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 Y=new je,ze="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2NlZDRkYSI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg==";class Be{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,c,d)=>{const u=d.startsWith("www.")?`https://${d}`:d;return`${c}<a href="${u}" target="${a.target}" rel="${a.rel}">${d}</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(A){"use strict";class oe{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 He{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 De=["light","dark","system"];class qe{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=De.includes(e)?e:"system",this._apply(!1),this.preference==="system"&&this._attachSystemListener(),this}getPreference(){return this.preference}getResolved(){return this.resolved}set(e){if(!De.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 je{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),c=await this.processResponseInterceptors(l,a);return r.dataOnly&&c.data&&typeof c.data=="object"&&"data"in c.data&&(c.message=c.message||c.data.message,c.data=c.data.data),c}catch(l){if(l.name==="AbortError")throw l;const c=this.categorizeError(l),d={success:!1,status:0,statusText:"Network Error",headers:{},data:null,errors:{network:l.message},message:c.message,reason:c.reason},u={ok:!1,status:0,statusText:"Network Error",headers:new Headers,json:async()=>({}),text:async()=>""};return await this.processResponseInterceptors(u,a),d}}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 m=n.match(/filename="?(.+)"?/);m&&m.length>1&&(o=m[1])}const l=a.body.getReader(),c=new ReadableStream({start(m){function f(){return l.read().then(({done:g,value:b})=>{if(g){m.close();return}return m.enqueue(b),f()})}return f()}}),d=await new Response(c).blob(),u=window.URL.createObjectURL(d),p=document.createElement("a");return p.style.display="none",p.href=u,p.download=o,document.body.appendChild(p),p.click(),window.URL.revokeObjectURL(u),p.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 c=window.URL.createObjectURL(n),d=document.createElement("a");return d.style.display="none",d.href=c,d.download=l,document.body.appendChild(d),d.click(),window.URL.revokeObjectURL(c),d.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 Y=new je,ze="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2NlZDRkYSI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg==";class Be{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,c,d)=>{const u=d.startsWith("www.")?`https://${d}`:d;return`${c}<a href="${u}" target="${a.target}" rel="${a.rel}">${d}</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=`
2
2
  <button type="button"
3
3
  class="btn btn-sm btn-outline-secondary ms-1 p-0 border-0 bg-transparent"
4
4
  title="Copy"
@@ -11,8 +11,8 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
11
11
  ${r?`<span class="font-monospace">${i}</span>`:""}
12
12
  ${a}
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){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 I="";try{const B=new Intl.DateTimeFormat(a,{hour:"2-digit",minute:"2-digit",timeZoneName:"short",...n?{timeZone:n}:{}}).formatToParts(r).find(L=>L.type==="timeZoneName");if(I=B?B.value:"",I&&/^GMT[+-]/i.test(I))try{const U=new Intl.DateTimeFormat(a,{timeStyle:"short",timeZoneName:"short",...n?{timeZone:n}:{}}).formatToParts(r).find(wt=>wt.type==="timeZoneName");U&&U.value&&!/^GMT[+-]/i.test(U.value)&&(I=U.value)}catch{}if(I&&/\s/.test(I)){const L=I.split(/\s+/).map(U=>U[0]).join("").toUpperCase();L.length>=2&&L.length<=4&&(I=L)}}catch{I=""}return I};if(!n){const I=this.date(r,t),R=this.time(r,s),B=o();return I&&R?`${I} ${R} ${B}`.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),c=I=>{const R=l.find(B=>B.type===I);return R?R.value:""},d=c("year"),u=c("month"),m=c("day"),p=c("hour"),f=c("minute"),g=c("second"),b=u?String(parseInt(u,10)):"",y=m?String(parseInt(m,10)):"",x=p?String(parseInt(p,10)):"",F=p?parseInt(p,10)%12||12:"",D=p?parseInt(p,10)>=12?"PM":"AM":"",V=D?D.toLowerCase():"",H=new Intl.DateTimeFormat(a,{timeZone:n,month:"long"}).format(r),P=new Intl.DateTimeFormat(a,{timeZone:n,month:"short"}).format(r),N=new Intl.DateTimeFormat(a,{timeZone:n,weekday:"long"}).format(r),ne=new Intl.DateTimeFormat(a,{timeZone:n,weekday:"short"}).format(r),Ae={YYYY:d,YY:d?d.slice(-2):"",MMMM:H,MMM:P,MM:u,M:b,dddd:N,ddd:ne,DD:m,D:y},Ee={HH:p,H:x,hh:F!==""?String(F).padStart(2,"0"):"",h:F!==""?String(F):"",mm:f,m:f?String(parseInt(f,10)):"",ss:g,s:g?String(parseInt(g,10)):"",A:D,a:V},T=(I,R)=>{if(!I)return"";const B=new RegExp(`(${Object.keys(R).sort((L,U)=>U.length-L.length).join("|")})`,"g");return I.replace(B,L=>R[L]??L)},O=T(t,Ae),Re=T(s,Ee),yt=o();return O&&Re?`${O} ${Re} ${yt}`.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),c=Math.floor(l/24),d=r>0;if(t)return c>365?Math.floor(c/365)+"y":c>30?Math.floor(c/30)+"mo":c>7?Math.floor(c/7)+"w":c>0?c+"d":l>0?l+"h":o>0?o+"m":"now";if(c>365){const u=Math.floor(c/365),m=d?"in ":"",p=d?"":" ago";return m+u+" year"+(u>1?"s":"")+p}if(c>30){const u=Math.floor(c/30),m=d?"in ":"",p=d?"":" ago";return m+u+" month"+(u>1?"s":"")+p}if(c>7){const u=Math.floor(c/7),m=d?"in ":"",p=d?"":" ago";return m+u+" week"+(u>1?"s":"")+p}if(c===1)return d?"tomorrow":"yesterday";if(c>0){const u=d?"in ":"",m=d?"":" ago";return u+c+" days"+m}if(l>0){const u=d?"in ":"",m=d?"":" ago";return u+l+" hour"+(l>1?"s":"")+m}if(o>0){const u=d?"in ":"",m=d?"":" ago";return u+o+" minute"+(o>1?"s":"")+m}if(n>30){const u=d?"in ":"",m=d?"":" 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 c=o.slice(0,s).padEnd(s,"0");l=`${n}.${c}`}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(c=>c.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]||"",c=s[a]||o[a]||"secondary";let d="";!i&&l&&(d=`<i class="${l}"></i>`);let u="";return r||(u=e),`<span class="text-${c}">${d}${d?" ":""}${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")||ze,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?"-":"",c=[];let d=o;for(const u of n)if(d>=u.value){const m=Math.floor(d/u.value);d=d%u.value;const p=s?u.short:m===1?u.name:u.name+"s";if(c.push(s?`${m}${p}`:`${m} ${p}`),c.length>=i)break}return c.length===0?s?`${Math.round(o)}ms`:`${Math.round(o)} milliseconds`:l+(s?c.join(""):c.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 _=new Be;window.dataFormatter=_;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?_.pipe(n,i,e):n}static getNestedValue(e,t){if(!t||e==null)return;if(!t.includes(".")){if(t in e){const r=e[t];return typeof r=="function"?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(i.hasOwnProperty(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(i.hasOwnProperty(a))i=i[a];else if(typeof i[a]=="function")i=i[a].call(i);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 c="";for(const d of l)c+=d;for(let d=c.length;d<s.length;d++)c+=o[Math.floor(Math.random()*o.length)];return c.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 le(i,t):i):new le(e,t)}}class le{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&&t!=="_data"&&t!=="_rootContext"?a=this[t]:a=$.getNestedValue(this._data,t),s&&a!==void 0?_.pipe(a,s,this._rootContext||this._data):a}has(e){return this._data&&this._data.hasOwnProperty(e)}toJSON(){return this._data}}$.DataWrapper=le,typeof window<"u"&&(window.utils=$);const Ue=Object.prototype.toString,G=Array.isArray||function(h){return Ue.call(h)==="[object Array]"},Q=function(h){return typeof h=="function"},Te=function(h){return h!==null&&typeof h=="object"};function Ye(){return typeof window>"u"?null:window.MOJO?.dataFormatter?window.MOJO.dataFormatter:window.dataFormatter?window.dataFormatter:null}const Ie=function(h){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(h).replace(/[&<>"'`=\/]/g,function(t){return e[t]})};class ke{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 ie{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 ie(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(".")){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&&Q(o)&&(o=o.call(this.view))}catch{o=void 0}if(o===void 0&&i in this.view&&(o=this.view[i],Q(o)&&(o=o.call(this.view))),a&&o!==void 0)try{const l=Ye();l&&typeof l.pipe=="function"&&(o=l.pipe(o,a,this))}catch{}return G(o)?r?o:o.length>0:Te(o)?r?Object.entries(o).map(([l,c])=>({key:l,value:c})):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=ce(r,a[n])||_e(r,a[n])),r=r[a[n++]]}else n===a.length-1&&(o=ce(r,a[n])||_e(r,a[n])),r=r[a[n++]];else r=i.view[e],o=ce(i.view,e);if(o){s=r;break}i=i.parent}t[e]=s}if(Q(s)&&(s=s.call(this.view)),this.renderCache&&this.view?._cacheId){const i=`${this.view._cacheId}:${e}`;this.renderCache.set(i,s)}return s}}function ce(h,e){return h!=null&&typeof h=="object"&&e in h}function _e(h,e){return h!=null&&typeof h!="object"&&h.hasOwnProperty&&h.hasOwnProperty(e)}class Me{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 ke(e),a=[];let n,o,l,c,d;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)c=l.charAt(f),c===`
15
- `?a.push(["text",c]):a.push(["text",c]);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==="^")d=[o,l,n,r.pos],a.push(d);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 ie(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 c;switch(l[0]){case"#":if(c=t.lookup(l[1]),!c)continue;const d=l[4];if(!d||!G(d)){console.warn(`MUSTACHE WARNING - Section ${l[1]} has no child tokens:`,l);continue}if(G(c))for(let u=0;u<c.length;++u){const m=t.push(c[u]);t.renderCache&&(m.renderCache=t.renderCache);const p=this.renderTokens(d,m,s,i,r,a);n+=p}else if(typeof c=="object"||typeof c=="string"||typeof c=="number"){const u=t.push(c);t.renderCache&&(u.renderCache=t.renderCache),n+=this.renderTokens(d,u,s,i,r,a)}else if(Q(c)){const u=i==null?null:i.slice(l[3],l[5]);c=c.call(t.view,u,m=>this.render(m,t.view,s,r)),c!=null&&(n+=c)}else c&&(n+=this.renderTokens(d,t,s,i,r,a));break;case"^":if(c=t.lookup(l[1]),!c||G(c)&&c.length===0){const u=l[4];u&&G(u)&&(n+=this.renderTokens(u,t,s,i,r,a))}break;case">":if(!s)continue;c=Q(s)?s(l[1]):s[l[1]],c!=null&&(n+=this.render(c,t.view,s,r));break;case"&":c=t.lookup(l[1]),c!=null&&(n+=c);break;case"name":c=t.lookup(l[1]),c!=null&&(n+=Ie(c));break;case"text":n+=l[1];break}}return n}getConfigTags(e){return Te(e)&&G(e.tags)?e.tags:null}}function de(h){return h.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}const he=new Me,E={name:"MOJO Mustache",version:"1.0.0",tags:["{{","}}"],Scanner:ke,Context:ie,Writer:Me,escape:Ie,clearCache(){return he.clearCache()},parse(h,e){return he.parse(h,e)},render(h,e,t,s){if(typeof h!="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)),he.render(h,e,t,s)}};class We{constructor(e){this.view=e,this.domListeners=[],this.debounceTimers=new Map}bind(e){if(this.unbind(),!e)return;const t=async n=>{const o=n.target.closest("[data-action]");if(o&&this.shouldHandle(o,n)){const c=o.getAttribute("data-action");if(o.tagName==="A"&&n.preventDefault(),this.hideTooltip(o),await this.dispatch(c,n,o)){n.preventDefault(),n.stopPropagation(),n.handledByChild=!0;return}}const l=n.target.closest("a[href], [data-page]");if(l&&!l.hasAttribute("data-action")&&this.shouldHandle(l,n)){if(n.ctrlKey||n.metaKey||n.shiftKey||n.button===1)return;if(l.tagName==="A"){const c=l.getAttribute("href");if(c&&c!=="#"&&!c.startsWith("#")&&(this.view.isExternalLink(c)||l.hasAttribute("data-external")))return}this.hideTooltip(l),n.preventDefault(),n.stopPropagation(),n.handledByChild=!0,l.hasAttribute("data-page")?await this.view.handlePageNavigation(l):await this.view.handleHrefNavigation(l)}},s=n=>{const o=n.target.closest("[data-change-action]");if(o&&this.shouldHandle(o,n)){const c=o.getAttribute("data-change-action");this.dispatchChange(c,n,o).then(d=>{d&&(n.stopPropagation(),n.handledByChild=!0)});return}const l=n.target.closest("[data-action]");if(l&&this.isFormControl(l)&&this.shouldHandle(l,n)){const c=l.getAttribute("data-action");this.dispatch(c,n,l).then(d=>{d&&(n.stopPropagation(),n.handledByChild=!0)})}},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 c=l.getAttribute("data-action"),d=l.getAttribute("data-action-debounce"),u=d!=null&&parseInt(d)||0;if(u>0){const m=`action-${c}-${l.getAttribute("data-container")||"default"}`;this.debounceTimers.has(m)&&clearTimeout(this.debounceTimers.get(m));const p=setTimeout(()=>{this.debounceTimers.delete(m),this.dispatch(c,n,l).then(f=>{f&&(n.stopPropagation(),n.handledByChild=!0)})},u);this.debounceTimers.set(m,p);return}this.dispatch(c,n,l).then(m=>{m&&(n.stopPropagation(),n.handledByChild=!0)})},r=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||!this.shouldHandle(o,n))return;let l=["Enter"];if(o.getAttribute("data-change-keys")&&(l=o.getAttribute("data-change-keys").split(",").map(c=>c.trim())),l.includes("*")||l.includes(n.key)){const c=o.getAttribute("data-keydown-action")||o.getAttribute("data-change-action");this.dispatch(c,n,o).then(d=>{d&&(n.preventDefault(),n.stopPropagation(),n.handledByChild=!0)})}},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(c=>c[0].toUpperCase()+c.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 ue={on(h,e,t){this._listeners||(this._listeners={}),this._listeners[h]||(this._listeners[h]=[]);const s={callback:e,context:t,fn:t?e.bind(t):e};return this._listeners[h].push(s),this},off(h,e,t){return!this._listeners||!this._listeners[h]?this:(e?(this._listeners[h]=this._listeners[h].filter(s=>s.callback!==e||arguments.length===3&&s.context!==t),this._listeners[h].length===0&&delete this._listeners[h]):delete this._listeners[h],this)},once(h,e,t){const s=(...i)=>{this.off(h,s),(t?e.bind(t):e).apply(t||this,i)};return this.on(h,s),this},emit(h,...e){if(!this._listeners||!this._listeners[h])return this;const t=this._listeners[h].slice();for(const s of t)try{s.fn.apply(s.context||this,e)}catch(i){console&&console.error&&console.error(`Error in ${h} event handler:`,i)}return this}};typeof window<"u"&&(window.Mustache=E);class C{constructor(e={}){this.tagName=e.tagName??"div",this.className=e.className??"mojo-view",this.style=e.style??null,this.id=e.id??C._genId(),this.containerId=e.containerId??null,this.container=e.container??null,typeof this.container=="string"&&(this.containerId=this.container,this.container=null),this.parent=e.parent??null,this.children=e.children??{},this.template=e.template||e.templateUrl||"",this.data=e.data??{},this.isRendering=!1,this.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 We(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){C._warn("addChild error",s)}return e}removeChild(e){try{const t=typeof e=="string"?e:e&&e.id;if(!t)return this;const s=this.children[t];s&&(Promise.resolve(s.destroy()).catch(i=>C._warn("removeChild destroy error",i)),delete this.children[t])}catch(t){C._warn("removeChild error",t)}return this}getChild(e){return this.children[e]}async updateData(e,t=!1){return Object.assign(this.data,e),t&&this.isMounted()&&await this.render(),this}toggleClass(e,t){return t===void 0&&(t=!this.element.classList.contains(e)),this.element.classList.toggle(e,t),this}addClass(e){return this.element.classList.add(e),this}setClass(e){return this.element.className=e,this}removeClass(e){return this.element.classList.remove(e),this}canRender(){if(this.isRendering)return!1;const e=Date.now();if(this.options.renderCooldown>0&&e-this.lastRenderTime<this.options.renderCooldown)return C._warn(`View ${this.id}: Render called too quickly, cooldown active`),!1;if(this.options.noAppend&&this.parent)if(this.parent.contains(this.containerId||this.container)){if(this.containerId&&!document.getElementById(this.containerId))return!1;if(this.container&&!document.contains(this.container))return!1}else return!1;return!0}async render(e=!0,t=null){const s=Date.now();if(!this.canRender())return this;this.isRendering=!0,this.lastRenderTime=s;try{this.initialized||await this.onInitView(),this.unbindEvents(),await this.onBeforeRender(),this.getViewData&&(this.data=await this.getViewData());const i=await this.renderTemplate();this.element.innerHTML=i,e&&!this.isMounted()&&await this.mount(t),await this._renderChildren(),await this.onAfterRender(),this.bindEvents()}catch(i){C._warn(`Render error in ${this.id}`,i)}finally{this.isRendering=!1}return this}async _renderChildren(){const e=[];for(const t in this.children){const s=this.children[t];if(s){if(s.parent=this,s._lazyMount&&!s._lazyTriggered){e.push(s);continue}await Promise.resolve(s.render()).catch(i=>C._warn(`Child render error (${t})`,i))}}e.length&&this._setupLazyMountObserver(e)}_setupLazyMountObserver(e){if(typeof IntersectionObserver>"u"){e.forEach(t=>{t._lazyTriggered=!0,Promise.resolve(t.render()).catch(s=>C._warn(`Lazy child render error (${t.id})`,s))});return}this._lazyObserver||(this._lazyObserver=new IntersectionObserver((t,s)=>{for(const i of t){if(!i.isIntersecting)continue;const r=i.target.__mojoLazyChild;s.unobserve(i.target),!(!r||r._lazyTriggered)&&(r._lazyTriggered=!0,Promise.resolve(r.render()).catch(a=>C._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=>C._warn(`Lazy child render error (${t.id})`,o)))}))}}async _unmountChildren(){for(const e in this.children){const t=this.children[e];t&&t.unbindEvents()}}isMounted(){return this.element?.isConnected}getChildElementById(e,t=null){const s=e.startsWith("#")?e.substring(1):e;return t?t.querySelector(`#${s}`):this.element.querySelector(`#${s}`)}getChildElement(e){if(e.startsWith("#"))return this.getChildElementById(e);let t=this.element?.querySelector(`[data-container="${e}"]`);return t||this.getChildElementById(e)}getContainer(){return this.replaceById?this.parent?this.parent.getChildElementById(this.id):null:this.containerId?this.parent?this.parent.getChildElement(this.containerId):this.getChildElementById(this.containerId,document.body):null}async mount(e=null){if(await this.onBeforeMount(),e||(e=this.getContainer()),this.containerId&&!e){console.error(`Container not found for ${this.containerId}`);return}e&&this.replaceById?e.replaceWith(this.element):e?e.replaceChildren(this.element):!this.containerId&&this.parent?this.parent.element.appendChild(this.element):!this.containerId&&!this.parent&&this.options.allowAppendToBody?(console.log("APPENDING TO BODY!!!!"),document.body.appendChild(this.element)):console.error(`Container not found for ${this.containerId}`),await this.onAfterMount(),this.mounted=!0}async unmount(){!this.element||!this.element.parentNode||(await this.onBeforeUnmount(),await this._unmountChildren(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),this.events.unbind(),await this.onAfterUnmount(),this.mounted=!1)}async destroy(){try{this.events.unbind(),this._lazyObserver&&(this._lazyObserver.disconnect(),this._lazyObserver=null);for(const e in this.children){const t=this.children[e];t&&await Promise.resolve(t.destroy()).catch(s=>C._warn(`Child destroy error (${e})`,s))}this.mounted=!1,this.element&&this.element.parentNode&&(await this.onBeforeDestroy(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),await this.onAfterDestroy())}catch(e){C._warn(`Destroy error in ${this.id}`,e)}}_ensureElement(){try{if(this.element&&this.element.tagName?.toLowerCase()===this.tagName)return this._syncAttrs(),this.element;const e=document.createElement(this.tagName);return this.element=e,this.el=e,this._syncAttrs(),e}catch(e){C._warn("ensureElement error",e);const t=document.createElement("div");return t.id=this.id||C._genId(),t}}_syncAttrs(){try{if(!this.element)return;this.id&&(this.element.id=this.id),this.element.className=this.className||"",this.style==null?this.element.removeAttribute("style"):this.element.style.cssText=String(this.style)}catch(e){C._warn("_syncAttrs error",e)}}bindEvents(){this.events.bind(this.element),this.enableTooltips&&this.initializeTooltips()}unbindEvents(){this.events.unbind(),this.enableTooltips&&this.disposeTooltips()}async renderTemplate(){const e=await this.getTemplate();if(!e)return"";const t=this.getPartials();return E.render(e,this,t)}renderTemplateString(e,t,s){return E.render(e,t,s)}getPartials(){return{}}async getTemplate(){if(this._templateCache&&this.cacheTemplate)return this._templateCache;const e=this.template||this.templateUrl;if(!e)throw new Error("Template not found");let t="";if(typeof e=="string")if(e.includes("<")||e.includes("{"))t=e;else try{let s=e;this.app||(this.app=this.getApp()),this.app&&this.app.basePath&&!s.startsWith("/")&&!s.startsWith("http://")&&!s.startsWith("https://")&&(s=`${this.app.basePath.endsWith("/")?this.app.basePath.slice(0,-1):this.app.basePath}/${s}`);const i=await fetch(s);if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);t=await i.text()}catch(s){C._warn(`Failed to load template from ${e}: ${s}`),this.showError?.(`Failed to load template from ${e}: ${s.message}`)}else typeof e=="function"&&(t=await this.template(this.data,this.state));return this.cacheTemplate&&t&&(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(C.prototype,ue);class S extends C{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:S._baseZIndex}static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=S._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(){S.fixAllBackdropStacking()}static getMountTarget(){return document.querySelector(".table-fullscreen")||document.body}constructor(e={}){const t=e.id||`modal-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;super({...e,id:t,tagName:"div",className:`modal ${e.fade!==!1?"fade":""} ${e.className||""}`.trim().replace(/\s+/g," "),attributes:{tabindex:"-1","aria-hidden":"true","aria-labelledby":e.labelledBy||`${t}-label`,"aria-describedby":e.describedBy||null,...e.attributes}}),this.modalId=t,this.title=e.title||"",this.titleId=`${this.modalId}-label`,this.size=e.size||"",this.centered=e.centered!==void 0?e.centered:!1,this.scrollable=e.scrollable!==void 0?e.scrollable:!1,this.autoSize=e.autoSize||e.size==="auto",this.backdrop=e.backdrop!==void 0?e.backdrop:!0,this.keyboard=e.keyboard!==void 0?e.keyboard:!0,this.focus=e.focus!==void 0?e.focus:!0,this.header=e.header!==void 0?e.header:!0,this.headerContent=e.headerContent||null,this.headerView=null,this.closeButton=e.closeButton!==void 0?e.closeButton:!0,this.contextMenu=e.contextMenu||null,this._processHeaderContent(this.headerContent),this.body=e.body??e.view??e.message??e.content??"",this.bodyView=null,this.bodyClass=e.bodyClass||"",this.noBodyPadding=e.noBodyPadding||!1,this.minWidth=e.minWidth||300,this.minHeight=e.minHeight||200,e.maxHeight&&(this.maxHeight=e.maxHeight),this.maxWidthPercent=e.maxWidthPercent||.9,this.maxHeightPercent=e.maxHeightPercent||.8,this._processBodyContent(this.body),this.footer=e.footer||null,this.footerView=null,this.footerClass=e.footerClass||"",this._processFooterContent(this.footer),this.buttons=e.buttons||null,this.onShow=e.onShow||null,this.onShown=e.onShown||null,this.onHide=e.onHide||null,this.onHidden=e.onHidden||null,this.onHidePrevented=e.onHidePrevented||null,this.autoShow=e.autoShow!==void 0?e.autoShow:!1,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(e){if(e instanceof C||e&&typeof e=="object"&&typeof e.render=="function")this.bodyView=e,this.body="",this.addChild(this.bodyView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.bodyView=t,this.body="",this.addChild(this.bodyView)):t instanceof Promise?(this.bodyPromise=t,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=t}catch(t){console.error("ModalView: error processing body function:",t),this.body=e}else this.body=e}_processHeaderContent(e){if(e instanceof C)this.headerView=e,this.headerContent=null,this.addChild(this.headerView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.headerView=t,this.headerContent=null,this.addChild(this.headerView)):t instanceof Promise?(this.headerPromise=t,this.headerContent='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.headerContent=t}catch(t){console.error("ModalView: error processing headerContent function:",t),this.headerContent=e}else this.headerContent=e}_processFooterContent(e){if(e instanceof C)this.footerView=e,this.footer=null,this.addChild(this.footerView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.footerView=t,this.footer=null,this.addChild(this.footerView)):t instanceof Promise?(this.footerPromise=t,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=t}catch(t){console.error("ModalView: error processing footer function:",t),this.footer=e}else this.footer=e}async getTemplate(){const e=["modal-dialog"];return this.size&&this.size!=="auto"&&(this.size.startsWith("fullscreen")?e.push(`modal-${this.size}`):["sm","lg","xl","xxl"].includes(this.size)&&(e.push(`modal-${this.size}`),["lg","xl","xxl"].includes(this.size)&&e.push("modal-fullscreen-sm-down"))),this.centered&&e.push("modal-dialog-centered"),this.scrollable&&(this.maxHeight?e.push("overflow-hidden"):e.push("modal-dialog-scrollable")),`
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){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 I="";try{const B=new Intl.DateTimeFormat(a,{hour:"2-digit",minute:"2-digit",timeZoneName:"short",...n?{timeZone:n}:{}}).formatToParts(r).find(L=>L.type==="timeZoneName");if(I=B?B.value:"",I&&/^GMT[+-]/i.test(I))try{const U=new Intl.DateTimeFormat(a,{timeStyle:"short",timeZoneName:"short",...n?{timeZone:n}:{}}).formatToParts(r).find(wt=>wt.type==="timeZoneName");U&&U.value&&!/^GMT[+-]/i.test(U.value)&&(I=U.value)}catch{}if(I&&/\s/.test(I)){const L=I.split(/\s+/).map(U=>U[0]).join("").toUpperCase();L.length>=2&&L.length<=4&&(I=L)}}catch{I=""}return I};if(!n){const I=this.date(r,t),R=this.time(r,s),B=o();return I&&R?`${I} ${R} ${B}`.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),c=I=>{const R=l.find(B=>B.type===I);return R?R.value:""},d=c("year"),u=c("month"),p=c("day"),m=c("hour"),f=c("minute"),g=c("second"),b=u?String(parseInt(u,10)):"",y=p?String(parseInt(p,10)):"",x=m?String(parseInt(m,10)):"",F=m?parseInt(m,10)%12||12:"",D=m?parseInt(m,10)>=12?"PM":"AM":"",V=D?D.toLowerCase():"",H=new Intl.DateTimeFormat(a,{timeZone:n,month:"long"}).format(r),P=new Intl.DateTimeFormat(a,{timeZone:n,month:"short"}).format(r),N=new Intl.DateTimeFormat(a,{timeZone:n,weekday:"long"}).format(r),ne=new Intl.DateTimeFormat(a,{timeZone:n,weekday:"short"}).format(r),Ae={YYYY:d,YY:d?d.slice(-2):"",MMMM:H,MMM:P,MM:u,M:b,dddd:N,ddd:ne,DD:p,D:y},Ee={HH:m,H:x,hh:F!==""?String(F).padStart(2,"0"):"",h:F!==""?String(F):"",mm:f,m:f?String(parseInt(f,10)):"",ss:g,s:g?String(parseInt(g,10)):"",A:D,a:V},T=(I,R)=>{if(!I)return"";const B=new RegExp(`(${Object.keys(R).sort((L,U)=>U.length-L.length).join("|")})`,"g");return I.replace(B,L=>R[L]??L)},O=T(t,Ae),Re=T(s,Ee),yt=o();return O&&Re?`${O} ${Re} ${yt}`.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),c=Math.floor(l/24),d=r>0;if(t)return c>365?Math.floor(c/365)+"y":c>30?Math.floor(c/30)+"mo":c>7?Math.floor(c/7)+"w":c>0?c+"d":l>0?l+"h":o>0?o+"m":"now";if(c>365){const u=Math.floor(c/365),p=d?"in ":"",m=d?"":" ago";return p+u+" year"+(u>1?"s":"")+m}if(c>30){const u=Math.floor(c/30),p=d?"in ":"",m=d?"":" ago";return p+u+" month"+(u>1?"s":"")+m}if(c>7){const u=Math.floor(c/7),p=d?"in ":"",m=d?"":" ago";return p+u+" week"+(u>1?"s":"")+m}if(c===1)return d?"tomorrow":"yesterday";if(c>0){const u=d?"in ":"",p=d?"":" ago";return u+c+" days"+p}if(l>0){const u=d?"in ":"",p=d?"":" ago";return u+l+" hour"+(l>1?"s":"")+p}if(o>0){const u=d?"in ":"",p=d?"":" ago";return u+o+" minute"+(o>1?"s":"")+p}if(n>30){const u=d?"in ":"",p=d?"":" ago";return u+n+" seconds"+p}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 c=o.slice(0,s).padEnd(s,"0");l=`${n}.${c}`}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(c=>c.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]||"",c=s[a]||o[a]||"secondary";let d="";!i&&l&&(d=`<i class="${l}"></i>`);let u="";return r||(u=e),`<span class="text-${c}">${d}${d?" ":""}${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")||ze,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?"-":"",c=[];let d=o;for(const u of n)if(d>=u.value){const p=Math.floor(d/u.value);d=d%u.value;const m=s?u.short:p===1?u.name:u.name+"s";if(c.push(s?`${p}${m}`:`${p} ${m}`),c.length>=i)break}return c.length===0?s?`${Math.round(o)}ms`:`${Math.round(o)} milliseconds`:l+(s?c.join(""):c.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 _=new Be;window.dataFormatter=_;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?_.pipe(n,i,e):n}static getNestedValue(e,t){if(!t||e==null)return;if(!t.includes(".")){if(t in e){const r=e[t];return typeof r=="function"?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(i.hasOwnProperty(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(i.hasOwnProperty(a))i=i[a];else if(typeof i[a]=="function")i=i[a].call(i);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 c="";for(const d of l)c+=d;for(let d=c.length;d<s.length;d++)c+=o[Math.floor(Math.random()*o.length)];return c.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 le(i,t):i):new le(e,t)}}class le{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&&t!=="_data"&&t!=="_rootContext"?a=this[t]:a=$.getNestedValue(this._data,t),s&&a!==void 0?_.pipe(a,s,this._rootContext||this._data):a}has(e){return this._data&&this._data.hasOwnProperty(e)}toJSON(){return this._data}}$.DataWrapper=le,typeof window<"u"&&(window.utils=$);const Ue=Object.prototype.toString,G=Array.isArray||function(h){return Ue.call(h)==="[object Array]"},Q=function(h){return typeof h=="function"},Te=function(h){return h!==null&&typeof h=="object"};function Ye(){return typeof window>"u"?null:window.MOJO?.dataFormatter?window.MOJO.dataFormatter:window.dataFormatter?window.dataFormatter:null}const Ie=function(h){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};return String(h).replace(/[&<>"'`=\/]/g,function(t){return e[t]})};class ke{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 ie{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 ie(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(".")){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&&Q(o)&&(o=o.call(this.view))}catch{o=void 0}if(o===void 0&&i in this.view&&(o=this.view[i],Q(o)&&(o=o.call(this.view))),a&&o!==void 0)try{const l=Ye();l&&typeof l.pipe=="function"&&(o=l.pipe(o,a,this))}catch{}return G(o)?r?o:o.length>0:Te(o)?r?Object.entries(o).map(([l,c])=>({key:l,value:c})):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=ce(r,a[n])||_e(r,a[n])),r=r[a[n++]]}else n===a.length-1&&(o=ce(r,a[n])||_e(r,a[n])),r=r[a[n++]];else r=i.view[e],o=ce(i.view,e);if(o){s=r;break}i=i.parent}t[e]=s}if(Q(s)&&(s=s.call(this.view)),this.renderCache&&this.view?._cacheId){const i=`${this.view._cacheId}:${e}`;this.renderCache.set(i,s)}return s}}function ce(h,e){return h!=null&&typeof h=="object"&&e in h}function _e(h,e){return h!=null&&typeof h!="object"&&h.hasOwnProperty&&h.hasOwnProperty(e)}class Me{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 ke(e),a=[];let n,o,l,c,d;const u=new RegExp(de(s)+"\\s*"),p=new RegExp("\\s*"+de(i)),m=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)c=l.charAt(f),c===`
15
+ `?a.push(["text",c]):a.push(["text",c]);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(p)):o==="{"?(l=r.scanUntil(m),r.scan(m),o="&"):l=r.scanUntil(p),r.scan(p),o==="#"||o==="^")d=[o,l,n,r.pos],a.push(d);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 ie(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 c;switch(l[0]){case"#":if(c=t.lookup(l[1]),!c)continue;const d=l[4];if(!d||!G(d)){console.warn(`MUSTACHE WARNING - Section ${l[1]} has no child tokens:`,l);continue}if(G(c))for(let u=0;u<c.length;++u){const p=t.push(c[u]);t.renderCache&&(p.renderCache=t.renderCache);const m=this.renderTokens(d,p,s,i,r,a);n+=m}else if(typeof c=="object"||typeof c=="string"||typeof c=="number"){const u=t.push(c);t.renderCache&&(u.renderCache=t.renderCache),n+=this.renderTokens(d,u,s,i,r,a)}else if(Q(c)){const u=i==null?null:i.slice(l[3],l[5]);c=c.call(t.view,u,p=>this.render(p,t.view,s,r)),c!=null&&(n+=c)}else c&&(n+=this.renderTokens(d,t,s,i,r,a));break;case"^":if(c=t.lookup(l[1]),!c||G(c)&&c.length===0){const u=l[4];u&&G(u)&&(n+=this.renderTokens(u,t,s,i,r,a))}break;case">":if(!s)continue;c=Q(s)?s(l[1]):s[l[1]],c!=null&&(n+=this.render(c,t.view,s,r));break;case"&":c=t.lookup(l[1]),c!=null&&(n+=c);break;case"name":c=t.lookup(l[1]),c!=null&&(n+=Ie(c));break;case"text":n+=l[1];break}}return n}getConfigTags(e){return Te(e)&&G(e.tags)?e.tags:null}}function de(h){return h.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}const he=new Me,E={name:"MOJO Mustache",version:"1.0.0",tags:["{{","}}"],Scanner:ke,Context:ie,Writer:Me,escape:Ie,clearCache(){return he.clearCache()},parse(h,e){return he.parse(h,e)},render(h,e,t,s){if(typeof h!="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)),he.render(h,e,t,s)}};class We{constructor(e){this.view=e,this.domListeners=[],this.debounceTimers=new Map}bind(e){if(this.unbind(),!e)return;const t=async n=>{const o=n.target.closest("[data-action]");if(o&&this.shouldHandle(o,n)){const c=o.getAttribute("data-action");if(o.tagName==="A"&&n.preventDefault(),this.hideTooltip(o),await this.dispatch(c,n,o)){n.preventDefault(),n.stopPropagation(),n.handledByChild=!0;return}}const l=n.target.closest("a[href], [data-page]");if(l&&!l.hasAttribute("data-action")&&this.shouldHandle(l,n)){if(n.ctrlKey||n.metaKey||n.shiftKey||n.button===1)return;if(l.tagName==="A"){const c=l.getAttribute("href");if(c&&c!=="#"&&!c.startsWith("#")&&(this.view.isExternalLink(c)||l.hasAttribute("data-external")))return}this.hideTooltip(l),n.preventDefault(),n.stopPropagation(),n.handledByChild=!0,l.hasAttribute("data-page")?await this.view.handlePageNavigation(l):await this.view.handleHrefNavigation(l)}},s=n=>{const o=n.target.closest("[data-change-action]");if(o&&this.shouldHandle(o,n)){const c=o.getAttribute("data-change-action");this.dispatchChange(c,n,o).then(d=>{d&&(n.stopPropagation(),n.handledByChild=!0)});return}const l=n.target.closest("[data-action]");if(l&&this.isFormControl(l)&&this.shouldHandle(l,n)){const c=l.getAttribute("data-action");this.dispatch(c,n,l).then(d=>{d&&(n.stopPropagation(),n.handledByChild=!0)})}},i=n=>{const o=n.target.closest("[data-change-action]");if(o&&this.shouldHandle(o,n)&&n.target.matches('[data-filter="live-search"]')){const p=o.getAttribute("data-change-action"),m=parseInt(o.getAttribute("data-filter-debounce"))||300,f=`change-${p}-${o.getAttribute("data-container")||"default"}`;this.debounceTimers.has(f)&&clearTimeout(this.debounceTimers.get(f));const g=setTimeout(()=>{this.debounceTimers.delete(f),this.dispatchChange(p,n,o).then(b=>{b&&(n.stopPropagation(),n.handledByChild=!0)})},m);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 c=l.getAttribute("data-action"),d=l.getAttribute("data-action-debounce"),u=d!=null&&parseInt(d)||0;if(u>0){const p=`action-${c}-${l.getAttribute("data-container")||"default"}`;this.debounceTimers.has(p)&&clearTimeout(this.debounceTimers.get(p));const m=setTimeout(()=>{this.debounceTimers.delete(p),this.dispatch(c,n,l).then(f=>{f&&(n.stopPropagation(),n.handledByChild=!0)})},u);this.debounceTimers.set(p,m);return}this.dispatch(c,n,l).then(p=>{p&&(n.stopPropagation(),n.handledByChild=!0)})},r=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||!this.shouldHandle(o,n))return;let l=["Enter"];if(o.getAttribute("data-change-keys")&&(l=o.getAttribute("data-change-keys").split(",").map(c=>c.trim())),l.includes("*")||l.includes(n.key)){const c=o.getAttribute("data-keydown-action")||o.getAttribute("data-change-action");this.dispatch(c,n,o).then(d=>{d&&(n.preventDefault(),n.stopPropagation(),n.handledByChild=!0)})}},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(c=>c[0].toUpperCase()+c.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 ue={on(h,e,t){this._listeners||(this._listeners={}),this._listeners[h]||(this._listeners[h]=[]);const s={callback:e,context:t,fn:t?e.bind(t):e};return this._listeners[h].push(s),this},off(h,e,t){return!this._listeners||!this._listeners[h]?this:(e?(this._listeners[h]=this._listeners[h].filter(s=>s.callback!==e||arguments.length===3&&s.context!==t),this._listeners[h].length===0&&delete this._listeners[h]):delete this._listeners[h],this)},once(h,e,t){const s=(...i)=>{this.off(h,s),(t?e.bind(t):e).apply(t||this,i)};return this.on(h,s),this},emit(h,...e){if(!this._listeners||!this._listeners[h])return this;const t=this._listeners[h].slice();for(const s of t)try{s.fn.apply(s.context||this,e)}catch(i){console&&console.error&&console.error(`Error in ${h} event handler:`,i)}return this}};typeof window<"u"&&(window.Mustache=E);class C{constructor(e={}){this.tagName=e.tagName??"div",this.className=e.className??"mojo-view",this.style=e.style??null,this.id=e.id??C._genId(),this.containerId=e.containerId??null,this.container=e.container??null,typeof this.container=="string"&&(this.containerId=this.container,this.container=null),this.parent=e.parent??null,this.children=e.children??{},this.template=e.template||e.templateUrl||"",this.data=e.data??{},this.isRendering=!1,this.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 We(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){C._warn("addChild error",s)}return e}removeChild(e){try{const t=typeof e=="string"?e:e&&e.id;if(!t)return this;const s=this.children[t];s&&(Promise.resolve(s.destroy()).catch(i=>C._warn("removeChild destroy error",i)),delete this.children[t])}catch(t){C._warn("removeChild error",t)}return this}getChild(e){return this.children[e]}async updateData(e,t=!1){return Object.assign(this.data,e),t&&this.isMounted()&&await this.render(),this}toggleClass(e,t){return t===void 0&&(t=!this.element.classList.contains(e)),this.element.classList.toggle(e,t),this}addClass(e){return this.element.classList.add(e),this}setClass(e){return this.element.className=e,this}removeClass(e){return this.element.classList.remove(e),this}canRender(){if(this.isRendering)return!1;const e=Date.now();if(this.options.renderCooldown>0&&e-this.lastRenderTime<this.options.renderCooldown)return C._warn(`View ${this.id}: Render called too quickly, cooldown active`),!1;if(this.options.noAppend&&this.parent)if(this.parent.contains(this.containerId||this.container)){if(this.containerId&&!document.getElementById(this.containerId))return!1;if(this.container&&!document.contains(this.container))return!1}else return!1;return!0}async render(e=!0,t=null){const s=Date.now();if(!this.canRender())return this;this.isRendering=!0,this.lastRenderTime=s;try{this.initialized||await this.onInitView(),this.unbindEvents(),await this.onBeforeRender(),this.getViewData&&(this.data=await this.getViewData());const i=await this.renderTemplate();this.element.innerHTML=i,e&&!this.isMounted()&&await this.mount(t),await this._renderChildren(),await this.onAfterRender(),this.bindEvents()}catch(i){C._warn(`Render error in ${this.id}`,i)}finally{this.isRendering=!1}return this}async _renderChildren(){const e=[];for(const t in this.children){const s=this.children[t];if(s){if(s.parent=this,s._lazyMount&&!s._lazyTriggered){e.push(s);continue}await Promise.resolve(s.render()).catch(i=>C._warn(`Child render error (${t})`,i))}}e.length&&this._setupLazyMountObserver(e)}_setupLazyMountObserver(e){if(typeof IntersectionObserver>"u"){e.forEach(t=>{t._lazyTriggered=!0,Promise.resolve(t.render()).catch(s=>C._warn(`Lazy child render error (${t.id})`,s))});return}this._lazyObserver||(this._lazyObserver=new IntersectionObserver((t,s)=>{for(const i of t){if(!i.isIntersecting)continue;const r=i.target.__mojoLazyChild;s.unobserve(i.target),!(!r||r._lazyTriggered)&&(r._lazyTriggered=!0,Promise.resolve(r.render()).catch(a=>C._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=>C._warn(`Lazy child render error (${t.id})`,o)))}))}}async _unmountChildren(){for(const e in this.children){const t=this.children[e];t&&t.unbindEvents()}}isMounted(){return this.element?.isConnected}getChildElementById(e,t=null){const s=e.startsWith("#")?e.substring(1):e;return t?t.querySelector(`#${s}`):this.element.querySelector(`#${s}`)}getChildElement(e){if(e.startsWith("#"))return this.getChildElementById(e);let t=this.element?.querySelector(`[data-container="${e}"]`);return t||this.getChildElementById(e)}getContainer(){return this.replaceById?this.parent?this.parent.getChildElementById(this.id):null:this.containerId?this.parent?this.parent.getChildElement(this.containerId):this.getChildElementById(this.containerId,document.body):null}async mount(e=null){if(await this.onBeforeMount(),e||(e=this.getContainer()),this.containerId&&!e){console.error(`Container not found for ${this.containerId}`);return}e&&this.replaceById?e.replaceWith(this.element):e?e.replaceChildren(this.element):!this.containerId&&this.parent?this.parent.element.appendChild(this.element):!this.containerId&&!this.parent&&this.options.allowAppendToBody?(console.log("APPENDING TO BODY!!!!"),document.body.appendChild(this.element)):console.error(`Container not found for ${this.containerId}`),await this.onAfterMount(),this.mounted=!0}async unmount(){!this.element||!this.element.parentNode||(await this.onBeforeUnmount(),await this._unmountChildren(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),this.events.unbind(),await this.onAfterUnmount(),this.mounted=!1)}async destroy(){try{this.events.unbind(),this._lazyObserver&&(this._lazyObserver.disconnect(),this._lazyObserver=null);for(const e in this.children){const t=this.children[e];t&&await Promise.resolve(t.destroy()).catch(s=>C._warn(`Child destroy error (${e})`,s))}this.mounted=!1,this.element&&this.element.parentNode&&(await this.onBeforeDestroy(),this.element.parentNode&&this.element.parentNode.removeChild(this.element),await this.onAfterDestroy())}catch(e){C._warn(`Destroy error in ${this.id}`,e)}}_ensureElement(){try{if(this.element&&this.element.tagName?.toLowerCase()===this.tagName)return this._syncAttrs(),this.element;const e=document.createElement(this.tagName);return this.element=e,this.el=e,this._syncAttrs(),e}catch(e){C._warn("ensureElement error",e);const t=document.createElement("div");return t.id=this.id||C._genId(),t}}_syncAttrs(){try{if(!this.element)return;this.id&&(this.element.id=this.id),this.element.className=this.className||"",this.style==null?this.element.removeAttribute("style"):this.element.style.cssText=String(this.style)}catch(e){C._warn("_syncAttrs error",e)}}bindEvents(){this.events.bind(this.element),this.enableTooltips&&this.initializeTooltips()}unbindEvents(){this.events.unbind(),this.enableTooltips&&this.disposeTooltips()}async renderTemplate(){const e=await this.getTemplate();if(!e)return"";const t=this.getPartials();return E.render(e,this,t)}renderTemplateString(e,t,s){return E.render(e,t,s)}getPartials(){return{}}async getTemplate(){if(this._templateCache&&this.cacheTemplate)return this._templateCache;const e=this.template||this.templateUrl;if(!e)throw new Error("Template not found");let t="";if(typeof e=="string")if(e.includes("<")||e.includes("{"))t=e;else try{let s=e;this.app||(this.app=this.getApp()),this.app&&this.app.basePath&&!s.startsWith("/")&&!s.startsWith("http://")&&!s.startsWith("https://")&&(s=`${this.app.basePath.endsWith("/")?this.app.basePath.slice(0,-1):this.app.basePath}/${s}`);const i=await fetch(s);if(!i.ok)throw new Error(`HTTP ${i.status}: ${i.statusText}`);t=await i.text()}catch(s){C._warn(`Failed to load template from ${e}: ${s}`),this.showError?.(`Failed to load template from ${e}: ${s.message}`)}else typeof e=="function"&&(t=await this.template(this.data,this.state));return this.cacheTemplate&&t&&(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(C.prototype,ue);class S extends C{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:S._baseZIndex}static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=S._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(){S.fixAllBackdropStacking()}static getMountTarget(){return document.querySelector(".table-fullscreen")||document.body}constructor(e={}){const t=e.id||`modal-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;super({...e,id:t,tagName:"div",className:`modal ${e.fade!==!1?"fade":""} ${e.className||""}`.trim().replace(/\s+/g," "),attributes:{tabindex:"-1","aria-hidden":"true","aria-labelledby":e.labelledBy||`${t}-label`,"aria-describedby":e.describedBy||null,...e.attributes}}),this.modalId=t,this.title=e.title||"",this.titleId=`${this.modalId}-label`,this.size=e.size||"",this.centered=e.centered!==void 0?e.centered:!1,this.scrollable=e.scrollable!==void 0?e.scrollable:!1,this.autoSize=e.autoSize||e.size==="auto",this.backdrop=e.backdrop!==void 0?e.backdrop:!0,this.keyboard=e.keyboard!==void 0?e.keyboard:!0,this.focus=e.focus!==void 0?e.focus:!0,this.header=e.header!==void 0?e.header:!0,this.headerContent=e.headerContent||null,this.headerView=null,this.closeButton=e.closeButton!==void 0?e.closeButton:!0,this.contextMenu=e.contextMenu||null,this._processHeaderContent(this.headerContent),this.body=e.body??e.view??e.message??e.content??"",this.bodyView=null,this.bodyClass=e.bodyClass||"",this.noBodyPadding=e.noBodyPadding||!1,this.minWidth=e.minWidth||300,this.minHeight=e.minHeight||200,e.maxHeight&&(this.maxHeight=e.maxHeight),this.maxWidthPercent=e.maxWidthPercent||.9,this.maxHeightPercent=e.maxHeightPercent||.8,this._processBodyContent(this.body),this.footer=e.footer||null,this.footerView=null,this.footerClass=e.footerClass||"",this._processFooterContent(this.footer),this.buttons=e.buttons||null,this.onShow=e.onShow||null,this.onShown=e.onShown||null,this.onHide=e.onHide||null,this.onHidden=e.onHidden||null,this.onHidePrevented=e.onHidePrevented||null,this.autoShow=e.autoShow!==void 0?e.autoShow:!1,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(e){if(e instanceof C||e&&typeof e=="object"&&typeof e.render=="function")this.bodyView=e,this.body="",this.addChild(this.bodyView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.bodyView=t,this.body="",this.addChild(this.bodyView)):t instanceof Promise?(this.bodyPromise=t,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=t}catch(t){console.error("ModalView: error processing body function:",t),this.body=e}else this.body=e}_processHeaderContent(e){if(e instanceof C)this.headerView=e,this.headerContent=null,this.addChild(this.headerView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.headerView=t,this.headerContent=null,this.addChild(this.headerView)):t instanceof Promise?(this.headerPromise=t,this.headerContent='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.headerContent=t}catch(t){console.error("ModalView: error processing headerContent function:",t),this.headerContent=e}else this.headerContent=e}_processFooterContent(e){if(e instanceof C)this.footerView=e,this.footer=null,this.addChild(this.footerView);else if(typeof e=="function")try{const t=e();t instanceof C?(this.footerView=t,this.footer=null,this.addChild(this.footerView)):t instanceof Promise?(this.footerPromise=t,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=t}catch(t){console.error("ModalView: error processing footer function:",t),this.footer=e}else this.footer=e}async getTemplate(){const e=["modal-dialog"];return this.size&&this.size!=="auto"&&(this.size.startsWith("fullscreen")?e.push(`modal-${this.size}`):["sm","lg","xl","xxl"].includes(this.size)&&(e.push(`modal-${this.size}`),["lg","xl","xxl"].includes(this.size)&&e.push("modal-fullscreen-sm-down"))),this.centered&&e.push("modal-dialog-centered"),this.scrollable&&(this.maxHeight?e.push("overflow-hidden"):e.push("modal-dialog-scrollable")),`
16
16
  <div class="${e.join(" ")}">
17
17
  <div class="modal-content">
18
18
  ${await this.buildHeader()}
@@ -85,13 +85,13 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
85
85
  white-space: nowrap;
86
86
  }
87
87
  @keyframes mojo-spin { to { transform: rotate(360deg); } }
88
- `,me={show(h){typeof h=="string"&&(h={message:h});const{message:e="Loading...",timeout:t=3e4}=h||{};if(q++,q===1){J&&clearTimeout(J);const i=S.getFullscreenAwareZIndex().modal+1e3;k||(k=document.createElement("div"),k.className="mojo-loading-overlay",k.innerHTML=`
88
+ `,pe={show(h){typeof h=="string"&&(h={message:h});const{message:e="Loading...",timeout:t=3e4}=h||{};if(q++,q===1){J&&clearTimeout(J);const i=S.getFullscreenAwareZIndex().modal+1e3;k||(k=document.createElement("div"),k.className="mojo-loading-overlay",k.innerHTML=`
89
89
  <div class="mojo-loading-card">
90
90
  <div class="mojo-loading-spinner"></div>
91
91
  <div class="mojo-loading-message">${e}</div>
92
92
  </div>
93
93
  <style>${Ge}</style>
94
- `,document.body.appendChild(k)),k.style.zIndex=String(i);const r=k.querySelector(".mojo-loading-message");r&&(r.textContent=e),requestAnimationFrame(()=>{k&&k.classList.add("show")}),t>0&&(J=setTimeout(()=>{console.error("BusyIndicator timed out."),me.hide(!0)},t))}else if(k){const s=k.querySelector(".mojo-loading-message");s&&(s.textContent=e)}},hide(h=!1){h?q=0:q--,!(q>0)&&(q=0,J&&(clearTimeout(J),J=null),k&&(k.classList.remove("show"),setTimeout(()=>{k&&q===0&&(k.remove(),k=null)},200)))},isShown(){return k!==null&&q>0}},Je=`
94
+ `,document.body.appendChild(k)),k.style.zIndex=String(i);const r=k.querySelector(".mojo-loading-message");r&&(r.textContent=e),requestAnimationFrame(()=>{k&&k.classList.add("show")}),t>0&&(J=setTimeout(()=>{console.error("BusyIndicator timed out."),pe.hide(!0)},t))}else if(k){const s=k.querySelector(".mojo-loading-message");s&&(s.textContent=e)}},hide(h=!1){h?q=0:q--,!(q>0)&&(q=0,J&&(clearTimeout(J),J=null),k&&(k.classList.remove("show"),setTimeout(()=>{k&&q===0&&(k.remove(),k=null)},200)))},isShown(){return k!==null&&q>0}},Je=`
95
95
  max-height: 60vh;
96
96
  overflow-y: auto;
97
97
  background: #1e1e1e;
@@ -160,7 +160,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
160
160
  ${t?`<i class="${this.getDefaultIcon("info")} toast-service-icon me-2"></i>`:""}
161
161
  <span>${this.escapeHtml(e)}</span>
162
162
  </div>
163
- `}getDefaultTitle(e){return{success:"Success",error:"Error",warning:"Warning",info:"Information",plain:""}[e]||"Notification"}getDefaultIcon(e){return{success:"bi-check-circle-fill",error:"bi-exclamation-triangle-fill",warning:"bi-exclamation-triangle-fill",info:"bi-info-circle-fill",plain:""}[e]||"bi-info-circle-fill"}enforceMaxToasts(){if(Array.from(this.toasts.values()).length>=this.options.maxToasts){const t=this.toasts.keys().next().value,s=this.toasts.get(t);s&&s.bootstrap.hide()}}cleanup(e){const t=this.toasts.get(e);if(t){try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}cleanupView(e){const t=this.toasts.get(e);if(t){if(t.view&&typeof t.view.dispose=="function")try{t.view.dispose()}catch(s){console.warn("Error disposing view in toast:",s)}try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}hideAll(){this.toasts.forEach((e,t)=>{e.bootstrap.hide()})}clearAll(){this.toasts.forEach((e,t)=>{this.cleanup(t)})}getTimeString(){return new Date().toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}dispose(){this.clearAll(),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container)}getStats(){const e={total:this.toasts.size,byType:{}};return this.toasts.forEach(t=>{e.byType[t.type]=(e.byType[t.type]||0)+1}),e}setOptions(e){this.options={...this.options,...e},e.position&&this.container&&(this.container.className=`toast-container position-fixed ${this.getPositionClasses()}`)}}class pe extends C{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=_.pipe(this.filesize,"filesize"),this.progress=0,this.percentage=0,this.loaded=0,this.total=this.filesize,this.loadedFormatted="0 B",this.totalFormatted=this.filesizeFormatted,this.status="Starting upload...",this.showCancel=e.showCancel!==!1,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return`
163
+ `}getDefaultTitle(e){return{success:"Success",error:"Error",warning:"Warning",info:"Information",plain:""}[e]||"Notification"}getDefaultIcon(e){return{success:"bi-check-circle-fill",error:"bi-exclamation-triangle-fill",warning:"bi-exclamation-triangle-fill",info:"bi-info-circle-fill",plain:""}[e]||"bi-info-circle-fill"}enforceMaxToasts(){if(Array.from(this.toasts.values()).length>=this.options.maxToasts){const t=this.toasts.keys().next().value,s=this.toasts.get(t);s&&s.bootstrap.hide()}}cleanup(e){const t=this.toasts.get(e);if(t){try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}cleanupView(e){const t=this.toasts.get(e);if(t){if(t.view&&typeof t.view.dispose=="function")try{t.view.dispose()}catch(s){console.warn("Error disposing view in toast:",s)}try{t.bootstrap.dispose()}catch(s){console.warn("Error disposing toast:",s)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}hideAll(){this.toasts.forEach((e,t)=>{e.bootstrap.hide()})}clearAll(){this.toasts.forEach((e,t)=>{this.cleanup(t)})}getTimeString(){return new Date().toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}dispose(){this.clearAll(),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container)}getStats(){const e={total:this.toasts.size,byType:{}};return this.toasts.forEach(t=>{e.byType[t.type]=(e.byType[t.type]||0)+1}),e}setOptions(e){this.options={...this.options,...e},e.position&&this.container&&(this.container.className=`toast-container position-fixed ${this.getPositionClasses()}`)}}class me extends C{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=_.pipe(this.filesize,"filesize"),this.progress=0,this.percentage=0,this.loaded=0,this.total=this.filesize,this.loadedFormatted="0 B",this.totalFormatted=this.filesizeFormatted,this.status="Starting upload...",this.showCancel=e.showCancel!==!1,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return`
164
164
  <div class="progress-view">
165
165
  <div class="d-flex justify-content-between align-items-start mb-2">
166
166
  <div class="flex-grow-1 min-width-0">
@@ -199,7 +199,7 @@ var MOJO=(function(A){"use strict";class oe{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=_.pipe(this.loaded,"filesize"),this.totalFormatted=_.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=_.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 Xe{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 Qe),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 c=i;i.startsWith("/")&&!i.startsWith("/api/")&&(c="/api"+i);const d=this.fileModel.rest.buildUrl(c);if(l.open(r,d),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 pe({filename:this.options.name||this.options.file.name,filesize:this.options.file.size,showCancel:!0,onCancel:()=>this.cancel()}),this.progressToast=this.toastService.showView(this.progressView,"info",{title:"File Upload",autohide:!1,dismissible:!1})}cancel(){return this.cancelled?!1:(this.cancelled=!0,this.uploadRequest&&typeof this.uploadRequest.abort=="function"&&this.uploadRequest.abort(),this.progressView&&this.progressView.markCancelled(),this.progressToast&&setTimeout(()=>{try{this.progressToast&&typeof this.progressToast.hide=="function"&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast on cancel:",e)}},1500),!0)}isCancelled(){return this.cancelled}then(e,t){return this.promise.then(e,t)}catch(e){return this.promise.catch(e)}finally(e){return this.promise.finally(e)}getStats(){return{filename:this.options.file.name,size:this.options.file.size,type:this.options.file.type,cancelled:this.cancelled,group:this.options.group,description:this.options.description}}}class K extends W{constructor(e={}){super(e,{endpoint:"/api/group"})}}class fe extends Z{constructor(e={}){super({ModelClass:K,endpoint:"/api/group",size:10,...e})}}const Ve={org:"Organization",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"},ge=Object.entries(Ve).map(([h,e])=>({value:h,label:e})),be={create:{title:"Create Group",fields:[{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name"},{name:"kind",type:"select",label:"Group Kind",required:!0,options:ge},{type:"collection",name:"parent",label:"Parent Group",Collection:fe,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300}]},edit:{title:"Edit Group",fields:[{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name"},{name:"kind",type:"select",label:"Group Kind",required:!0,options:ge},{type:"collection",name:"parent",label:"Parent Group",Collection:fe,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300},{name:"metadata.domain",type:"text",label:"Default Domain",placeholder:"Enter Domain"},{name:"metadata.portal",type:"text",label:"Default Portal",placeholder:"Enter Portal URL"},{name:"is_active",type:"switch",label:"Is Active",cols:4}]}};K.EDIT_FORM=be.edit,K.ADD_FORM=be.create,K.CREATE_FORM=be.create,K.GroupKindOptions=ge,K.GroupKinds=Ve;class v extends W{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=v.GRANULAR_TO_CATEGORY[e];return!!(s&&t[s]==!0)}hasPerm(e){return this.hasPermission(e)}}v.CATEGORY_PERMISSIONS=[{name:"view_admin",label:"Admin Panel",tooltip:"Access the admin panel, assistant, 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:"AI Assistant",tooltip:"Access to the AI Assistant"},{name:"comms",label:"Communication",tooltip:"Ability to notify users"}],v.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"}]}],v.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"]},v.APP_CATEGORY_PERMISSIONS=[],v.APP_GRANULAR_PERMISSIONS=[],v._permSwitch=function(h){return{name:`permissions.${h.name}`,type:"switch",label:h.label,columns:6,...h.tooltip?{tooltip:h.tooltip}:{}}},v.PERMISSIONS=[],v.PERMISSION_FIELDS=[],v.CATEGORY_PERMISSION_FIELDS=[],v.GRANULAR_PERMISSION_FIELDS=[],v.GRANULAR_TO_CATEGORY={},v.rebuildPermissions=function(){const h=v._permSwitch;v.PERMISSIONS.length=0,v.PERMISSIONS.push(...v.CATEGORY_PERMISSIONS,...v.GRANULAR_PERMISSION_TABS.flatMap(s=>s.permissions),...v.APP_CATEGORY_PERMISSIONS,...v.APP_GRANULAR_PERMISSIONS),v.PERMISSION_FIELDS.length=0,v.PERMISSION_FIELDS.push(...v.PERMISSIONS.map(h));const e=[{label:"System",fields:v.CATEGORY_PERMISSIONS.map(h)}];v.APP_CATEGORY_PERMISSIONS.length>0&&e.push({label:"App",fields:v.APP_CATEGORY_PERMISSIONS.map(h)}),v.CATEGORY_PERMISSION_FIELDS.length=0,v.CATEGORY_PERMISSION_FIELDS.push({type:"tabset",tabs:e});const t=v.GRANULAR_PERMISSION_TABS.map(s=>({label:s.label,fields:s.permissions.map(h)}));v.APP_GRANULAR_PERMISSIONS.length>0&&t.push({label:"App",fields:v.APP_GRANULAR_PERMISSIONS.map(h)}),v.GRANULAR_PERMISSION_FIELDS.length=0,v.GRANULAR_PERMISSION_FIELDS.push({type:"tabset",tabs:t});for(const s of Object.keys(v.GRANULAR_TO_CATEGORY))delete v.GRANULAR_TO_CATEGORY[s];for(const[s,i]of Object.entries(v.CATEGORY_GRANULAR_MAP))for(const r of i)v.GRANULAR_TO_CATEGORY[r]=s},v.registerCategoryMap=function(h){if(!h)return;let e=!1;for(const[t,s]of Object.entries(h)){if(!Array.isArray(s))continue;const i=v.CATEGORY_GRANULAR_MAP[t]||[];v.CATEGORY_GRANULAR_MAP[t]=Array.from(new Set([...i,...s])),e=!0}e&&v.rebuildPermissions()},v.registerPermissions=function(h){if(h){if(Array.isArray(h.categories)&&v.APP_CATEGORY_PERMISSIONS.push(...h.categories),Array.isArray(h.granularPermissions)&&v.APP_GRANULAR_PERMISSIONS.push(...h.granularPermissions),Array.isArray(h.granularTabs)&&v.GRANULAR_PERMISSION_TABS.push(...h.granularTabs),h.categoryGranularMap)for(const[e,t]of Object.entries(h.categoryGranularMap)){if(!Array.isArray(t))continue;const s=v.CATEGORY_GRANULAR_MAP[e]||[];v.CATEGORY_GRANULAR_MAP[e]=Array.from(new Set([...s,...t]))}v.rebuildPermissions()}},v.rebuildPermissions();const Le={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:fe,labelField:"name",valueField:"id",columns:12}]},permissions:{fields:v.PERMISSION_FIELDS}},et={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}]}};v.DATA_VIEW=et.detailed,v.EDIT_FORM=Le.edit,v.ADD_FORM=Le.create;let tt=class extends W{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 Xe(this,e)}};class w{static _renderAndAwait(e,{buttons:t=null,rejectOnDismiss:s=!1,onAction:i=null,cleanup:r=null}={}){const a=S.getMountTarget();return new Promise((n,o)=>{let l=!1;const c=u=>{l||(l=!0,n(u))},d=u=>{l||(l=!0,o(u))};(async()=>{try{await e.render(!0,a)}catch(u){d(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 x=y===!0||y===void 0?b:y;f.dismiss||e.hide(),c(x)}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 x=y===!0||y===void 0?b:y;f.dismiss||e.hide(),c(x)}catch(y){console.error("Modal onAction error:",y)}return}f.dismiss||e.hide(),c(b)})}),e.on("hidden",()=>{l||(s?d(new Error("Dialog dismissed")):c(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:c=!1,...d}=e,u=i??r??a??s??"",m=new S({title:t,body:u,size:n,centered:o,buttons:l,...d});return w._renderAndAwait(m,{buttons:l,rejectOnDismiss:c})}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=_.pipe(this.loaded,"filesize"),this.totalFormatted=_.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=_.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 Xe{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 Qe),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 c=i;i.startsWith("/")&&!i.startsWith("/api/")&&(c="/api"+i);const d=this.fileModel.rest.buildUrl(c);if(l.open(r,d),l.timeout=3e4,o){for(const[p,m]of Object.entries(n||{}))p.toLowerCase()!=="content-type"&&l.setRequestHeader(p,m);const u=new FormData;for(const[p,m]of Object.entries(a))u.append(p,m);u.append("file",this.options.file),l.send(u)}else{l.setRequestHeader("Content-Type",this.options.file.type);for(const[u,p]of Object.entries(n||{}))u.toLowerCase()!=="content-type"&&l.setRequestHeader(u,p);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 me({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 K extends W{constructor(e={}){super(e,{endpoint:"/api/group"})}}class fe extends Z{constructor(e={}){super({ModelClass:K,endpoint:"/api/group",size:10,...e})}}const Ve={org:"Organization",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"},ge=Object.entries(Ve).map(([h,e])=>({value:h,label:e})),be={create:{title:"Create Group",fields:[{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name"},{name:"kind",type:"select",label:"Group Kind",required:!0,options:ge},{type:"collection",name:"parent",label:"Parent Group",Collection:fe,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300}]},edit:{title:"Edit Group",fields:[{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name"},{name:"kind",type:"select",label:"Group Kind",required:!0,options:ge},{type:"collection",name:"parent",label:"Parent Group",Collection:fe,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300},{name:"metadata.domain",type:"text",label:"Default Domain",placeholder:"Enter Domain"},{name:"metadata.portal",type:"text",label:"Default Portal",placeholder:"Enter Portal URL"},{name:"is_active",type:"switch",label:"Is Active",cols:4}]}};K.EDIT_FORM=be.edit,K.ADD_FORM=be.create,K.CREATE_FORM=be.create,K.GroupKindOptions=ge,K.GroupKinds=Ve;class v extends W{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=v.GRANULAR_TO_CATEGORY[e];return!!(s&&t[s]==!0)}hasPerm(e){return this.hasPermission(e)}}v.CATEGORY_PERMISSIONS=[{name:"view_admin",label:"Admin Panel",tooltip:"Access the admin panel, assistant, 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:"AI Assistant",tooltip:"Access to the AI Assistant"},{name:"comms",label:"Communication",tooltip:"Ability to notify users"}],v.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"}]}],v.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"]},v.APP_CATEGORY_PERMISSIONS=[],v.APP_GRANULAR_PERMISSIONS=[],v._permSwitch=function(h){return{name:`permissions.${h.name}`,type:"switch",label:h.label,columns:6,...h.tooltip?{tooltip:h.tooltip}:{}}},v.PERMISSIONS=[],v.PERMISSION_FIELDS=[],v.CATEGORY_PERMISSION_FIELDS=[],v.GRANULAR_PERMISSION_FIELDS=[],v.GRANULAR_TO_CATEGORY={},v.rebuildPermissions=function(){const h=v._permSwitch;v.PERMISSIONS.length=0,v.PERMISSIONS.push(...v.CATEGORY_PERMISSIONS,...v.GRANULAR_PERMISSION_TABS.flatMap(s=>s.permissions),...v.APP_CATEGORY_PERMISSIONS,...v.APP_GRANULAR_PERMISSIONS),v.PERMISSION_FIELDS.length=0,v.PERMISSION_FIELDS.push(...v.PERMISSIONS.map(h));const e=[{label:"System",fields:v.CATEGORY_PERMISSIONS.map(h)}];v.APP_CATEGORY_PERMISSIONS.length>0&&e.push({label:"App",fields:v.APP_CATEGORY_PERMISSIONS.map(h)}),v.CATEGORY_PERMISSION_FIELDS.length=0,v.CATEGORY_PERMISSION_FIELDS.push({type:"tabset",tabs:e});const t=v.GRANULAR_PERMISSION_TABS.map(s=>({label:s.label,fields:s.permissions.map(h)}));v.APP_GRANULAR_PERMISSIONS.length>0&&t.push({label:"App",fields:v.APP_GRANULAR_PERMISSIONS.map(h)}),v.GRANULAR_PERMISSION_FIELDS.length=0,v.GRANULAR_PERMISSION_FIELDS.push({type:"tabset",tabs:t});for(const s of Object.keys(v.GRANULAR_TO_CATEGORY))delete v.GRANULAR_TO_CATEGORY[s];for(const[s,i]of Object.entries(v.CATEGORY_GRANULAR_MAP))for(const r of i)v.GRANULAR_TO_CATEGORY[r]=s},v.registerCategoryMap=function(h){if(!h)return;let e=!1;for(const[t,s]of Object.entries(h)){if(!Array.isArray(s))continue;const i=v.CATEGORY_GRANULAR_MAP[t]||[];v.CATEGORY_GRANULAR_MAP[t]=Array.from(new Set([...i,...s])),e=!0}e&&v.rebuildPermissions()},v.registerPermissions=function(h){if(h){if(Array.isArray(h.categories)&&v.APP_CATEGORY_PERMISSIONS.push(...h.categories),Array.isArray(h.granularPermissions)&&v.APP_GRANULAR_PERMISSIONS.push(...h.granularPermissions),Array.isArray(h.granularTabs)&&v.GRANULAR_PERMISSION_TABS.push(...h.granularTabs),h.categoryGranularMap)for(const[e,t]of Object.entries(h.categoryGranularMap)){if(!Array.isArray(t))continue;const s=v.CATEGORY_GRANULAR_MAP[e]||[];v.CATEGORY_GRANULAR_MAP[e]=Array.from(new Set([...s,...t]))}v.rebuildPermissions()}},v.rebuildPermissions();const Le={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:fe,labelField:"name",valueField:"id",columns:12}]},permissions:{fields:v.PERMISSION_FIELDS}},et={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}]}};v.DATA_VIEW=et.detailed,v.EDIT_FORM=Le.edit,v.ADD_FORM=Le.create;let tt=class extends W{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 Xe(this,e)}};class w{static _renderAndAwait(e,{buttons:t=null,rejectOnDismiss:s=!1,onAction:i=null,cleanup:r=null}={}){const a=S.getMountTarget();return new Promise((n,o)=>{let l=!1;const c=u=>{l||(l=!0,n(u))},d=u=>{l||(l=!0,o(u))};(async()=>{try{await e.render(!0,a)}catch(u){d(u);return}t&&t.length>0&&e.element&&e.element.querySelectorAll(".modal-footer button").forEach((p,m)=>{const f=t[m];f&&p.addEventListener("click",async g=>{if(l)return;const b=f.value!==void 0?f.value:f.action??m;if(typeof f.handler=="function"){try{const y=await f.handler({dialog:e,button:f,index:m,event:g});if(y===null||y===!1)return;const x=y===!0||y===void 0?b:y;f.dismiss||e.hide(),c(x)}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:m,event:g});if(y===null||y===!1)return;const x=y===!0||y===void 0?b:y;f.dismiss||e.hide(),c(x)}catch(y){console.error("Modal onAction error:",y)}return}f.dismiss||e.hide(),c(b)})}),e.on("hidden",()=>{l||(s?d(new Error("Dialog dismissed")):c(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 m=arguments[0],f=arguments[1]||"Alert";e={...arguments[2]||{},body:m,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:c=!1,...d}=e,u=i??r??a??s??"",p=new S({title:t,body:u,size:n,centered:o,buttons:l,...d});return w._renderAndAwait(p,{buttons:l,rejectOnDismiss:c})}static async drawer(e={}){const{eyebrow:t,title:s,meta:i=[],view:r,body:a,size:n="lg",...o}=e,l=i.length?`
203
203
  <div class="modal-drawer-meta">
204
204
  ${i.map(u=>typeof u=="string"?`<span>${w._esc(u)}</span>`:`<span>${u.icon?`<i class="${w._esc(u.icon)} me-1"></i>`:""}${w._esc(u.text||"")}</span>`).join("")}
205
205
  </div>`:"",c=`
@@ -208,14 +208,14 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
208
208
  <h2 class="modal-drawer-title">${w._esc(s||"")}</h2>
209
209
  ${l}
210
210
  </div>
211
- `;let d;if(r&&typeof r=="object"&&typeof r.render=="function"){const u=class extends C{async getTemplate(){return`${c}<div class="modal-drawer-body" data-container="drawer-body"></div>`}async onInit(){r.containerId="drawer-body",this.addChild(r)}};d=new u}else d=`${c}<div class="modal-drawer-body">${a||""}</div>`;return w.dialog({header:!1,body:d,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 w.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 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 w.show(r,t)}static async showModelById(e,t,s={}){const i=new e({id:t});return await i.fetch(),i.id?w.showModel(i,s):(w.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 w.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,...c}=i,d=n==="danger"?"error":n,m=[`modal-alert modal-alert-${d}`,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"}[d],g=f?`<i class="bi ${f} modal-alert-icon"></i>`:"",b=`<span class="modal-alert-headline">${a}</span>`;return w.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}],...c})}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 S({title:t,body:`<p>${i}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:r,...s});return await w._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 S({title:t,body:`
211
+ `;let d;if(r&&typeof r=="object"&&typeof r.render=="function"){const u=class extends C{async getTemplate(){return`${c}<div class="modal-drawer-body" data-container="drawer-body"></div>`}async onInit(){r.containerId="drawer-body",this.addChild(r)}};d=new u}else d=`${c}<div class="modal-drawer-body">${a||""}</div>`;return w.dialog({header:!1,body:d,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 w.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 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 w.show(r,t)}static async showModelById(e,t,s={}){const i=new e({id:t});return await i.fetch(),i.id?w.showModel(i,s):(w.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 w.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,...c}=i,d=n==="danger"?"error":n,p=[`modal-alert modal-alert-${d}`,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"}[d],g=f?`<i class="bi ${f} modal-alert-icon"></i>`:"",b=`<span class="modal-alert-headline">${a}</span>`;return w.dialog({title:`${g}${b}`,body:`<p class="modal-alert-message">${r}</p>`,size:"sm",centered:!0,className:p,buttons:[{text:"OK",class:"btn-primary",value:!0}],...c})}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 S({title:t,body:`<p>${i}</p>`,size:s.size||"sm",centered:!0,backdrop:"static",buttons:r,...s});return await w._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 S({title:t,body:`
212
212
  <p>${e}</p>
213
213
  <input type="${a}"
214
214
  class="form-control"
215
215
  id="${i}"
216
216
  value="${r}"
217
217
  placeholder="${n}">
218
- `,size:s.size||"sm",centered:!0,backdrop:"static",buttons:o,...s});return l.on("shown",()=>{const c=l.element.querySelector(`#${i}`);c&&(c.focus(),c.select())}),w._renderAndAwait(l,{buttons:o,onAction:async c=>{if(c!=="ok")return null;const d=l.element.querySelector(`#${i}`);return d?d.value:null}})}static showError(e){return w.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(()=>Pe)).default,c=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}}),d=[{text:n,class:"btn-secondary",action:"cancel"},{text:a,class:"btn-primary",action:"submit"}],u=new S({title:t,body:c,size:i,centered:r,buttons:d,...o});return w._renderAndAwait(u,{buttons:d,onAction:async m=>{if(m==="cancel")return u.hide(),null;if(m!=="submit")return null;if(!c.validate())return c.focusFirstError(),!1;if(e.autoSave&&e.model){u.setLoading(!0);const p=await c.saveModel();return p.success?p:(u.setLoading(!1),await u.render(),u.getApp()?.toast?.error(p.message),!1)}try{return await c.getFormData()}catch(p){return console.error("Modal.form: error collecting form data:",p),c.showError("Error collecting form data"),!1}},cleanup:async()=>{try{await c.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,...c}=e;if(!o)throw new Error("Modal.modelForm requires a model");const d=(await Promise.resolve().then(()=>Pe)).default,u=new d({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 S({title:t,body:u,size:i,centered:r,buttons:m,...c});return w._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:c="lg",centered:d=!0,closeText:u="Close",...m}=e,p=(await Promise.resolve().then(()=>bt)).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 S({title:t,body:f,size:c,centered:d,buttons:g,...m});return f.on("field:click",y=>b.emit("dataview:field:click",y)),f.on("error",y=>b.emit("dataview:error",y)),w._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 X({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 S({title:i,body:n,size:r,scrollable:!0,buttons:o,...a});return w._renderAndAwait(l,{buttons:o,onAction:async c=>{if(c!=="copy")return null;if(!navigator.clipboard)return!1;try{await navigator.clipboard.writeText(t),w._showCopySuccess(l)}catch(d){console.error("Modal.code: clipboard write failed:",d)}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 Ke({html:t,height:r}),o=[{text:"Close",class:"btn-secondary",dismiss:!0}],l=new S({title:s,body:n,size:i,scrollable:!1,buttons:o,...a});return w._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 w.form(r);if(!s||!a||!e.model)return a;const n=a[i];if(!n||!n.startsWith("data:"))return a;const o=n.split(","),c=o[0]?.match(/:(.*?);/)?.[1]||"image/png",d=atob(o[1]);let u=d.length;const m=new Uint8Array(u);for(;u--;)m[u]=d.charCodeAt(u);const p=c.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:c}),b=new tt;return await b.upload({file:g,name:`${i}.${p}`,description:e.uploadDescription||`${i} upload`,showToast:!0}),e.model.save({[i]:b.id})}static loading(e){me.show(e)}static hideLoading(e){me.hide(e)}static showBusy(e){return w.loading(e)}static hideBusy(e){return w.hideLoading(e)}}const M=Object.freeze(Object.defineProperty({__proto__:null,default:w},Symbol.toStringTag,{value:"Module"}));class re{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 He,this.rest=Y,this.modal=w,e.api&&this.rest.configure(e.api);const t=(this.name||"mojo").replace(/\s+/g,"_").toLowerCase();this.theme=new qe({storageKey:`${t}:theme`,eventBus:this.events}),this.theme.init(),this.router=new oe({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.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 c=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}c&&c!==o&&await this._exitOldPage(c),await o.onParams(s,t),c!==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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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)}setupRest(){this.rest=Y,Y.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 re(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 ee extends C{constructor(e={}){e.tagName=e.tagName||"main",e.className=e.className||"mojo-page";const t=e.pageName||"";t&&!e.id&&(e.id="page_"+t.toLowerCase().replace(/\s+/g,"_")),super(e),this.pageName=e.pageName||this.constructor.pageName||"",this.route=e.route||this.constructor.route||"",this.title=e.title||this.pageName||"",!this.id&&this.constructor.pageName&&!e.pageName&&(this.id="page_"+this.constructor.pageName.toLowerCase().replace(/\s+/g,"_")),this.pageIcon=e.icon||e.pageIcon||this.constructor.pageIcon||"bi bi-file-text",this.displayName=e.displayName||this.constructor.displayName||this.pageName||"",this.pageDescription=e.pageDescription||this.constructor.pageDescription||"",this.params={},this.query={},this.matched=!1,this.isActive=!1,this.pageOptions={title:e.title||this.pageName||"Untitled Page",description:e.description||"",requiresAuth:e.requiresAuth||!1,...e.pageOptions},this.savedState=null,console.log(`Page ${this.pageName} constructed with route: ${this.route}`)}async onParams(e={},t={}){this.params=e,this.query=t}canEnter(){if(this.options.permissions){const e=this.getApp().activeUser;if(!e||!e.hasPermission(this.options.permissions))return!1}return!(this.options.requiresGroup&&!this.getApp().activeGroup)}async onEnter(){this.isActive=!0,this._wasExited=!1,await this.onInitView(),this.savedState&&(this.restoreState(this.savedState),this.savedState=null),this.pageOptions&&this.pageOptions.title&&typeof document<"u"&&(document.title=this.pageOptions.title),this.emit("activated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} entered`)}async onExit(){this.savedState=this.captureState(),this.isActive=!1,this._wasExited=!0,this._clearScheduledRefreshes(),this.emit("deactivated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} exiting`)}scheduleRefresh(e,t,s={}){if(this._scheduledRefreshes||(this._scheduledRefreshes=[]),typeof e!="function"||!(t>0))return null;const i=async()=>{try{await e()}catch(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=`
218
+ `,size:s.size||"sm",centered:!0,backdrop:"static",buttons:o,...s});return l.on("shown",()=>{const c=l.element.querySelector(`#${i}`);c&&(c.focus(),c.select())}),w._renderAndAwait(l,{buttons:o,onAction:async c=>{if(c!=="ok")return null;const d=l.element.querySelector(`#${i}`);return d?d.value:null}})}static showError(e){return w.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(()=>Pe)).default,c=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}}),d=[{text:n,class:"btn-secondary",action:"cancel"},{text:a,class:"btn-primary",action:"submit"}],u=new S({title:t,body:c,size:i,centered:r,buttons:d,...o});return w._renderAndAwait(u,{buttons:d,onAction:async p=>{if(p==="cancel")return u.hide(),null;if(p!=="submit")return null;if(!c.validate())return c.focusFirstError(),!1;if(e.autoSave&&e.model){u.setLoading(!0);const m=await c.saveModel();return m.success?m:(u.setLoading(!1),await u.render(),u.getApp()?.toast?.error(m.message),!1)}try{return await c.getFormData()}catch(m){return console.error("Modal.form: error collecting form data:",m),c.showError("Error collecting form data"),!1}},cleanup:async()=>{try{await c.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,...c}=e;if(!o)throw new Error("Modal.modelForm requires a model");const d=(await Promise.resolve().then(()=>Pe)).default,u=new d({fileHandling:e.fileHandling||"base64",model:o,data:e.data,defaults:e.defaults,formConfig:{fields:l||s.fields||[],...s,submitButton:!1,resetButton:!1}}),p=[{text:n,class:"btn-secondary",action:"cancel"},{text:a,class:"btn-primary",action:"submit"}],m=new S({title:t,body:u,size:i,centered:r,buttons:p,...c});return w._renderAndAwait(m,{buttons:p,onAction:async f=>{if(f==="cancel")return m.hide(),null;if(f!=="submit")return null;m.setLoading(!0,"Saving...");try{const g=await u.handleSubmit();if(g.success)return g;m.setLoading(!1);let b=g.error;return g.data?.error&&(b=g.data.error),m.getApp()?.toast?.error(b),!1}catch(g){return console.error("Modal.modelForm: error saving:",g),await m.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:c="lg",centered:d=!0,closeText:u="Close",...p}=e,m=(await Promise.resolve().then(()=>bt)).default,f=new m({data:s,model:i,fields:r,columns:a,responsive:n,showEmptyValues:o,emptyValueText:l}),g=[{text:u,class:"btn-secondary",value:"close"}],b=new S({title:t,body:f,size:c,centered:d,buttons:g,...p});return f.on("field:click",y=>b.emit("dataview:field:click",y)),f.on("error",y=>b.emit("dataview:error",y)),w._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 X({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 S({title:i,body:n,size:r,scrollable:!0,buttons:o,...a});return w._renderAndAwait(l,{buttons:o,onAction:async c=>{if(c!=="copy")return null;if(!navigator.clipboard)return!1;try{await navigator.clipboard.writeText(t),w._showCopySuccess(l)}catch(d){console.error("Modal.code: clipboard write failed:",d)}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 Ke({html:t,height:r}),o=[{text:"Close",class:"btn-secondary",dismiss:!0}],l=new S({title:s,body:n,size:i,scrollable:!1,buttons:o,...a});return w._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 w.form(r);if(!s||!a||!e.model)return a;const n=a[i];if(!n||!n.startsWith("data:"))return a;const o=n.split(","),c=o[0]?.match(/:(.*?);/)?.[1]||"image/png",d=atob(o[1]);let u=d.length;const p=new Uint8Array(u);for(;u--;)p[u]=d.charCodeAt(u);const m=c.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([p],`${i}.${m}`,{type:c}),b=new tt;return await b.upload({file:g,name:`${i}.${m}`,description:e.uploadDescription||`${i} upload`,showToast:!0}),e.model.save({[i]:b.id})}static loading(e){pe.show(e)}static hideLoading(e){pe.hide(e)}static showBusy(e){return w.loading(e)}static hideBusy(e){return w.hideLoading(e)}}const M=Object.freeze(Object.defineProperty({__proto__:null,default:w},Symbol.toStringTag,{value:"Module"}));class re{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 He,this.rest=Y,this.modal=w,e.api&&this.rest.configure(e.api);const t=(this.name||"mojo").replace(/\s+/g,"_").toLowerCase();this.theme=new qe({storageKey:`${t}:theme`,eventBus:this.events}),this.theme.init(),this.router=new oe({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.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 c=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}c&&c!==o&&await this._exitOldPage(c),await o.onParams(s,t),c!==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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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(()=>M)).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)}setupRest(){this.rest=Y,Y.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 re(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 ee extends C{constructor(e={}){e.tagName=e.tagName||"main",e.className=e.className||"mojo-page";const t=e.pageName||"";t&&!e.id&&(e.id="page_"+t.toLowerCase().replace(/\s+/g,"_")),super(e),this.pageName=e.pageName||this.constructor.pageName||"",this.route=e.route||this.constructor.route||"",this.title=e.title||this.pageName||"",!this.id&&this.constructor.pageName&&!e.pageName&&(this.id="page_"+this.constructor.pageName.toLowerCase().replace(/\s+/g,"_")),this.pageIcon=e.icon||e.pageIcon||this.constructor.pageIcon||"bi bi-file-text",this.displayName=e.displayName||this.constructor.displayName||this.pageName||"",this.pageDescription=e.pageDescription||this.constructor.pageDescription||"",this.params={},this.query={},this.matched=!1,this.isActive=!1,this.pageOptions={title:e.title||this.pageName||"Untitled Page",description:e.description||"",requiresAuth:e.requiresAuth||!1,...e.pageOptions},this.savedState=null,console.log(`Page ${this.pageName} constructed with route: ${this.route}`)}async onParams(e={},t={}){this.params=e,this.query=t}canEnter(){if(this.options.permissions){const e=this.getApp().activeUser;if(!e||!e.hasPermission(this.options.permissions))return!1}return!(this.options.requiresGroup&&!this.getApp().activeGroup)}async onEnter(){this.isActive=!0,this._wasExited=!1,await this.onInitView(),this.savedState&&(this.restoreState(this.savedState),this.savedState=null),this.pageOptions&&this.pageOptions.title&&typeof document<"u"&&(document.title=this.pageOptions.title),this.emit("activated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} entered`)}async onExit(){this.savedState=this.captureState(),this.isActive=!1,this._wasExited=!0,this._clearScheduledRefreshes(),this.emit("deactivated",{page:this.getMetadata()}),console.log(`Page ${this.pageName} exiting`)}scheduleRefresh(e,t,s={}){if(this._scheduledRefreshes||(this._scheduledRefreshes=[]),typeof e!="function"||!(t>0))return null;const i=async()=>{try{await e()}catch(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=`
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=`
@@ -569,7 +569,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
569
569
  </div>
570
570
  </div>
571
571
  </div>
572
- `}buildFieldHTML(e){const{type:t,columns:s,class:i=""}=e;let r="";const a=j&&typeof j.getRenderer=="function"?j.getRenderer(t):null;if(typeof a=="function")try{const c=a(this,e);c!=null&&(r=String(c))}catch(c){console.error("FormPlugins custom renderer error:",c)}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"daterange":r=this.renderDateRangeField(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;this.isAutoSizingField(e)?n=`col ${i}`.trim():n=`col-${s} ${i}`.trim();let o="",l="";if(e.showWhen){const c=e.showWhen,d=Array.isArray(c.value)?c.value:[c.value];o=` data-show-when-field="${c.field}" data-show-when-value="${d.join(",")}"`,c.negate&&(o+=' data-show-when-negate="true"');let u=this.data[c.field];if(u==null){const g=this._findField(c.field,this.fields);g&&(u=g.value)}const m=String(u??""),p=d.map(String).includes(m);(c.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,c]=o.split("=");return n[l]=c.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,c,d;switch(t){case"color":n=s?"^#?[0-9A-Fa-f]{6}$":"^[0-9A-Fa-f]{6}$",o=6,l=s?7:6,c=s?"#FF0000":"FF0000",d=d||"Enter a valid hex color (e.g., "+c+")";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,c=s?"#F00 or #FF0000":"F00 or FF0000",d=d||"Enter a valid hex color (3 or 6 digits)";break;case"string":n="^[0-9A-Fa-f]+$",o=i||1,l=r||64,c="ABCDEF123456",d=d||"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,c=s?"#ABCDEF or ABCDEF":"ABCDEF",d=d||"Enter hexadecimal characters only"}const u={...a,pattern:n,minLength:o,maxLength:l,placeholder:a.placeholder||c,help:a.help||d,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:c="",attributes:d={},help:u=e.helpText||e.help||""}=e,m=`${this.options.inputClass} ${c}`.trim(),p=this.errors[s],f=this.getFieldValue(s)??r,g=Object.entries(d).map(([x,F])=>`${x}="${this.escapeHtml(F)}"`).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 x={...y,showToggle:!!e.showToggle,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return E.render(this.templates.password,x)}if(t==="password"){const x={...y,showToggle:e.showToggle!==!1,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return E.render(this.templates.password,x)}return E.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:c,class:d="",attributes:u={},help:m=e.helpText||e.help||""}=e,p=`${this.options.inputClass} ${d}`.trim(),f=this.errors[t],g=this.getFieldValue(t)??i,b=Object.entries(u).map(([F,D])=>`${F}="${this.escapeHtml(D)}"`).join(" "),y=this.getFieldId(t),x={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 E.render(this.templates.textarea,x)}renderHtmlPreviewField(e){const{name:t,label:s,value:i="",placeholder:r="",required:a=!1,disabled:n=!1,readonly:o=!1,rows:l=5,class:c="",attributes:d={},help:u=e.helpText||e.help||""}=e,m=`${this.options.inputClass} ${c}`.trim(),p=this.errors[t],f=this.getFieldValue(t)??i,g=Object.entries(d).map(([x,F])=>`${x}="${this.escapeHtml(F)}"`).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 E.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:c={},help:d=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({...c,"data-field-type":"json"}).map(([x,F])=>`${x}="${this.escapeHtml(F)}"`).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:d?this.escapeHtml(d):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 E.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:c="",attributes:d={},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,x=`form-select ${c}`.trim(),F=this.errors[t],V=this.getFieldValue(t)??r,H=Object.entries(d).map(([T,O])=>`${T}="${this.escapeHtml(O)}"`).join(" "),P=this.getFieldId(t);let N=[...i];if(m!==void 0&&p!==void 0){const T=f!==void 0?f:1,O=this.generateSelectOptions(m,p,T,{format:g,prefix:b,suffix:y});N=[...N,...O]}let ne="";Array.isArray(N)&&(ne=N.map(T=>{if(typeof T=="string"){const O=T===V?"selected":"";return`<option value="${this.escapeHtml(T)}" ${O}>${this.escapeHtml(T)}</option>`}else if(T&&typeof T=="object"){const O=T.value==V?"selected":"";return`<option value="${this.escapeHtml(T.value)}" ${O}>${this.escapeHtml(T.label||T.text||T.value)}</option>`}return""}).join(""));const Ae=l?`
572
+ `}buildFieldHTML(e){const{type:t,columns:s,class:i=""}=e;let r="";const a=j&&typeof j.getRenderer=="function"?j.getRenderer(t):null;if(typeof a=="function")try{const c=a(this,e);c!=null&&(r=String(c))}catch(c){console.error("FormPlugins custom renderer error:",c)}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"daterange":r=this.renderDateRangeField(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;this.isAutoSizingField(e)?n=`col ${i}`.trim():n=`col-${s} ${i}`.trim();let o="",l="";if(e.showWhen){const c=e.showWhen,d=Array.isArray(c.value)?c.value:[c.value];o=` data-show-when-field="${c.field}" data-show-when-value="${d.join(",")}"`,c.negate&&(o+=' data-show-when-negate="true"');let u=this.data[c.field];if(u==null){const g=this._findField(c.field,this.fields);g&&(u=g.value)}const p=String(u??""),m=d.map(String).includes(p);(c.negate?!m:m)||(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,c]=o.split("=");return n[l]=c.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,c,d;switch(t){case"color":n=s?"^#?[0-9A-Fa-f]{6}$":"^[0-9A-Fa-f]{6}$",o=6,l=s?7:6,c=s?"#FF0000":"FF0000",d=d||"Enter a valid hex color (e.g., "+c+")";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,c=s?"#F00 or #FF0000":"F00 or FF0000",d=d||"Enter a valid hex color (3 or 6 digits)";break;case"string":n="^[0-9A-Fa-f]+$",o=i||1,l=r||64,c="ABCDEF123456",d=d||"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,c=s?"#ABCDEF or ABCDEF":"ABCDEF",d=d||"Enter hexadecimal characters only"}const u={...a,pattern:n,minLength:o,maxLength:l,placeholder:a.placeholder||c,help:a.help||d,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:c="",attributes:d={},help:u=e.helpText||e.help||""}=e,p=`${this.options.inputClass} ${c}`.trim(),m=this.errors[s],f=this.getFieldValue(s)??r,g=Object.entries(d).map(([x,F])=>`${x}="${this.escapeHtml(F)}"`).join(" "),b=this.getFieldId(s),y={labelClass:this.options.labelClass,inputClass:p,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:m?this.escapeHtml(m):null,required:n,disabled:o,readonly:l,attrs:g,showCopy:!!e.showCopy};if(t==="password"&&(e.showToggle||e.strengthMeter||e.capsLockWarning)){const x={...y,showToggle:!!e.showToggle,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return E.render(this.templates.password,x)}if(t==="password"){const x={...y,showToggle:e.showToggle!==!1,strengthMeter:!!e.strengthMeter,capsLockWarning:!!e.capsLockWarning};return E.render(this.templates.password,x)}return E.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:c,class:d="",attributes:u={},help:p=e.helpText||e.help||""}=e,m=`${this.options.inputClass} ${d}`.trim(),f=this.errors[t],g=this.getFieldValue(t)??i,b=Object.entries(u).map(([F,D])=>`${F}="${this.escapeHtml(D)}"`).join(" "),y=this.getFieldId(t),x={labelClass:this.options.labelClass,inputClass:m,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:p?this.escapeHtml(p):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 E.render(this.templates.textarea,x)}renderHtmlPreviewField(e){const{name:t,label:s,value:i="",placeholder:r="",required:a=!1,disabled:n=!1,readonly:o=!1,rows:l=5,class:c="",attributes:d={},help:u=e.helpText||e.help||""}=e,p=`${this.options.inputClass} ${c}`.trim(),m=this.errors[t],f=this.getFieldValue(t)??i,g=Object.entries(d).map(([x,F])=>`${x}="${this.escapeHtml(F)}"`).join(" "),b=this.getFieldId(t),y={labelClass:this.options.labelClass,inputClass:p,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:m?this.escapeHtml(m):null,rows:l||5,required:a,disabled:n,readonly:o,attrs:g,showCopy:!!e.showCopy};return E.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:c={},help:d=e.helpText||e.help||""}=e,u=this.getFieldValue(e.name)??e.value??{};let p=u;if(typeof u=="object"&&u!==null)try{p=JSON.stringify(u,null,2)}catch{p="{}"}else typeof u!="string"&&(p=String(u));const m=`${this.options.inputClass} ${l}`.trim(),f=this.errors[t],g=this.getFieldId(t),b=Object.entries({...c,"data-field-type":"json"}).map(([x,F])=>`${x}="${this.escapeHtml(F)}"`).join(" "),y={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:t,fieldValue:p,label:s?this.escapeHtml(s):null,placeholder:i?this.escapeHtml(i):null,help:d?this.escapeHtml(d):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 E.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:c="",attributes:d={},help:u=e.helpText||e.help||"",start:p=e.start,end:m=e.end,step:f=e.step,format:g=e.format,prefix:b=e.prefix,suffix:y=e.suffix}=e,x=`form-select ${c}`.trim(),F=this.errors[t],V=this.getFieldValue(t)??r,H=Object.entries(d).map(([T,O])=>`${T}="${this.escapeHtml(O)}"`).join(" "),P=this.getFieldId(t);let N=[...i];if(p!==void 0&&m!==void 0){const T=f!==void 0?f:1,O=this.generateSelectOptions(p,m,T,{format:g,prefix:b,suffix:y});N=[...N,...O]}let ne="";Array.isArray(N)&&(ne=N.map(T=>{if(typeof T=="string"){const O=T===V?"selected":"";return`<option value="${this.escapeHtml(T)}" ${O}>${this.escapeHtml(T)}</option>`}else if(T&&typeof T=="object"){const O=T.value==V?"selected":"";return`<option value="${this.escapeHtml(T.value)}" ${O}>${this.escapeHtml(T.label||T.text||T.value)}</option>`}return""}).join(""));const Ae=l?`
573
573
  <input type="text"
574
574
  class="form-control form-control-sm mb-2"
575
575
  placeholder="Search options..."
@@ -586,11 +586,11 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
586
586
  multiple
587
587
  ${n?"disabled":""}
588
588
  ${a?"required":""}>
589
- ${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("")}
589
+ ${i.map(p=>{const m=typeof p=="string"?p:p.value,f=typeof p=="string"?p:p.label||p.value,g=Array.isArray(u)&&u.includes(m)?"selected":"";return`<option value="${this.escapeHtml(m)}" ${g}>${this.escapeHtml(f)}</option>`}).join("")}
590
590
  </select>
591
591
  <small class="form-text text-muted">This will be enhanced with MultiSelectDropdown component</small>
592
592
  </div>
593
- `}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,c=this.errors[t],d=this.getFieldValue(t)??i,u=d===!0||d==="true"||d==="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:c?this.escapeHtml(c):null,value:this.escapeHtml(i),fieldClass:n,checked:u,required:r,disabled:a,attrs:m};return E.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:c=e.helpText||e.help||""}=e,d=this.errors[t],u=this.getFieldValue(t)??i,m=u===!0||u==="true"||u==="1",p=Object.entries(l).map(([y,x])=>`${y}="${this.escapeHtml(x)}"`).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:c?this.escapeHtml(c):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:d?this.escapeHtml(d):null,value:this.escapeHtml(i),sizeClass:g,fieldClass:o,checked:m,required:r,disabled:a,attrs:p};return E.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:c=e.helpText||e.help||""}=e,d=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,x=typeof f=="string"?f:f.label||f.text||f.value,F=y===u?"checked":"";return`
593
+ `}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,c=this.errors[t],d=this.getFieldValue(t)??i,u=d===!0||d==="true"||d==="1",p=Object.entries(o).map(([g,b])=>`${g}="${this.escapeHtml(b)}"`).join(" "),m=this.getFieldId(t),f={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:m,name:t,label:this.escapeHtml(s),help:l?this.escapeHtml(l):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:c?this.escapeHtml(c):null,value:this.escapeHtml(i),fieldClass:n,checked:u,required:r,disabled:a,attrs:p};return E.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:c=e.helpText||e.help||""}=e,d=this.errors[t],u=this.getFieldValue(t)??i,p=u===!0||u==="true"||u==="1",m=Object.entries(l).map(([y,x])=>`${y}="${this.escapeHtml(x)}"`).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:c?this.escapeHtml(c):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:d?this.escapeHtml(d):null,value:this.escapeHtml(i),sizeClass:g,fieldClass:o,checked:p,required:r,disabled:a,attrs:m};return E.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:c=e.helpText||e.help||""}=e,d=this.errors[t],u=this.getFieldValue(t)??r,p=Object.entries(l).map(([f,g])=>`${f}="${this.escapeHtml(g)}"`).join(" ");let m="";return Array.isArray(i)&&(m=i.map((f,g)=>{const b=`${t}_${g}`,y=typeof f=="string"?f:f.value,x=typeof f=="string"?f:f.label||f.text||f.value,F=y===u?"checked":"";return`
594
594
  <div class="form-check ${n?"form-check-inline":""}">
595
595
  <input
596
596
  type="radio"
@@ -601,7 +601,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
601
601
  ${F}
602
602
  ${a?"disabled":""}
603
603
 
604
- ${m}
604
+ ${p}
605
605
  >
606
606
  <label class="form-check-label" for="${b}">
607
607
  ${this.escapeHtml(x)}
@@ -612,13 +612,13 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
612
612
  ${s?`<fieldset>
613
613
  <legend class="${this.options.labelClass}">${this.escapeHtml(s)}${this.renderTooltipIcon(e)}</legend>
614
614
  <div class="${o}">
615
- ${p}
615
+ ${m}
616
616
  </div>
617
- </fieldset>`:`<div class="${o}">${p}</div>`}
617
+ </fieldset>`:`<div class="${o}">${m}</div>`}
618
618
  ${c?`<div class="${this.options.helpClass}">${this.escapeHtml(c)}</div>`:""}
619
619
  ${d?`<div class="${this.options.errorClass}">${this.escapeHtml(d)}</div>`:""}
620
620
  </div>
621
- `}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:c=e.helpText||e.help||""}=e,d=`${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:d,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:p,name:t,label:s?this.escapeHtml(s):null,help:c?this.escapeHtml(c):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 E.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:c="md",allowDrop:d=!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"}},x=y[c]||y.md,F=Object.entries(o).map(([P,N])=>`${P}="${this.escapeHtml(N)}"`).join(" "),D=this.getFieldValue(t),V=this.extractImageUrl(D,c),H={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:x.containerClass,width:x.width,height:x.height,accept:a,imageUrl:V,placeholderText:r?"No image":this.escapeHtml(u),cursor:r?"default":"pointer",allowDrop:d,showRemove:!r,required:i,disabled:r,attrs:F};return E.render(this.templates.image,H)}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:c={},help:d=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),m=this.errors[t],p=this.getFieldValue(t)??i,f=Object.entries(c).map(([y,x])=>`${y}="${this.escapeHtml(x)}"`).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:d?this.escapeHtml(d):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:m?this.escapeHtml(m):null,required:a,disabled:n,readonly:o,attrs:f};return E.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:c={},help:d=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),m=this.errors[t],p=this.getFieldValue(t)??n,f=Object.entries(c).map(([y,x])=>`${y}="${this.escapeHtml(x)}"`).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:d?this.escapeHtml(d):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 E.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 c=Object.entries(o).map(([d,u])=>`${d}="${this.escapeHtml(u)}"`).join(" ");return`
621
+ `}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:c=e.helpText||e.help||""}=e,d=`${this.options.inputClass} ${o}`.trim(),u=this.errors[t],p=Object.entries(l).map(([g,b])=>`${g}="${this.escapeHtml(b)}"`).join(" "),m=this.getFieldId(t),f={labelClass:this.options.labelClass,inputClass:d,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:m,name:t,label:s?this.escapeHtml(s):null,help:c?this.escapeHtml(c):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:u?this.escapeHtml(u):null,accept:n,required:i,disabled:r,multiple:a,attrs:p};return E.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:c="md",allowDrop:d=!0,placeholder:u="Drop image here or click to upload"}=e,p=`${this.options.inputClass} ${n}`.trim(),m=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"}},x=y[c]||y.md,F=Object.entries(o).map(([P,N])=>`${P}="${this.escapeHtml(N)}"`).join(" "),D=this.getFieldValue(t),V=this.extractImageUrl(D,c),H={labelClass:this.options.labelClass,inputClass:p,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:m?this.escapeHtml(m):null,dropZoneId:g,previewId:b,containerClass:x.containerClass,width:x.width,height:x.height,accept:a,imageUrl:V,placeholderText:r?"No image":this.escapeHtml(u),cursor:r?"default":"pointer",allowDrop:d,showRemove:!r,required:i,disabled:r,attrs:F};return E.render(this.templates.image,H)}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:c={},help:d=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),p=this.errors[t],m=this.getFieldValue(t)??i,f=Object.entries(c).map(([y,x])=>`${y}="${this.escapeHtml(x)}"`).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(m),label:s?this.escapeHtml(s):null,placeholder:r?this.escapeHtml(r):null,help:d?this.escapeHtml(d):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:p?this.escapeHtml(p):null,required:a,disabled:n,readonly:o,attrs:f};return E.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:c={},help:d=e.helpText||e.help||""}=e,u=`${this.options.inputClass} ${l}`.trim(),p=this.errors[t],m=this.getFieldValue(t)??n,f=Object.entries(c).map(([y,x])=>`${y}="${this.escapeHtml(x)}"`).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:d?this.escapeHtml(d):null,tooltip:e.tooltip?this.escapeHtml(e.tooltip):null,error:p?this.escapeHtml(p):null,min:i,max:r,step:a,fieldValue:m,disabled:o,attrs:f};return E.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 c=Object.entries(o).map(([d,u])=>`${d}="${this.escapeHtml(u)}"`).join(" ");return`
622
622
  <button
623
623
  type="button"
624
624
  ${t?`name="${t}"`:""}
@@ -642,17 +642,17 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
642
642
  <div class="form-actions mt-3">
643
643
  ${e}
644
644
  </div>
645
- `:""}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:c=!1,separator:d=",",help:u=e.helpText||e.help||""}=e,m=this.getFieldId(t),p=this.errors[t],f=this.getFieldValue(t)??i;return`
645
+ `:""}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:c=!1,separator:d=",",help:u=e.helpText||e.help||""}=e,p=this.getFieldId(t),m=this.errors[t],f=this.getFieldValue(t)??i;return`
646
646
  <div class="mojo-form-control">
647
- ${s?`<label for="${m}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
647
+ ${s?`<label for="${p}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
648
648
  <div class="tag-input-placeholder"
649
649
  data-field-name="${t}"
650
650
  data-field-type="tag"
651
651
  data-field-config='${JSON.stringify({name:t,value:f,placeholder:r,maxTags:l,allowDuplicates:c,separator:d,disabled:n,readonly:o,required:a})}'>
652
652
  <input type="text"
653
- id="${m}"
653
+ id="${p}"
654
654
  name="${t}_display"
655
- class="${this.options.inputClass}${p?" is-invalid":""}"
655
+ class="${this.options.inputClass}${m?" is-invalid":""}"
656
656
  placeholder="${this.escapeHtml(r)}"
657
657
  ${n?"disabled":""}
658
658
  ${o?"readonly":""}
@@ -661,15 +661,15 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
661
661
  <small class="form-text text-muted">This will be enhanced with TagInput component</small>
662
662
  </div>
663
663
  ${u?`<div class="${this.options.helpClass}">${this.escapeHtml(u)}</div>`:""}
664
- ${p?`<div class="${this.options.errorClass}">${this.escapeHtml(p)}</div>`:""}
664
+ ${m?`<div class="${this.options.errorClass}">${this.escapeHtml(m)}</div>`:""}
665
665
  </div>
666
- `}renderCollectionField(e){const{name:t,label:s,value:i="",placeholder:r="Search...",required:a=!1,disabled:n=!1,readonly:o=!1,Collection:l,labelField:c="name",valueField:d="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],x=this.getFieldValue(t)??i;return`
666
+ `}renderCollectionField(e){const{name:t,label:s,value:i="",placeholder:r="Search...",required:a=!1,disabled:n=!1,readonly:o=!1,Collection:l,labelField:c="name",valueField:d="id",maxItems:u=10,emptyFetch:p=!1,debounceMs:m=300,requiresActiveGroup:f=!1,help:g=e.helpText||e.help||""}=e,b=this.getFieldId(t),y=this.errors[t],x=this.getFieldValue(t)??i;return`
667
667
  <div class="mojo-form-control">
668
668
  ${s?`<label for="${b}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
669
669
  <div class="collection-select-placeholder"
670
670
  data-field-name="${t}"
671
671
  data-field-type="collection"
672
- data-field-config='${JSON.stringify({name:t,value:x,placeholder:r,labelField:c,valueField:d,maxItems:u,emptyFetch:m,debounceMs:p,disabled:n,readonly:o,required:a,requiresActiveGroup:f})}'>
672
+ data-field-config='${JSON.stringify({name:t,value:x,placeholder:r,labelField:c,valueField:d,maxItems:u,emptyFetch:p,debounceMs:m,disabled:n,readonly:o,required:a,requiresActiveGroup:f})}'>
673
673
  <input type="text"
674
674
  id="${b}"
675
675
  name="${t}_display"
@@ -684,28 +684,28 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
684
684
  ${g?`<div class="${this.options.helpClass}">${this.escapeHtml(g)}</div>`:""}
685
685
  ${y?`<div class="${this.options.errorClass}">${this.escapeHtml(y)}</div>`:""}
686
686
  </div>
687
- `}renderCollectionMultiSelectField(e){const{name:t,label:s,value:i=[],required:r=!1,disabled:a=!1,Collection:n,collectionParams:o={},labelField:l="name",valueField:c="id",excludeIds:d=[],ignoreIds:u=[],size:m=8,maxHeight:p=null,showSelectAll:f=!0,enableSearch:g=!1,searchPlaceholder:b="Search...",searchDebounce:y=400,requiresActiveGroup:x=!1,help:F=e.helpText||e.help||""}=e;this.getFieldId(t);const D=this.errors[t],V=this.getFieldValue(t)??i;return`
687
+ `}renderCollectionMultiSelectField(e){const{name:t,label:s,value:i=[],required:r=!1,disabled:a=!1,Collection:n,collectionParams:o={},labelField:l="name",valueField:c="id",excludeIds:d=[],ignoreIds:u=[],size:p=8,maxHeight:m=null,showSelectAll:f=!0,enableSearch:g=!1,searchPlaceholder:b="Search...",searchDebounce:y=400,requiresActiveGroup:x=!1,help:F=e.helpText||e.help||""}=e;this.getFieldId(t);const D=this.errors[t],V=this.getFieldValue(t)??i;return`
688
688
  <div class="mojo-form-control">
689
689
  ${s?`<label class="${this.options.labelClass}">${this.escapeHtml(s)}${r?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
690
690
  <div class="collection-multiselect-placeholder"
691
691
  data-field-name="${t}"
692
692
  data-field-type="collectionmultiselect"
693
- data-field-config='${JSON.stringify({name:t,value:V,labelField:l,valueField:c,excludeIds:d,ignoreIds:u,size:m,maxHeight:p,showSelectAll:f,enableSearch:g,searchPlaceholder:b,searchDebounce:y,disabled:a,required:r,requiresActiveGroup:x})}'>
693
+ data-field-config='${JSON.stringify({name:t,value:V,labelField:l,valueField:c,excludeIds:d,ignoreIds:u,size:p,maxHeight:m,showSelectAll:f,enableSearch:g,searchPlaceholder:b,searchDebounce:y,disabled:a,required:r,requiresActiveGroup:x})}'>
694
694
  <input type="hidden" name="${t}" value="${this.escapeHtml(JSON.stringify(V))}">
695
695
  <small class="form-text text-muted">This will be enhanced with CollectionMultiSelect component</small>
696
696
  </div>
697
697
  ${F?`<div class="${this.options.helpClass}">${this.escapeHtml(F)}</div>`:""}
698
698
  ${D?`<div class="${this.options.errorClass}">${this.escapeHtml(D)}</div>`:""}
699
699
  </div>
700
- `}renderDatePickerField(e){const{name:t,label:s,value:i="",placeholder:r="Select date...",required:a=!1,disabled:n=!1,readonly:o=!1,min:l=null,max:c=null,format:d="YYYY-MM-DD",displayFormat:u="MMM DD, YYYY",help:m=e.helpText||e.help||""}=e,p=this.getFieldId(t),f=this.errors[t],g=this.getFieldValue(t)??i;return`
700
+ `}renderDatePickerField(e){const{name:t,label:s,value:i="",placeholder:r="Select date...",required:a=!1,disabled:n=!1,readonly:o=!1,min:l=null,max:c=null,format:d="YYYY-MM-DD",displayFormat:u="MMM DD, YYYY",help:p=e.helpText||e.help||""}=e,m=this.getFieldId(t),f=this.errors[t],g=this.getFieldValue(t)??i;return`
701
701
  <div class="mojo-form-control">
702
- ${s?`<label for="${p}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
702
+ ${s?`<label for="${m}" class="${this.options.labelClass}">${this.escapeHtml(s)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
703
703
  <div class="date-picker-placeholder"
704
704
  data-field-name="${t}"
705
705
  data-field-type="datepicker"
706
706
  data-field-config='${JSON.stringify({name:t,value:g,placeholder:r,min:l,max:c,format:d,displayFormat:u,disabled:n,readonly:o,required:a})}'>
707
707
  <input type="date"
708
- id="${p}"
708
+ id="${m}"
709
709
  name="${t}"
710
710
  class="${this.options.inputClass}${f?" is-invalid":""}"
711
711
  value="${this.escapeHtml(g)}"
@@ -718,16 +718,16 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
718
718
 
719
719
  <small class="form-text text-muted">This will be enhanced with Easepick DatePicker</small>
720
720
  </div>
721
- ${m?`<div class="${this.options.helpClass}">${this.escapeHtml(m)}</div>`:""}
721
+ ${p?`<div class="${this.options.helpClass}">${this.escapeHtml(p)}</div>`:""}
722
722
  ${f?`<div class="${this.options.errorClass}">${this.escapeHtml(f)}</div>`:""}
723
723
  </div>
724
- `}renderDateRangeField(e){const{name:t,startName:s,endName:i,fieldName:r,label:a,startDate:n="",endDate:o="",placeholder:l="Select date range...",required:c=!1,disabled:d=!1,readonly:u=!1,min:m=null,max:p=null,format:f="YYYY-MM-DD",displayFormat:g="MMM DD, YYYY",outputFormat:b="date",separator:y=" - ",help:x=e.helpText||e.help||""}=e,F=this.getFieldId(t||s||"daterange"),D=this.errors[t],V=s||(t?t+"_start":""),H=i||(t?t+"_end":""),P=this.getFieldValue(V)||n,N=this.getFieldValue(H)||o;return`
724
+ `}renderDateRangeField(e){const{name:t,startName:s,endName:i,fieldName:r,label:a,startDate:n="",endDate:o="",placeholder:l="Select date range...",required:c=!1,disabled:d=!1,readonly:u=!1,min:p=null,max:m=null,format:f="YYYY-MM-DD",displayFormat:g="MMM DD, YYYY",outputFormat:b="date",separator:y=" - ",help:x=e.helpText||e.help||""}=e,F=this.getFieldId(t||s||"daterange"),D=this.errors[t],V=s||(t?t+"_start":""),H=i||(t?t+"_end":""),P=this.getFieldValue(V)||n,N=this.getFieldValue(H)||o;return`
725
725
  <div class="mojo-form-control">
726
726
  ${a?`<label for="${F}" class="${this.options.labelClass}">${this.escapeHtml(a)}${c?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}
727
727
  <div class="date-range-picker-placeholder"
728
728
  data-field-name="${t||s||"daterange"}"
729
729
  data-field-type="daterange"
730
- data-field-config='${JSON.stringify({name:t,startName:s,endName:i,fieldName:r,startDate:P,endDate:N,placeholder:l,min:m,max:p,format:f,displayFormat:g,outputFormat:b,separator:y,disabled:d,readonly:u,required:c})}'>
730
+ data-field-config='${JSON.stringify({name:t,startName:s,endName:i,fieldName:r,startDate:P,endDate:N,placeholder:l,min:p,max:m,format:f,displayFormat:g,outputFormat:b,separator:y,disabled:d,readonly:u,required:c})}'>
731
731
  <div class="row g-2">
732
732
  <div class="col">
733
733
  <input type="date"
@@ -736,8 +736,8 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
736
736
  class="${this.options.inputClass}${D?" is-invalid":""}"
737
737
  value="${this.escapeHtml(P)}"
738
738
  placeholder="Start date..."
739
- ${m?`min="${m}"`:""}
740
- ${p?`max="${p}"`:""}
739
+ ${p?`min="${p}"`:""}
740
+ ${m?`max="${m}"`:""}
741
741
  ${d?"disabled":""}
742
742
  ${u?"readonly":""}
743
743
  ${c?"required":""}
@@ -753,8 +753,8 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
753
753
  class="${this.options.inputClass}${D?" is-invalid":""}"
754
754
  value="${this.escapeHtml(N)}"
755
755
  placeholder="End date..."
756
- ${m?`min="${m}"`:""}
757
- ${p?`max="${p}"`:""}
756
+ ${p?`min="${p}"`:""}
757
+ ${m?`max="${m}"`:""}
758
758
  ${d?"disabled":""}
759
759
  ${u?"readonly":""}
760
760
  ${c?"required":""}
@@ -797,14 +797,14 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
797
797
  ${this.escapeHtml(l.label||`Tab ${c+1}`)}
798
798
  </button>
799
799
  </li>
800
- `}).join(""),o=t.map((l,c)=>{const d=`${a}-pane-${c}`,u=c===0,m=(l.fields||[]).map(p=>p.type==="group"?this.buildGroupHTML(p):this.buildFieldHTML(p)).join("");return`
800
+ `}).join(""),o=t.map((l,c)=>{const d=`${a}-pane-${c}`,u=c===0,p=(l.fields||[]).map(m=>m.type==="group"?this.buildGroupHTML(m):this.buildFieldHTML(m)).join("");return`
801
801
  <div class="tab-pane fade ${u?"show active":""}"
802
802
  id="${d}"
803
803
  role="tabpanel"
804
804
  aria-labelledby="${d}-tab"
805
805
  data-tab-index="${c}">
806
806
  <div class="row">
807
- ${m}
807
+ ${p}
808
808
  </div>
809
809
  </div>
810
810
  `}).join("");return`
@@ -816,7 +816,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
816
816
  ${o}
817
817
  </div>
818
818
  </div>
819
- `}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 c=e;e<=t?c<=t:c>=t;c+=l){let d=String(c);if(typeof r=="function")d=r(c);else if(r==="padded"||r==="pad"){const u=String(Math.max(Math.abs(e),Math.abs(t))).length;d=String(c).padStart(u,"0")}else r==="ordinal"&&(d=this.formatOrdinal(c));d=`${a}${d}${n}`,o.push({value:c,label:d})}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 st={enableFileDrop(h={}){if(this._fileDropConfig={acceptedTypes:h.acceptedTypes||["*/*"],maxFileSize:h.maxFileSize||10*1024*1024,dropZoneSelector:h.dropZoneSelector||null,visualFeedback:h.visualFeedback!==!1,multiple:h.multiple||!1,validateOnDrop:h.validateOnDrop!==!1,dragOverClass:h.dragOverClass||"drag-over",dragActiveClass:h.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 h=this._getFileDropZone();if(!h){console.warn("FileDropMixin: Drop zone not found");return}this._fileDropZone=h,h.addEventListener("dragenter",this._boundFileDropHandlers.dragEnter),h.addEventListener("dragover",this._boundFileDropHandlers.dragOver),h.addEventListener("dragleave",this._boundFileDropHandlers.dragLeave),h.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(h=>{document.removeEventListener(h,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(h){h.preventDefault(),h.stopPropagation()},_onFileDropDragEnter(h){this._onFileDropPreventDefault(h),this._fileDropState.dragCounter++,this._fileDropState.isDragActive||(this._fileDropState.isDragActive=!0,this._applyFileDropVisualFeedback(!0))},_onFileDropDragOver(h){this._onFileDropPreventDefault(h),h.dataTransfer.dropEffect="copy"},_onFileDropDragLeave(h){this._onFileDropPreventDefault(h),this._fileDropState.dragCounter--,this._fileDropState.dragCounter<=0&&(this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1))},async _onFileDropDrop(h){this._onFileDropPreventDefault(h),this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1);const e=Array.from(h.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(", ")),h,t);return}if(typeof this.onFileDrop=="function")try{await this.onFileDrop(t,h,s)}catch(i){typeof this.onFileDropError=="function"?await this.onFileDropError(i,h,t):console.error("FileDropMixin: Error in onFileDrop callback:",i)}else console.warn("FileDropMixin: No onFileDrop method found on view")},_applyFileDropVisualFeedback(h){if(!this._fileDropConfig.visualFeedback||!this._fileDropZone)return;const{dragOverClass:e,dragActiveClass:t}=this._fileDropConfig;h?this._fileDropZone.classList.add(e,t):this._fileDropZone.classList.remove(e,t)},_validateFileDropFiles(h){const e=[],t=this._fileDropConfig;for(const s of h){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(h){const{acceptedTypes:e}=this._fileDropConfig;return e.includes("*/*")?!0:e.some(t=>{if(t===h)return!0;if(t.endsWith("/*")){const s=t.split("/")[0];return h.startsWith(s+"/")}return!1})},_formatFileDropSize(h){if(h===0)return"0 Bytes";const e=1024,t=["Bytes","KB","MB","GB"],s=Math.floor(Math.log(h)/Math.log(e));return parseFloat((h/Math.pow(e,s)).toFixed(2))+" "+t[s]}};function it(h){Object.assign(h.prototype,st)}class ye extends C{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:c=50,disabled:d=!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=c,this.disabled=d,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`
819
+ `}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 c=e;e<=t?c<=t:c>=t;c+=l){let d=String(c);if(typeof r=="function")d=r(c);else if(r==="padded"||r==="pad"){const u=String(Math.max(Math.abs(e),Math.abs(t))).length;d=String(c).padStart(u,"0")}else r==="ordinal"&&(d=this.formatOrdinal(c));d=`${a}${d}${n}`,o.push({value:c,label:d})}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 st={enableFileDrop(h={}){if(this._fileDropConfig={acceptedTypes:h.acceptedTypes||["*/*"],maxFileSize:h.maxFileSize||10*1024*1024,dropZoneSelector:h.dropZoneSelector||null,visualFeedback:h.visualFeedback!==!1,multiple:h.multiple||!1,validateOnDrop:h.validateOnDrop!==!1,dragOverClass:h.dragOverClass||"drag-over",dragActiveClass:h.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 h=this._getFileDropZone();if(!h){console.warn("FileDropMixin: Drop zone not found");return}this._fileDropZone=h,h.addEventListener("dragenter",this._boundFileDropHandlers.dragEnter),h.addEventListener("dragover",this._boundFileDropHandlers.dragOver),h.addEventListener("dragleave",this._boundFileDropHandlers.dragLeave),h.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(h=>{document.removeEventListener(h,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(h){h.preventDefault(),h.stopPropagation()},_onFileDropDragEnter(h){this._onFileDropPreventDefault(h),this._fileDropState.dragCounter++,this._fileDropState.isDragActive||(this._fileDropState.isDragActive=!0,this._applyFileDropVisualFeedback(!0))},_onFileDropDragOver(h){this._onFileDropPreventDefault(h),h.dataTransfer.dropEffect="copy"},_onFileDropDragLeave(h){this._onFileDropPreventDefault(h),this._fileDropState.dragCounter--,this._fileDropState.dragCounter<=0&&(this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1))},async _onFileDropDrop(h){this._onFileDropPreventDefault(h),this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1);const e=Array.from(h.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(", ")),h,t);return}if(typeof this.onFileDrop=="function")try{await this.onFileDrop(t,h,s)}catch(i){typeof this.onFileDropError=="function"?await this.onFileDropError(i,h,t):console.error("FileDropMixin: Error in onFileDrop callback:",i)}else console.warn("FileDropMixin: No onFileDrop method found on view")},_applyFileDropVisualFeedback(h){if(!this._fileDropConfig.visualFeedback||!this._fileDropZone)return;const{dragOverClass:e,dragActiveClass:t}=this._fileDropConfig;h?this._fileDropZone.classList.add(e,t):this._fileDropZone.classList.remove(e,t)},_validateFileDropFiles(h){const e=[],t=this._fileDropConfig;for(const s of h){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(h){const{acceptedTypes:e}=this._fileDropConfig;return e.includes("*/*")?!0:e.some(t=>{if(t===h)return!0;if(t.endsWith("/*")){const s=t.split("/")[0];return h.startsWith(s+"/")}return!1})},_formatFileDropSize(h){if(h===0)return"0 Bytes";const e=1024,t=["Bytes","KB","MB","GB"],s=Math.floor(Math.log(h)/Math.log(e));return parseFloat((h/Math.pow(e,s)).toFixed(2))+" "+t[s]}};function it(h){Object.assign(h.prototype,st)}class ye extends C{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:c=50,disabled:d=!1,readonly:u=!1,class:p="",tagClass:m="badge bg-primary",inputClass:f="form-control",...g}=e;super({tagName:"div",className:`tag-input-view ${p}`,...g}),this.name=t,this.placeholder=i,this.maxTags=r,this.allowDuplicates=a,this.separator=n,this.trimTags=o,this.minLength=l,this.maxLength=c,this.disabled=d,this.readonly=u,this.tagClass=m,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`
820
820
  <div class="tag-input-container">
821
821
  <div class="tag-input-wrapper border rounded p-2"
822
822
  data-action="focus-input"
@@ -1053,7 +1053,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1053
1053
  <div class="invalid-feedback d-block">{{error}}</div>
1054
1054
  {{/error}}
1055
1055
  </div>
1056
- `,...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 ct({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()}}class we extends C{constructor(e={}){const{name:t,value:s="",format:i="YYYY-MM-DD",displayFormat:r="MMM DD, YYYY",min:a=null,max:n=null,placeholder:o="Select date...",disabled:l=!1,readonly:c=!1,required:d=!1,class:u="",inputClass:m="form-control",autoApply:p=!0,inline:f=!1,...g}=e;super({tagName:"div",className:`date-picker-view ${u}`,...g}),this.name=t,this.format=i,this.displayFormat=r,this.min=a,this.max=n,this.placeholder=o,this.disabled=l,this.readonly=c,this.required=d,this.inputClass=m,this.autoApply=p,this.inline=f,this.currentValue=s,this.picker=null,this.useNative=!1,this.easepickLoaded=!1,this.checkEasepickAvailability()}async checkEasepickAvailability(){if(typeof window<"u"&&window.easepick)return this.easepickLoaded=!0,!0;try{return await this.loadEasepick(),this.easepickLoaded=!0,!0}catch(e){return console.warn("Easepick failed to load, falling back to native date input:",e),this.useNative=!0,!1}}async loadEasepick(){return new Promise((e,t)=>{if(window.easepick){e();return}const s=document.createElement("link");s.rel="stylesheet",s.href="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",document.head.appendChild(s);const i=document.createElement("script");i.src="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.umd.min.js",i.onload=()=>{window.easepick?e():t(new Error("Easepick not available after loading"))},i.onerror=()=>t(new Error("Failed to load Easepick script")),document.head.appendChild(i)})}async renderTemplate(){const e=this.getInputId(),t=this.useNative?"date":"text",s=this.formatValueForInput(this.currentValue);return`
1056
+ `,...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 ct({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()}}class we extends C{constructor(e={}){const{name:t,value:s="",format:i="YYYY-MM-DD",displayFormat:r="MMM DD, YYYY",min:a=null,max:n=null,placeholder:o="Select date...",disabled:l=!1,readonly:c=!1,required:d=!1,class:u="",inputClass:p="form-control",autoApply:m=!0,inline:f=!1,...g}=e;super({tagName:"div",className:`date-picker-view ${u}`,...g}),this.name=t,this.format=i,this.displayFormat=r,this.min=a,this.max=n,this.placeholder=o,this.disabled=l,this.readonly=c,this.required=d,this.inputClass=p,this.autoApply=m,this.inline=f,this.currentValue=s,this.picker=null,this.useNative=!1,this.easepickLoaded=!1,this.checkEasepickAvailability()}async checkEasepickAvailability(){if(typeof window<"u"&&window.easepick)return this.easepickLoaded=!0,!0;try{return await this.loadEasepick(),this.easepickLoaded=!0,!0}catch(e){return console.warn("Easepick failed to load, falling back to native date input:",e),this.useNative=!0,!1}}async loadEasepick(){return new Promise((e,t)=>{if(window.easepick){e();return}const s=document.createElement("link");s.rel="stylesheet",s.href="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",document.head.appendChild(s);const i=document.createElement("script");i.src="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.umd.min.js",i.onload=()=>{window.easepick?e():t(new Error("Easepick not available after loading"))},i.onerror=()=>t(new Error("Failed to load Easepick script")),document.head.appendChild(i)})}async renderTemplate(){const e=this.getInputId(),t=this.useNative?"date":"text",s=this.formatValueForInput(this.currentValue);return`
1057
1057
  <div class="date-picker-container">
1058
1058
  <input
1059
1059
  type="${t}"
@@ -1072,7 +1072,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1072
1072
  />
1073
1073
  <div class="date-picker-feedback"></div>
1074
1074
  </div>
1075
- `}async onAfterRender(){await super.onAfterRender(),this.easepickLoaded&&!this.useNative?await this.initializeEasepick():this.initializeNativeFallback()}async initializeEasepick(){const e=this.getInputElement();if(!(!e||!window.easepick))try{const t={element:e,css:["https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css"],format:this.displayFormat,lang:"en-US",autoApply:this.autoApply,inline:this.inline,readonly:this.readonly,zIndex:9999};this.min&&(t.minDate=new Date(this.min)),this.max&&(t.maxDate=new Date(this.max)),t.setup=s=>{s.on("select",i=>{const r=i.detail.date;this.handleDateChange(r?this.formatDate(r,this.format):"")}),s.on("clear",()=>{this.handleDateChange("")}),s.on("show",()=>{this.emit("picker:show")}),s.on("hide",()=>{this.emit("picker:hide")})},this.picker=new window.easepick.create(t),this.currentValue&&this.picker.setDate(this.currentValue)}catch(t){console.error("Failed to initialize Easepick:",t),this.useNative=!0,this.initializeNativeFallback()}}initializeNativeFallback(){const e=this.getInputElement();e&&(e.type="date",this.currentValue&&(e.value=this.formatDate(this.currentValue,"YYYY-MM-DD")))}async onChangeDateChanged(e,t,s){const i=s.value;this.handleDateChange(i)}handleDateChange(e){const t=this.currentValue;this.currentValue=e,this.updateHiddenInput(),t!==e&&(this.emit("change",{value:e,formatted:this.formatValueForDisplay(e),oldValue:t}),this.emit("date:changed",{value:e,oldValue:t}))}formatDate(e,t=this.format){if(!e)return"";const s=new Date(e);if(isNaN(s.getTime()))return"";const i=s.getFullYear(),r=String(s.getMonth()+1).padStart(2,"0"),a=String(s.getDate()).padStart(2,"0");switch(t){case"YYYY-MM-DD":return`${i}-${r}-${a}`;case"MM/DD/YYYY":return`${r}/${a}/${i}`;case"DD/MM/YYYY":return`${a}/${r}/${i}`;case"MMM DD, YYYY":return`${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][s.getMonth()]} ${a}, ${i}`;default:return`${i}-${r}-${a}`}}formatValueForInput(e){return e?this.useNative?this.formatDate(e,"YYYY-MM-DD"):e:""}formatValueForDisplay(e){return e?this.formatDate(e,this.displayFormat):""}getInputId(){return this.name?`datepicker_${this.name}_${Date.now()}`:`datepicker_${Date.now()}`}getInputElement(){return this.element?.querySelector("input")}updateHiddenInput(){}hasError(){return!1}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}setValue(e){if(this.currentValue=e,this.picker&&this.easepickLoaded)this.picker.setDate(e||null);else{const t=this.getInputElement();t&&(t.value=this.formatValueForInput(e))}this.emit("value:set",{value:e})}getValue(){return this.currentValue}getFormattedValue(e=this.displayFormat){return this.formatDate(this.currentValue,e)}clear(){this.setValue("")}setMin(e){if(this.min=e,this.picker&&this.easepickLoaded)this.picker.options.minDate=new Date(e);else{const t=this.getInputElement();t&&(t.min=e)}}setMax(e){if(this.max=e,this.picker&&this.easepickLoaded)this.picker.options.maxDate=new Date(e);else{const t=this.getInputElement();t&&(t.max=e)}}setEnabled(e){this.disabled=!e;const t=this.getInputElement();t&&(t.disabled=this.disabled),this.picker&&this.easepickLoaded&&this.disabled&&this.picker.hide()}setReadonly(e){this.readonly=e;const t=this.getInputElement();t&&(t.readonly=e)}focus(){const e=this.getInputElement();e&&e.focus()}show(){this.picker&&this.easepickLoaded&&this.picker.show()}hide(){this.picker&&this.easepickLoaded&&this.picker.hide()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}async onBeforeDestroy(){if(this.picker&&this.easepickLoaded)try{this.picker.destroy()}catch(e){console.warn("Error destroying Easepick instance:",e)}this.picker=null,await super.onBeforeDestroy()}static create(e={}){return new we(e)}}class ve extends C{constructor(e={}){const{name:t,startName:s,endName:i,fieldName:r,startDate:a="",endDate:n="",format:o="YYYY-MM-DD",displayFormat:l="MMM DD, YYYY",outputFormat:c="date",min:d=null,max:u=null,placeholder:m="Select date range...",startPlaceholder:p="Start date...",endPlaceholder:f="End date...",disabled:g=!1,readonly:b=!1,required:y=!1,class:x="",inputClass:F="form-control",autoApply:D=!0,inline:V=!1,separator:H=" - ",...P}=e;super({tagName:"div",className:`date-range-picker-view ${x}`,...P}),this.name=t,this.startName=s,this.endName=i,this.fieldName=r,this.format=o,this.displayFormat=l,this.outputFormat=c,this.min=d,this.max=u,this.placeholder=m,this.startPlaceholder=p,this.endPlaceholder=f,this.disabled=g,this.readonly=b,this.required=y,this.inputClass=F,this.autoApply=D,this.inline=V,this.separator=H,this.currentStartDate=a,this.currentEndDate=n,this.picker=null,this.useNative=!1,this.easepickLoaded=!1,this.checkEasepickAvailability()}async checkEasepickAvailability(){if(typeof window<"u"&&window.easepick)return this.easepickLoaded=!0,!0;try{return await this.loadEasepick(),this.easepickLoaded=!0,!0}catch(e){return console.warn("Easepick failed to load, falling back to native date inputs:",e),this.useNative=!0,!1}}async loadEasepick(){return new Promise((e,t)=>{if(window.easepick){e();return}const s=document.createElement("link");s.rel="stylesheet",s.href="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",document.head.appendChild(s);const i=document.createElement("script");i.src="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.umd.min.js",i.onload=()=>{window.easepick?e():t(new Error("Easepick not available after loading"))},i.onerror=()=>t(new Error("Failed to load Easepick script")),document.head.appendChild(i)})}async renderTemplate(){const e=this.getInputId(),t=this.getDisplayValue();if(this.useNative)return this.renderNativeTemplate(e);const s=this.startName||(this.name?`${this.name}_start`:""),i=this.endName||(this.name?`${this.name}_end`:""),r=this.currentStartDate?this.formatForOutput(this.currentStartDate):"",a=this.currentEndDate?this.formatForOutput(this.currentEndDate):"";return`
1075
+ `}async onAfterRender(){await super.onAfterRender(),this.easepickLoaded&&!this.useNative?await this.initializeEasepick():this.initializeNativeFallback()}async initializeEasepick(){const e=this.getInputElement();if(!(!e||!window.easepick))try{const t={element:e,css:["https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css"],format:this.displayFormat,lang:"en-US",autoApply:this.autoApply,inline:this.inline,readonly:this.readonly,zIndex:9999};this.min&&(t.minDate=new Date(this.min)),this.max&&(t.maxDate=new Date(this.max)),t.setup=s=>{s.on("select",i=>{const r=i.detail.date;this.handleDateChange(r?this.formatDate(r,this.format):"")}),s.on("clear",()=>{this.handleDateChange("")}),s.on("show",()=>{this.emit("picker:show")}),s.on("hide",()=>{this.emit("picker:hide")})},this.picker=new window.easepick.create(t),this.currentValue&&this.picker.setDate(this.currentValue)}catch(t){console.error("Failed to initialize Easepick:",t),this.useNative=!0,this.initializeNativeFallback()}}initializeNativeFallback(){const e=this.getInputElement();e&&(e.type="date",this.currentValue&&(e.value=this.formatDate(this.currentValue,"YYYY-MM-DD")))}async onChangeDateChanged(e,t,s){const i=s.value;this.handleDateChange(i)}handleDateChange(e){const t=this.currentValue;this.currentValue=e,this.updateHiddenInput(),t!==e&&(this.emit("change",{value:e,formatted:this.formatValueForDisplay(e),oldValue:t}),this.emit("date:changed",{value:e,oldValue:t}))}formatDate(e,t=this.format){if(!e)return"";const s=new Date(e);if(isNaN(s.getTime()))return"";const i=s.getFullYear(),r=String(s.getMonth()+1).padStart(2,"0"),a=String(s.getDate()).padStart(2,"0");switch(t){case"YYYY-MM-DD":return`${i}-${r}-${a}`;case"MM/DD/YYYY":return`${r}/${a}/${i}`;case"DD/MM/YYYY":return`${a}/${r}/${i}`;case"MMM DD, YYYY":return`${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][s.getMonth()]} ${a}, ${i}`;default:return`${i}-${r}-${a}`}}formatValueForInput(e){return e?this.useNative?this.formatDate(e,"YYYY-MM-DD"):e:""}formatValueForDisplay(e){return e?this.formatDate(e,this.displayFormat):""}getInputId(){return this.name?`datepicker_${this.name}_${Date.now()}`:`datepicker_${Date.now()}`}getInputElement(){return this.element?.querySelector("input")}updateHiddenInput(){}hasError(){return!1}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}setValue(e){if(this.currentValue=e,this.picker&&this.easepickLoaded)this.picker.setDate(e||null);else{const t=this.getInputElement();t&&(t.value=this.formatValueForInput(e))}this.emit("value:set",{value:e})}getValue(){return this.currentValue}getFormattedValue(e=this.displayFormat){return this.formatDate(this.currentValue,e)}clear(){this.setValue("")}setMin(e){if(this.min=e,this.picker&&this.easepickLoaded)this.picker.options.minDate=new Date(e);else{const t=this.getInputElement();t&&(t.min=e)}}setMax(e){if(this.max=e,this.picker&&this.easepickLoaded)this.picker.options.maxDate=new Date(e);else{const t=this.getInputElement();t&&(t.max=e)}}setEnabled(e){this.disabled=!e;const t=this.getInputElement();t&&(t.disabled=this.disabled),this.picker&&this.easepickLoaded&&this.disabled&&this.picker.hide()}setReadonly(e){this.readonly=e;const t=this.getInputElement();t&&(t.readonly=e)}focus(){const e=this.getInputElement();e&&e.focus()}show(){this.picker&&this.easepickLoaded&&this.picker.show()}hide(){this.picker&&this.easepickLoaded&&this.picker.hide()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}async onBeforeDestroy(){if(this.picker&&this.easepickLoaded)try{this.picker.destroy()}catch(e){console.warn("Error destroying Easepick instance:",e)}this.picker=null,await super.onBeforeDestroy()}static create(e={}){return new we(e)}}class ve extends C{constructor(e={}){const{name:t,startName:s,endName:i,fieldName:r,startDate:a="",endDate:n="",format:o="YYYY-MM-DD",displayFormat:l="MMM DD, YYYY",outputFormat:c="date",min:d=null,max:u=null,placeholder:p="Select date range...",startPlaceholder:m="Start date...",endPlaceholder:f="End date...",disabled:g=!1,readonly:b=!1,required:y=!1,class:x="",inputClass:F="form-control",autoApply:D=!0,inline:V=!1,separator:H=" - ",...P}=e;super({tagName:"div",className:`date-range-picker-view ${x}`,...P}),this.name=t,this.startName=s,this.endName=i,this.fieldName=r,this.format=o,this.displayFormat=l,this.outputFormat=c,this.min=d,this.max=u,this.placeholder=p,this.startPlaceholder=m,this.endPlaceholder=f,this.disabled=g,this.readonly=b,this.required=y,this.inputClass=F,this.autoApply=D,this.inline=V,this.separator=H,this.currentStartDate=a,this.currentEndDate=n,this.picker=null,this.useNative=!1,this.easepickLoaded=!1,this.checkEasepickAvailability()}async checkEasepickAvailability(){if(typeof window<"u"&&window.easepick)return this.easepickLoaded=!0,!0;try{return await this.loadEasepick(),this.easepickLoaded=!0,!0}catch(e){return console.warn("Easepick failed to load, falling back to native date inputs:",e),this.useNative=!0,!1}}async loadEasepick(){return new Promise((e,t)=>{if(window.easepick){e();return}const s=document.createElement("link");s.rel="stylesheet",s.href="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css",document.head.appendChild(s);const i=document.createElement("script");i.src="https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.umd.min.js",i.onload=()=>{window.easepick?e():t(new Error("Easepick not available after loading"))},i.onerror=()=>t(new Error("Failed to load Easepick script")),document.head.appendChild(i)})}async renderTemplate(){const e=this.getInputId(),t=this.getDisplayValue();if(this.useNative)return this.renderNativeTemplate(e);const s=this.startName||(this.name?`${this.name}_start`:""),i=this.endName||(this.name?`${this.name}_end`:""),r=this.currentStartDate?this.formatForOutput(this.currentStartDate):"",a=this.currentEndDate?this.formatForOutput(this.currentEndDate):"";return`
1076
1076
  <div class="date-range-picker-container">
1077
1077
  <input
1078
1078
  type="text"
@@ -1142,7 +1142,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1142
1142
 
1143
1143
  <div class="date-range-picker-feedback"></div>
1144
1144
  </div>
1145
- `}async onAfterRender(){await super.onAfterRender(),this.easepickLoaded&&!this.useNative?await this.initializeEasepick():this.initializeNativeFallback()}async initializeEasepick(){const e=this.getInputElement();if(!(!e||!window.easepick))try{const t={element:e,css:["https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css"],format:this.displayFormat,lang:"en-US",autoApply:this.autoApply,inline:this.inline,readonly:this.readonly,zIndex:9999,plugins:["RangePlugin"],RangePlugin:{tooltip:!0,locale:{one:"day",other:"days"}}};this.min&&(t.minDate=new Date(this.min)),this.max&&(t.maxDate=new Date(this.max)),t.setup=s=>{s.on("select",i=>{const{start:r,end:a}=i.detail,n=r?this.normalizeDateFromPicker(r):"",o=a?this.normalizeDateFromPicker(a):"";this.handleRangeChange(n,o)}),s.on("clear",()=>{this.handleRangeChange("","")}),s.on("show",()=>{this.emit("picker:show")}),s.on("hide",()=>{this.emit("picker:hide")}),s.on("ready",()=>{this.applyInitialRange(s)})},this.picker=new window.easepick.create(t),this.applyInitialRange(this.picker)}catch(t){console.error("Failed to initialize Easepick range picker:",t),this.useNative=!0,await this.render(),this.initializeNativeFallback()}}initializeNativeFallback(){this.updateConstraints()}async onChangeRangeChanged(e,t,s){}async onChangeStartDateChanged(e,t,s){const i=s.value;this.handleRangeChange(i,this.currentEndDate),this.updateConstraints()}async onChangeEndDateChanged(e,t,s){const i=s.value;this.handleRangeChange(this.currentStartDate,i),this.updateConstraints()}handleRangeChange(e,t){const s=this.currentStartDate,i=this.currentEndDate;this.currentStartDate=e,this.currentEndDate=t,this.updateHiddenInputs(),(s!==e||i!==t)&&(this.emit("change",{startDate:e,endDate:t,combined:this.getCombinedValue(),formatted:this.getDisplayValue(),oldStartDate:s,oldEndDate:i}),this.emit("range:changed",{startDate:e,endDate:t,oldStartDate:s,oldEndDate:i}))}updateConstraints(){if(!this.useNative)return;const e=this.element?.querySelector(`[name="${this.name}_start"]`),t=this.element?.querySelector(`[name="${this.name}_end"]`);e&&t&&(this.currentStartDate&&(t.min=this.currentStartDate),this.currentEndDate&&(e.max=this.currentEndDate))}normalizeDateFromPicker(e){if(!e)return"";if(typeof e.toJSDate=="function"){const t=e.toJSDate();return this.formatDate(t,this.format)}if(typeof e.getFullYear=="function"){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),i=String(e.getDate()).padStart(2,"0");switch(this.format){case"YYYY-MM-DD":return`${t}-${s}-${i}`;case"MM/DD/YYYY":return`${s}/${i}/${t}`;case"DD/MM/YYYY":return`${i}/${s}/${t}`;default:return`${t}-${s}-${i}`}}return this.formatDate(e,this.format)}formatDate(e,t=this.format){if(!e)return"";let s,i,r,a;if(typeof e=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(e)){const n=e.split("-");s=parseInt(n[0]),i=String(parseInt(n[1])).padStart(2,"0"),r=String(parseInt(n[2])).padStart(2,"0")}else{if(e instanceof Date?a=e:a=new Date(e),isNaN(a.getTime()))return"";s=a.getFullYear(),i=String(a.getMonth()+1).padStart(2,"0"),r=String(a.getDate()).padStart(2,"0")}switch(t){case"YYYY-MM-DD":return`${s}-${i}-${r}`;case"MM/DD/YYYY":return`${i}/${r}/${s}`;case"DD/MM/YYYY":return`${r}/${i}/${s}`;case"MMM DD, YYYY":{const n=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],o=parseInt(i)-1;return`${n[o]} ${r}, ${s}`}default:return`${s}-${i}-${r}`}}formatForOutput(e){if(!e)return"";if(typeof e=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(e))switch(this.outputFormat){case"epoch":const s=e.split("-"),i=new Date(parseInt(s[0]),parseInt(s[1])-1,parseInt(s[2]));return Math.floor(i.getTime()/1e3).toString();case"iso":return new Date(e+"T00:00:00").toISOString();default:return e}const t=new Date(e);if(isNaN(t.getTime()))return"";switch(this.outputFormat){case"epoch":return Math.floor(t.getTime()/1e3).toString();case"iso":return t.toISOString();default:return this.formatDate(e,this.format)}}getDisplayValue(){if(!this.currentStartDate&&!this.currentEndDate)return"";const e=this.currentStartDate?this.formatDate(this.currentStartDate,this.displayFormat):"",t=this.currentEndDate?this.formatDate(this.currentEndDate,this.displayFormat):"";return e&&t?`${e}${this.separator}${t}`:e||t||""}getCombinedValue(){return!this.currentStartDate&&!this.currentEndDate?"":JSON.stringify({start:this.currentStartDate,end:this.currentEndDate})}getInputId(){return this.name?`daterange_${this.name}_${Date.now()}`:`daterange_${Date.now()}`}getInputElement(){return this.element?.querySelector('input[type="text"], input[name="'+this.name+'"]')}updateHiddenInputs(){const e=this.startName||(this.name?`${this.name}_start`:""),t=this.endName||(this.name?`${this.name}_end`:""),s=e?this.element?.querySelector(`[name="${e}"]`):null,i=t?this.element?.querySelector(`[name="${t}"]`):null,r=this.name?this.element?.querySelector(`[name="${this.name}"]`):null,a=this.fieldName?this.element?.querySelector(`[name="${this.fieldName}"]`):null,n=this.currentStartDate?this.formatForOutput(this.currentStartDate):"",o=this.currentEndDate?this.formatForOutput(this.currentEndDate):"";s&&(s.value=n),i&&(i.value=o),r&&(r.value=this.getDisplayValue()),a&&(a.value=this.name||"")}hasError(){return this.currentStartDate&&this.currentEndDate?new Date(this.currentEndDate)<new Date(this.currentStartDate):!1}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}setRange(e,t){if(this.currentStartDate=e,this.currentEndDate=t,this.picker&&this.easepickLoaded){const s=this.normalizeDateValue(e),i=this.normalizeDateValue(t);this.picker.setDateRange(s||null,i||null)}else if(this.useNative){const s=this.element?.querySelector(`[name="${this.name}_start"]`),i=this.element?.querySelector(`[name="${this.name}_end"]`);s&&(s.value=this.formatDate(e,"YYYY-MM-DD")),i&&(i.value=this.formatDate(t,"YYYY-MM-DD"))}else{const s=this.getInputElement();s&&(s.value=this.getDisplayValue())}this.updateHiddenInputs(),this.emit("range:set",{startDate:e,endDate:t})}applyInitialRange(e){if(!e||!(this.currentStartDate||this.currentEndDate))return;const t=this.normalizeDateValue(this.currentStartDate),s=this.normalizeDateValue(this.currentEndDate);(t||s)&&e.setDateRange(t||null,s||null)}normalizeDateValue(e){if(!e&&e!==0)return null;if(e instanceof Date)return isNaN(e)?null:e;const t=String(e).trim();if(!t)return null;if(/^\d{4}-\d{2}-\d{2}$/.test(t)){const[i,r,a]=t.split("-").map(Number),n=new Date(i,r-1,a);return isNaN(n)?null:n}if(/^-?\d+$/.test(t)){const i=Number(t),r=t.length<=10?i*1e3:i,a=new Date(r);return isNaN(a)?null:a}const s=new Date(t);return isNaN(s)?null:s}getRange(){return{start:this.currentStartDate,end:this.currentEndDate,combined:this.getCombinedValue()}}clear(){this.setRange("","")}setStartDate(e){this.setRange(e,this.currentEndDate)}setEndDate(e){this.setRange(this.currentStartDate,e)}getStartDate(){return this.currentStartDate}getEndDate(){return this.currentEndDate}setEnabled(e){this.disabled=!e,this.element?.querySelectorAll("input")?.forEach(s=>{s.disabled=this.disabled})}setReadonly(e){this.readonly=e,this.element?.querySelectorAll('input:not([type="hidden"])')?.forEach(s=>{s.readonly=e})}focus(){const e=this.getInputElement();e&&e.focus()}show(){this.picker&&this.easepickLoaded&&this.picker.show()}hide(){this.picker&&this.easepickLoaded&&this.picker.hide()}getFormValue(){return this.getRange()}async setFormValue(e){if(typeof e=="string")try{const t=JSON.parse(e);this.setRange(t.start,t.end)}catch{this.setRange(e,"")}else e&&typeof e=="object"&&this.setRange(e.start||"",e.end||"")}async onBeforeDestroy(){if(this.picker&&this.easepickLoaded)try{this.picker.destroy()}catch(e){console.warn("Error destroying Easepick range picker instance:",e)}this.picker=null,await super.onBeforeDestroy()}static create(e={}){return new ve(e)}}class Ce extends C{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:c=!1,readonly:d=!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=c,this.readonly=d,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`
1145
+ `}async onAfterRender(){await super.onAfterRender(),this.easepickLoaded&&!this.useNative?await this.initializeEasepick():this.initializeNativeFallback()}async initializeEasepick(){const e=this.getInputElement();if(!(!e||!window.easepick))try{const t={element:e,css:["https://cdn.jsdelivr.net/npm/@easepick/bundle@1.2.1/dist/index.css"],format:this.displayFormat,lang:"en-US",autoApply:this.autoApply,inline:this.inline,readonly:this.readonly,zIndex:9999,plugins:["RangePlugin"],RangePlugin:{tooltip:!0,locale:{one:"day",other:"days"}}};this.min&&(t.minDate=new Date(this.min)),this.max&&(t.maxDate=new Date(this.max)),t.setup=s=>{s.on("select",i=>{const{start:r,end:a}=i.detail,n=r?this.normalizeDateFromPicker(r):"",o=a?this.normalizeDateFromPicker(a):"";this.handleRangeChange(n,o)}),s.on("clear",()=>{this.handleRangeChange("","")}),s.on("show",()=>{this.emit("picker:show")}),s.on("hide",()=>{this.emit("picker:hide")}),s.on("ready",()=>{this.applyInitialRange(s)})},this.picker=new window.easepick.create(t),this.applyInitialRange(this.picker)}catch(t){console.error("Failed to initialize Easepick range picker:",t),this.useNative=!0,await this.render(),this.initializeNativeFallback()}}initializeNativeFallback(){this.updateConstraints()}async onChangeRangeChanged(e,t,s){}async onChangeStartDateChanged(e,t,s){const i=s.value;this.handleRangeChange(i,this.currentEndDate),this.updateConstraints()}async onChangeEndDateChanged(e,t,s){const i=s.value;this.handleRangeChange(this.currentStartDate,i),this.updateConstraints()}handleRangeChange(e,t){const s=this.currentStartDate,i=this.currentEndDate;this.currentStartDate=e,this.currentEndDate=t,this.updateHiddenInputs(),(s!==e||i!==t)&&(this.emit("change",{startDate:e,endDate:t,combined:this.getCombinedValue(),formatted:this.getDisplayValue(),oldStartDate:s,oldEndDate:i}),this.emit("range:changed",{startDate:e,endDate:t,oldStartDate:s,oldEndDate:i}))}updateConstraints(){if(!this.useNative)return;const e=this.element?.querySelector(`[name="${this.name}_start"]`),t=this.element?.querySelector(`[name="${this.name}_end"]`);e&&t&&(this.currentStartDate&&(t.min=this.currentStartDate),this.currentEndDate&&(e.max=this.currentEndDate))}normalizeDateFromPicker(e){if(!e)return"";if(typeof e.toJSDate=="function"){const t=e.toJSDate();return this.formatDate(t,this.format)}if(typeof e.getFullYear=="function"){const t=e.getFullYear(),s=String(e.getMonth()+1).padStart(2,"0"),i=String(e.getDate()).padStart(2,"0");switch(this.format){case"YYYY-MM-DD":return`${t}-${s}-${i}`;case"MM/DD/YYYY":return`${s}/${i}/${t}`;case"DD/MM/YYYY":return`${i}/${s}/${t}`;default:return`${t}-${s}-${i}`}}return this.formatDate(e,this.format)}formatDate(e,t=this.format){if(!e)return"";let s,i,r,a;if(typeof e=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(e)){const n=e.split("-");s=parseInt(n[0]),i=String(parseInt(n[1])).padStart(2,"0"),r=String(parseInt(n[2])).padStart(2,"0")}else{if(e instanceof Date?a=e:a=new Date(e),isNaN(a.getTime()))return"";s=a.getFullYear(),i=String(a.getMonth()+1).padStart(2,"0"),r=String(a.getDate()).padStart(2,"0")}switch(t){case"YYYY-MM-DD":return`${s}-${i}-${r}`;case"MM/DD/YYYY":return`${i}/${r}/${s}`;case"DD/MM/YYYY":return`${r}/${i}/${s}`;case"MMM DD, YYYY":{const n=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],o=parseInt(i)-1;return`${n[o]} ${r}, ${s}`}default:return`${s}-${i}-${r}`}}formatForOutput(e){if(!e)return"";if(typeof e=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(e))switch(this.outputFormat){case"epoch":const s=e.split("-"),i=new Date(parseInt(s[0]),parseInt(s[1])-1,parseInt(s[2]));return Math.floor(i.getTime()/1e3).toString();case"iso":return new Date(e+"T00:00:00").toISOString();default:return e}const t=new Date(e);if(isNaN(t.getTime()))return"";switch(this.outputFormat){case"epoch":return Math.floor(t.getTime()/1e3).toString();case"iso":return t.toISOString();default:return this.formatDate(e,this.format)}}getDisplayValue(){if(!this.currentStartDate&&!this.currentEndDate)return"";const e=this.currentStartDate?this.formatDate(this.currentStartDate,this.displayFormat):"",t=this.currentEndDate?this.formatDate(this.currentEndDate,this.displayFormat):"";return e&&t?`${e}${this.separator}${t}`:e||t||""}getCombinedValue(){return!this.currentStartDate&&!this.currentEndDate?"":JSON.stringify({start:this.currentStartDate,end:this.currentEndDate})}getInputId(){return this.name?`daterange_${this.name}_${Date.now()}`:`daterange_${Date.now()}`}getInputElement(){return this.element?.querySelector('input[type="text"], input[name="'+this.name+'"]')}updateHiddenInputs(){const e=this.startName||(this.name?`${this.name}_start`:""),t=this.endName||(this.name?`${this.name}_end`:""),s=e?this.element?.querySelector(`[name="${e}"]`):null,i=t?this.element?.querySelector(`[name="${t}"]`):null,r=this.name?this.element?.querySelector(`[name="${this.name}"]`):null,a=this.fieldName?this.element?.querySelector(`[name="${this.fieldName}"]`):null,n=this.currentStartDate?this.formatForOutput(this.currentStartDate):"",o=this.currentEndDate?this.formatForOutput(this.currentEndDate):"";s&&(s.value=n),i&&(i.value=o),r&&(r.value=this.getDisplayValue()),a&&(a.value=this.name||"")}hasError(){return this.currentStartDate&&this.currentEndDate?new Date(this.currentEndDate)<new Date(this.currentStartDate):!1}escapeHtml(e){if(e==null)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}setRange(e,t){if(this.currentStartDate=e,this.currentEndDate=t,this.picker&&this.easepickLoaded){const s=this.normalizeDateValue(e),i=this.normalizeDateValue(t);this.picker.setDateRange(s||null,i||null)}else if(this.useNative){const s=this.element?.querySelector(`[name="${this.name}_start"]`),i=this.element?.querySelector(`[name="${this.name}_end"]`);s&&(s.value=this.formatDate(e,"YYYY-MM-DD")),i&&(i.value=this.formatDate(t,"YYYY-MM-DD"))}else{const s=this.getInputElement();s&&(s.value=this.getDisplayValue())}this.updateHiddenInputs(),this.emit("range:set",{startDate:e,endDate:t})}applyInitialRange(e){if(!e||!(this.currentStartDate||this.currentEndDate))return;const t=this.normalizeDateValue(this.currentStartDate),s=this.normalizeDateValue(this.currentEndDate);(t||s)&&e.setDateRange(t||null,s||null)}normalizeDateValue(e){if(!e&&e!==0)return null;if(e instanceof Date)return isNaN(e)?null:e;const t=String(e).trim();if(!t)return null;if(/^\d{4}-\d{2}-\d{2}$/.test(t)){const[i,r,a]=t.split("-").map(Number),n=new Date(i,r-1,a);return isNaN(n)?null:n}if(/^-?\d+$/.test(t)){const i=Number(t),r=t.length<=10?i*1e3:i,a=new Date(r);return isNaN(a)?null:a}const s=new Date(t);return isNaN(s)?null:s}getRange(){return{start:this.currentStartDate,end:this.currentEndDate,combined:this.getCombinedValue()}}clear(){this.setRange("","")}setStartDate(e){this.setRange(e,this.currentEndDate)}setEndDate(e){this.setRange(this.currentStartDate,e)}getStartDate(){return this.currentStartDate}getEndDate(){return this.currentEndDate}setEnabled(e){this.disabled=!e,this.element?.querySelectorAll("input")?.forEach(s=>{s.disabled=this.disabled})}setReadonly(e){this.readonly=e,this.element?.querySelectorAll('input:not([type="hidden"])')?.forEach(s=>{s.readonly=e})}focus(){const e=this.getInputElement();e&&e.focus()}show(){this.picker&&this.easepickLoaded&&this.picker.show()}hide(){this.picker&&this.easepickLoaded&&this.picker.hide()}getFormValue(){return this.getRange()}async setFormValue(e){if(typeof e=="string")try{const t=JSON.parse(e);this.setRange(t.start,t.end)}catch{this.setRange(e,"")}else e&&typeof e=="object"&&this.setRange(e.start||"",e.end||"")}async onBeforeDestroy(){if(this.picker&&this.easepickLoaded)try{this.picker.destroy()}catch(e){console.warn("Error destroying Easepick range picker instance:",e)}this.picker=null,await super.onBeforeDestroy()}static create(e={}){return new ve(e)}}class Ce extends C{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:c=!1,readonly:d=!1,required:u=!1,class:p="",inputClass:m="form-control",onSelect:f=null,onChange:g=null,...b}=e;super({tagName:"div",className:`combo-input ${p}`,...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=c,this.readonly=d,this.required=u,this.inputClass=m,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`
1146
1146
  <div class="combo-input-container position-relative">
1147
1147
  <div class="input-wrapper position-relative">
1148
1148
  ${this.renderInput()}
@@ -1290,7 +1290,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1290
1290
  </div>
1291
1291
  <i class="bi bi-check-circle text-success d-none" data-status="saved"></i>
1292
1292
  <i class="bi bi-exclamation-circle text-danger d-none" data-status="error"></i>
1293
- `}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()}}it(z);const Pe=Object.freeze(Object.defineProperty({__proto__:null,FormView:z,default:z},Symbol.toStringTag,{value:"Module"}));class mt extends ee{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 z({containerId:"form-view-container",fields:this.options.fields,autosaveModelField:!0}),this.addChild(this.formView);const e=await this.getModel();e&&this.formView.setModel(e)}}S.showDialog=(...h)=>w.dialog(...h),S.alert=(...h)=>w.alert(...h),S.confirm=(...h)=>w.confirm(...h),S.prompt=(...h)=>w.prompt(...h),S.showError=(...h)=>w.showError(...h),S.showForm=(...h)=>w.form(...h),S.showModelForm=(...h)=>w.modelForm(...h),S.showData=(...h)=>w.data(...h),S.showModelView=(...h)=>w.showModelView(...h),S.updateModelImage=(...h)=>w.updateModelImage(...h),S.showCode=(...h)=>w.code(...h),S.showHtmlPreview=(...h)=>w.htmlPreview(...h),S.formatCode=(...h)=>X.formatCode(...h),S.highlightCodeBlocks=(...h)=>X.highlightCodeBlocks(...h),S.showBusy=(...h)=>w.showBusy(...h),S.hideBusy=(...h)=>w.hideBusy(...h),S.showConfirm=S.confirm;class ae extends C{constructor(e={}){super({className:"list-view-item",...e}),this.selected=!1,this.index=e.index??0,this.listView=e.listView??null,this.template||(this.template=`
1293
+ `}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()}}it(z);const Pe=Object.freeze(Object.defineProperty({__proto__:null,FormView:z,default:z},Symbol.toStringTag,{value:"Module"}));class pt extends ee{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 z({containerId:"form-view-container",fields:this.options.fields,autosaveModelField:!0}),this.addChild(this.formView);const e=await this.getModel();e&&this.formView.setModel(e)}}S.showDialog=(...h)=>w.dialog(...h),S.alert=(...h)=>w.alert(...h),S.confirm=(...h)=>w.confirm(...h),S.prompt=(...h)=>w.prompt(...h),S.showError=(...h)=>w.showError(...h),S.showForm=(...h)=>w.form(...h),S.showModelForm=(...h)=>w.modelForm(...h),S.showData=(...h)=>w.data(...h),S.showModelView=(...h)=>w.showModelView(...h),S.updateModelImage=(...h)=>w.updateModelImage(...h),S.showCode=(...h)=>w.code(...h),S.showHtmlPreview=(...h)=>w.htmlPreview(...h),S.formatCode=(...h)=>X.formatCode(...h),S.highlightCodeBlocks=(...h)=>X.highlightCodeBlocks(...h),S.showBusy=(...h)=>w.showBusy(...h),S.hideBusy=(...h)=>w.hideBusy(...h),S.showConfirm=S.confirm;class ae extends C{constructor(e={}){super({className:"list-view-item",...e}),this.selected=!1,this.index=e.index??0,this.listView=e.listView??null,this.template||(this.template=`
1294
1294
  <div class="list-item-content" data-action="select">
1295
1295
  {{#model}}
1296
1296
  {{#id}}<span class="item-id">{{id}}</span>{{/id}}
@@ -1333,7 +1333,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1333
1333
  </div>
1334
1334
  </div>
1335
1335
  </td>
1336
- `),this.columns.forEach((t,s)=>{const i=t.class||t.className||"",r=this.getResponsiveClasses(t.visibility),a=t.editable?"editable-cell":"",n=[i,r,a].filter(c=>c).join(" "),o=this.buildCellTemplate(t,s);let l=t.action;!l&&t.editable?l="edit-cell":!l&&this.tableView.rowAction&&(l=this.tableView.rowAction),l?e+=`<td class="${n}" data-action="${l}" data-column="${t.key}">${o}</td>`:e+=`<td class="${n}" data-column="${t.key}">${o}</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;if(i){if(typeof i=="string")return`{{{${s}|${i}}}}`;if(typeof i=="function")return`<span data-formatter="${e.key}" data-formatter-id="${t}">{{${s}}}</span>`}return e.template?e.template:e.editable?`<span class="cell-content" data-field="${e.key}">{{{${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`
1336
+ `),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(d=>d).join(" "),l=this.buildCellTemplate(t,s);let c=t.action;!c&&t.editable?c="edit-cell":!c&&this.tableView.rowAction&&(c=this.tableView.rowAction),c?e+=`<td class="${o}" data-action="${c}" 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;if(i){if(typeof i=="string")return`{{{${s}|${i}}}}`;if(typeof i=="function")return`<span data-formatter="${e.key}" data-formatter-id="${t}">{{${s}}}</span>`}return e.template?e.template:e.editable?`<span class="cell-content" data-field="${e.key}">{{{${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`
1337
1337
  <button class="btn btn-sm btn-outline-primary"
1338
1338
  data-action="view"
1339
1339
  title="View">
@@ -1437,7 +1437,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1437
1437
  </button>
1438
1438
  </div>
1439
1439
  </div>
1440
- `}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=_.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")}}const Ne={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:h=>h==="true"||h===!0?"is null":"is not null",description:"Check if value is null or not"},range:{display:"between",description:"Between two values (comma-separated)"}};function se(h){if(!h||typeof h!="string")return{field:h,lookup:null};const e=h.split("__");if(e.length===1)return{field:h,lookup:null};const t=e[e.length-1];return Ne[t]?{field:e.slice(0,-1).join("__"),lookup:t}:{field:h,lookup:null}}function pt(h,e,t){if(!h||e===null||e===void 0)return"";const{field:s,lookup:i}=se(h),r=Ne[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 Oe extends Se{constructor(e={}){const t={className:"table-view-component",itemClass:e.itemClass||xe,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.clickAction=e.clickAction||"view",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.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""}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();console.log("Updating footer totals in DOM:",e);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 _.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],c=parseFloat(l)||0;a+=c}),console.log(`Footer total for ${t.key}: ${a} (from ${this.collection.length} items)`);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}})}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():"";return`
1440
+ `}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=_.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")}}const Ne={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:h=>h==="true"||h===!0?"is null":"is not null",description:"Check if value is null or not"},range:{display:"between",description:"Between two values (comma-separated)"}};function se(h){if(!h||typeof h!="string")return{field:h,lookup:null};const e=h.split("__");if(e.length===1)return{field:h,lookup:null};const t=e[e.length-1];return Ne[t]?{field:e.slice(0,-1).join("__"),lookup:t}:{field:h,lookup:null}}function mt(h,e,t){if(!h||e===null||e===void 0)return"";const{field:s,lookup:i}=se(h),r=Ne[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 Oe extends Se{constructor(e={}){const t={className:"table-view-component",itemClass:e.itemClass||xe,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.clickAction=e.clickAction||"view",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.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();console.log("Updating footer totals in DOM:",e);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 _.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],c=parseFloat(l)||0;a+=c}),console.log(`Footer total for ${t.key}: ${a} (from ${this.collection.length} items)`);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}})}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():"";return`
1441
1441
  <div class="mojo-table-wrapper">
1442
1442
  ${this.buildToolbarTemplate()}
1443
1443
  ${e}
@@ -1522,11 +1522,11 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1522
1522
  <i class="bi bi-download me-1"></i>
1523
1523
  <span class="d-none d-lg-inline">Export</span>
1524
1524
  </button>
1525
- `)}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:c="",permissions:d=null}=t;if(d&&!this.checkPermissions(d))return;const u=r?`<i class="${r} me-1"></i>`:"",m=`<span class="d-none d-lg-inline">${i}</span>`;let p="";n?p=`data-action="custom-toolbar-button" data-button-index="${s}"`:a&&(p=`data-action="${a}"`);const f=`btn btn-sm btn-${o} ${c}`.trim();e.push(`
1525
+ `)}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:c="",permissions:d=null}=t;if(d&&!this.checkPermissions(d))return;const u=r?`<i class="${r} me-1"></i>`:"",p=`<span class="d-none d-lg-inline">${i}</span>`;let m="";n?m=`data-action="custom-toolbar-button" data-button-index="${s}"`:a&&(m=`data-action="${a}"`);const f=`btn btn-sm btn-${o} ${c}`.trim();e.push(`
1526
1526
  <button class="${f}"
1527
- ${p}
1527
+ ${m}
1528
1528
  title="${l}">
1529
- ${u}${m}
1529
+ ${u}${p}
1530
1530
  </button>
1531
1531
  `)}),e.join("")}buildSearchTemplate(){return`
1532
1532
  <div class="flex-grow-1" style="max-width: 400px;">
@@ -1577,7 +1577,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1577
1577
  <i class="bi bi-x-circle me-2"></i>Clear All Filters
1578
1578
  </button>
1579
1579
  `:""}
1580
- `}updateFilterPills(){const e=this.element?.querySelector('[data-container="filter-pills"]');if(!e)return;this.getActiveFilters();const t=this.buildActivePills();e.innerHTML=t}updateSearchInputs(e){const t=this.element?.querySelectorAll('[data-filter="search"]');t&&t.forEach(s=>{s.value=e||""})}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}=se(n),c=this.getFilterLabel(l),d=pt(n,o,c);return`
1580
+ `}updateFilterPills(){const e=this.element?.querySelector('[data-container="filter-pills"]');if(!e)return;this.getActiveFilters();const t=this.buildActivePills();e.innerHTML=t}updateSearchInputs(e){const t=this.element?.querySelectorAll('[data-filter="search"]');t&&t.forEach(s=>{s.value=e||""})}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}=se(n),c=this.getFilterLabel(l),d=mt(n,o,c);return`
1581
1581
  <span class="badge bg-primary me-1 mb-1 py-1 px-2 position-relative" style="font-size: 0.75rem;">
1582
1582
  <i class="bi bi-filter me-1" style="font-size: 0.65rem;"></i>
1583
1583
 
@@ -1640,9 +1640,9 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1640
1640
  </a></li>
1641
1641
  </ul>
1642
1642
  </div>
1643
- `:"";e+=`
1644
- <th class="${i?"sortable":""} ${o}">
1645
- <div class="d-flex align-items-center">
1643
+ `:"",c=this.getAlignClass(t.align);e+=`
1644
+ <th class="${i?"sortable":""} ${o} ${c}">
1645
+ <div class="d-flex align-items-center ${c==="text-center"?"justify-content-center":c==="text-end"?"justify-content-end":""}">
1646
1646
  <span>${n}</span>
1647
1647
  ${l}
1648
1648
  </div>
@@ -1653,7 +1653,7 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1653
1653
  ${e}
1654
1654
  </tr>
1655
1655
  </thead>
1656
- `}buildTableFooterTemplate(){let e="";this.isSelectable()&&(e+="<td></td>");let t=0;return this.columns.forEach((s,i)=>{const r=this.getResponsiveClasses(s.visibility);if(s.footer_total){const a=`col_${t}`,n=this.parseColumnKey(s.key).formatter||s.formatter;let o;n&&typeof n=="string"?o=`{{{footerTotals.${a}.value|${n}}}}`:o=`{{footerTotals.${a}.value}}`,e+=`<td class="table-footer-total ${r}" data-total-column="${a}">${o}</td>`,t++}else i===0?e+=`<td class="table-footer-label ${r}"><strong>Totals</strong></td>`:e+=`<td class="${r}"></td>`}),(this.actions||this.contextMenu)&&(e+="<td></td>"),`
1656
+ `}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>"),`
1657
1657
  <tfoot>
1658
1658
  <tr class="table-totals-row">
1659
1659
  ${e}
@@ -1741,19 +1741,19 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1741
1741
  <i class="bi bi-chevron-left"></i>
1742
1742
  </a>
1743
1743
  </li>
1744
- `);const c=1,d=new Set([1,a]);for(let p=r-c;p<=r+c;p++)p>=1&&p<=a&&d.add(p);const u=Array.from(d).sort((p,f)=>p-f);let m=0;for(const p of u)m&&p-m>1&&l.push(`
1744
+ `);const c=1,d=new Set([1,a]);for(let m=r-c;m<=r+c;m++)m>=1&&m<=a&&d.add(m);const u=Array.from(d).sort((m,f)=>m-f);let p=0;for(const m of u)p&&m-p>1&&l.push(`
1745
1745
  <li class="page-item disabled"><span class="page-link">…</span></li>
1746
1746
  `),l.push(`
1747
- <li class="page-item ${p===r?"active":""}">
1748
- <a class="page-link" href="#" data-action="page" data-page="${p}">${p}</a>
1747
+ <li class="page-item ${m===r?"active":""}">
1748
+ <a class="page-link" href="#" data-action="page" data-page="${m}">${m}</a>
1749
1749
  </li>
1750
- `),m=p;l.push(`
1750
+ `),p=m;l.push(`
1751
1751
  <li class="page-item">
1752
1752
  <a class="page-link" href="#" data-action="page" data-page="${o}">
1753
1753
  <i class="bi bi-chevron-right"></i>
1754
1754
  </a>
1755
1755
  </li>
1756
- `),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("table:page",{page:n,event:e}),this.emit("params-changed")}async onChangePageSize(e,t){const s=parseInt(t.value);this.collection&&(this.collection.setParams({...this.collection.params,start:0,size:s}),this.collection.restEnabled&&await this.collection.fetch(),this.render()),this.emit("table:pagesize",{size:s,event:e}),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,c=o.config.startName||"dr_start",d=o.config.endName||"dr_end",u=o.config.fieldName||"dr_field";i[u]===l&&(i[c]||i[d])&&(r[l]={start:i[c]||"",end:i[d]||""},a.add(c),a.add(d),a.add(u))}}),Object.keys(i).forEach(o=>{a.has(o)||(r[o]=i[o])}),Object.keys(r).forEach(o=>{if(r.hasOwnProperty(o)){const l=`${o}__in`;r.hasOwnProperty(l)&&(delete r[o],r[l]=r[l])}}),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,lookup:r}=se(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 this.columns.forEach(t=>{if(t.filter){const{fieldKey:s}=this.parseColumnKey(t.key);e.push({key:s,label:t.filter.label||t.label||s,type:t.filter.type,config:t.filter})}}),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){const t=this.columns.find(s=>{const{fieldKey:i}=this.parseColumnKey(s.key);return i===e});if(t&&t.filter)return t.filter;if(this.additionalFilters&&Array.isArray(this.additionalFilters)){const s=this.additionalFilters.find(i=>(i.name||i.key)===e);if(s)return s}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)}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}getFilterIcon(e){return{text:"search",select:"funnel",date:"calendar",daterange:"calendar-range",number:"123",boolean:"toggle-on"}[e]||"filter"}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 w.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()}}buildFilterDialogField(e,t,s){const i={name:"filter_value",label:e.label,value:t,...e,placeholder:e.placeholder||e.placeHolder};if(e.type==="daterange"){if(i.startName=i.startName||"dr_start",i.endName=i.endName||"dr_end",i.fieldName=i.fieldName||"dr_field",i.format=i.format||"YYYY-MM-DD",i.displayFormat=i.displayFormat||"MMM DD, YYYY",i.separator=i.separator||" to ",i.label=i.label||"Date Range",t&&typeof t=="object"){const r=a=>{if(!a&&a!==0)return"";if(a instanceof Date&&!isNaN(a))return a.toISOString().slice(0,10);const n=String(a).trim();if(!n)return"";if(/^-?\d+$/.test(n)){const l=Number(n),c=n.length<=10?l*1e3:l,d=new Date(c);if(!isNaN(d))return d.toISOString().slice(0,10)}const o=new Date(n);return isNaN(o)?n:o.toISOString().slice(0,10)};i.startDate=r(t.start||t.from||t.begin||""),i.endDate=r(t.end||t.to||t.finish||"")}}else if(e.type==="multiselect"){let r=[];t&&(Array.isArray(t)?r=t:typeof t=="string"&&(r=t.split(",").map(a=>a.trim()).filter(a=>a))),i.value=r,!i.placeholder&&!i.placeHolder&&(e.placeholder||e.placeHolder?i.placeholder=e.placeholder||e.placeHolder:e.label&&(i.placeholder=`Select ${e.label}...`))}return i}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}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")}async onActionEditFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=se(s);let r=this.getFilterConfig(i)||this.getFilterConfig(s);const 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 c=r.startName||"dr_start",d=r.endName||"dr_end";o[c]=n.start||"",o[d]=n.end||""}const l=await w.form({title:`Edit ${this.getFilterLabel(i)} Filter`,size:"md",data:o,fields:[this.buildFilterDialogField(r,n,i)]});if(l){const c=this.extractFilterValue(r,l);this.setFilter(s,c),await this.applyFilters()}}async onActionRemoveFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=se(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;this.collection.params={start:s,size:i},r&&(this.collection.params.sort=r),this.updateSearchInputs(""),this.collection.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filters:clear"),this.emit("params-changed")}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()}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)}}function ft(){return typeof window>"u"?null:((!window.MOJO||typeof window.MOJO!="object")&&(window.MOJO={}),window.MOJO)}function gt(h){return h.__lite&&h.__lite.version||(h.WebApp=re,h.View=C,h.Page=ee,h.Router=oe,h.Model=W,h.Collection=Z,h.Rest=Y,h.FormBuilder=te,h.FormView=z,h.Dialog=S,h.ModalView=S,h.ProgressView=pe,h.ListView=Se,h.ListViewItem=ae,h.TableView=Oe,h.TableRow=xe,h.DataFormatter=_,h.MOJOUtils=$,h.__lite={version:"dev",build:"web-mojo.lite"},h.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}),h}const $e=ft();$e&&gt($e);class Fe extends C{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`
1756
+ `),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("table:page",{page:n,event:e}),this.emit("params-changed")}async onChangePageSize(e,t){const s=parseInt(t.value);this.collection&&(this.collection.setParams({...this.collection.params,start:0,size:s}),this.collection.restEnabled&&await this.collection.fetch(),this.render()),this.emit("table:pagesize",{size:s,event:e}),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,c=o.config.startName||"dr_start",d=o.config.endName||"dr_end",u=o.config.fieldName||"dr_field";i[u]===l&&(i[c]||i[d])&&(r[l]={start:i[c]||"",end:i[d]||""},a.add(c),a.add(d),a.add(u))}}),Object.keys(i).forEach(o=>{a.has(o)||(r[o]=i[o])}),Object.keys(r).forEach(o=>{if(r.hasOwnProperty(o)){const l=`${o}__in`;r.hasOwnProperty(l)&&(delete r[o],r[l]=r[l])}}),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,lookup:r}=se(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 this.columns.forEach(t=>{if(t.filter){const{fieldKey:s}=this.parseColumnKey(t.key);e.push({key:s,label:t.filter.label||t.label||s,type:t.filter.type,config:t.filter})}}),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){const t=this.columns.find(s=>{const{fieldKey:i}=this.parseColumnKey(s.key);return i===e});if(t&&t.filter)return t.filter;if(this.additionalFilters&&Array.isArray(this.additionalFilters)){const s=this.additionalFilters.find(i=>(i.name||i.key)===e);if(s)return s}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)}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}getFilterIcon(e){return{text:"search",select:"funnel",date:"calendar",daterange:"calendar-range",number:"123",boolean:"toggle-on"}[e]||"filter"}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 w.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()}}buildFilterDialogField(e,t,s){const i={name:"filter_value",label:e.label,value:t,...e,placeholder:e.placeholder||e.placeHolder};if(e.type==="daterange"){if(i.startName=i.startName||"dr_start",i.endName=i.endName||"dr_end",i.fieldName=i.fieldName||"dr_field",i.format=i.format||"YYYY-MM-DD",i.displayFormat=i.displayFormat||"MMM DD, YYYY",i.separator=i.separator||" to ",i.label=i.label||"Date Range",t&&typeof t=="object"){const r=a=>{if(!a&&a!==0)return"";if(a instanceof Date&&!isNaN(a))return a.toISOString().slice(0,10);const n=String(a).trim();if(!n)return"";if(/^-?\d+$/.test(n)){const l=Number(n),c=n.length<=10?l*1e3:l,d=new Date(c);if(!isNaN(d))return d.toISOString().slice(0,10)}const o=new Date(n);return isNaN(o)?n:o.toISOString().slice(0,10)};i.startDate=r(t.start||t.from||t.begin||""),i.endDate=r(t.end||t.to||t.finish||"")}}else if(e.type==="multiselect"){let r=[];t&&(Array.isArray(t)?r=t:typeof t=="string"&&(r=t.split(",").map(a=>a.trim()).filter(a=>a))),i.value=r,!i.placeholder&&!i.placeHolder&&(e.placeholder||e.placeHolder?i.placeholder=e.placeholder||e.placeHolder:e.label&&(i.placeholder=`Select ${e.label}...`))}return i}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}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")}async onActionEditFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=se(s);let r=this.getFilterConfig(i)||this.getFilterConfig(s);const 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 c=r.startName||"dr_start",d=r.endName||"dr_end";o[c]=n.start||"",o[d]=n.end||""}const l=await w.form({title:`Edit ${this.getFilterLabel(i)} Filter`,size:"md",data:o,fields:[this.buildFilterDialogField(r,n,i)]});if(l){const c=this.extractFilterValue(r,l);this.setFilter(s,c),await this.applyFilters()}}async onActionRemoveFilter(e,t){const s=t.getAttribute("data-filter"),{field:i}=se(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;this.collection.params={start:s,size:i},r&&(this.collection.params.sort=r),this.updateSearchInputs(""),this.collection.restEnabled&&await this.collection.fetch(),this.render(),this.updateFilterPills(),this.emit("filters:clear"),this.emit("params-changed")}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()}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)}}function ft(){return typeof window>"u"?null:((!window.MOJO||typeof window.MOJO!="object")&&(window.MOJO={}),window.MOJO)}function gt(h){return h.__lite&&h.__lite.version||(h.WebApp=re,h.View=C,h.Page=ee,h.Router=oe,h.Model=W,h.Collection=Z,h.Rest=Y,h.FormBuilder=te,h.FormView=z,h.Dialog=S,h.ModalView=S,h.ProgressView=me,h.ListView=Se,h.ListViewItem=ae,h.TableView=Oe,h.TableRow=xe,h.DataFormatter=_,h.MOJOUtils=$,h.__lite={version:"dev",build:"web-mojo.lite"},h.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}),h}const $e=ft();$e&&gt($e);class Fe extends C{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`
1757
1757
  <div class="${this.dataViewOptions.rowClass}">
1758
1758
  ${e}
1759
1759
  </div>
@@ -1801,5 +1801,5 @@ var MOJO=(function(A){"use strict";class oe{constructor(e={}){this.defaultRoute=
1801
1801
  ${i}
1802
1802
  </div>
1803
1803
  </div>
1804
- `}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?_.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 Fe(e)}}const bt=Object.freeze(Object.defineProperty({__proto__:null,default:Fe},Symbol.toStringTag,{value:"Module"}));return A.Collection=Z,A.DataFormatter=_,A.Dialog=S,A.FormBuilder=te,A.FormPage=mt,A.FormView=z,A.ListView=Se,A.ListViewItem=ae,A.MOJOUtils=$,A.ModalView=S,A.Model=W,A.Page=ee,A.ProgressView=pe,A.Rest=Y,A.Router=oe,A.TableRow=xe,A.TableView=Oe,A.View=C,A.WebApp=re,A.default=$e,Object.defineProperties(A,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),A})({});
1804
+ `}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?_.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 Fe(e)}}const bt=Object.freeze(Object.defineProperty({__proto__:null,default:Fe},Symbol.toStringTag,{value:"Module"}));return A.Collection=Z,A.DataFormatter=_,A.Dialog=S,A.FormBuilder=te,A.FormPage=pt,A.FormView=z,A.ListView=Se,A.ListViewItem=ae,A.MOJOUtils=$,A.ModalView=S,A.Model=W,A.Page=ee,A.ProgressView=me,A.Rest=Y,A.Router=oe,A.TableRow=xe,A.TableView=Oe,A.View=C,A.WebApp=re,A.default=$e,Object.defineProperties(A,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}}),A})({});
1805
1805
  //# sourceMappingURL=web-mojo.lite.iife.min.js.map