web-mojo 2.3.7 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -0
- package/dist/admin-models.cjs.js +1 -1
- package/dist/admin-models.es.js +1 -1
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.es.js +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.es.js +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +1 -1
- package/dist/chunks/{AssistantPanelView-B5tMna_t.js → AssistantPanelView-C2UrR8N7.js} +2 -2
- package/dist/chunks/{AssistantPanelView-B5tMna_t.js.map → AssistantPanelView-C2UrR8N7.js.map} +1 -1
- package/dist/chunks/{AssistantPanelView-BOdIQuqK.js → AssistantPanelView-DVeXmhzx.js} +2 -2
- package/dist/chunks/{AssistantPanelView-BOdIQuqK.js.map → AssistantPanelView-DVeXmhzx.js.map} +1 -1
- package/dist/chunks/{ChatView-BquP2SP_.js → ChatView-B0xHv7Nq.js} +2 -2
- package/dist/chunks/{ChatView-BquP2SP_.js.map → ChatView-B0xHv7Nq.js.map} +1 -1
- package/dist/chunks/{ChatView-rWg4ZSJy.js → ChatView-CUmRTKna.js} +2 -2
- package/dist/chunks/{ChatView-rWg4ZSJy.js.map → ChatView-CUmRTKna.js.map} +1 -1
- package/dist/chunks/{Collection-CtSGTegm.js → Collection-7F3lsq4z.js} +2 -2
- package/dist/chunks/{Collection-CtSGTegm.js.map → Collection-7F3lsq4z.js.map} +1 -1
- package/dist/chunks/{Collection-BtSHP_BV.js → Collection-Cgxbmj8G.js} +2 -2
- package/dist/chunks/{Collection-BtSHP_BV.js.map → Collection-Cgxbmj8G.js.map} +1 -1
- package/dist/chunks/{ContextMenu-DvQTJA49.js → ContextMenu-Ba4fjHxg.js} +2 -2
- package/dist/chunks/{ContextMenu-DvQTJA49.js.map → ContextMenu-Ba4fjHxg.js.map} +1 -1
- package/dist/chunks/{ContextMenu-0KtfqyQm.js → ContextMenu-afYD0lFk.js} +2 -2
- package/dist/chunks/{ContextMenu-0KtfqyQm.js.map → ContextMenu-afYD0lFk.js.map} +1 -1
- package/dist/chunks/{DataView-jHxX-6Gh.js → DataView-DFGIE3wK.js} +2 -2
- package/dist/chunks/{DataView-jHxX-6Gh.js.map → DataView-DFGIE3wK.js.map} +1 -1
- package/dist/chunks/{DataView-DJMOmlKN.js → DataView-fA6qQbvN.js} +2 -2
- package/dist/chunks/{DataView-DJMOmlKN.js.map → DataView-fA6qQbvN.js.map} +1 -1
- package/dist/chunks/FormView-CgnaTPkQ.js +2 -0
- package/dist/chunks/FormView-CgnaTPkQ.js.map +1 -0
- package/dist/chunks/FormView-LRb8scDI.js +2 -0
- package/dist/chunks/FormView-LRb8scDI.js.map +1 -0
- package/dist/chunks/{ListView-mr1Kmuj-.js → ListView-Cu6iQ0aG.js} +2 -2
- package/dist/chunks/{ListView-mr1Kmuj-.js.map → ListView-Cu6iQ0aG.js.map} +1 -1
- package/dist/chunks/{ListView-CjJ-4gD7.js → ListView-Dsezts8J.js} +2 -2
- package/dist/chunks/{ListView-CjJ-4gD7.js.map → ListView-Dsezts8J.js.map} +1 -1
- package/dist/chunks/{MetricsCountryMapView-D9J4Gwdi.js → MetricsCountryMapView-BkLDonK4.js} +2 -2
- package/dist/chunks/{MetricsCountryMapView-D9J4Gwdi.js.map → MetricsCountryMapView-BkLDonK4.js.map} +1 -1
- package/dist/chunks/{MetricsCountryMapView-BIsfmvE0.js → MetricsCountryMapView-BsJoEsUE.js} +2 -2
- package/dist/chunks/{MetricsCountryMapView-BIsfmvE0.js.map → MetricsCountryMapView-BsJoEsUE.js.map} +1 -1
- package/dist/chunks/{Modal-DYJadSN8.js → Modal-BRKy85bz.js} +3 -3
- package/dist/chunks/{Modal-DYJadSN8.js.map → Modal-BRKy85bz.js.map} +1 -1
- package/dist/chunks/{Modal-DF98u_sN.js → Modal-DKjxtaZI.js} +3 -3
- package/dist/chunks/{Modal-DF98u_sN.js.map → Modal-DKjxtaZI.js.map} +1 -1
- package/dist/chunks/{Passkeys-Dx5bduZJ.js → Passkeys-CMh9iSax.js} +2 -2
- package/dist/chunks/{Passkeys-C1m6avHh.js.map → Passkeys-CMh9iSax.js.map} +1 -1
- package/dist/chunks/{Passkeys-C1m6avHh.js → Passkeys-DF7mRGYj.js} +2 -2
- package/dist/chunks/{Passkeys-Dx5bduZJ.js.map → Passkeys-DF7mRGYj.js.map} +1 -1
- package/dist/chunks/{TokenManager-B-xR8zPl.js → TokenManager-CVR3ENIS.js} +2 -2
- package/dist/chunks/{TokenManager-B-xR8zPl.js.map → TokenManager-CVR3ENIS.js.map} +1 -1
- package/dist/chunks/{TokenManager-CZTL4OqZ.js → TokenManager-CWRL33UM.js} +2 -2
- package/dist/chunks/{TokenManager-CZTL4OqZ.js.map → TokenManager-CWRL33UM.js.map} +1 -1
- package/dist/chunks/{User-DRbw-wOB.js → User-BmS8zImI.js} +2 -2
- package/dist/chunks/{User-DRbw-wOB.js.map → User-BmS8zImI.js.map} +1 -1
- package/dist/chunks/{User-C6Tbn6vZ.js → User-CayBjzMG.js} +2 -2
- package/dist/chunks/{User-C6Tbn6vZ.js.map → User-CayBjzMG.js.map} +1 -1
- package/dist/chunks/{UserProfileView-CJKQNzSj.js → UserProfileView-B56WeGL1.js} +2 -2
- package/dist/chunks/{UserProfileView-CJKQNzSj.js.map → UserProfileView-B56WeGL1.js.map} +1 -1
- package/dist/chunks/{UserProfileView-AhUCUowp.js → UserProfileView-CrmACQjJ.js} +2 -2
- package/dist/chunks/{UserProfileView-AhUCUowp.js.map → UserProfileView-CrmACQjJ.js.map} +1 -1
- package/dist/chunks/{View-BWOE7WJm.js → View-IgBQlwd0.js} +2 -2
- package/dist/chunks/{View-BWOE7WJm.js.map → View-IgBQlwd0.js.map} +1 -1
- package/dist/chunks/{View-D6Ug7M6k.js → View-gAghvPMN.js} +2 -2
- package/dist/chunks/{View-D6Ug7M6k.js.map → View-gAghvPMN.js.map} +1 -1
- package/dist/chunks/{WebApp-By80XfTK.js → WebApp-B6wrmIaj.js} +2 -2
- package/dist/chunks/{WebApp-By80XfTK.js.map → WebApp-B6wrmIaj.js.map} +1 -1
- package/dist/chunks/{WebApp-CLTFSbto.js → WebApp-DeHPnmbD.js} +2 -2
- package/dist/chunks/{WebApp-CLTFSbto.js.map → WebApp-DeHPnmbD.js.map} +1 -1
- package/dist/chunks/{admin-D2CqCMaa.js → admin-D3DtCOgt.js} +2 -2
- package/dist/chunks/{admin-D2CqCMaa.js.map → admin-D3DtCOgt.js.map} +1 -1
- package/dist/chunks/{admin-Beq0Eckn.js → admin-oYYbqLlb.js} +2 -2
- package/dist/chunks/{admin-Beq0Eckn.js.map → admin-oYYbqLlb.js.map} +1 -1
- package/dist/chunks/{exportChart-DqydcfXz.js → exportChart-BK9mLt36.js} +2 -2
- package/dist/chunks/{exportChart-DqydcfXz.js.map → exportChart-BK9mLt36.js.map} +1 -1
- package/dist/chunks/{exportChart-Cn6owWxP.js → exportChart-mrfTf2Df.js} +2 -2
- package/dist/chunks/{exportChart-Cn6owWxP.js.map → exportChart-mrfTf2Df.js.map} +1 -1
- package/dist/chunks/{index-BKR6vFMH.js → index-DTXotoXw.js} +2 -2
- package/dist/chunks/{index-BKR6vFMH.js.map → index-DTXotoXw.js.map} +1 -1
- package/dist/chunks/{index-CMKYMKaH.js → index-NXnA6T-5.js} +2 -2
- package/dist/chunks/{index-CMKYMKaH.js.map → index-NXnA6T-5.js.map} +1 -1
- package/dist/chunks/{version-DQwtLRjN.js → version-Bpfg5FM3.js} +2 -2
- package/dist/chunks/{version-DQwtLRjN.js.map → version-Bpfg5FM3.js.map} +1 -1
- package/dist/chunks/{version-CBjwNXEK.js → version-CopJeO_u.js} +2 -2
- package/dist/chunks/{version-CBjwNXEK.js.map → version-CopJeO_u.js.map} +1 -1
- package/dist/css/web-mojo.css +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.es.js.map +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +1 -1
- package/dist/map.cjs.js +1 -1
- package/dist/map.es.js +1 -1
- package/dist/timeline.cjs.js +1 -1
- package/dist/timeline.es.js +1 -1
- package/dist/user-profile.cjs.js +1 -1
- package/dist/user-profile.es.js +1 -1
- package/dist/web-mojo.lite.iife.js +3507 -1562
- package/dist/web-mojo.lite.iife.js.map +1 -1
- package/dist/web-mojo.lite.iife.min.js +261 -327
- package/dist/web-mojo.lite.iife.min.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/FormView-C_7xQuI4.js +0 -3
- package/dist/chunks/FormView-C_7xQuI4.js.map +0 -1
- package/dist/chunks/FormView-D8YrH2V4.js +0 -3
- package/dist/chunks/FormView-D8YrH2V4.js.map +0 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{V as e}from"./View-
|
|
2
|
-
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 ProgressView extends e{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=t.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=!1!==e.showCancel,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return'\n <div class="progress-view">\n <div class="d-flex justify-content-between align-items-start mb-2">\n <div class="flex-grow-1 min-width-0">\n <div class="fw-medium text-truncate" title="{{filename}}">\n <i class="bi bi-file-earmark me-1"></i>\n {{filename}}\n </div>\n <small class="text-muted">{{status}}</small>\n </div>\n {{#showCancel}}\n <button type="button" \n class="btn btn-sm btn-outline-secondary ms-2" \n data-action="cancel"\n {{#cancelled}}disabled{{/cancelled}}>\n <i class="bi bi-x"></i>\n </button>\n {{/showCancel}}\n </div>\n \n <div class="progress mb-2" style="height: 8px;">\n <div class="progress-bar" \n role="progressbar" \n style="width: {{percentage}}%"\n aria-valuenow="{{percentage}}" \n aria-valuemin="0" \n aria-valuemax="100">\n </div>\n </div>\n \n <div class="d-flex justify-content-between">\n <small class="text-muted">\n {{loadedFormatted}} / {{totalFormatted}}\n </small>\n <small class="text-muted">\n {{percentage}}%\n </small>\n </div>\n </div>\n '}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=t.pipe(this.loaded,"filesize"),this.totalFormatted=t.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,i){if(!this.cancelled&&!this.completed&&(i.disabled=!0,this.markCancelled(),this.emit("cancel"),"function"==typeof this.onCancel))try{await this.onCancel()}catch(o){console.error("Error in cancel callback:",o)}}setFilename(e){this.filename=e,this.render()}setFilesize(e){this.filesize=e,this.filesizeFormatted=t.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 FileUpload{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 ToastService),this.promise=this._startUpload()}async _startUpload(){try{let t,i,o;this.options.showToast&&this._showProgressToast();try{t=await this._initiateUpload()}catch(e){throw new Error(`Failed to initiate upload: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");if(!t||!t.upload_url)throw new Error("Invalid upload response: missing upload URL");if("string"==typeof t.upload_url)i={url:t.upload_url,method:"PUT",fields:null,headers:{}};else{if(!t.upload_url||"object"!=typeof t.upload_url||!t.upload_url.upload_url)throw new Error(`Invalid upload response: unrecognised upload_url format. Server returned: ${JSON.stringify(t.upload_url)}`);i={url:t.upload_url.upload_url,method:t.upload_url.method||"POST",fields:t.upload_url.fields||null,headers:t.upload_url.headers||{}}}try{o=await this._performUpload(i)}catch(e){throw new Error(`File upload failed: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");try{await this._completeUpload()}catch(e){console.warn("Failed to mark upload as completed:",e)}return this._onComplete(this.fileModel),this.fileModel}catch(e){throw"Upload cancelled"!==e.message&&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 e=t.data.error||"Upload initiation failed";throw new Error(e)}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){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload initiation. Please check your connection.");throw e}}async _performUpload(e){return new Promise((t,i)=>{if(!(this.options.file instanceof File))return void i(new Error("Only single File objects are supported"));const{url:o,method:s,fields:n,headers:a}=e,r="POST"===s&&null!==n,l=new XMLHttpRequest;this.uploadRequest=l,l.upload.onprogress=e=>{this.cancelled||this._onProgress({progress:e.loaded/e.total,loaded:e.loaded,total:e.total,percentage:Math.round(e.loaded/e.total*100)})},l.onload=()=>{l.status>=200&&l.status<300?t({data:l.response,status:l.status,statusText:l.statusText,xhr:l}):i(new Error(`Upload failed: ${l.status} ${l.statusText}`))},l.onerror=()=>i(new Error("Upload failed: Network error")),l.ontimeout=()=>i(new Error("Upload timed out — file may be too large or connection too slow")),l.onabort=()=>i(new Error("Upload cancelled"));let d=o;o.startsWith("/")&&!o.startsWith("/api/")&&(d="/api"+o);const c=this.fileModel.rest.buildUrl(d);if(l.open(s,c),l.timeout=3e4,r){for(const[t,i]of Object.entries(a||{}))"content-type"!==t.toLowerCase()&&l.setRequestHeader(t,i);const e=new FormData;for(const[t,i]of Object.entries(n))e.append(t,i);e.append("file",this.options.file),l.send(e)}else{l.setRequestHeader("Content-Type",this.options.file.type);for(const[e,t]of Object.entries(a||{}))"content-type"!==e.toLowerCase()&&l.setRequestHeader(e,t);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){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload completion. The file may have uploaded successfully.");throw e}}_onProgress(e){this.progressToast&&this.progressToast.updateProgress&&this.progressToast.updateProgress(e),"function"==typeof this.options.onProgress&&this.options.onProgress(e)}_onComplete(e){this.progressView&&this.progressView.markCompleted("Upload completed successfully!"),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast:",e)}},2e3),"function"==typeof this.options.onComplete&&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}`),"function"==typeof this.options.onError&&this.options.onError(e)}_showProgressToast(){this.progressView=new ProgressView({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&&(this.cancelled=!0,this.uploadRequest&&"function"==typeof this.uploadRequest.abort&&this.uploadRequest.abort(),this.progressView&&this.progressView.markCancelled(),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&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 FileManager extends i{constructor(e={}){super(e,{endpoint:"/api/fileman/manager"})}}class FileManagerList extends o{constructor(e={}){super({ModelClass:FileManager,endpoint:"/api/fileman/manager",size:10,...e})}}const a={create:{title:"Add Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,value:"s3://BUCKET_NAME/OPTION_FOLDER",placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6}]},edit:{title:"Edit Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"allowed_origins",type:"text",label:"Domains Who Can Upload",cols:12},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6},{name:"is_public",type:"switch",label:"Is Public",default:!0,cols:6}]},owners:{fields:[{type:"collection",name:"group",label:"Group (Owner)",Collection:s,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300},{type:"collection",name:"user",label:"User (Owner)",Collection:n,labelField:"display_name",valueField:"id",maxItems:10,placeholder:"Search users...",emptyFetch:!1,debounceMs:300}]},credentials:{fields:[{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"}]}};let r=class extends i{constructor(e={}){super(e,{endpoint:"/api/fileman/file"})}isImage(){return"image"===this.get("category")}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":"application/pdf"===e?"pdf":e.startsWith("text/")||"application/msword"===e||e.startsWith("application/vnd.openxmlformats-officedocument.wordprocessingml")||"application/vnd.oasis.opendocument.text"===e?"document":"application/vnd.ms-excel"===e||e.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml")||"application/vnd.oasis.opendocument.spreadsheet"===e?"spreadsheet":"application/vnd.ms-powerpoint"===e||e.startsWith("application/vnd.openxmlformats-officedocument.presentationml")||"application/vnd.oasis.opendocument.presentation"===e?"presentation":"application/zip"===e||"application/x-rar-compressed"===e||"application/x-7z-compressed"===e||"application/x-tar"===e||"application/gzip"===e?"archive":"other":"other"}hasRenditions(){const e=this.get("renditions");return!(!e||!Object.keys(e).length)}isUploadPending(){const e=this.get("upload_status");return!(!e||"completed"===e||"failed"===e)}regenerateRenditions(e){const t=this.id||this.get("id");if(!t)return Promise.reject(new Error("Cannot regenerate renditions on an unsaved file"));const i=Array.isArray(e)&&e.length?{regenerate_renditions:e}:{regenerate_renditions:!0};return this.rest.POST(`${this.endpoint}/${t}`,i)}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(e=>e&&"string"==typeof e.content_type&&e.content_type.startsWith("image/"));return e.length?e.reduce((e,t)=>{const i=(parseInt(e.width)||0)*(parseInt(e.height)||0);return(parseInt(t.width)||0)*(parseInt(t.height)||0)>i?t:e}):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 FileUpload(this,e)}};class FileList extends o{constructor(e={}){super({ModelClass:r,endpoint:"/api/fileman/file",size:10,...e})}}const l={create:{title:"Add File",fields:[]},edit:{title:"Edit File Backend",fields:[]}};class ModalView extends e{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:ModalView._baseZIndex}static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=ModalView._openDialogs;if(0===e.length||0===t.length)return;const i=[...t].sort((e,t)=>(e._dialogZIndex||0)-(t._dialogZIndex||0)),o=document.querySelector(".table-fullscreen")||document.body;e.forEach((e,t)=>{if(t>=i.length)return;const s=i[t];e.style.zIndex=s._dialogZIndex-5,e.parentNode!==o&&o.appendChild(e)})}static updateAllBackdropStacking(){ModalView.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 ${!1!==e.fade?"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=void 0!==e.centered&&e.centered,this.scrollable=void 0!==e.scrollable&&e.scrollable,this.autoSize=e.autoSize||"auto"===e.size,this.backdrop=void 0===e.backdrop||e.backdrop,this.keyboard=void 0===e.keyboard||e.keyboard,this.focus=void 0===e.focus||e.focus,this.header=void 0===e.header||e.header,this.headerContent=e.headerContent||null,this.headerView=null,this.closeButton=void 0===e.closeButton||e.closeButton,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=void 0!==e.autoShow&&e.autoShow,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(t){if(t instanceof e||t&&"object"==typeof t&&"function"==typeof t.render)this.bodyView=t,this.body="",this.addChild(this.bodyView);else if("function"==typeof t)try{const i=t();i instanceof e?(this.bodyView=i,this.body="",this.addChild(this.bodyView)):i instanceof Promise?(this.bodyPromise=i,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=i}catch(i){console.error("ModalView: error processing body function:",i),this.body=t}else this.body=t}_processHeaderContent(t){if(t instanceof e)this.headerView=t,this.headerContent=null,this.addChild(this.headerView);else if("function"==typeof t)try{const i=t();i instanceof e?(this.headerView=i,this.headerContent=null,this.addChild(this.headerView)):i instanceof Promise?(this.headerPromise=i,this.headerContent='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.headerContent=i}catch(i){console.error("ModalView: error processing headerContent function:",i),this.headerContent=t}else this.headerContent=t}_processFooterContent(t){if(t instanceof e)this.footerView=t,this.footer=null,this.addChild(this.footerView);else if("function"==typeof t)try{const i=t();i instanceof e?(this.footerView=i,this.footer=null,this.addChild(this.footerView)):i instanceof Promise?(this.footerPromise=i,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=i}catch(i){console.error("ModalView: error processing footer function:",i),this.footer=t}else this.footer=t}async getTemplate(){const e=["modal-dialog"];return this.size&&"auto"!==this.size&&(this.size.startsWith("fullscreen")?e.push(`modal-${this.size}`):["sm","lg","xl","xxl"].includes(this.size)&&(e.push(`modal-${this.size}`),["lg","xl","xxl"].includes(this.size)&&e.push("modal-fullscreen-sm-down"))),this.centered&&e.push("modal-dialog-centered"),this.scrollable&&(this.maxHeight?e.push("overflow-hidden"):e.push("modal-dialog-scrollable")),`\n <div class="${e.join(" ")}">\n <div class="modal-content">\n ${await this.buildHeader()}\n ${await this.buildBody()}\n ${await this.buildFooter()}\n </div>\n </div>\n `}async buildHeader(){if(!this.header)return"";if(this.headerView)return this.headerView.replaceById=!0,`<div class="modal-header" data-view-container="header">\n <div id="${this.headerView.id}"></div>\n </div>`;if(this.headerContent)return`<div class="modal-header">${this.headerContent}</div>`;let e="";return this.contextMenu&&this.contextMenu.items&&this.contextMenu.items.length>0?e=await this.buildContextMenu():this.closeButton&&(e='<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>'),`\n <div class="modal-header">\n ${this.title?`<h5 class="modal-title" id="${this.titleId}">${this.title}</h5>`:""}\n ${e}\n </div>\n `}async buildContextMenu(){const e=await this.filterContextMenuItems();if(0===e.length)return this.closeButton?'<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>':"";const t=this.contextMenu.icon||"bi-three-dots-vertical";return`\n <div class="dropdown">\n <button class="${this.contextMenu.buttonClass||"btn btn-link p-1 mojo-modal-context-menu-btn"}" type="button" data-bs-toggle="dropdown" aria-expanded="false">\n <i class="${t}"></i>\n </button>\n <ul class="dropdown-menu dropdown-menu-end">\n ${e.map(e=>{if("divider"===e.type)return'<li><hr class="dropdown-divider"></li>';const t=e.icon?`<i class="${e.icon} me-2"></i>`:"",i=e.label||"";if(e.href)return`<li><a class="dropdown-item" href="${e.href}"${e.target?` target="${e.target}"`:""}>${t}${i}</a></li>`;if(e.action){const o=Object.keys(e).filter(e=>e.startsWith("data-")).map(t=>`${t}="${e[t]}"`).join(" ");return`<li><a class="dropdown-item" data-action="${e.action}" ${o}>${t}${i}</a></li>`}return""}).join("")}\n </ul>\n </div>\n `}async filterContextMenuItems(){if(!this.contextMenu||!this.contextMenu.items)return[];const e=[];for(const i of this.contextMenu.items)if("divider"!==i.type){if(i.permissions)try{const e=this.getApp?.();let t=e?.activeUser||e?.getState?.("activeUser")||null;if(!t&&"undefined"!=typeof window&&window.getApp)try{t=window.getApp()?.activeUser}catch{}if(!t?.hasPermission)continue;if(!t.hasPermission(i.permissions))continue}catch(t){console.warn("ModalView: error checking permissions for context menu item:",t);continue}e.push(i)}else e.push(i);return e}async buildBody(){const e=`modal-body ${this.noBodyPadding?"modal-body-flush":""} ${this.bodyClass}`.replace(/\s+/g," ").trim();return this.bodyView?(this.bodyView.replaceById=!0,`<div class="${e}" data-view-container="body">\n <div id="${this.bodyView.id}"></div>\n </div>`):this.body||""===this.body?`<div class="${e}">${this.body}</div>`:""}async buildFooter(){if(this.footerView)return`<div class="modal-footer ${this.footerClass}" data-view-container="footer"></div>`;if(null!==this.footer&&"string"==typeof this.footer)return`<div class="modal-footer ${this.footerClass}">${this.footer}</div>`;if(this.buttons&&this.buttons.length>0){const e=this.buttons.map(e=>{const t=e.dismiss?'data-bs-dismiss="modal"':"",i=e.action?`data-action="${e.action}"`:"",o=e.id?`id="${e.id}"`:"",s=e.disabled?"disabled":"";return`\n <button type="${e.type||"button"}"\n class="btn ${e.class||"btn-secondary"}"\n ${o} ${t} ${i} ${s}>\n ${e.icon?`<i class="bi ${e.icon} me-1"></i>`:""}\n ${e.text||"Button"}\n </button>\n `}).join("");return`<div class="modal-footer ${this.footerClass}">${e}</div>`}return""}async mount(e=null){if(!this.mounted&&!this.destroyed){if(!this.element)throw new Error("Cannot mount modal without element");return await this.onBeforeMount(),ModalView.getMountTarget().appendChild(this.element),this.bindEvents(),this.mounted=!0,await this.onAfterMount(),this.emit("mounted",{view:this}),this}}async onAfterRender(){if(await super.onAfterRender(),window.Prism&&this.element&&this.element.querySelectorAll("pre code").length>0&&window.Prism.highlightAllUnder(this.element),this.autoSize)this.setupAutoSizing();else if(this.maxHeight){const e=this.element.querySelector(".modal-body");e&&(e.style.maxHeight=`${this.maxHeight}px`)}}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof window&&window.bootstrap?.Modal&&("static"===this.backdrop&&this.element.setAttribute("data-bs-backdrop","static"),this.keyboard||this.element.setAttribute("data-bs-keyboard","false"),this.modal=new window.bootstrap.Modal(this.element,{backdrop:this.backdrop,keyboard:this.keyboard,focus:this.focus}),this.bindBootstrapEvents(),this.autoShow&&this.show(this.relatedTarget))}setupAutoSizing(){this.element&&(this.element.addEventListener("shown.bs.modal",()=>{this.applyAutoSizing()},{once:!0}),setTimeout(()=>{this.isShown()&&this.applyAutoSizing()},100))}applyAutoSizing(){if(this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),i=this.element.querySelector(".modal-body");if(!e||!t||!i)return void console.warn("ModalView auto-sizing: required elements not found");if(this.bodyView&&!this.bodyView.element)return void setTimeout(()=>this.applyAutoSizing(),50);const o={dialogMaxWidth:e.style.maxWidth,dialogWidth:e.style.width,contentWidth:t.style.width,contentMaxHeight:t.style.maxHeight,hadScrollableClass:e.classList.contains("modal-dialog-scrollable")};e.style.maxWidth="none",e.style.width="auto",t.style.width="auto",t.style.maxHeight="none",t.offsetHeight;const s=t.getBoundingClientRect(),n=40,a=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-n);let r=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-n),l=Math.max(this.minWidth,Math.ceil(s.width+20)),d=Math.max(this.minHeight,Math.ceil(s.height));this.maxHeight&&(r=Math.min(this.maxHeight,r),e.style.maxHeight=`${r}px`),l=Math.min(l,a);const c=s.height>r;e.style.maxWidth=`${l}px`,e.style.width=`${l}px`,c&&(e.classList.contains("modal-dialog-scrollable")||e.classList.add("modal-dialog-scrollable"),t.style.maxHeight=`${r}px`,d=r),this.autoSizedWidth=l,this.autoSizedHeight=d,this._originalStyles=o}catch(e){console.error("ModalView: error in auto-sizing:",e);const t=this.element?.querySelector(".modal-dialog");t&&(t.style.maxWidth="")}}resetAutoSizing(){if(this.autoSize&&this._originalStyles&&this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),i=this.element.querySelector(".modal-body");e&&t&&i&&(e.style.maxWidth=this._originalStyles.dialogMaxWidth||"",e.style.width=this._originalStyles.dialogWidth||"",t.style.width=this._originalStyles.contentWidth||"",t.style.maxHeight=this._originalStyles.contentMaxHeight||"",!this._originalStyles.hadScrollableClass&&e.classList.contains("modal-dialog-scrollable")&&e.classList.remove("modal-dialog-scrollable"),delete this.autoSizedWidth,delete this.autoSizedHeight,delete this._originalStyles)}catch(e){console.error("ModalView: error resetting auto-sizing:",e)}}bindBootstrapEvents(){this.element.addEventListener("show.bs.modal",e=>{const t=ModalView._openDialogs.length,i=ModalView.getFullscreenAwareZIndex().modal+20*t;this.element.style.zIndex=i,this._dialogZIndex=i,this._backdropZIndex=i-10,ModalView._openDialogs.push(this),this.onShow&&this.onShow(e),this.emit("show",{dialog:this,relatedTarget:e.relatedTarget})}),this.element.addEventListener("shown.bs.modal",e=>{if(setTimeout(()=>ModalView.fixAllBackdropStacking(),50),this.onShown&&this.onShown(e),this.emit("shown",{dialog:this,relatedTarget:e.relatedTarget}),this.focus){const e=this.element.querySelector('input:not([type="hidden"]), textarea, select');e&&e.focus()}}),this.element.addEventListener("hide.bs.modal",e=>{const t=this.element.querySelector(":focus");t&&t.blur(),this.onHide&&!1===this.onHide(e)?e.preventDefault():this.emit("hide",{dialog:this})}),this.element.addEventListener("hidden.bs.modal",e=>{const t=ModalView._openDialogs.indexOf(this);t>-1&&ModalView._openDialogs.splice(t,1),ModalView._openDialogs.length>0&&(document.body.classList.add("modal-open"),setTimeout(()=>ModalView.fixAllBackdropStacking(),50)),this.previousFocus&&document.body.contains(this.previousFocus)&&this.previousFocus.focus(),this.onHidden&&this.onHidden(e),this.emit("hidden",{dialog:this})}),this.element.addEventListener("hidePrevented.bs.modal",e=>{this.onHidePrevented&&this.onHidePrevented(e),this.emit("hidePrevented",{dialog:this})})}show(e=null){this.previousFocus=document.activeElement,window.lastDialog=this,this.modal&&this.modal.show(e)}hide(){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal&&this.modal.hide()}toggle(e=null){this.modal&&this.modal.toggle(e)}isShown(){return this.element?.classList.contains("show")||!1}getModal(){return this.modal}handleUpdate(){this.modal&&this.modal.handleUpdate()}async setContent(t){if(t instanceof e){this.bodyView&&(await this.bodyView.destroy(),this.removeChild(this.bodyView)),this.bodyView=t,this.body="",this.addChild(this.bodyView);const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML="",await this.bodyView.render(e))}else{this.body=t;const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML=t)}this.handleUpdate()}setTitle(e){this.title=e;const t=this.element?.querySelector(".modal-title");t&&(t.textContent=e)}setLoading(e=!0,t="Loading..."){const i=this.element?.querySelector(".modal-body");i&&(e?i.innerHTML=`\n <div class="text-center py-4">\n <div class="spinner-border text-primary mb-3" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p>${t}</p>\n </div>\n `:this.bodyView&&i.replaceChildren(this.bodyView.element))}async destroy(){if(this.modal){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal.dispose(),this.modal=null}this.previousFocus&&document.body.contains(this.previousFocus)&&(this.previousFocus.focus(),this.previousFocus=null),this.autoSize&&this.resetAutoSizing(),await super.destroy()}async onBeforeDestroy(){this.headerView&&await this.headerView.destroy(),this.bodyView&&await this.bodyView.destroy(),this.footerView&&await this.footerView.destroy(),await super.onBeforeDestroy(),this.modal&&(this.modal.dispose(),this.modal=null)}}let d=null,c=0,h=null;const u={show(e){"string"==typeof e&&(e={message:e});const{message:t="Loading...",timeout:i=3e4}=e||{};if(c++,1===c){h&&clearTimeout(h);const e=ModalView.getFullscreenAwareZIndex().modal+1e3;d||(d=document.createElement("div"),d.className="mojo-loading-overlay",d.innerHTML=`\n <div class="mojo-loading-card">\n <div class="mojo-loading-spinner"></div>\n <div class="mojo-loading-message">${t}</div>\n </div>\n <style>\n .mojo-loading-overlay {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background: rgba(255, 255, 255, 0.4);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.2s ease;\n }\n .mojo-loading-overlay.show { opacity: 1; }\n .mojo-loading-card {\n display: flex; align-items: center; gap: 0.85rem;\n background: #fff;\n border: 1px solid #e9ecef;\n border-radius: 12px;\n padding: 1rem 1.5rem;\n box-shadow: 0 4px 24px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);\n }\n .mojo-loading-spinner {\n width: 22px; height: 22px;\n border: 2.5px solid #e9ecef;\n border-top-color: #0d6efd;\n border-radius: 50%;\n animation: mojo-spin 0.7s linear infinite;\n flex-shrink: 0;\n }\n .mojo-loading-message {\n font-size: 0.88rem;\n font-weight: 500;\n color: #495057;\n white-space: nowrap;\n }\n @keyframes mojo-spin { to { transform: rotate(360deg); } }\n</style>\n `,document.body.appendChild(d)),d.style.zIndex=String(e);const o=d.querySelector(".mojo-loading-message");o&&(o.textContent=t),requestAnimationFrame(()=>{d&&d.classList.add("show")}),i>0&&(h=setTimeout(()=>{console.error("BusyIndicator timed out."),u.hide(!0)},i))}else if(d){const e=d.querySelector(".mojo-loading-message");e&&(e.textContent=t)}},hide(e=!1){e?c=0:c--,c>0||(c=0,h&&(clearTimeout(h),h=null),d&&(d.classList.remove("show"),setTimeout(()=>{d&&0===c&&(d.remove(),d=null)},200)))},isShown:()=>null!==d&&c>0},p="\n max-height: 60vh;\n overflow-y: auto;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 1.25rem;\n border-radius: 0.5rem;\n margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Consolas', 'Monaco', monospace;\n font-size: 0.9rem;\n line-height: 1.6;\n border: 1px solid #2d2d30;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);\n".replace(/\s+/g," ").trim();class CodeViewer extends e{constructor(e={}){super({tagName:"div",className:"mojo-code-viewer",...e}),this.code=e.code||"",this.language=e.language||"javascript"}async getTemplate(){return CodeViewer.formatCode(this.code,this.language)}static formatCode(e,t="javascript"){let i;i=window.Prism&&window.Prism.languages[t]?window.Prism.highlight(e,window.Prism.languages[t],t):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'");const o=window.Prism?`language-${t}`:"";return`\n <style>\n .dialog-code-block .token.comment { color: #6a9955; }\n .dialog-code-block .token.string { color: #ce9178; }\n .dialog-code-block .token.keyword { color: #569cd6; }\n .dialog-code-block .token.function { color: #dcdcaa; }\n .dialog-code-block .token.number { color: #b5cea8; }\n .dialog-code-block .token.operator { color: #d4d4d4; }\n .dialog-code-block .token.class-name { color: #4ec9b0; }\n .dialog-code-block .token.punctuation { color: #d4d4d4; }\n .dialog-code-block .token.boolean { color: #569cd6; }\n .dialog-code-block .token.property { color: #9cdcfe; }\n .dialog-code-block .token.tag { color: #569cd6; }\n .dialog-code-block .token.attr-name { color: #9cdcfe; }\n .dialog-code-block .token.attr-value { color: #ce9178; }\n .dialog-code-block ::selection { background: #264f78; }\n</style>\n <pre class="${o} dialog-code-block" style="${p}">\n <code class="${o}" style="color: inherit; background: transparent; text-shadow: none;">${i}</code>\n </pre>\n `}static highlightCodeBlocks(e=document){window.Prism&&window.Prism.highlightAllUnder&&window.Prism.highlightAllUnder(e)}}class HtmlPreview extends e{constructor(e={}){super({tagName:"div",className:"mojo-html-preview",...e}),this.html=e.html||e.content||"",this.height=e.height||500}async getTemplate(){return`\n <div class="html-preview-container">\n <div class="d-flex justify-content-between align-items-center mb-2">\n <small class="text-muted">Preview (sandboxed)</small>\n <button type="button" class="btn btn-sm btn-outline-secondary" data-action="refresh">\n <i class="bi bi-arrow-clockwise"></i> Refresh\n </button>\n </div>\n <iframe\n class="border rounded w-100 mojo-html-preview-frame"\n style="height: ${this.height}px; background: white;"\n sandbox="allow-same-origin"\n frameborder="0"\n ></iframe>\n </div>\n `}async onAfterMount(){await super.onAfterMount(),this._writeIframe()}onActionRefresh(){this._writeIframe()}_writeIframe(){const e=this.element?.querySelector(".mojo-html-preview-frame");if(!e)return;const t=e.contentDocument||e.contentWindow?.document;t&&(t.open(),t.write(this.html),t.close())}setHtml(e){this.html=e,this._writeIframe()}}class Modal{static _renderAndAwait(e,{buttons:t=null,rejectOnDismiss:i=!1,onAction:o=null,cleanup:s=null}={}){const n=ModalView.getMountTarget();return new Promise((a,r)=>{let l=!1;const d=e=>{l||(l=!0,a(e))},c=e=>{l||(l=!0,r(e))};(async()=>{try{await e.render(!0,n)}catch(a){return void c(a)}t&&t.length>0&&e.element&&e.element.querySelectorAll(".modal-footer button").forEach((i,s)=>{const n=t[s];n&&i.addEventListener("click",async t=>{if(l)return;const i=void 0!==n.value?n.value:n.action??s;if("function"!=typeof n.handler)if("function"==typeof o&&n.action)try{const a=await o(n.action,{dialog:e,button:n,index:s,event:t});if(null===a||!1===a)return;const r=!0===a||void 0===a?i:a;n.dismiss||e.hide(),d(r)}catch(a){console.error("Modal onAction error:",a)}else n.dismiss||e.hide(),d(i);else try{const o=await n.handler({dialog:e,button:n,index:s,event:t});if(null===o||!1===o)return;const a=!0===o||void 0===o?i:o;n.dismiss||e.hide(),d(a)}catch(a){console.error("Modal button handler error:",a)}})}),e.on("hidden",()=>{l||(i?c(new Error("Dialog dismissed")):d(null)),setTimeout(async()=>{try{"function"==typeof s&&await s(e)}catch(a){console.error("Modal cleanup error:",a)}try{await e.destroy()}catch(a){console.error("Modal destroy error:",a)}e.element?.parentNode&&e.element.parentNode.removeChild(e.element)},100)}),e.show()})()})}static async dialog(e={}){"string"==typeof e&&(e={...arguments[2]||{},body:arguments[0],title:arguments[1]||"Alert"});const{title:t="Dialog",content:i,body:o,view:s,message:n,size:a="md",centered:r=!0,buttons:l=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:d=!1,...c}=e,h=new ModalView({title:t,body:o??s??n??i??"",size:a,centered:r,buttons:l,...c});return Modal._renderAndAwait(h,{buttons:l,rejectOnDismiss:d})}static async drawer(t={}){const{eyebrow:i,title:o,meta:s=[],view:n,body:a,size:r="lg",...l}=t,d=s.length?`\n <div class="modal-drawer-meta">\n ${s.map(e=>"string"==typeof e?`<span>${Modal._esc(e)}</span>`:`<span>${e.icon?`<i class="${Modal._esc(e.icon)} me-1"></i>`:""}${Modal._esc(e.text||"")}</span>`).join("")}\n </div>`:"",c=`\n <div class="modal-drawer-head">\n ${i?`<span class="modal-drawer-eyebrow">${Modal._esc(i)}</span>`:""}\n <h2 class="modal-drawer-title">${Modal._esc(o||"")}</h2>\n ${d}\n </div>\n `;let h;return h=n&&"object"==typeof n&&"function"==typeof n.render?new class extends e{async getTemplate(){return`${c}<div class="modal-drawer-body" data-container="drawer-body"></div>`}async onInit(){n.containerId="drawer-body",this.addChild(n)}}:`${c}<div class="modal-drawer-body">${a||""}</div>`,Modal.dialog({header:!1,body:h,size:r,centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...l})}static _esc(e){const t="undefined"!=typeof document?document.createElement("div"):null;return t?(t.textContent=String(e??""),t.innerHTML):String(e??"")}static async show(e,t={}){return Modal.dialog({header:void 0!==t.title&&!!t.title,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 i=e.constructor,o=i?.VIEW_CLASS;if(!o)throw new Error(`Modal.showModel: No VIEW_CLASS defined on ${i?.name||"model"}. Set ${i?.name||"Model"}.VIEW_CLASS = YourView to use this method.`);const s=new o({model:e});return Modal.show(s,t)}static async showModelById(e,t,i={}){const o=new e({id:t});return await o.fetch(),o.id?Modal.showModel(o,i):(Modal.alert({message:`Could not find ${e.name||"record"} with ID: ${t}`,type:"warning"}),null)}static async showModelView(e,t={}){const i=e.constructor,o=i?.VIEW_CLASS;if(!o)throw new Error(`Modal.showModelView: No VIEW_CLASS defined on ${i?.name||"model"}.`);const s=new o({model:e});return Modal.dialog({header:!1,body:s,size:"lg",centered:!1,...t})}static async alert(e={},t,i){let o;o="string"==typeof e?{message:e,...void 0!==t?{title:t}:{},...i||{}}:{...e};const{message:s="",title:n="Alert",type:a="info",icon:r,className:l,...d}=o,c="danger"===a?"error":a,h=[`modal-alert modal-alert-${c}`,l].filter(Boolean).join(" "),u=void 0!==r?r:{info:"bi-info-circle",success:"bi-check-circle",warning:"bi-exclamation-triangle",error:"bi-x-circle"}[c],p=u?`<i class="bi ${u} modal-alert-icon"></i>`:"",m=`<span class="modal-alert-headline">${n}</span>`;return Modal.dialog({title:`${p}${m}`,body:`<p class="modal-alert-message">${s}</p>`,size:"sm",centered:!0,className:h,buttons:[{text:"OK",class:"btn-primary",value:!0}],...d})}static async confirm(e,t="Confirm",i={}){let o;"object"==typeof e&&null!==e?(o=(i=e).message,t=i.title||t):o=e;const s=[{text:i.cancelText||"Cancel",class:"btn-secondary",dismiss:!0,action:"cancel"},{text:i.confirmText||"Confirm",class:i.confirmClass||"btn-primary",action:"confirm"}],n=new ModalView({title:t,body:`<p>${o}</p>`,size:i.size||"sm",centered:!0,backdrop:"static",buttons:s,...i});return"confirm"===await Modal._renderAndAwait(n,{buttons:s})}static async prompt(e,t="Input",i={}){const o=`prompt-input-${Date.now()}`,s=i.defaultValue||"",n=i.inputType||"text",a=i.placeholder||"",r=[{text:"Cancel",class:"btn-secondary",dismiss:!0},{text:"OK",class:"btn-primary",action:"ok"}],l=new ModalView({title:t,body:`\n <p>${e}</p>\n <input type="${n}"\n class="form-control"\n id="${o}"\n value="${s}"\n placeholder="${a}">\n `,size:i.size||"sm",centered:!0,backdrop:"static",buttons:r,...i});return l.on("shown",()=>{const e=l.element.querySelector(`#${o}`);e&&(e.focus(),e.select())}),Modal._renderAndAwait(l,{buttons:r,onAction:async e=>{if("ok"!==e)return null;const t=l.element.querySelector(`#${o}`);return t?t.value:null}})}static showError(e){return Modal.alert(e,"Error",{type:"error"})}static async form(e={}){const{title:t="Form",formConfig:i={},size:o="md",centered:s=!0,submitText:n="Submit",cancelText:a="Cancel",...r}=e,l=new(0,(await import("./FormView-C_7xQuI4.js").then(e=>e.c)).default)({fileHandling:e.fileHandling||"base64",data:e.data,defaults:e.defaults,model:e.model,formConfig:{fields:i.fields||e.fields,...i,submitButton:!1,resetButton:!1}}),d=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],c=new ModalView({title:t,body:l,size:o,centered:s,buttons:d,...r});return Modal._renderAndAwait(c,{buttons:d,onAction:async t=>{if("cancel"===t)return c.hide(),null;if("submit"!==t)return null;if(!l.validate())return l.focusFirstError(),!1;if(e.autoSave&&e.model){c.setLoading(!0);const e=await l.saveModel();return e.success?e:(c.setLoading(!1),await c.render(),c.getApp()?.toast?.error(e.message),!1)}try{return await l.getFormData()}catch(i){return console.error("Modal.form: error collecting form data:",i),l.showError("Error collecting form data"),!1}},cleanup:async()=>{try{await l.destroy()}catch{}}})}static async modelForm(e={}){const{title:t="Edit",formConfig:i={},size:o="md",centered:s=!0,submitText:n="Save",cancelText:a="Cancel",model:r,fields:l,...d}=e;if(!r)throw new Error("Modal.modelForm requires a model");const c=new(0,(await import("./FormView-C_7xQuI4.js").then(e=>e.c)).default)({fileHandling:e.fileHandling||"base64",model:r,data:e.data,defaults:e.defaults,formConfig:{fields:l||i.fields||[],...i,submitButton:!1,resetButton:!1}}),h=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],u=new ModalView({title:t,body:c,size:o,centered:s,buttons:h,...d});return Modal._renderAndAwait(u,{buttons:h,onAction:async e=>{if("cancel"===e)return u.hide(),null;if("submit"!==e)return null;u.setLoading(!0,"Saving...");try{const e=await c.handleSubmit();if(e.success)return e;u.setLoading(!1);let t=e.error;return e.data?.error&&(t=e.data.error),u.getApp()?.toast?.error(t),!1}catch(t){return console.error("Modal.modelForm: error saving:",t),await u.setContent(c),c.showError(t.message||"An error occurred while saving"),!1}},cleanup:async()=>{try{await c.destroy()}catch{}}})}static async data(e={}){const{title:t="Data View",data:i={},model:o=null,fields:s=[],columns:n=2,responsive:a=!0,showEmptyValues:r=!1,emptyValueText:l="—",size:d="lg",centered:c=!0,closeText:h="Close",...u}=e,p=new(0,(await import("./DataView-DJMOmlKN.js")).default)({data:i,model:o,fields:s,columns:n,responsive:a,showEmptyValues:r,emptyValueText:l}),m=[{text:h,class:"btn-secondary",value:"close"}],g=new ModalView({title:t,body:p,size:d,centered:c,buttons:m,...u});return p.on("field:click",e=>g.emit("dataview:field:click",e)),p.on("error",e=>g.emit("dataview:error",e)),Modal._renderAndAwait(g,{buttons:m,cleanup:async()=>{try{await p.destroy()}catch{}}})}static async code(e={}){const{code:t="",language:i="javascript",title:o="Source Code",size:s="lg",...n}=e,a=new CodeViewer({code:t,language:i}),r=[{text:"Copy to Clipboard",class:"btn-primary",icon:"bi-clipboard",action:"copy"},{text:"Close",class:"btn-secondary",dismiss:!0}],l=new ModalView({title:o,body:a,size:s,scrollable:!0,buttons:r,...n});return Modal._renderAndAwait(l,{buttons:r,onAction:async e=>{if("copy"!==e)return null;if(!navigator.clipboard)return!1;try{await navigator.clipboard.writeText(t),Modal._showCopySuccess(l)}catch(i){console.error("Modal.code: clipboard write failed:",i)}return!1}})}static _showCopySuccess(e){const t=e.element?.querySelector('[data-action="copy"]');if(!t)return;const i=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=i,t.classList.remove("btn-success"),t.classList.add("btn-primary"),t.disabled=!1},2e3)}static async htmlPreview(e={}){const{html:t=e.content||"",title:i="HTML Preview",size:o="lg",height:s=500,...n}=e,a=new HtmlPreview({html:t,height:s}),r=[{text:"Close",class:"btn-secondary",dismiss:!0}],l=new ModalView({title:i,body:a,size:o,scrollable:!1,buttons:r,...n});return Modal._renderAndAwait(l,{buttons:r})}static async updateModelImage(e={},t={}){const i=e.upload||!1,o=t.name||e.field||"image",s={title:"Upload Your Avatar",model:null,autoSave:!i,size:"sm",fields:[{type:"image",name:o,size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your image",...t}],...e},n=await Modal.form(s);if(!i||!n||!e.model)return n;const a=n[o];if(!a||!a.startsWith("data:"))return n;const l=a.split(","),d=l[0]?.match(/:(.*?);/),c=d?.[1]||"image/png",h=atob(l[1]);let u=h.length;const p=new Uint8Array(u);for(;u--;)p[u]=h.charCodeAt(u);const m=c.split("/")[1]||"png",g="undefined"!=typeof window&&window.File||globalThis.File;if(!g)throw new Error("File API is not available in this environment");const f=new g([p],`${o}.${m}`,{type:c}),w=new r;return await w.upload({file:f,name:`${o}.${m}`,description:e.uploadDescription||`${o} upload`,showToast:!0}),e.model.save({[o]:w.id})}static loading(e){u.show(e)}static hideLoading(e){u.hide(e)}static showBusy(e){return Modal.loading(e)}static hideBusy(e){return Modal.hideLoading(e)}}const m=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,default:Modal},Symbol.toStringTag,{value:"Module"}));export{CodeViewer as C,r as F,ModalView as M,ProgressView as P,ToastService as T,Modal as a,l as b,FileList as c,FileManager as d,a as e,FileManagerList as f,FileUpload as g,m as h};
|
|
3
|
-
//# sourceMappingURL=Modal-
|
|
1
|
+
import{V as e}from"./View-gAghvPMN.js";import{d as t,M as i,C as o}from"./Collection-Cgxbmj8G.js";import{G as s,a as n}from"./User-CayBjzMG.js";class ToastService{constructor(e={}){this.options={containerId:"toast-container",position:"top-end",autohide:!0,defaultDelay:3e3,maxToasts:5,...e},this.toasts=/* @__PURE__ */new Map,this.toastCounter=0,this.init()}init(){this.createContainer()}createContainer(){let e=document.getElementById(this.options.containerId);e||(e=document.createElement("div"),e.id=this.options.containerId,e.className=`toast-container position-fixed ${this.getPositionClasses()}`,e.style.zIndex="1070",e.setAttribute("aria-live","polite"),e.setAttribute("aria-atomic","true"),document.body.appendChild(e)),this.container=e}getPositionClasses(){const e={"top-start":"top-0 start-0 p-3","top-center":"top-0 start-50 translate-middle-x p-3","top-end":"top-0 end-0 p-3","middle-start":"top-50 start-0 translate-middle-y p-3","middle-center":"top-50 start-50 translate-middle p-3","middle-end":"top-50 end-0 translate-middle-y p-3","bottom-start":"bottom-0 start-0 p-3","bottom-center":"bottom-0 start-50 translate-middle-x p-3","bottom-end":"bottom-0 end-0 p-3"};return e[this.options.position]||e["top-end"]}success(e,t={}){return this.show(e,"success",{icon:"bi-check-circle-fill",...t})}error(e,t={}){return this.show(e,"error",{icon:"bi-exclamation-triangle-fill",autohide:!0,...t})}info(e,t={}){return this.show(e,"info",{icon:"bi-info-circle-fill",...t})}warning(e,t={}){return this.show(e,"warning",{icon:"bi-exclamation-triangle-fill",...t})}plain(e,t={}){return this.show(e,"plain",{...t})}show(e,t="info",i={}){this.enforceMaxToasts();const o="toast-"+ ++this.toastCounter,s={title:this.getDefaultTitle(t),icon:this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,...i},n=this.createToastElement(o,e,t,s);if(this.container.appendChild(n),"undefined"==typeof bootstrap)throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const a=new bootstrap.Toast(n,{autohide:s.autohide,delay:s.delay});return this.toasts.set(o,{element:n,bootstrap:a,type:t,message:e}),n.addEventListener("hidden.bs.toast",()=>{this.cleanup(o)}),a.show(),{id:o,hide:()=>{try{a.hide()}catch(e){console.warn("Error hiding toast:",e)}},dispose:()=>this.cleanup(o),updateProgress:i.updateProgress||null}}showView(e,t="info",i={}){this.enforceMaxToasts();const o="toast-"+ ++this.toastCounter,s={title:i.title||this.getDefaultTitle(t),icon:i.icon||this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,size:"md",...i},n=this.createViewToastElement(o,e,t,s);if(this.container.appendChild(n),"undefined"==typeof bootstrap)throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const a=new bootstrap.Toast(n,{autohide:s.autohide,delay:s.delay});this.toasts.set(o,{element:n,bootstrap:a,type:t,view:e,message:"View toast"}),n.addEventListener("hidden.bs.toast",()=>{this.cleanupView(o)});const r=n.querySelector(".toast-view-body");return r&&e&&e.render(!0,r),a.show(),{id:o,view:e,hide:()=>{try{a.hide()}catch(e){console.warn("Error hiding view toast:",e)}},dispose:()=>this.cleanupView(o),updateProgress:t=>{e&&"function"==typeof e.updateProgress&&e.updateProgress(t)}}}createToastElement(e,t,i,o){const s=document.createElement("div");s.id=e,s.className=`toast toast-service-${i}${o.size?` toast-${o.size}`:""}`,s.setAttribute("role","alert"),s.setAttribute("aria-live","assertive"),s.setAttribute("aria-atomic","true");const n=o.title||o.icon?this.createToastHeader(o,i):"",a=this.createToastBody(t,o.icon&&!o.title);return s.innerHTML=`\n ${n}\n ${a}\n `,s}createViewToastElement(e,t,i,o){const s=document.createElement("div");s.id=e,s.className=`toast toast-service-${i}${o.size?` toast-${o.size}`:""}`,s.setAttribute("role","alert"),s.setAttribute("aria-live","assertive"),s.setAttribute("aria-atomic","true");const n=o.title||o.icon?this.createToastHeader(o,i):"",a=this.createViewToastBody();return s.innerHTML=`\n ${n}\n ${a}\n `,s}createViewToastBody(){return'\n <div class="toast-body p-0">\n <div class="toast-view-body p-3"></div>\n </div>\n '}createToastHeader(e,t){const i=e.icon?`<i class="${e.icon} toast-service-icon me-2"></i>`:"",o=e.title?`<strong class="me-auto">${i}${this.escapeHtml(e.title)}</strong>`:"",s=e.showTime?`<small class="text-muted">${this.getTimeString()}</small>`:"",n=e.dismissible?'<button type="button" class="btn-close toast-service-close" data-bs-dismiss="toast" aria-label="Close"></button>':"";return o||s||n?`\n <div class="toast-header">\n ${o}\n ${s}\n ${n}\n </div>\n `:""}createToastBody(e,t=!1){return`\n <div class="toast-body d-flex align-items-center">\n ${t?`<i class="${this.getDefaultIcon("info")} toast-service-icon me-2"></i>`:""}\n <span>${this.escapeHtml(e)}</span>\n </div>\n `}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 e=this.toasts.keys().next().value,t=this.toasts.get(e);t&&t.bootstrap.hide()}}cleanup(e){const t=this.toasts.get(e);if(t){try{t.bootstrap.dispose()}catch(i){console.warn("Error disposing toast:",i)}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&&"function"==typeof t.view.dispose)try{t.view.dispose()}catch(i){console.warn("Error disposing view in toast:",i)}try{t.bootstrap.dispose()}catch(i){console.warn("Error disposing toast:",i)}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(){/* @__PURE__ */
|
|
2
|
+
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 ProgressView extends e{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=t.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=!1!==e.showCancel,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return'\n <div class="progress-view">\n <div class="d-flex justify-content-between align-items-start mb-2">\n <div class="flex-grow-1 min-width-0">\n <div class="fw-medium text-truncate" title="{{filename}}">\n <i class="bi bi-file-earmark me-1"></i>\n {{filename}}\n </div>\n <small class="text-muted">{{status}}</small>\n </div>\n {{#showCancel}}\n <button type="button" \n class="btn btn-sm btn-outline-secondary ms-2" \n data-action="cancel"\n {{#cancelled}}disabled{{/cancelled}}>\n <i class="bi bi-x"></i>\n </button>\n {{/showCancel}}\n </div>\n \n <div class="progress mb-2" style="height: 8px;">\n <div class="progress-bar" \n role="progressbar" \n style="width: {{percentage}}%"\n aria-valuenow="{{percentage}}" \n aria-valuemin="0" \n aria-valuemax="100">\n </div>\n </div>\n \n <div class="d-flex justify-content-between">\n <small class="text-muted">\n {{loadedFormatted}} / {{totalFormatted}}\n </small>\n <small class="text-muted">\n {{percentage}}%\n </small>\n </div>\n </div>\n '}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=t.pipe(this.loaded,"filesize"),this.totalFormatted=t.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,i){if(!this.cancelled&&!this.completed&&(i.disabled=!0,this.markCancelled(),this.emit("cancel"),"function"==typeof this.onCancel))try{await this.onCancel()}catch(o){console.error("Error in cancel callback:",o)}}setFilename(e){this.filename=e,this.render()}setFilesize(e){this.filesize=e,this.filesizeFormatted=t.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 FileUpload{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 ToastService),this.promise=this._startUpload()}async _startUpload(){try{let t,i,o;this.options.showToast&&this._showProgressToast();try{t=await this._initiateUpload()}catch(e){throw new Error(`Failed to initiate upload: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");if(!t||!t.upload_url)throw new Error("Invalid upload response: missing upload URL");if("string"==typeof t.upload_url)i={url:t.upload_url,method:"PUT",fields:null,headers:{}};else{if(!t.upload_url||"object"!=typeof t.upload_url||!t.upload_url.upload_url)throw new Error(`Invalid upload response: unrecognised upload_url format. Server returned: ${JSON.stringify(t.upload_url)}`);i={url:t.upload_url.upload_url,method:t.upload_url.method||"POST",fields:t.upload_url.fields||null,headers:t.upload_url.headers||{}}}try{o=await this._performUpload(i)}catch(e){throw new Error(`File upload failed: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");try{await this._completeUpload()}catch(e){console.warn("Failed to mark upload as completed:",e)}return this._onComplete(this.fileModel),this.fileModel}catch(e){throw"Upload cancelled"!==e.message&&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 e=t.data.error||"Upload initiation failed";throw new Error(e)}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){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload initiation. Please check your connection.");throw e}}async _performUpload(e){return new Promise((t,i)=>{if(!(this.options.file instanceof File))return void i(new Error("Only single File objects are supported"));const{url:o,method:s,fields:n,headers:a}=e,r="POST"===s&&null!==n,l=new XMLHttpRequest;this.uploadRequest=l,l.upload.onprogress=e=>{this.cancelled||this._onProgress({progress:e.loaded/e.total,loaded:e.loaded,total:e.total,percentage:Math.round(e.loaded/e.total*100)})},l.onload=()=>{l.status>=200&&l.status<300?t({data:l.response,status:l.status,statusText:l.statusText,xhr:l}):i(new Error(`Upload failed: ${l.status} ${l.statusText}`))},l.onerror=()=>i(new Error("Upload failed: Network error")),l.ontimeout=()=>i(new Error("Upload timed out — file may be too large or connection too slow")),l.onabort=()=>i(new Error("Upload cancelled"));let d=o;o.startsWith("/")&&!o.startsWith("/api/")&&(d="/api"+o);const c=this.fileModel.rest.buildUrl(d);if(l.open(s,c),l.timeout=3e4,r){for(const[t,i]of Object.entries(a||{}))"content-type"!==t.toLowerCase()&&l.setRequestHeader(t,i);const e=new FormData;for(const[t,i]of Object.entries(n))e.append(t,i);e.append("file",this.options.file),l.send(e)}else{l.setRequestHeader("Content-Type",this.options.file.type);for(const[e,t]of Object.entries(a||{}))"content-type"!==e.toLowerCase()&&l.setRequestHeader(e,t);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){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload completion. The file may have uploaded successfully.");throw e}}_onProgress(e){this.progressToast&&this.progressToast.updateProgress&&this.progressToast.updateProgress(e),"function"==typeof this.options.onProgress&&this.options.onProgress(e)}_onComplete(e){this.progressView&&this.progressView.markCompleted("Upload completed successfully!"),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast:",e)}},2e3),"function"==typeof this.options.onComplete&&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}`),"function"==typeof this.options.onError&&this.options.onError(e)}_showProgressToast(){this.progressView=new ProgressView({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&&(this.cancelled=!0,this.uploadRequest&&"function"==typeof this.uploadRequest.abort&&this.uploadRequest.abort(),this.progressView&&this.progressView.markCancelled(),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&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 FileManager extends i{constructor(e={}){super(e,{endpoint:"/api/fileman/manager"})}}class FileManagerList extends o{constructor(e={}){super({ModelClass:FileManager,endpoint:"/api/fileman/manager",size:10,...e})}}const a={create:{title:"Add Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,value:"s3://BUCKET_NAME/OPTION_FOLDER",placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6}]},edit:{title:"Edit Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"allowed_origins",type:"text",label:"Domains Who Can Upload",cols:12},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6},{name:"is_public",type:"switch",label:"Is Public",default:!0,cols:6}]},owners:{fields:[{type:"collection",name:"group",label:"Group (Owner)",Collection:s,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300},{type:"collection",name:"user",label:"User (Owner)",Collection:n,labelField:"display_name",valueField:"id",maxItems:10,placeholder:"Search users...",emptyFetch:!1,debounceMs:300}]},credentials:{fields:[{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"}]}};let r=class extends i{constructor(e={}){super(e,{endpoint:"/api/fileman/file"})}isImage(){return"image"===this.get("category")}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":"application/pdf"===e?"pdf":e.startsWith("text/")||"application/msword"===e||e.startsWith("application/vnd.openxmlformats-officedocument.wordprocessingml")||"application/vnd.oasis.opendocument.text"===e?"document":"application/vnd.ms-excel"===e||e.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml")||"application/vnd.oasis.opendocument.spreadsheet"===e?"spreadsheet":"application/vnd.ms-powerpoint"===e||e.startsWith("application/vnd.openxmlformats-officedocument.presentationml")||"application/vnd.oasis.opendocument.presentation"===e?"presentation":"application/zip"===e||"application/x-rar-compressed"===e||"application/x-7z-compressed"===e||"application/x-tar"===e||"application/gzip"===e?"archive":"other":"other"}hasRenditions(){const e=this.get("renditions");return!(!e||!Object.keys(e).length)}isUploadPending(){const e=this.get("upload_status");return!(!e||"completed"===e||"failed"===e)}regenerateRenditions(e){const t=this.id||this.get("id");if(!t)return Promise.reject(new Error("Cannot regenerate renditions on an unsaved file"));const i=Array.isArray(e)&&e.length?{regenerate_renditions:e}:{regenerate_renditions:!0};return this.rest.POST(`${this.endpoint}/${t}`,i)}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(e=>e&&"string"==typeof e.content_type&&e.content_type.startsWith("image/"));return e.length?e.reduce((e,t)=>{const i=(parseInt(e.width)||0)*(parseInt(e.height)||0);return(parseInt(t.width)||0)*(parseInt(t.height)||0)>i?t:e}):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 FileUpload(this,e)}};class FileList extends o{constructor(e={}){super({ModelClass:r,endpoint:"/api/fileman/file",size:10,...e})}}const l={create:{title:"Add File",fields:[]},edit:{title:"Edit File Backend",fields:[]}};class ModalView extends e{static _openDialogs=[];static _baseZIndex={backdrop:1050,modal:1055};static getFullscreenAwareZIndex(){return document.querySelector(".table-fullscreen")?{backdrop:10040,modal:10050}:ModalView._baseZIndex}static fixAllBackdropStacking(){const e=document.querySelectorAll(".modal-backdrop"),t=ModalView._openDialogs;if(0===e.length||0===t.length)return;const i=[...t].sort((e,t)=>(e._dialogZIndex||0)-(t._dialogZIndex||0)),o=document.querySelector(".table-fullscreen")||document.body;e.forEach((e,t)=>{if(t>=i.length)return;const s=i[t];e.style.zIndex=s._dialogZIndex-5,e.parentNode!==o&&o.appendChild(e)})}static updateAllBackdropStacking(){ModalView.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 ${!1!==e.fade?"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=void 0!==e.centered&&e.centered,this.scrollable=void 0!==e.scrollable&&e.scrollable,this.autoSize=e.autoSize||"auto"===e.size,this.backdrop=void 0===e.backdrop||e.backdrop,this.keyboard=void 0===e.keyboard||e.keyboard,this.focus=void 0===e.focus||e.focus,this.header=void 0===e.header||e.header,this.headerContent=e.headerContent||null,this.headerView=null,this.closeButton=void 0===e.closeButton||e.closeButton,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=void 0!==e.autoShow&&e.autoShow,this.modal=null,this.relatedTarget=e.relatedTarget||null}_processBodyContent(t){if(t instanceof e||t&&"object"==typeof t&&"function"==typeof t.render)this.bodyView=t,this.body="",this.addChild(this.bodyView);else if("function"==typeof t)try{const i=t();i instanceof e?(this.bodyView=i,this.body="",this.addChild(this.bodyView)):i instanceof Promise?(this.bodyPromise=i,this.body='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.body=i}catch(i){console.error("ModalView: error processing body function:",i),this.body=t}else this.body=t}_processHeaderContent(t){if(t instanceof e)this.headerView=t,this.headerContent=null,this.addChild(this.headerView);else if("function"==typeof t)try{const i=t();i instanceof e?(this.headerView=i,this.headerContent=null,this.addChild(this.headerView)):i instanceof Promise?(this.headerPromise=i,this.headerContent='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.headerContent=i}catch(i){console.error("ModalView: error processing headerContent function:",i),this.headerContent=t}else this.headerContent=t}_processFooterContent(t){if(t instanceof e)this.footerView=t,this.footer=null,this.addChild(this.footerView);else if("function"==typeof t)try{const i=t();i instanceof e?(this.footerView=i,this.footer=null,this.addChild(this.footerView)):i instanceof Promise?(this.footerPromise=i,this.footer='<div class="text-center"><div class="spinner-border spinner-border-sm"></div></div>'):this.footer=i}catch(i){console.error("ModalView: error processing footer function:",i),this.footer=t}else this.footer=t}async getTemplate(){const e=["modal-dialog"];return this.size&&"auto"!==this.size&&(this.size.startsWith("fullscreen")?e.push(`modal-${this.size}`):["sm","lg","xl","xxl"].includes(this.size)&&(e.push(`modal-${this.size}`),["lg","xl","xxl"].includes(this.size)&&e.push("modal-fullscreen-sm-down"))),this.centered&&e.push("modal-dialog-centered"),this.scrollable&&(this.maxHeight?e.push("overflow-hidden"):e.push("modal-dialog-scrollable")),`\n <div class="${e.join(" ")}">\n <div class="modal-content">\n ${await this.buildHeader()}\n ${await this.buildBody()}\n ${await this.buildFooter()}\n </div>\n </div>\n `}async buildHeader(){if(!this.header)return"";if(this.headerView)return this.headerView.replaceById=!0,`<div class="modal-header" data-view-container="header">\n <div id="${this.headerView.id}"></div>\n </div>`;if(this.headerContent)return`<div class="modal-header">${this.headerContent}</div>`;let e="";return this.contextMenu&&this.contextMenu.items&&this.contextMenu.items.length>0?e=await this.buildContextMenu():this.closeButton&&(e='<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>'),`\n <div class="modal-header">\n ${this.title?`<h5 class="modal-title" id="${this.titleId}">${this.title}</h5>`:""}\n ${e}\n </div>\n `}async buildContextMenu(){const e=await this.filterContextMenuItems();if(0===e.length)return this.closeButton?'<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>':"";const t=this.contextMenu.icon||"bi-three-dots-vertical";return`\n <div class="dropdown">\n <button class="${this.contextMenu.buttonClass||"btn btn-link p-1 mojo-modal-context-menu-btn"}" type="button" data-bs-toggle="dropdown" aria-expanded="false">\n <i class="${t}"></i>\n </button>\n <ul class="dropdown-menu dropdown-menu-end">\n ${e.map(e=>{if("divider"===e.type)return'<li><hr class="dropdown-divider"></li>';const t=e.icon?`<i class="${e.icon} me-2"></i>`:"",i=e.label||"";if(e.href)return`<li><a class="dropdown-item" href="${e.href}"${e.target?` target="${e.target}"`:""}>${t}${i}</a></li>`;if(e.action){const o=Object.keys(e).filter(e=>e.startsWith("data-")).map(t=>`${t}="${e[t]}"`).join(" ");return`<li><a class="dropdown-item" data-action="${e.action}" ${o}>${t}${i}</a></li>`}return""}).join("")}\n </ul>\n </div>\n `}async filterContextMenuItems(){if(!this.contextMenu||!this.contextMenu.items)return[];const e=[];for(const i of this.contextMenu.items)if("divider"!==i.type){if(i.permissions)try{const e=this.getApp?.();let t=e?.activeUser||e?.getState?.("activeUser")||null;if(!t&&"undefined"!=typeof window&&window.getApp)try{t=window.getApp()?.activeUser}catch{}if(!t?.hasPermission)continue;if(!t.hasPermission(i.permissions))continue}catch(t){console.warn("ModalView: error checking permissions for context menu item:",t);continue}e.push(i)}else e.push(i);return e}async buildBody(){const e=`modal-body ${this.noBodyPadding?"modal-body-flush":""} ${this.bodyClass}`.replace(/\s+/g," ").trim();return this.bodyView?(this.bodyView.replaceById=!0,`<div class="${e}" data-view-container="body">\n <div id="${this.bodyView.id}"></div>\n </div>`):this.body||""===this.body?`<div class="${e}">${this.body}</div>`:""}async buildFooter(){if(this.footerView)return`<div class="modal-footer ${this.footerClass}" data-view-container="footer"></div>`;if(null!==this.footer&&"string"==typeof this.footer)return`<div class="modal-footer ${this.footerClass}">${this.footer}</div>`;if(this.buttons&&this.buttons.length>0){const e=this.buttons.map(e=>{const t=e.dismiss?'data-bs-dismiss="modal"':"",i=e.action?`data-action="${e.action}"`:"",o=e.id?`id="${e.id}"`:"",s=e.disabled?"disabled":"";return`\n <button type="${e.type||"button"}"\n class="btn ${e.class||"btn-secondary"}"\n ${o} ${t} ${i} ${s}>\n ${e.icon?`<i class="bi ${e.icon} me-1"></i>`:""}\n ${e.text||"Button"}\n </button>\n `}).join("");return`<div class="modal-footer ${this.footerClass}">${e}</div>`}return""}async mount(e=null){if(!this.mounted&&!this.destroyed){if(!this.element)throw new Error("Cannot mount modal without element");return await this.onBeforeMount(),ModalView.getMountTarget().appendChild(this.element),this.bindEvents(),this.mounted=!0,await this.onAfterMount(),this.emit("mounted",{view:this}),this}}async onAfterRender(){if(await super.onAfterRender(),window.Prism&&this.element&&this.element.querySelectorAll("pre code").length>0&&window.Prism.highlightAllUnder(this.element),this.autoSize)this.setupAutoSizing();else if(this.maxHeight){const e=this.element.querySelector(".modal-body");e&&(e.style.maxHeight=`${this.maxHeight}px`)}}async onAfterMount(){await super.onAfterMount(),"undefined"!=typeof window&&window.bootstrap?.Modal&&("static"===this.backdrop&&this.element.setAttribute("data-bs-backdrop","static"),this.keyboard||this.element.setAttribute("data-bs-keyboard","false"),this.modal=new window.bootstrap.Modal(this.element,{backdrop:this.backdrop,keyboard:this.keyboard,focus:this.focus}),this.bindBootstrapEvents(),this.autoShow&&this.show(this.relatedTarget))}setupAutoSizing(){this.element&&(this.element.addEventListener("shown.bs.modal",()=>{this.applyAutoSizing()},{once:!0}),setTimeout(()=>{this.isShown()&&this.applyAutoSizing()},100))}applyAutoSizing(){if(this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),i=this.element.querySelector(".modal-body");if(!e||!t||!i)return void console.warn("ModalView auto-sizing: required elements not found");if(this.bodyView&&!this.bodyView.element)return void setTimeout(()=>this.applyAutoSizing(),50);const o={dialogMaxWidth:e.style.maxWidth,dialogWidth:e.style.width,contentWidth:t.style.width,contentMaxHeight:t.style.maxHeight,hadScrollableClass:e.classList.contains("modal-dialog-scrollable")};e.style.maxWidth="none",e.style.width="auto",t.style.width="auto",t.style.maxHeight="none",t.offsetHeight;const s=t.getBoundingClientRect(),n=40,a=Math.min(window.innerWidth*this.maxWidthPercent,window.innerWidth-n);let r=Math.min(window.innerHeight*this.maxHeightPercent,window.innerHeight-n),l=Math.max(this.minWidth,Math.ceil(s.width+20)),d=Math.max(this.minHeight,Math.ceil(s.height));this.maxHeight&&(r=Math.min(this.maxHeight,r),e.style.maxHeight=`${r}px`),l=Math.min(l,a);const c=s.height>r;e.style.maxWidth=`${l}px`,e.style.width=`${l}px`,c&&(e.classList.contains("modal-dialog-scrollable")||e.classList.add("modal-dialog-scrollable"),t.style.maxHeight=`${r}px`,d=r),this.autoSizedWidth=l,this.autoSizedHeight=d,this._originalStyles=o}catch(e){console.error("ModalView: error in auto-sizing:",e);const t=this.element?.querySelector(".modal-dialog");t&&(t.style.maxWidth="")}}resetAutoSizing(){if(this.autoSize&&this._originalStyles&&this.element)try{const e=this.element.querySelector(".modal-dialog"),t=this.element.querySelector(".modal-content"),i=this.element.querySelector(".modal-body");e&&t&&i&&(e.style.maxWidth=this._originalStyles.dialogMaxWidth||"",e.style.width=this._originalStyles.dialogWidth||"",t.style.width=this._originalStyles.contentWidth||"",t.style.maxHeight=this._originalStyles.contentMaxHeight||"",!this._originalStyles.hadScrollableClass&&e.classList.contains("modal-dialog-scrollable")&&e.classList.remove("modal-dialog-scrollable"),delete this.autoSizedWidth,delete this.autoSizedHeight,delete this._originalStyles)}catch(e){console.error("ModalView: error resetting auto-sizing:",e)}}bindBootstrapEvents(){this.element.addEventListener("show.bs.modal",e=>{const t=ModalView._openDialogs.length,i=ModalView.getFullscreenAwareZIndex().modal+20*t;this.element.style.zIndex=i,this._dialogZIndex=i,this._backdropZIndex=i-10,ModalView._openDialogs.push(this),this.onShow&&this.onShow(e),this.emit("show",{dialog:this,relatedTarget:e.relatedTarget})}),this.element.addEventListener("shown.bs.modal",e=>{if(setTimeout(()=>ModalView.fixAllBackdropStacking(),50),this.onShown&&this.onShown(e),this.emit("shown",{dialog:this,relatedTarget:e.relatedTarget}),this.focus){const e=this.element.querySelector('input:not([type="hidden"]), textarea, select');e&&e.focus()}}),this.element.addEventListener("hide.bs.modal",e=>{const t=this.element.querySelector(":focus");t&&t.blur(),this.onHide&&!1===this.onHide(e)?e.preventDefault():this.emit("hide",{dialog:this})}),this.element.addEventListener("hidden.bs.modal",e=>{const t=ModalView._openDialogs.indexOf(this);t>-1&&ModalView._openDialogs.splice(t,1),ModalView._openDialogs.length>0&&(document.body.classList.add("modal-open"),setTimeout(()=>ModalView.fixAllBackdropStacking(),50)),this.previousFocus&&document.body.contains(this.previousFocus)&&this.previousFocus.focus(),this.onHidden&&this.onHidden(e),this.emit("hidden",{dialog:this})}),this.element.addEventListener("hidePrevented.bs.modal",e=>{this.onHidePrevented&&this.onHidePrevented(e),this.emit("hidePrevented",{dialog:this})})}show(e=null){this.previousFocus=document.activeElement,window.lastDialog=this,this.modal&&this.modal.show(e)}hide(){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal&&this.modal.hide()}toggle(e=null){this.modal&&this.modal.toggle(e)}isShown(){return this.element?.classList.contains("show")||!1}getModal(){return this.modal}handleUpdate(){this.modal&&this.modal.handleUpdate()}async setContent(t){if(t instanceof e){this.bodyView&&(await this.bodyView.destroy(),this.removeChild(this.bodyView)),this.bodyView=t,this.body="",this.addChild(this.bodyView);const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML="",await this.bodyView.render(e))}else{this.body=t;const e=this.element?.querySelector(".modal-body");e&&(e.innerHTML=t)}this.handleUpdate()}setTitle(e){this.title=e;const t=this.element?.querySelector(".modal-title");t&&(t.textContent=e)}setLoading(e=!0,t="Loading..."){const i=this.element?.querySelector(".modal-body");i&&(e?i.innerHTML=`\n <div class="text-center py-4">\n <div class="spinner-border text-primary mb-3" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <p>${t}</p>\n </div>\n `:this.bodyView&&i.replaceChildren(this.bodyView.element))}async destroy(){if(this.modal){const e=this.element?.querySelector(":focus");e&&e.blur(),this.modal.dispose(),this.modal=null}this.previousFocus&&document.body.contains(this.previousFocus)&&(this.previousFocus.focus(),this.previousFocus=null),this.autoSize&&this.resetAutoSizing(),await super.destroy()}async onBeforeDestroy(){this.headerView&&await this.headerView.destroy(),this.bodyView&&await this.bodyView.destroy(),this.footerView&&await this.footerView.destroy(),await super.onBeforeDestroy(),this.modal&&(this.modal.dispose(),this.modal=null)}}let d=null,c=0,h=null;const u={show(e){"string"==typeof e&&(e={message:e});const{message:t="Loading...",timeout:i=3e4}=e||{};if(c++,1===c){h&&clearTimeout(h);const e=ModalView.getFullscreenAwareZIndex().modal+1e3;d||(d=document.createElement("div"),d.className="mojo-loading-overlay",d.innerHTML=`\n <div class="mojo-loading-card">\n <div class="mojo-loading-spinner"></div>\n <div class="mojo-loading-message">${t}</div>\n </div>\n <style>\n .mojo-loading-overlay {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background: rgba(255, 255, 255, 0.4);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.2s ease;\n }\n .mojo-loading-overlay.show { opacity: 1; }\n .mojo-loading-card {\n display: flex; align-items: center; gap: 0.85rem;\n background: #fff;\n border: 1px solid #e9ecef;\n border-radius: 12px;\n padding: 1rem 1.5rem;\n box-shadow: 0 4px 24px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);\n }\n .mojo-loading-spinner {\n width: 22px; height: 22px;\n border: 2.5px solid #e9ecef;\n border-top-color: #0d6efd;\n border-radius: 50%;\n animation: mojo-spin 0.7s linear infinite;\n flex-shrink: 0;\n }\n .mojo-loading-message {\n font-size: 0.88rem;\n font-weight: 500;\n color: #495057;\n white-space: nowrap;\n }\n @keyframes mojo-spin { to { transform: rotate(360deg); } }\n</style>\n `,document.body.appendChild(d)),d.style.zIndex=String(e);const o=d.querySelector(".mojo-loading-message");o&&(o.textContent=t),requestAnimationFrame(()=>{d&&d.classList.add("show")}),i>0&&(h=setTimeout(()=>{console.error("BusyIndicator timed out."),u.hide(!0)},i))}else if(d){const e=d.querySelector(".mojo-loading-message");e&&(e.textContent=t)}},hide(e=!1){e?c=0:c--,c>0||(c=0,h&&(clearTimeout(h),h=null),d&&(d.classList.remove("show"),setTimeout(()=>{d&&0===c&&(d.remove(),d=null)},200)))},isShown:()=>null!==d&&c>0},p="\n max-height: 60vh;\n overflow-y: auto;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 1.25rem;\n border-radius: 0.5rem;\n margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Consolas', 'Monaco', monospace;\n font-size: 0.9rem;\n line-height: 1.6;\n border: 1px solid #2d2d30;\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);\n".replace(/\s+/g," ").trim();class CodeViewer extends e{constructor(e={}){super({tagName:"div",className:"mojo-code-viewer",...e}),this.code=e.code||"",this.language=e.language||"javascript"}async getTemplate(){return CodeViewer.formatCode(this.code,this.language)}static formatCode(e,t="javascript"){let i;i=window.Prism&&window.Prism.languages[t]?window.Prism.highlight(e,window.Prism.languages[t],t):String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'");const o=window.Prism?`language-${t}`:"";return`\n <style>\n .dialog-code-block .token.comment { color: #6a9955; }\n .dialog-code-block .token.string { color: #ce9178; }\n .dialog-code-block .token.keyword { color: #569cd6; }\n .dialog-code-block .token.function { color: #dcdcaa; }\n .dialog-code-block .token.number { color: #b5cea8; }\n .dialog-code-block .token.operator { color: #d4d4d4; }\n .dialog-code-block .token.class-name { color: #4ec9b0; }\n .dialog-code-block .token.punctuation { color: #d4d4d4; }\n .dialog-code-block .token.boolean { color: #569cd6; }\n .dialog-code-block .token.property { color: #9cdcfe; }\n .dialog-code-block .token.tag { color: #569cd6; }\n .dialog-code-block .token.attr-name { color: #9cdcfe; }\n .dialog-code-block .token.attr-value { color: #ce9178; }\n .dialog-code-block ::selection { background: #264f78; }\n</style>\n <pre class="${o} dialog-code-block" style="${p}">\n <code class="${o}" style="color: inherit; background: transparent; text-shadow: none;">${i}</code>\n </pre>\n `}static highlightCodeBlocks(e=document){window.Prism&&window.Prism.highlightAllUnder&&window.Prism.highlightAllUnder(e)}}class HtmlPreview extends e{constructor(e={}){super({tagName:"div",className:"mojo-html-preview",...e}),this.html=e.html||e.content||"",this.height=e.height||500}async getTemplate(){return`\n <div class="html-preview-container">\n <div class="d-flex justify-content-between align-items-center mb-2">\n <small class="text-muted">Preview (sandboxed)</small>\n <button type="button" class="btn btn-sm btn-outline-secondary" data-action="refresh">\n <i class="bi bi-arrow-clockwise"></i> Refresh\n </button>\n </div>\n <iframe\n class="border rounded w-100 mojo-html-preview-frame"\n style="height: ${this.height}px; background: white;"\n sandbox="allow-same-origin"\n frameborder="0"\n ></iframe>\n </div>\n `}async onAfterMount(){await super.onAfterMount(),this._writeIframe()}onActionRefresh(){this._writeIframe()}_writeIframe(){const e=this.element?.querySelector(".mojo-html-preview-frame");if(!e)return;const t=e.contentDocument||e.contentWindow?.document;t&&(t.open(),t.write(this.html),t.close())}setHtml(e){this.html=e,this._writeIframe()}}class Modal{static _renderAndAwait(e,{buttons:t=null,rejectOnDismiss:i=!1,onAction:o=null,cleanup:s=null}={}){const n=ModalView.getMountTarget();return new Promise((a,r)=>{let l=!1;const d=e=>{l||(l=!0,a(e))},c=e=>{l||(l=!0,r(e))};(async()=>{try{await e.render(!0,n)}catch(a){return void c(a)}t&&t.length>0&&e.element&&e.element.querySelectorAll(".modal-footer button").forEach((i,s)=>{const n=t[s];n&&i.addEventListener("click",async t=>{if(l)return;const i=void 0!==n.value?n.value:n.action??s;if("function"!=typeof n.handler)if("function"==typeof o&&n.action)try{const a=await o(n.action,{dialog:e,button:n,index:s,event:t});if(null===a||!1===a)return;const r=!0===a||void 0===a?i:a;n.dismiss||e.hide(),d(r)}catch(a){console.error("Modal onAction error:",a)}else n.dismiss||e.hide(),d(i);else try{const o=await n.handler({dialog:e,button:n,index:s,event:t});if(null===o||!1===o)return;const a=!0===o||void 0===o?i:o;n.dismiss||e.hide(),d(a)}catch(a){console.error("Modal button handler error:",a)}})}),e.on("hidden",()=>{l||(i?c(new Error("Dialog dismissed")):d(null)),setTimeout(async()=>{try{"function"==typeof s&&await s(e)}catch(a){console.error("Modal cleanup error:",a)}try{await e.destroy()}catch(a){console.error("Modal destroy error:",a)}e.element?.parentNode&&e.element.parentNode.removeChild(e.element)},100)}),e.show()})()})}static async dialog(e={}){"string"==typeof e&&(e={...arguments[2]||{},body:arguments[0],title:arguments[1]||"Alert"});const{title:t="Dialog",content:i,body:o,view:s,message:n,size:a="md",centered:r=!0,buttons:l=[{text:"OK",class:"btn-primary",value:!0}],rejectOnDismiss:d=!1,...c}=e,h=new ModalView({title:t,body:o??s??n??i??"",size:a,centered:r,buttons:l,...c});return Modal._renderAndAwait(h,{buttons:l,rejectOnDismiss:d})}static async drawer(t={}){const{eyebrow:i,title:o,meta:s=[],view:n,body:a,size:r="lg",...l}=t,d=s.length?`\n <div class="modal-drawer-meta">\n ${s.map(e=>"string"==typeof e?`<span>${Modal._esc(e)}</span>`:`<span>${e.icon?`<i class="${Modal._esc(e.icon)} me-1"></i>`:""}${Modal._esc(e.text||"")}</span>`).join("")}\n </div>`:"",c=`\n <div class="modal-drawer-head">\n ${i?`<span class="modal-drawer-eyebrow">${Modal._esc(i)}</span>`:""}\n <h2 class="modal-drawer-title">${Modal._esc(o||"")}</h2>\n ${d}\n </div>\n `;let h;return h=n&&"object"==typeof n&&"function"==typeof n.render?new class extends e{async getTemplate(){return`${c}<div class="modal-drawer-body" data-container="drawer-body"></div>`}async onInit(){n.containerId="drawer-body",this.addChild(n)}}:`${c}<div class="modal-drawer-body">${a||""}</div>`,Modal.dialog({header:!1,body:h,size:r,centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...l})}static _esc(e){const t="undefined"!=typeof document?document.createElement("div"):null;return t?(t.textContent=String(e??""),t.innerHTML):String(e??"")}static async show(e,t={}){return Modal.dialog({header:void 0!==t.title&&!!t.title,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 i=e.constructor,o=i?.VIEW_CLASS;if(!o)throw new Error(`Modal.showModel: No VIEW_CLASS defined on ${i?.name||"model"}. Set ${i?.name||"Model"}.VIEW_CLASS = YourView to use this method.`);const s=new o({model:e});return Modal.show(s,t)}static async showModelById(e,t,i={}){const o=new e({id:t});return await o.fetch(),o.id?Modal.showModel(o,i):(Modal.alert({message:`Could not find ${e.name||"record"} with ID: ${t}`,type:"warning"}),null)}static async showModelView(e,t={}){const i=e.constructor,o=i?.VIEW_CLASS;if(!o)throw new Error(`Modal.showModelView: No VIEW_CLASS defined on ${i?.name||"model"}.`);const s=new o({model:e});return Modal.dialog({header:!1,body:s,size:"lg",centered:!1,...t})}static async alert(e={},t,i){let o;o="string"==typeof e?{message:e,...void 0!==t?{title:t}:{},...i||{}}:{...e};const{message:s="",title:n="Alert",type:a="info",icon:r,className:l,...d}=o,c="danger"===a?"error":a,h=[`modal-alert modal-alert-${c}`,l].filter(Boolean).join(" "),u=void 0!==r?r:{info:"bi-info-circle",success:"bi-check-circle",warning:"bi-exclamation-triangle",error:"bi-x-circle"}[c],p=u?`<i class="bi ${u} modal-alert-icon"></i>`:"",m=`<span class="modal-alert-headline">${n}</span>`;return Modal.dialog({title:`${p}${m}`,body:`<p class="modal-alert-message">${s}</p>`,size:"sm",centered:!0,className:h,buttons:[{text:"OK",class:"btn-primary",value:!0}],...d})}static async confirm(e,t="Confirm",i={}){let o;"object"==typeof e&&null!==e?(o=(i=e).message,t=i.title||t):o=e;const s=[{text:i.cancelText||"Cancel",class:"btn-secondary",dismiss:!0,action:"cancel"},{text:i.confirmText||"Confirm",class:i.confirmClass||"btn-primary",action:"confirm"}],n=new ModalView({title:t,body:`<p>${o}</p>`,size:i.size||"sm",centered:!0,backdrop:"static",buttons:s,...i});return"confirm"===await Modal._renderAndAwait(n,{buttons:s})}static async prompt(e,t="Input",i={}){const o=`prompt-input-${Date.now()}`,s=i.defaultValue||"",n=i.inputType||"text",a=i.placeholder||"",r=[{text:"Cancel",class:"btn-secondary",dismiss:!0},{text:"OK",class:"btn-primary",action:"ok"}],l=new ModalView({title:t,body:`\n <p>${e}</p>\n <input type="${n}"\n class="form-control"\n id="${o}"\n value="${s}"\n placeholder="${a}">\n `,size:i.size||"sm",centered:!0,backdrop:"static",buttons:r,...i});return l.on("shown",()=>{const e=l.element.querySelector(`#${o}`);e&&(e.focus(),e.select())}),Modal._renderAndAwait(l,{buttons:r,onAction:async e=>{if("ok"!==e)return null;const t=l.element.querySelector(`#${o}`);return t?t.value:null}})}static showError(e){return Modal.alert(e,"Error",{type:"error"})}static async form(e={}){const{title:t="Form",formConfig:i={},size:o="md",centered:s=!0,submitText:n="Submit",cancelText:a="Cancel",...r}=e,l=new(0,(await import("./FormView-CgnaTPkQ.js").then(e=>e.c)).default)({fileHandling:e.fileHandling||"base64",data:e.data,defaults:e.defaults,model:e.model,formConfig:{fields:i.fields||e.fields,...i,submitButton:!1,resetButton:!1}}),d=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],c=new ModalView({title:t,body:l,size:o,centered:s,buttons:d,...r});return Modal._renderAndAwait(c,{buttons:d,onAction:async t=>{if("cancel"===t)return c.hide(),null;if("submit"!==t)return null;if(!l.validate())return l.focusFirstError(),!1;if(e.autoSave&&e.model){c.setLoading(!0);const e=await l.saveModel();return e.success?e:(c.setLoading(!1),await c.render(),c.getApp()?.toast?.error(e.message),!1)}try{return await l.getFormData()}catch(i){return console.error("Modal.form: error collecting form data:",i),l.showError("Error collecting form data"),!1}},cleanup:async()=>{try{await l.destroy()}catch{}}})}static async modelForm(e={}){const{title:t="Edit",formConfig:i={},size:o="md",centered:s=!0,submitText:n="Save",cancelText:a="Cancel",model:r,fields:l,...d}=e;if(!r)throw new Error("Modal.modelForm requires a model");const c=new(0,(await import("./FormView-CgnaTPkQ.js").then(e=>e.c)).default)({fileHandling:e.fileHandling||"base64",model:r,data:e.data,defaults:e.defaults,formConfig:{fields:l||i.fields||[],...i,submitButton:!1,resetButton:!1}}),h=[{text:a,class:"btn-secondary",action:"cancel"},{text:n,class:"btn-primary",action:"submit"}],u=new ModalView({title:t,body:c,size:o,centered:s,buttons:h,...d});return Modal._renderAndAwait(u,{buttons:h,onAction:async e=>{if("cancel"===e)return u.hide(),null;if("submit"!==e)return null;u.setLoading(!0,"Saving...");try{const e=await c.handleSubmit();if(e.success)return e;u.setLoading(!1);let t=e.error;return e.data?.error&&(t=e.data.error),u.getApp()?.toast?.error(t),!1}catch(t){return console.error("Modal.modelForm: error saving:",t),await u.setContent(c),c.showError(t.message||"An error occurred while saving"),!1}},cleanup:async()=>{try{await c.destroy()}catch{}}})}static async data(e={}){const{title:t="Data View",data:i={},model:o=null,fields:s=[],columns:n=2,responsive:a=!0,showEmptyValues:r=!1,emptyValueText:l="—",size:d="lg",centered:c=!0,closeText:h="Close",...u}=e,p=new(0,(await import("./DataView-fA6qQbvN.js")).default)({data:i,model:o,fields:s,columns:n,responsive:a,showEmptyValues:r,emptyValueText:l}),m=[{text:h,class:"btn-secondary",value:"close"}],g=new ModalView({title:t,body:p,size:d,centered:c,buttons:m,...u});return p.on("field:click",e=>g.emit("dataview:field:click",e)),p.on("error",e=>g.emit("dataview:error",e)),Modal._renderAndAwait(g,{buttons:m,cleanup:async()=>{try{await p.destroy()}catch{}}})}static async code(e={}){const{code:t="",language:i="javascript",title:o="Source Code",size:s="lg",...n}=e,a=new CodeViewer({code:t,language:i}),r=[{text:"Copy to Clipboard",class:"btn-primary",icon:"bi-clipboard",action:"copy"},{text:"Close",class:"btn-secondary",dismiss:!0}],l=new ModalView({title:o,body:a,size:s,scrollable:!0,buttons:r,...n});return Modal._renderAndAwait(l,{buttons:r,onAction:async e=>{if("copy"!==e)return null;if(!navigator.clipboard)return!1;try{await navigator.clipboard.writeText(t),Modal._showCopySuccess(l)}catch(i){console.error("Modal.code: clipboard write failed:",i)}return!1}})}static _showCopySuccess(e){const t=e.element?.querySelector('[data-action="copy"]');if(!t)return;const i=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=i,t.classList.remove("btn-success"),t.classList.add("btn-primary"),t.disabled=!1},2e3)}static async htmlPreview(e={}){const{html:t=e.content||"",title:i="HTML Preview",size:o="lg",height:s=500,...n}=e,a=new HtmlPreview({html:t,height:s}),r=[{text:"Close",class:"btn-secondary",dismiss:!0}],l=new ModalView({title:i,body:a,size:o,scrollable:!1,buttons:r,...n});return Modal._renderAndAwait(l,{buttons:r})}static async updateModelImage(e={},t={}){const i=e.upload||!1,o=t.name||e.field||"image",s={title:"Upload Your Avatar",model:null,autoSave:!i,size:"sm",fields:[{type:"image",name:o,size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your image",...t}],...e},n=await Modal.form(s);if(!i||!n||!e.model)return n;const a=n[o];if(!a||!a.startsWith("data:"))return n;const l=a.split(","),d=l[0]?.match(/:(.*?);/),c=d?.[1]||"image/png",h=atob(l[1]);let u=h.length;const p=new Uint8Array(u);for(;u--;)p[u]=h.charCodeAt(u);const m=c.split("/")[1]||"png",g="undefined"!=typeof window&&window.File||globalThis.File;if(!g)throw new Error("File API is not available in this environment");const f=new g([p],`${o}.${m}`,{type:c}),w=new r;return await w.upload({file:f,name:`${o}.${m}`,description:e.uploadDescription||`${o} upload`,showToast:!0}),e.model.save({[o]:w.id})}static loading(e){u.show(e)}static hideLoading(e){u.hide(e)}static showBusy(e){return Modal.loading(e)}static hideBusy(e){return Modal.hideLoading(e)}}const m=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,default:Modal},Symbol.toStringTag,{value:"Module"}));export{CodeViewer as C,r as F,ModalView as M,ProgressView as P,ToastService as T,Modal as a,l as b,FileList as c,FileManager as d,a as e,FileManagerList as f,FileUpload as g,m as h};
|
|
3
|
+
//# sourceMappingURL=Modal-DKjxtaZI.js.map
|