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
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const e=require("./View-IgBQlwd0.js"),t=require("./Collection-7F3lsq4z.js"),i=require("./FormPlugins-CEjco_Hb.js");class FormBuilder{constructor(e={}){this.fields=e.fields||[],this.structureOnly=e.structureOnly||!1,this.fields.forEach(e=>{e.cols&&!e.columns?(e.columns=e.cols,delete e.cols):e.columns||(e.columns=12),"group"===e.type&&e.fields&&e.fields.forEach(e=>{e.cols&&!e.columns?(e.columns=e.cols,delete e.cols):e.columns||(e.columns=12)})}),this.options={formClass:"needs-validation",formMethod:"POST",formAction:"",groupClass:"row mb-3",fieldWrapper:"",labelClass:"form-label",inputClass:"form-control",errorClass:"invalid-feedback",helpClass:"form-text",submitButton:!1,resetButton:!1,...e.options},this.buttons=e.buttons||[],this.data=e.data||{},this.errors=e.errors||{},this.initializeTemplates()}initializeTemplates(){i.FormPlugins.onFormBuilderInit?.(this),this.templates={input:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n {{#showCopy}}\n <div class="input-group">\n <input type="{{type}}" id="{{fieldId}}" name="{{name}}"\n class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n value="{{fieldValue}}" {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#readonly}}readonly{{/readonly}} {{{attrs}}}>\n <button class="btn btn-outline-secondary" type="button" data-action="copy-to-clipboard" data-target="{{fieldId}}" title="Copy to clipboard">\n <i class="bi bi-clipboard"></i>\n </button>\n </div>\n {{/showCopy}}\n {{^showCopy}}\n <input type="{{type}}" id="{{fieldId}}" name="{{name}}"\n class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n value="{{fieldValue}}" {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#readonly}}readonly{{/readonly}} {{{attrs}}}>\n {{/showCopy}}\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',password:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n <div class="input-group">\n <input type="password" id="{{fieldId}}" name="{{name}}"\n class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n value="{{fieldValue}}" {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#readonly}}readonly{{/readonly}}\n data-field-type="password" {{{attrs}}}>\n {{#showToggle}}\n <button type="button" class="btn btn-outline-secondary"\n data-action="toggle-password"\n data-target="{{fieldId}}"\n aria-label="Show password" aria-pressed="false">\n <i class="bi bi-eye"></i>\n </button>\n {{/showToggle}}\n </div>\n {{#strengthMeter}}\n <div class="mt-2">\n <div class="progress" style="height: 4px;">\n <div class="progress-bar bg-secondary" role="progressbar"\n style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"\n id="{{fieldId}}_strength_bar"></div>\n </div>\n <small class="{{helpClass}}" id="{{fieldId}}_strength_text">Strength</small>\n </div>\n {{/strengthMeter}}\n {{#capsLockWarning}}\n <div class="{{helpClass}} text-warning d-none" id="{{fieldId}}_caps_warning">\n Caps Lock is on\n </div>\n {{/capsLockWarning}}\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',textarea:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n {{#showCopy}}\n <div class="position-relative">\n <textarea id="{{fieldId}}" name="{{name}}" class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n rows="{{rows}}" {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#readonly}}readonly{{/readonly}} {{{attrs}}}>{{fieldValue}}</textarea>\n <button class="btn btn-sm btn-outline-secondary position-absolute top-0 end-0 m-2" type="button" data-action="copy-to-clipboard" data-target="{{fieldId}}" title="Copy to clipboard">\n <i class="bi bi-clipboard"></i>\n </button>\n </div>\n {{/showCopy}}\n {{^showCopy}}\n <textarea id="{{fieldId}}" name="{{name}}" class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n rows="{{rows}}" {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#readonly}}readonly{{/readonly}} {{{attrs}}}>{{fieldValue}}</textarea>\n {{/showCopy}}\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',htmlpreview:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n <div class="position-relative">\n <textarea id="{{fieldId}}" name="{{name}}" class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n rows="{{rows}}" {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#readonly}}readonly{{/readonly}}\n data-field-type="htmlpreview" {{{attrs}}}>{{fieldValue}}</textarea>\n <div class="position-absolute d-flex gap-1" style="top: 8px; right: 8px; z-index: 10;">\n {{#showCopy}}\n <button type="button" class="btn btn-sm btn-outline-secondary"\n data-action="copy-to-clipboard"\n data-target="{{fieldId}}"\n title="Copy to clipboard"\n aria-label="Copy to clipboard">\n <i class="bi bi-clipboard"></i>\n </button>\n {{/showCopy}}\n <button type="button" class="btn btn-sm btn-outline-secondary"\n data-action="preview-html"\n data-target="{{fieldId}}"\n title="Preview HTML"\n aria-label="Preview HTML">\n <i class="bi bi-eye"></i>\n </button>\n </div>\n </div>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',select:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n {{#searchInput}}{{{searchInput}}}{{/searchInput}}\n <select id="{{fieldId}}" name="{{name}}" class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#multiple}}multiple{{/multiple}} {{{attrs}}}>\n {{{optionsHTML}}}\n </select>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',checkbox:'\n <div class="mojo-form-control">\n <div class="form-check {{fieldClass}}">\n <input type="checkbox" id="{{fieldId}}" name="{{name}}"\n class="form-check-input{{#error}} is-invalid{{/error}}" value="{{value}}"\n {{#checked}}checked{{/checked}} {{#required}}required{{/required}}\n {{#disabled}}disabled{{/disabled}} {{{attrs}}}>\n <label class="form-check-label" for="{{fieldId}}">{{label}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}</label>\n </div>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',switch:'\n <div class="mojo-form-control">\n <div class="form-check form-switch {{sizeClass}} {{fieldClass}}">\n <input type="checkbox" id="{{fieldId}}" name="{{name}}" role="switch"\n class="form-check-input{{#error}} is-invalid{{/error}}" value="{{value}}"\n {{#checked}}checked{{/checked}} {{#required}}required{{/required}}\n {{#disabled}}disabled{{/disabled}} data-change-action="toggle-switch"\n data-field="{{name}}" {{{attrs}}}>\n <label class="form-check-label" for="{{fieldId}}">{{label}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}</label>\n </div>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',image:'\n <div class="mojo-form-control" style="display: flex; flex-direction: column; align-items: center;">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n <div class="image-field-container {{containerClass}}" id="{{dropZoneId}}" style="width: {{width}}px; height: {{height}}px;">\n <input type="file" id="{{fieldId}}" name="{{name}}" class="{{inputClass}} d-none{{#error}} is-invalid{{/error}}"\n accept="{{accept}}" {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n data-change-action="image-selected" data-field="{{name}}" {{{attrs}}}>\n <div class="image-drop-zone{{#allowDrop}} droppable{{/allowDrop}}" data-action="click-image-upload"\n data-field-id="{{fieldId}}" data-field="{{name}}" style="width: 100%; height: 100%; cursor: {{cursor}};">\n {{#imageUrl}}\n <img id="{{previewId}}" src="{{imageUrl}}" alt="Preview" class="img-thumbnail w-100 h-100" style="object-fit: cover;">\n {{#showRemove}}\n <button type="button" class="btn btn-sm btn-danger position-absolute top-0 end-0 m-1"\n data-action="remove-image" data-field-id="{{fieldId}}" data-field="{{name}}" style="opacity: 0.8;">\n <i class="bi bi-x"></i>\n </button>\n {{/showRemove}}\n {{/imageUrl}}\n {{^imageUrl}}\n <div class="d-flex flex-column align-items-center justify-content-center h-100 text-muted border border-2 border-dashed">\n <i class="bi bi-image fs-1 mb-2"></i>\n <small class="text-center px-2">{{placeholderText}}</small>\n </div>\n {{/imageUrl}}\n </div>\n </div>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',range:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}: <span id="{{fieldId}}_value">{{fieldValue}}</span>\n </label>\n {{/label}}\n <input type="range" id="{{fieldId}}" name="{{name}}" class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n min="{{min}}" max="{{max}}" step="{{step}}" value="{{fieldValue}}" {{#disabled}}disabled{{/disabled}}\n data-change-action="range-changed" data-target="{{fieldId}}_value" {{{attrs}}}>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',file:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n <input type="file" id="{{fieldId}}" name="{{name}}" class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n accept="{{accept}}" {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#multiple}}multiple{{/multiple}} data-change-action="file-selected" {{{attrs}}}>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',radio:'\n <div class="mojo-form-control">\n {{#label}}<div class="{{labelClass}}">{{label}}{{#required}}<span class="text-danger">*</span>{{/required}}</div>{{/label}}\n {{#options}}\n <div class="form-check">\n <input type="radio" id="{{fieldId}}_{{value}}" name="{{name}}" value="{{value}}"\n class="form-check-input{{#error}} is-invalid{{/error}}" {{#checked}}checked{{/checked}}\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{{attrs}}}>\n <label class="form-check-label" for="{{fieldId}}_{{value}}">{{text}}</label>\n </div>\n {{/options}}\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n ',button:'\n <button type="button" {{#name}}name="{{name}}"{{/name}} class="btn {{fieldClass}}"\n {{#action}}data-action="{{action}}"{{/action}} {{#disabled}}disabled{{/disabled}} {{{attrs}}}>\n {{label}}\n </button>\n ',divider:'\n <hr class="{{dividerClass}}">\n ',html:'\n <div class="form-html {{fieldClass}}">{{{html}}}</div>\n ',header:'\n <h{{level}} {{#id}}id="{{id}}"{{/id}} class="text-primary mb-3 {{fieldClass}}">{{text}}</h{{level}}>\n ',hidden:'\n <input type="hidden" id="{{fieldId}}" name="{{name}}" value="{{fieldValue}}">\n ',checklistdropdown:'\n <div class="dropdown">\n <button class="{{buttonClass}}" type="button" data-bs-toggle="dropdown">\n <i class="{{buttonIcon}} me-1"></i> {{buttonText}}\n </button>\n <div class="{{dropdownClass}}" style="min-width: {{minWidth}};">\n {{#options}}\n <div class="form-check">\n <input class="form-check-input" type="checkbox"\n value="{{value}}"\n id="{{id}}"\n {{#checked}}checked{{/checked}}\n data-change-action="update-checklist"\n data-field="{{fieldName}}">\n <label class="form-check-label" for="{{id}}">\n {{label}}\n </label>\n </div>\n {{/options}}\n <hr class="my-2">\n <button class="btn btn-sm btn-primary w-100" data-action="apply-filter">\n Apply\n </button>\n </div>\n </div>\n ',buttongroup:'\n <div class="btn-group btn-group-{{size}}" role="group">\n {{#options}}\n <button type="button" class="{{buttonClass}} {{#active}}active{{/active}}"\n {{^action}}\n data-action="select-button-option"\n {{/action}}\n {{#action}}\n data-action=\'{{action}}\'\n {{/action}}\n data-field="{{fieldName}}"\n data-value="{{value}}">\n {{#icon}}<i class="{{icon}} me-1"></i> {{/icon}} {{label}}\n </button>\n {{/options}}\n </div>\n ',toolbarform:'\n <div class="mojo-toolbar-form">\n <div class="row g-2 align-items-center">\n {{#fields}}\n <div class="{{containerClass}}">\n {{#label}}<label class="form-label-sm mb-1">{{label}}</label>{{/label}}\n {{{fieldHtml}}}\n </div>\n {{/fields}}\n </div>\n </div>\n ',color:'\n <div class="mojo-form-control">\n {{#label}}\n <label for="{{fieldId}}" class="{{labelClass}}">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}{{#tooltip}} <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="{{tooltip}}" style="font-size: 0.75rem; cursor: help;"></i>{{/tooltip}}\n </label>\n {{/label}}\n <div class="d-flex align-items-center gap-2">\n <input type="color" id="{{fieldId}}" name="{{name}}"\n class="{{inputClass}}{{#error}} is-invalid{{/error}}"\n value="{{fieldValue}}"\n {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}\n {{#readonly}}readonly{{/readonly}} {{{attrs}}}>\n <button type="button" class="btn-sm text-muted border-0 bg-transparent p-1"\n data-action="clear-color" data-field="{{name}}"\n title="Clear color">\n <i class="bi bi-x fs-5"></i>\n </button>\n </div>\n {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}\n {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}\n </div>\n '}}buildFormHTML(){const e=this.buildFieldsHTML(),t=this.buildButtonsHTML();return`\n <form class="${this.options.formClass}" novalidate>\n ${e}\n ${t}\n </form>\n `}isAutoSizingField(e){return!e.columns||"auto"===e.columns||""===e.columns}buildFieldsHTML(){const e=[];let t=0;for(;t<this.fields.length;){const i=this.fields[t];if(i.columns=i.columns||i.cols,"group"===i.type){const s=[i];let n=i.columns||12;"object"==typeof n&&null!==n&&(n=n.md||n.sm||n.xs||12);let a=t+1;for(;a<this.fields.length&&"group"===this.fields[a].type&&n<12;){const e=this.fields[a];let t=e.columns||12;if("object"==typeof t&&null!==t&&(t=t.md||t.sm||t.xs||12),!(n+t<=12))break;s.push(e),n+=t,a++}let l=s.length>1;if(1===s.length&&i.columns){let e=i.columns;"object"==typeof e&&null!==e&&(e=e.md||e.sm||e.xs||12),l=l||e<12}if(l){const t=s.map(e=>this.buildGroupHTML(e)).join("");e.push(`<div class="row">${t}</div>`)}else e.push(this.buildGroupHTML(i));t=a}else if(i.columns&&i.columns<12){const s=[i];let n=i.columns||12;"object"==typeof n&&null!==n&&(n=n.md||n.sm||n.xs||12);let a=t+1;for(;a<this.fields.length&&this.fields[a].columns&&n<12;){const e=this.fields[a];let t=e.columns||12;if("object"==typeof t&&null!==t&&(t=t.md||t.sm||t.xs||12),!(n+t<=12))break;s.push(e),n+=t,a++}const l=s.map(e=>this.buildFieldHTML(e)).join("");e.push(`<div class="row">${l}</div>`),t=a}else if(this.isAutoSizingField(i)){const s=[i];let n=t+1;for(;n<this.fields.length;){const e=this.fields[n];if(!this.isAutoSizingField(e))break;s.push(e),n++}if(s.length>1){const t=s.map(e=>this.buildFieldHTML(e)).join("");e.push(`<div class="row">${t}</div>`)}else e.push(`<div class="row">${this.buildFieldHTML(i)}</div>`);t=n}else e.push(this.buildFieldHTML(i)),t++}return e.join("")}buildGroupHTML(e){const{columns:t=12,title:i,fields:s=[],class:n="",titleClass:a="h6 mb-3",responsive:l={}}=e;let r=[];if("object"==typeof t&&null!==t){if(t.xs&&r.push(`col-${t.xs}`),t.sm&&r.push(`col-sm-${t.sm}`),t.md&&r.push(`col-md-${t.md}`),t.lg&&r.push(`col-lg-${t.lg}`),t.xl&&r.push(`col-xl-${t.xl}`),t.xxl&&r.push(`col-xxl-${t.xxl}`),!t.md&&(t.xs||t.sm)){const e=t.sm||t.xs;r.push(`col-md-${e}`)}0===r.length&&r.push("col-md-12")}else r.push(`col-md-${t}`);l.xs&&r.push(`col-${l.xs}`),l.sm&&r.push(`col-sm-${l.sm}`),l.lg&&r.push(`col-lg-${l.lg}`),l.xl&&r.push(`col-xl-${l.xl}`);const o=r.join(" "),d=s.map(e=>"group"===e.type?this.buildGroupHTML(e):this.buildFieldHTML(e)).join("");return`\n <div class="${o}">\n <div class="mojo-form-group ${n}">\n ${i?`<div class="${a}">${this.escapeHtml(i)}</div>`:""}\n <div class="row">\n ${d}\n </div>\n </div>\n </div>\n `}buildFieldHTML(e){const{type:t,columns:s,class:n=""}=e;let a="";const l=i.FormPlugins&&"function"==typeof i.FormPlugins.getRenderer?i.FormPlugins.getRenderer(t):null;if("function"==typeof l)try{const t=l(this,e);null!=t&&(a=String(t))}catch(c){console.error("FormPlugins custom renderer error:",c)}if(!a)switch(t){case"text":a=this.renderTextField(e);break;case"email":a=this.renderEmailField(e);break;case"password":a=this.renderPasswordField(e);break;case"number":a=this.renderNumberField(e);break;case"tel":a=this.renderTelField(e);break;case"url":a=this.renderUrlField(e);break;case"search":a=this.renderSearchField(e);break;case"hex":a=this.renderHexField(e);break;case"textarea":a=this.renderTextareaField(e);break;case"htmlpreview":a=this.renderHtmlPreviewField(e);break;case"json":a=this.renderJsonField(e);break;case"select":a=this.renderSelectField(e);break;case"multiselect":a=this.renderMultiSelectField(e);break;case"checkbox":a=this.renderCheckboxField(e);break;case"toggle":case"switch":a=this.renderSwitchField(e);break;case"radio":a=this.renderRadioField(e);break;case"date":a=this.renderDateField(e);break;case"datetime":a=this.renderDateTimeField(e);break;case"time":a=this.renderTimeField(e);break;case"file":a=this.renderFileField(e);break;case"image":a=this.renderImageField(e);break;case"color":a=this.renderColorField(e);break;case"range":a=this.renderRangeField(e);break;case"hidden":a=this.renderHiddenField(e);break;case"button":a=this.renderButton(e);break;case"divider":a=this.renderDivider(e);break;case"html":a=this.renderHtmlField(e);break;case"heading":case"header":a=this.renderHeaderField(e);break;case"tag":case"tags":a=this.renderTagField(e);break;case"collection":a=this.renderCollectionField(e);break;case"collectionmultiselect":case"collection-multiselect":a=this.renderCollectionMultiSelectField(e);break;case"datepicker":a=this.renderDatePickerField(e);break;case"monthpicker":a=this.renderDatePickerField({...e,precision:"month"});break;case"yearpicker":a=this.renderDatePickerField({...e,precision:"year"});break;case"daterange":a=this.renderDateRangeField(e);break;case"monthrange":a=this.renderDateRangeField({...e,precision:"month"});break;case"yearrange":a=this.renderDateRangeField({...e,precision:"year"});break;case"timepicker":a=this.renderTimePickerField(e);break;case"datetimepicker":a=this.renderDateTimePickerField(e);break;case"checklistdropdown":a=this.renderChecklistDropdownField(e);break;case"buttongroup":a=this.renderButtonGroupField(e);break;case"combo":case"combobox":case"autocomplete":a=this.renderComboField(e);break;case"tabset":a=this.renderTabsetField(e);break;default:console.warn(`Unknown field type: ${t}`),a=this.renderTextField(e)}let r;r=this.isAutoSizingField(e)?`col ${n}`.trim():`col-${s} ${n}`.trim();let o="",d="";if(e.showWhen){const t=e.showWhen,i=Array.isArray(t.value)?t.value:[t.value];o=` data-show-when-field="${t.field}" data-show-when-value="${i.join(",")}"`,t.negate&&(o+=' data-show-when-negate="true"');let s=this.data[t.field];if(null==s){const e=this._findField(t.field,this.fields);e&&(s=e.value)}const n=String(s??""),a=i.map(String).includes(n);(t.negate?!a:a)||(d=' style="display:none"')}return`<div class="${r}"${o}${d}>${a}</div>`}_findField(e,t){for(const i of t){if(i.name===e)return i;if(i.fields){const t=this._findField(e,i.fields);if(t)return t}if(i.tabs)for(const t of i.tabs)if(t.fields){const i=this._findField(e,t.fields);if(i)return i}}return null}getFieldId(e){return e?`field_${e.replace(/[.\s\[\]]/g,"_")}`:`field_${Math.random().toString(36).substr(2,9)}`}renderTextField(e){return this.renderInputField(e,"text")}renderEmailField(e){return this.renderInputField(e,"email")}renderPasswordField(e){const t=e.passwordUsage||"current",i="new"===t||"new-password"===t?"new-password":"current-password",s={...e.attributes||{},autocomplete:e.attributes&&e.attributes.autocomplete||i};return this.renderInputField({...e,showToggle:!1!==e.showToggle,attributes:s},"password")}renderNumberField(e){const{min:t,max:i,step:s=1,...n}=e,a=[];return void 0!==t&&a.push(`min="${t}"`),void 0!==i&&a.push(`max="${i}"`),void 0!==s&&a.push(`step="${s}"`),this.renderInputField({...n,attributes:{...n.attributes,...a.reduce((e,t)=>{const[i,s]=t.split("=");return e[i]=s.replace(/"/g,""),e},{})}},"number")}renderTelField(e){return this.renderInputField(e,"tel")}renderUrlField(e){return this.renderInputField(e,"url")}renderSearchField(e){const t={...e,attributes:{"data-filter":"live-search","data-change-action":"filter-search","data-filter-debounce":e.debounce||"300",...e.attributes}};return this.renderInputField(t,"search")}renderHexField(e){const{hexType:t="color",allowPrefix:i=!0,minLength:s,maxLength:n,...a}=e;let l,r,o,d,c;switch(t){case"color":l=i?"^#?[0-9A-Fa-f]{6}$":"^[0-9A-Fa-f]{6}$",r=6,o=i?7:6,d=i?"#FF0000":"FF0000",c=c||"Enter a valid hex color (e.g., "+d+")";break;case"color-short":l=i?"^#?[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$":"^[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$",r=i?4:3,o=i?7:6,d=i?"#F00 or #FF0000":"F00 or FF0000",c=c||"Enter a valid hex color (3 or 6 digits)";break;case"string":l="^[0-9A-Fa-f]+$",r=s||1,o=n||64,d="ABCDEF123456",c=c||"Only hexadecimal characters (0-9, A-F) allowed";break;default:l=i?"^#?[0-9A-Fa-f]+$":"^[0-9A-Fa-f]+$",r=s||1,o=n||64,d=i?"#ABCDEF or ABCDEF":"ABCDEF",c=c||"Enter hexadecimal characters only"}const h={...a,pattern:l,minLength:r,maxLength:o,placeholder:a.placeholder||d,help:a.help||c,attributes:{"data-hex-type":t,"data-allow-prefix":i,style:"text-transform: uppercase;",...a.attributes}};return this.renderInputField(h,"text")}renderInputField(t,i="text"){const{name:s,label:n,value:a="",placeholder:l="",required:r=!1,disabled:o=!1,readonly:d=!1,class:c="",attributes:h={},help:u=t.helpText||t.help||""}=t,p=`${this.options.inputClass} ${c}`.trim(),m=this.errors[s],g=this.getFieldValue(s)??a,b=Object.entries(h).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),f=this.getFieldId(s),v={labelClass:this.options.labelClass,inputClass:p,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:f,name:s,type:i,fieldValue:this.escapeHtml(g),label:n?this.escapeHtml(n):null,placeholder:l?this.escapeHtml(l):null,help:u?this.escapeHtml(u):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:m?this.escapeHtml(m):null,required:r,disabled:o,readonly:d,attrs:b,showCopy:!!t.showCopy};if("password"===i&&(t.showToggle||t.strengthMeter||t.capsLockWarning)){const i={...v,showToggle:!!t.showToggle,strengthMeter:!!t.strengthMeter,capsLockWarning:!!t.capsLockWarning};return e.Mustache.render(this.templates.password,i)}if("password"===i){const i={...v,showToggle:!1!==t.showToggle,strengthMeter:!!t.strengthMeter,capsLockWarning:!!t.capsLockWarning};return e.Mustache.render(this.templates.password,i)}return e.Mustache.render(this.templates.input,v)}renderTextareaField(t){const{name:i,label:s,value:n="",placeholder:a="",required:l=!1,disabled:r=!1,readonly:o=!1,rows:d=3,cols:c,class:h="",attributes:u={},help:p=t.helpText||t.help||""}=t,m=`${this.options.inputClass} ${h}`.trim(),g=this.errors[i],b=this.getFieldValue(i)??n,f=Object.entries(u).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),v=this.getFieldId(i),y={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:v,name:i,fieldValue:b,label:s?this.escapeHtml(s):null,placeholder:a?this.escapeHtml(a):null,help:p?this.escapeHtml(p):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:g?this.escapeHtml(g):null,rows:d||3,required:l,disabled:r,readonly:o,showCopy:!!t.showCopy,attrs:f};return e.Mustache.render(this.templates.textarea,y)}renderHtmlPreviewField(t){const{name:i,label:s,value:n="",placeholder:a="",required:l=!1,disabled:r=!1,readonly:o=!1,rows:d=5,class:c="",attributes:h={},help:u=t.helpText||t.help||""}=t,p=`${this.options.inputClass} ${c}`.trim(),m=this.errors[i],g=this.getFieldValue(i)??n,b=Object.entries(h).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),f=this.getFieldId(i),v={labelClass:this.options.labelClass,inputClass:p,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:f,name:i,fieldValue:g,label:s?this.escapeHtml(s):null,placeholder:a?this.escapeHtml(a):null,help:u?this.escapeHtml(u):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:m?this.escapeHtml(m):null,rows:d||5,required:l,disabled:r,readonly:o,attrs:b,showCopy:!!t.showCopy};return e.Mustache.render(this.templates.htmlpreview,v)}renderJsonField(t){const{name:i,label:s,placeholder:n="",required:a=!1,disabled:l=!1,readonly:r=!1,rows:o=3,class:d="",attributes:c={},help:h=t.helpText||t.help||""}=t,u=this.getFieldValue(t.name)??t.value??{};let p=u;if("object"==typeof u&&null!==u)try{p=JSON.stringify(u,null,2)}catch(y){p="{}"}else"string"!=typeof u&&(p=String(u));const m=`${this.options.inputClass} ${d}`.trim(),g=this.errors[i],b=this.getFieldId(i),f=Object.entries({...c,"data-field-type":"json"}).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),v={labelClass:this.options.labelClass,inputClass:m,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:b,name:i,fieldValue:p,label:s?this.escapeHtml(s):null,placeholder:n?this.escapeHtml(n):null,help:h?this.escapeHtml(h):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:g?this.escapeHtml(g):null,rows:o||3,required:a,disabled:l,readonly:r,attrs:f};return e.Mustache.render(this.templates.textarea,v)}renderSelectField(t){const{name:i,label:s,options:n=[],value:a="",required:l=!1,disabled:r=!1,multiple:o=!1,searchable:d=!1,class:c="",attributes:h={},help:u=t.helpText||t.help||"",start:p=t.start,end:m=t.end,step:g=t.step,format:b=t.format,prefix:f=t.prefix,suffix:v=t.suffix}=t,y=`form-select ${c}`.trim(),w=this.errors[i],C=this.getFieldValue(i)??a,_=Object.entries(h).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),x=this.getFieldId(i);let S=[...n];if(void 0!==p&&void 0!==m){const e=void 0!==g?g:1,t=this.generateSelectOptions(p,m,e,{format:b,prefix:f,suffix:v});S=[...S,...t]}let F="";Array.isArray(S)&&(F=S.map(e=>{if("string"==typeof e){const t=e===C?"selected":"";return`<option value="${this.escapeHtml(e)}" ${t}>${this.escapeHtml(e)}</option>`}if(e&&"object"==typeof e){const t=e.value==C?"selected":"";return`<option value="${this.escapeHtml(e.value)}" ${t}>${this.escapeHtml(e.label||e.text||e.value)}</option>`}return""}).join(""));const D=d?`\n <input type="text"\n class="form-control form-control-sm mb-2"\n placeholder="Search options..."\n data-filter="live-search"\n data-change-action="filter-select-options"\n data-target="${x}">\n `:"",$={labelClass:this.options.labelClass,inputClass:y,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:x,name:i,label:s?this.escapeHtml(s):null,help:u?this.escapeHtml(u):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:w?this.escapeHtml(w):null,searchInput:d?D:null,optionsHTML:F,required:l,disabled:r,multiple:o,attrs:_};return e.Mustache.render(this.templates.select,$)}renderMultiSelectField(e){const{name:t,label:i,options:s=[],value:n=[],required:a=!1,disabled:l=!1,maxHeight:r=300,help:o=e.helpText||e.help||""}=e,d=e.placeholder||e.placeHolder||"Select...";this.getFieldId(t);const c=this.errors[t],h=e.value??this.getFieldValue(t)??n;return`\n <div class="multiselect-placeholder"\n data-field-name="${t}"\n data-field-type="multiselect"\n data-field-config='${JSON.stringify({name:t,value:h,placeholder:d,maxHeight:r,disabled:l,required:a})}'>\n <input type="hidden" name="${t}" value="${this.escapeHtml(JSON.stringify(h))}">\n <select class="form-select${c?" is-invalid":""}" \n multiple \n ${l?"disabled":""}\n ${a?"required":""}>\n ${s.map(e=>{const t="string"==typeof e?e:e.value,i="string"==typeof e?e:e.label||e.value,s=Array.isArray(h)&&h.includes(t)?"selected":"";return`<option value="${this.escapeHtml(t)}" ${s}>${this.escapeHtml(i)}</option>`}).join("")}\n </select>\n <small class="form-text text-muted">This will be enhanced with MultiSelectDropdown component</small>\n </div>\n `}renderCheckboxField(t){const{name:i,label:s,value:n=!1,required:a=!1,disabled:l=!1,class:r="",attributes:o={},help:d=t.helpText||t.help||""}=t,c=this.errors[i],h=this.getFieldValue(i)??n,u=!0===h||"true"===h||"1"===h,p=Object.entries(o).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),m=this.getFieldId(i),g={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:m,name:i,label:this.escapeHtml(s),help:d?this.escapeHtml(d):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:c?this.escapeHtml(c):null,value:this.escapeHtml(n),fieldClass:r,checked:u,required:a,disabled:l,attrs:p};return e.Mustache.render(this.templates.checkbox,g)}renderSwitchField(t){const{name:i,label:s,value:n=!1,required:a=!1,disabled:l=!1,size:r="md",class:o="",attributes:d={},help:c=t.helpText||t.help||""}=t,h=this.errors[i],u=this.getFieldValue(i)??n,p=!0===u||"true"===u||"1"===u,m=Object.entries(d).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),g=this.getFieldId(i),b="md"!==r?`form-switch-${r}`:"",f={helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:i,label:this.escapeHtml(s),help:c?this.escapeHtml(c):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:h?this.escapeHtml(h):null,value:this.escapeHtml(n),sizeClass:b,fieldClass:o,checked:p,required:a,disabled:l,attrs:m};return e.Mustache.render(this.templates.switch,f)}renderRadioField(e){const{name:t,label:i,options:s=[],value:n="",disabled:a=!1,inline:l=!1,class:r="",attributes:o={},help:d=e.helpText||e.help||""}=e,c=this.errors[t],h=this.getFieldValue(t)??n,u=Object.entries(o).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" ");let p="";return Array.isArray(s)&&(p=s.map((e,i)=>{const s=`${t}_${i}`,n="string"==typeof e?e:e.value,r="string"==typeof e?e:e.label||e.text||e.value,o=n===h?"checked":"";return`\n <div class="form-check ${l?"form-check-inline":""}">\n <input\n type="radio"\n id="${s}"\n name="${t}"\n class="form-check-input ${c?"is-invalid":""}"\n value="${this.escapeHtml(n)}"\n ${o}\n ${a?"disabled":""}\n\n ${u}\n >\n <label class="form-check-label" for="${s}">\n ${this.escapeHtml(r)}\n </label>\n </div>\n `}).join("")),`\n <div class="mojo-form-control">\n ${i?`<fieldset>\n <legend class="${this.options.labelClass}">${this.escapeHtml(i)}${this.renderTooltipIcon(e)}</legend>\n <div class="${r}">\n ${p}\n </div>\n </fieldset>`:`<div class="${r}">${p}</div>`}\n ${d?`<div class="${this.options.helpClass}">${this.escapeHtml(d)}</div>`:""}\n ${c?`<div class="${this.options.errorClass}">${this.escapeHtml(c)}</div>`:""}\n </div>\n `}renderDateField(e){return this.renderInputField(e,"date")}renderDateTimeField(e){return this.renderInputField(e,"datetime-local")}renderTimeField(e){return this.renderInputField(e,"time")}renderFileField(t){const{name:i,label:s,required:n=!1,disabled:a=!1,multiple:l=!1,accept:r="*/*",class:o="",attributes:d={},help:c=t.helpText||t.help||""}=t,h=`${this.options.inputClass} ${o}`.trim(),u=this.errors[i],p=Object.entries(d).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),m=this.getFieldId(i),g={labelClass:this.options.labelClass,inputClass:h,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:m,name:i,label:s?this.escapeHtml(s):null,help:c?this.escapeHtml(c):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:u?this.escapeHtml(u):null,accept:r,required:n,disabled:a,multiple:l,attrs:p};return e.Mustache.render(this.templates.file,g)}renderImageField(t){const{name:i,label:s,required:n=!1,disabled:a=!1,accept:l="image/*",class:r="",attributes:o={},help:d=t.helpText||t.help||"",size:c="md",allowDrop:h=!0,placeholder:u="Drop image here or click to upload"}=t,p=`${this.options.inputClass} ${r}`.trim(),m=this.errors[i],g=this.getFieldId(i),b=`${g}_dropzone`,f=`${g}_preview`,v={xs:{width:48,height:48,containerClass:"image-field-xs"},sm:{width:96,height:96,containerClass:"image-field-sm"},md:{width:150,height:150,containerClass:"image-field-md"},lg:{width:200,height:200,containerClass:"image-field-lg"},xl:{width:300,height:300,containerClass:"image-field-xl"}},y=v[c]||v.md,w=Object.entries(o).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),C=this.getFieldValue(i),_=this.extractImageUrl(C,c),x={labelClass:this.options.labelClass,inputClass:p,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:g,name:i,label:s?this.escapeHtml(s):null,help:d?this.escapeHtml(d):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:m?this.escapeHtml(m):null,dropZoneId:b,previewId:f,containerClass:y.containerClass,width:y.width,height:y.height,accept:l,imageUrl:_,placeholderText:a?"No image":this.escapeHtml(u),cursor:a?"default":"pointer",allowDrop:h,showRemove:!a,required:n,disabled:a,attrs:w};return e.Mustache.render(this.templates.image,x)}extractImageUrl(e,t="md"){if(!e)return null;if("string"==typeof e)return e;if("object"==typeof e&&e.url){if(e.renditions){const i={xs:["thumbnail_sm","thumbnail","square_sm"],sm:["thumbnail","thumbnail_sm","square_sm"],md:["thumbnail_md","thumbnail","thumbnail_lg"],lg:["thumbnail_lg","thumbnail_md","thumbnail"],xl:["original","thumbnail_lg"]},s=i[t]||i.md;for(const t of s)if(e.renditions[t]&&e.renditions[t].url)return e.renditions[t].url}return e.url}return null}renderColorField(t){const{name:i,label:s,value:n="",placeholder:a="",required:l=!1,disabled:r=!1,readonly:o=!1,class:d="",attributes:c={},help:h=t.helpText||t.help||""}=t,u=`${this.options.inputClass} ${d}`.trim(),p=this.errors[i],m=this.getFieldValue(i)??n,g=Object.entries(c).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),b=this.getFieldId(i),f={labelClass:this.options.labelClass,inputClass:u,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:b,name:i,fieldValue:this.escapeHtml(m),label:s?this.escapeHtml(s):null,placeholder:a?this.escapeHtml(a):null,help:h?this.escapeHtml(h):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:p?this.escapeHtml(p):null,required:l,disabled:r,readonly:o,attrs:g};return e.Mustache.render(this.templates.color,f)}renderRangeField(t){const{name:i,label:s,min:n=0,max:a=100,step:l=1,value:r=n,disabled:o=!1,class:d="",attributes:c={},help:h=t.helpText||t.help||""}=t,u=`${this.options.inputClass} ${d}`.trim(),p=this.errors[i],m=this.getFieldValue(i)??r,g=Object.entries(c).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" "),b=this.getFieldId(i),f={labelClass:this.options.labelClass,inputClass:u,helpClass:this.options.helpClass,errorClass:this.options.errorClass,fieldId:b,name:i,label:s?this.escapeHtml(s):null,help:h?this.escapeHtml(h):null,tooltip:t.tooltip?this.escapeHtml(t.tooltip):null,error:p?this.escapeHtml(p):null,min:n,max:a,step:l,fieldValue:m,disabled:o,attrs:g};return e.Mustache.render(this.templates.range,f)}renderHiddenField(e){const{name:t,value:i=""}=e,s=this.getFieldValue(t)??i;return`<input type="hidden" name="${t}" value="${this.escapeHtml(s)}">`}renderButton(e){const{name:t="",label:i="Button",type:s="button",action:n="",class:a="btn-secondary",disabled:l=!1,attributes:r={}}=e;let o=n;return o||("submit"===s?o="submit-form":"reset"===s&&(o="reset-form")),`\n <button\n type="button"\n ${t?`name="${t}"`:""}\n class="btn ${a}"\n ${o?`data-action="${o}"`:""}\n ${l?"disabled":""}\n ${Object.entries(r).map(([e,t])=>`${e}="${this.escapeHtml(t)}"`).join(" ")}\n >\n ${this.escapeHtml(i)}\n </button>\n `}renderDivider(e){const{label:t="",class:i=""}=e;return`\n <div class="form-divider ${i}">\n <hr>\n ${t?`<div class="form-divider-label">${this.escapeHtml(t)}</div>`:""}\n </div>\n `}renderHtmlField(e){const{html:t="",class:i=""}=e;return`\n <div class="form-html ${i}">\n ${t}\n </div>\n `}renderHeaderField(e){const{text:t="",level:i=3,class:s="",id:n=""}=e,a=Math.max(1,Math.min(6,parseInt(i)));return`<h${a}${n?` id="${this.escapeHtml(n)}"`:""}${s?` class="${this.escapeHtml(s)}"`:""}>${this.escapeHtml(t)}</h${a}>`}buildButtonsHTML(){if(!this.options.submitButton&&!this.options.resetButton&&!this.buttons.length)return"";let e="";if(this.buttons.forEach(t=>{e+=this.renderButton(t)+" "}),this.options.submitButton){let t="Submit";"string"==typeof this.options.submitButton?t=this.options.submitButton:!0===this.options.submitButton&&(t="Submit"),e+=`<button type="submit" class="btn btn-primary me-2" data-action="submit-form">${t}</button>`}if(this.options.resetButton){let t="Reset";"string"==typeof this.options.resetButton?t=this.options.resetButton:!0===this.options.resetButton&&(t="Reset"),e+=`<button type="button" class="btn btn-secondary" data-action="reset-form">${t}</button>`}return e?`\n <div class="form-actions mt-3">\n ${e}\n </div>\n `:""}getFieldValue(e){return this.structureOnly?"":t.MOJOUtils.getContextData(this.data,e)}renderTagField(e){const{name:t,label:i,value:s="",placeholder:n="Add tags...",required:a=!1,disabled:l=!1,readonly:r=!1,maxTags:o=50,allowDuplicates:d=!1,separator:c=",",help:h=e.helpText||e.help||""}=e,u=this.getFieldId(t),p=this.errors[t],m=this.getFieldValue(t)??s;return`\n <div class="mojo-form-control">\n ${i?`<label for="${u}" class="${this.options.labelClass}">${this.escapeHtml(i)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="tag-input-placeholder"\n data-field-name="${t}"\n data-field-type="tag"\n data-field-config='${JSON.stringify({name:t,value:m,placeholder:n,maxTags:o,allowDuplicates:d,separator:c,disabled:l,readonly:r,required:a})}'>\n <input type="text"\n id="${u}"\n name="${t}_display"\n class="${this.options.inputClass}${p?" is-invalid":""}"\n placeholder="${this.escapeHtml(n)}"\n ${l?"disabled":""}\n ${r?"readonly":""}\n\n <input type="hidden" name="${t}" value="${this.escapeHtml(m)}">\n <small class="form-text text-muted">This will be enhanced with TagInput component</small>\n </div>\n ${h?`<div class="${this.options.helpClass}">${this.escapeHtml(h)}</div>`:""}\n ${p?`<div class="${this.options.errorClass}">${this.escapeHtml(p)}</div>`:""}\n </div>\n `}renderCollectionField(e){const{name:t,label:i,value:s="",placeholder:n="Search...",required:a=!1,disabled:l=!1,readonly:r=!1,Collection:o,labelField:d="name",valueField:c="id",maxItems:h=10,emptyFetch:u=!1,debounceMs:p=300,requiresActiveGroup:m=!1,help:g=e.helpText||e.help||""}=e,b=this.getFieldId(t),f=this.errors[t],v=this.getFieldValue(t)??s;return`\n <div class="mojo-form-control">\n ${i?`<label for="${b}" class="${this.options.labelClass}">${this.escapeHtml(i)}${a?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="collection-select-placeholder"\n data-field-name="${t}"\n data-field-type="collection"\n data-field-config='${JSON.stringify({name:t,value:v,placeholder:n,labelField:d,valueField:c,maxItems:h,emptyFetch:u,debounceMs:p,disabled:l,readonly:r,required:a,requiresActiveGroup:m})}'>\n <input type="text"\n id="${b}"\n name="${t}_display"\n class="${this.options.inputClass}${f?" is-invalid":""}"\n placeholder="${this.escapeHtml(n)}"\n ${l?"disabled":""}\n ${r?"readonly":""}\n\n <input type="hidden" name="${t}" value="${this.escapeHtml(v)}">\n <small class="form-text text-muted">This will be enhanced with CollectionSelect component</small>\n </div>\n ${g?`<div class="${this.options.helpClass}">${this.escapeHtml(g)}</div>`:""}\n ${f?`<div class="${this.options.errorClass}">${this.escapeHtml(f)}</div>`:""}\n </div>\n `}renderCollectionMultiSelectField(e){const{name:t,label:i,value:s=[],required:n=!1,disabled:a=!1,Collection:l,collectionParams:r={},labelField:o="name",valueField:d="id",excludeIds:c=[],ignoreIds:h=[],size:u=8,maxHeight:p=null,showSelectAll:m=!0,enableSearch:g=!1,searchPlaceholder:b="Search...",searchDebounce:f=400,requiresActiveGroup:v=!1,help:y=e.helpText||e.help||""}=e;this.getFieldId(t);const w=this.errors[t],C=this.getFieldValue(t)??s;return`\n <div class="mojo-form-control">\n ${i?`<label class="${this.options.labelClass}">${this.escapeHtml(i)}${n?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="collection-multiselect-placeholder"\n data-field-name="${t}"\n data-field-type="collectionmultiselect"\n data-field-config='${JSON.stringify({name:t,value:C,labelField:o,valueField:d,excludeIds:c,ignoreIds:h,size:u,maxHeight:p,showSelectAll:m,enableSearch:g,searchPlaceholder:b,searchDebounce:f,disabled:a,required:n,requiresActiveGroup:v})}'>\n <input type="hidden" name="${t}" value="${this.escapeHtml(JSON.stringify(C))}">\n <small class="form-text text-muted">This will be enhanced with CollectionMultiSelect component</small>\n </div>\n ${y?`<div class="${this.options.helpClass}">${this.escapeHtml(y)}</div>`:""}\n ${w?`<div class="${this.options.errorClass}">${this.escapeHtml(w)}</div>`:""}\n </div>\n `}renderDatePickerField(e){const{name:t,label:i,value:s="",precision:n="day",placeholder:a,required:l=!1,disabled:r=!1,readonly:o=!1,min:d=null,max:c=null,format:h=null,displayFormat:u=null,disabledDates:p=[],firstDay:m=1,lang:g="en-US",autoApply:b=!0,inline:f=!1,help:v=e.helpText||e.help||""}=e,y=this.getFieldId(t),w=this.errors[t],C=this.getFieldValue(t)??s;return`\n <div class="mojo-form-control">\n ${i?`<label for="${y}" class="${this.options.labelClass}">${this.escapeHtml(i)}${l?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="date-picker-placeholder"\n data-field-name="${t}"\n data-field-type="datepicker"\n data-field-config='${JSON.stringify({name:t,value:C,precision:n,placeholder:a,min:d,max:c,format:h,displayFormat:u,disabledDates:p,firstDay:m,lang:g,autoApply:b,inline:f,disabled:r,readonly:o,required:l})}'></div>\n ${v?`<div class="${this.options.helpClass}">${this.escapeHtml(v)}</div>`:""}\n ${w?`<div class="${this.options.errorClass}">${this.escapeHtml(w)}</div>`:""}\n </div>\n `}renderDateRangeField(e){const{name:t,startName:i,endName:s,fieldName:n,label:a,startDate:l="",endDate:r="",precision:o="day",placeholder:d,required:c=!1,disabled:h=!1,readonly:u=!1,min:p=null,max:m=null,format:g=null,displayFormat:b=null,outputFormat:f="date",separator:v=" – ",months:y=null,presets:w=null,autoApply:C=!0,inline:_=!1,help:x=e.helpText||e.help||""}=e,S=this.getFieldId(t||i||"daterange"),F=this.errors[t],D=i||(t?t+"_start":""),$=s||(t?t+"_end":""),T=this.getFieldValue(D)||l,V=this.getFieldValue($)||r;return`\n <div class="mojo-form-control">\n ${a?`<label for="${S}" class="${this.options.labelClass}">${this.escapeHtml(a)}${c?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="date-range-picker-placeholder"\n data-field-name="${t||i||"daterange"}"\n data-field-type="daterange"\n data-field-config='${JSON.stringify({name:t,startName:i,endName:s,fieldName:n,startDate:T,endDate:V,precision:o,placeholder:d,min:p,max:m,format:g,displayFormat:b,outputFormat:f,separator:v,months:y,presets:w,autoApply:C,inline:_,disabled:h,readonly:u,required:c})}'></div>\n ${x?`<div class="${this.options.helpClass}">${this.escapeHtml(x)}</div>`:""}\n ${F?`<div class="${this.options.errorClass}">${this.escapeHtml(F)}</div>`:""}\n </div>\n `}renderTimePickerField(e){const{name:t,label:i,value:s="",format:n="24h",step:a=1,min:l=null,max:r=null,placeholder:o,required:d=!1,disabled:c=!1,readonly:h=!1,timezone:u=!1,timezones:p=null,outputFormat:m="string",autoApply:g=!1,inline:b=!1,help:f=e.helpText||e.help||""}=e,v=this.getFieldId(t),y=this.errors[t],w=this.getFieldValue(t)??s;return`\n <div class="mojo-form-control">\n ${i?`<label for="${v}" class="${this.options.labelClass}">${this.escapeHtml(i)}${d?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="time-picker-placeholder"\n data-field-name="${t}"\n data-field-type="timepicker"\n data-field-config='${JSON.stringify({name:t,value:w,format:n,step:a,min:l,max:r,placeholder:o,timezone:u,timezones:p,outputFormat:m,autoApply:g,inline:b,disabled:c,readonly:h,required:d})}'></div>\n ${f?`<div class="${this.options.helpClass}">${this.escapeHtml(f)}</div>`:""}\n ${y?`<div class="${this.options.errorClass}">${this.escapeHtml(y)}</div>`:""}\n </div>\n `}renderDateTimePickerField(e){const{name:t,label:i,value:s="",displayFormat:n=null,timeFormat:a="24h",timeStep:l=1,min:r=null,max:o=null,placeholder:d,required:c=!1,disabled:h=!1,readonly:u=!1,disabledDates:p=[],firstDay:m=1,lang:g="en-US",timezone:b=!1,timezones:f=null,outputFormat:v="string",autoApply:y=!1,inline:w=!1,help:C=e.helpText||e.help||""}=e,_=this.getFieldId(t),x=this.errors[t],S=this.getFieldValue(t)??s;return`\n <div class="mojo-form-control">\n ${i?`<label for="${_}" class="${this.options.labelClass}">${this.escapeHtml(i)}${c?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="datetime-picker-placeholder"\n data-field-name="${t}"\n data-field-type="datetimepicker"\n data-field-config='${JSON.stringify({name:t,value:S,displayFormat:n,timeFormat:a,timeStep:l,min:r,max:o,placeholder:d,disabledDates:p,firstDay:m,lang:g,timezone:b,timezones:f,outputFormat:v,autoApply:y,inline:w,disabled:h,readonly:u,required:c})}'></div>\n ${C?`<div class="${this.options.helpClass}">${this.escapeHtml(C)}</div>`:""}\n ${x?`<div class="${this.options.errorClass}">${this.escapeHtml(x)}</div>`:""}\n </div>\n `}renderChecklistDropdownField(t){const i=this.getFieldId(t.name),s=this.getFieldValue(t.name)??[],n={fieldId:i,fieldName:t.name,buttonText:t.buttonText||"Select Options",buttonIcon:t.buttonIcon||"bi-chevron-down",buttonClass:t.buttonClass||"btn btn-outline-secondary btn-sm dropdown-toggle",dropdownClass:t.dropdownClass||"dropdown-menu p-2",minWidth:t.minWidth||"200px",options:t.options.map(e=>({value:e.value,label:e.label,id:`${t.name}-${e.value}`,checked:s.includes(e.value)}))};return e.Mustache.render(this.templates.checklistdropdown,n)}renderButtonGroupField(t){const i=this.getFieldId(t.name),s=this.getFieldValue(t.name)??t.value,n={fieldId:i,fieldName:t.name,size:t.size||"sm",variant:t.variant||"outline-primary",options:t.options.map(e=>({value:e.value,label:e.label,action:e.action,active:e.value===s,buttonClass:this.getButtonClass(e.value===s,t.variant)}))};return e.Mustache.render(this.templates.buttongroup,n)}getButtonClass(e,t="outline-primary"){return e?`btn btn-${t.replace("outline-","")}`:`btn btn-${t}`}renderComboField(e){const{name:t,label:i,value:s="",required:n=!1,disabled:a=!1,maxHeight:l=300,help:r=e.helpText||e.help||""}=e,o=e.placeholder||e.placeHolder||"Type or select...",d=!1!==e.allowCustom;this.getFieldId(t);const c=this.errors[t],h=e.value??this.getFieldValue(t)??s;return`\n <div class="mojo-form-control">\n ${i?`<label class="${this.options.labelClass}">${this.escapeHtml(i)}${n?'<span class="text-danger">*</span>':""}${this.renderTooltipIcon(e)}</label>`:""}\n <div class="combobox-placeholder"\n data-field-name="${t}"\n data-field-type="combobox"\n data-field-config='${JSON.stringify({name:t,value:h,placeholder:o,maxHeight:l,allowCustom:d,disabled:a,required:n})}'>\n <input type="text" \n class="form-control${c?" is-invalid":""}"\n value="${this.escapeHtml(h)}"\n placeholder="${this.escapeHtml(o)}"\n ${a?"disabled":""}\n ${n?"required":""}>\n <small class="form-text text-muted">This will be enhanced with ComboBox component</small>\n </div>\n ${r?`<div class="${this.options.helpClass}">${this.escapeHtml(r)}</div>`:""}\n ${c?`<div class="${this.options.errorClass}">${this.escapeHtml(c)}</div>`:""}\n </div>\n `}renderTabsetField(e){const{tabs:t=[],name:i=`tabset-${Date.now()}`,navClass:s="nav nav-tabs mb-3",contentClass:n="tab-content"}=e,a=String(i).toLowerCase().replace(/[^a-z0-9]/g,"-");return`\n <div class="mojo-form-tabset">\n <ul class="${s}" role="tablist">\n ${t.map((e,t)=>{const i=`${a}-pane-${t}`,s=0===t;return`\n <li class="nav-item" role="presentation">\n <button class="nav-link ${s?"active":""}"\n id="${i}-tab"\n data-bs-toggle="tab"\n data-bs-target="#${i}"\n type="button"\n role="tab"\n aria-controls="${i}"\n aria-selected="${s}">\n ${this.escapeHtml(e.label||`Tab ${t+1}`)}\n </button>\n </li>\n `}).join("")}\n </ul>\n <div class="${n}">\n ${t.map((e,t)=>{const i=`${a}-pane-${t}`;return`\n <div class="tab-pane fade ${0===t?"show active":""}"\n id="${i}"\n role="tabpanel"\n aria-labelledby="${i}-tab"\n data-tab-index="${t}">\n <div class="row">\n ${(e.fields||[]).map(e=>"group"===e.type?this.buildGroupHTML(e):this.buildFieldHTML(e)).join("")}\n </div>\n </div>\n `}).join("")}\n </div>\n </div>\n `}generateSelectOptions(e,t,i=1,s={}){const{format:n,prefix:a="",suffix:l=""}=s,r=[],o=e<=t?Math.abs(i):-Math.abs(i);for(let d=e;e<=t?d<=t:d>=t;d+=o){let i=String(d);if("function"==typeof n)i=n(d);else if("padded"===n||"pad"===n){const s=String(Math.max(Math.abs(e),Math.abs(t))).length;i=String(d).padStart(s,"0")}else"ordinal"===n&&(i=this.formatOrdinal(d));i=`${a}${i}${l}`,r.push({value:d,label:i})}return r}formatOrdinal(e){const t=e%10,i=e%100;return 1===t&&11!==i?e+"st":2===t&&12!==i?e+"nd":3===t&&13!==i?e+"rd":e+"th"}escapeHtml(e){if(null==e)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}renderTooltipIcon(e){return e&&e.tooltip?` <i class="bi bi-info-circle text-muted" data-bs-toggle="tooltip" title="${this.escapeHtml(e.tooltip)}" style="font-size: 0.75rem; cursor: help;"></i>`:""}}const s={enableFileDrop(e={}){if(this._fileDropConfig={acceptedTypes:e.acceptedTypes||["*/*"],maxFileSize:e.maxFileSize||10485760,dropZoneSelector:e.dropZoneSelector||null,visualFeedback:!1!==e.visualFeedback,multiple:e.multiple||!1,validateOnDrop:!1!==e.validateOnDrop,dragOverClass:e.dragOverClass||"drag-over",dragActiveClass:e.dragActiveClass||"drag-active"},this._fileDropState={isDragActive:!1,dragCounter:0},this._boundFileDropHandlers={dragEnter:this._onFileDropDragEnter.bind(this),dragOver:this._onFileDropDragOver.bind(this),dragLeave:this._onFileDropDragLeave.bind(this),drop:this._onFileDropDrop.bind(this),preventDefault:this._onFileDropPreventDefault.bind(this)},this.element)this._setupFileDropListeners();else{const e=this.onAfterRender.bind(this);this.onAfterRender=async()=>{await e(),this._setupFileDropListeners()}}const t=this.onBeforeDestroy.bind(this);this.onBeforeDestroy=async()=>{this._cleanupFileDropListeners(),await t()}},_setupFileDropListeners(){if(!this._fileDropConfig)return;const e=this._getFileDropZone();e?(this._fileDropZone=e,e.addEventListener("dragenter",this._boundFileDropHandlers.dragEnter),e.addEventListener("dragover",this._boundFileDropHandlers.dragOver),e.addEventListener("dragleave",this._boundFileDropHandlers.dragLeave),e.addEventListener("drop",this._boundFileDropHandlers.drop),["dragenter","dragover","dragleave","drop"].forEach(e=>{document.addEventListener(e,this._boundFileDropHandlers.preventDefault)})):console.warn("FileDropMixin: Drop zone not found")},_cleanupFileDropListeners(){this._boundFileDropHandlers&&(this._fileDropZone&&(this._fileDropZone.removeEventListener("dragenter",this._boundFileDropHandlers.dragEnter),this._fileDropZone.removeEventListener("dragover",this._boundFileDropHandlers.dragOver),this._fileDropZone.removeEventListener("dragleave",this._boundFileDropHandlers.dragLeave),this._fileDropZone.removeEventListener("drop",this._boundFileDropHandlers.drop)),["dragenter","dragover","dragleave","drop"].forEach(e=>{document.removeEventListener(e,this._boundFileDropHandlers.preventDefault)}),this._fileDropZone=null,this._boundFileDropHandlers=null,this._fileDropConfig=null,this._fileDropState=null)},_getFileDropZone(){return this._fileDropConfig.dropZoneSelector?this.element.querySelector(this._fileDropConfig.dropZoneSelector):this.element},_onFileDropPreventDefault(e){e.preventDefault(),e.stopPropagation()},_onFileDropDragEnter(e){this._onFileDropPreventDefault(e),this._fileDropState.dragCounter++,this._fileDropState.isDragActive||(this._fileDropState.isDragActive=!0,this._applyFileDropVisualFeedback(!0))},_onFileDropDragOver(e){this._onFileDropPreventDefault(e),e.dataTransfer.dropEffect="copy"},_onFileDropDragLeave(e){this._onFileDropPreventDefault(e),this._fileDropState.dragCounter--,this._fileDropState.dragCounter<=0&&(this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1))},async _onFileDropDrop(e){this._onFileDropPreventDefault(e),this._fileDropState.isDragActive=!1,this._fileDropState.dragCounter=0,this._applyFileDropVisualFeedback(!1);const t=Array.from(e.dataTransfer.files);if(0===t.length)return;const i=this._fileDropConfig.multiple?t:[t[0]];let s={valid:!0,errors:[]};if(!this._fileDropConfig.validateOnDrop||(s=this._validateFileDropFiles(i),s.valid))if("function"==typeof this.onFileDrop)try{await this.onFileDrop(i,e,s)}catch(n){"function"==typeof this.onFileDropError?await this.onFileDropError(n,e,i):console.error("FileDropMixin: Error in onFileDrop callback:",n)}else console.warn("FileDropMixin: No onFileDrop method found on view");else"function"==typeof this.onFileDropError&&await this.onFileDropError(new Error(s.errors.join(", ")),e,i)},_applyFileDropVisualFeedback(e){if(!this._fileDropConfig.visualFeedback||!this._fileDropZone)return;const{dragOverClass:t,dragActiveClass:i}=this._fileDropConfig;e?this._fileDropZone.classList.add(t,i):this._fileDropZone.classList.remove(t,i)},_validateFileDropFiles(e){const t=[],i=this._fileDropConfig;for(const s of e)this._isFileDropTypeAccepted(s.type)?s.size>i.maxFileSize&&t.push(`File "${s.name}" (${this._formatFileDropSize(s.size)}) exceeds maximum size (${this._formatFileDropSize(i.maxFileSize)})`):t.push(`File type "${s.type}" is not accepted for file "${s.name}"`);return{valid:0===t.length,errors:t}},_isFileDropTypeAccepted(e){const{acceptedTypes:t}=this._fileDropConfig;return!!t.includes("*/*")||t.some(t=>{if(t===e)return!0;if(t.endsWith("/*")){const i=t.split("/")[0];return e.startsWith(i+"/")}return!1})},_formatFileDropSize(e){if(0===e)return"0 Bytes";const t=Math.floor(Math.log(e)/Math.log(1024));return parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+["Bytes","KB","MB","GB"][t]}};function n(e){Object.assign(e.prototype,s)}class TagInputView extends e.View{constructor(e={}){const{name:t,value:i="",placeholder:s="Add tags...",maxTags:n=50,allowDuplicates:a=!1,separator:l=",",trimTags:r=!0,minLength:o=1,maxLength:d=50,disabled:c=!1,readonly:h=!1,class:u="",tagClass:p="badge bg-primary",inputClass:m="form-control",...g}=e;super({tagName:"div",className:`tag-input-view ${u}`,...g}),this.name=t,this.placeholder=s,this.maxTags=n,this.allowDuplicates=a,this.separator=l,this.trimTags=r,this.minLength=o,this.maxLength=d,this.disabled=c,this.readonly=h,this.tagClass=p,this.inputClass=m,this.tags=[],this.focusedTagIndex=-1,i&&(this.tags=this.parseTagString(i))}async renderTemplate(){const e=this.renderTags(),t=this.renderHiddenInput();return`\n <div class="tag-input-container">\n <div class="tag-input-wrapper border rounded p-2"\n data-action="focus-input"\n tabindex="0"\n role="combobox"\n aria-expanded="false"\n aria-label="Tag input">\n <div class="tags-container d-flex flex-wrap gap-1 mb-2">\n ${e}\n </div>\n ${this.renderInput()}\n </div>\n ${t}\n <div class="tag-input-feedback small text-muted mt-1">\n <span class="tag-count">${this.tags.length}</span>/${this.maxTags} tags\n </div>\n </div>\n `}renderTags(){return this.tags.map((e,t)=>`\n <span class="${this.tagClass} tag-item"\n data-tag-index="${t}"\n tabindex="0"\n role="button"\n aria-label="Tag: ${this.escapeHtml(e)}. Press Delete or Backspace to remove.">\n <span class="tag-text">${this.escapeHtml(e)}</span>\n ${this.readonly||this.disabled?"":`\n <i class="bi bi-x tag-remove ms-1"\n data-action="remove-tag"\n data-tag-index="${t}"\n aria-label="Remove tag"></i>\n `}\n </span>\n `).join("")}renderInput(){return this.readonly?"":`\n <input type="text"\n class="${this.inputClass} tag-input-field border-0 p-0"\n placeholder="${this.escapeHtml(this.placeholder)}"\n ${this.disabled?"disabled":""}\n data-change-action="input-change"\n style="outline: none; box-shadow: none; min-width: 120px;"\n autocomplete="off">\n `}renderHiddenInput(){return this.name?`\n <input type="hidden"\n name="${this.name}"\n value="${this.escapeHtml(this.getTagString())}"\n class="tag-input-hidden">\n `:""}async onAfterRender(){await super.onAfterRender(),this.updateTagCount()}async onActionFocusInput(e,t){this.focus()}focus(){const e=this.element.querySelector(".tag-input-field");e&&!this.disabled&&e.focus(),this.focusedTagIndex=-1}async onActionRemoveTag(e,t){e.stopPropagation();const i=parseInt(t.getAttribute("data-tag-index"));i>=0&&i<this.tags.length&&await this.removeTag(i)}async onChangeInputChange(e,t){const i=t.value,s=i.slice(-1);if(s===this.separator||"\n"===s){e.preventDefault();const s=i.slice(0,-1);return void(s.trim()&&(await this.addTag(s),t.value=""))}}bindEvents(){this.__bnd_keydown||(this.__bnd_keydown=this.handleInputKeydown.bind(this)),this.element.addEventListener("keydown",this.__bnd_keydown),this.events.bind(this.element)}unbindEvents(){this.__bnd_keydown&&this.element.removeEventListener("keydown",this.__bnd_keydown),this.events.unbind()}handleInputKeydown(e){const t=e.target,i=t.value||"";switch(e.key){case"Enter":case"Tab":case",":i.trim()&&(e.preventDefault(),this.addTag(i),t.value="");break;case"Backspace":""===i&&this.tags.length>0&&(e.preventDefault(),this.focusedTagIndex>=0?(this.removeTag(this.focusedTagIndex),0==this.focusedTagIndex?this.focus():this.focusTag(this.focusedTagIndex-1)):this.removeTag(this.tags.length-1));break;case"ArrowLeft":if(""===i&&this.tags.length>0)if(e.preventDefault(),this.focusedTagIndex>=0){const e=this.focusedTagIndex-1;e>=0?this.focusTag(e):this.focus()}else this.focusTag(this.tags.length-1);break;case"ArrowRight":if(""===i&&this.tags.length>0)if(e.preventDefault(),this.focusedTagIndex>=0){const e=this.focusedTagIndex+1;e<this.tags.length?this.focusTag(e):this.focus()}else this.focusTag(0);break;case"Escape":t.value="",t.blur()}}async addTag(e){if(this.readonly||this.disabled)return!1;const t=this.trimTags?e.trim():e;return!(!this.isValidTag(t)||(!this.allowDuplicates&&this.tags.includes(t)?(this.showTagError(`Tag "${t}" already exists`),1):this.tags.length>=this.maxTags?(this.showTagError(`Maximum ${this.maxTags} tags allowed`),1):(this.tags.push(t),await this.updateDisplay(),this.emit("tag:added",{tag:t,tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags}),0)))}async removeTag(e){if(this.readonly||this.disabled)return!1;if(e>=0&&e<this.tags.length){const t=this.tags[e];return this.tags.splice(e,1),await this.updateDisplay(),this.emit("tag:removed",{tag:t,tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags}),!0}return!1}async removeTagByValue(e){const t=this.tags.indexOf(e);return t>=0&&await this.removeTag(t)}async clearTags(){if(this.readonly||this.disabled)return!1;const e=[...this.tags];return this.tags=[],await this.updateDisplay(),this.emit("tags:cleared",{oldTags:e}),this.emit("change",{value:"",tags:[]}),!0}async setTags(e){let t=[];Array.isArray(e)?t=e:"string"==typeof e&&(t=this.parseTagString(e)),t=t.filter(e=>this.isValidTag(e)).slice(0,this.maxTags),this.allowDuplicates||(t=[...new Set(t)]),this.tags=t,await this.updateDisplay(),this.emit("tags:set",{tags:this.tags}),this.emit("change",{value:this.getTagString(),tags:this.tags})}isValidTag(e){return!("string"!=typeof e||e.length<this.minLength||e.length>this.maxLength||""===e.trim())}parseTagString(e){return e?e.split(this.separator).map(e=>this.trimTags?e.trim():e).filter(e=>e.length>0):[]}getTagString(){return this.tags.join(this.separator)}getTags(){return[...this.tags]}focusTag(e){const t=this.element.querySelectorAll(".tag-item");t[e]&&(this.focusedTagIndex=e,t[e].focus())}async updateDisplay(){const e=this.element.querySelector(".tags-container");e&&(e.innerHTML=this.renderTags());const t=this.element.querySelector(".tag-input-hidden");t&&(t.value=this.getTagString()),this.updateTagCount()}updateTagCount(){const e=this.element.querySelector(".tag-count");e&&(e.textContent=this.tags.length)}showTagError(e){let t=this.element.querySelector(".tag-error");if(!t){t=document.createElement("div"),t.className="tag-error small text-danger mt-1";const e=this.element.querySelector(".tag-input-feedback");e&&e.parentNode.insertBefore(t,e.nextSibling)}t.textContent=e,setTimeout(()=>{t.parentNode&&t.remove()},3e3)}setEnabled(e){this.disabled=!e;const t=this.element.querySelector(".tag-input-field");t&&(t.disabled=this.disabled);const i=this.element.querySelector(".tag-input-wrapper");i&&i.classList.toggle("disabled",this.disabled)}setReadonly(e){this.readonly=e;const t=this.element.querySelector(".tag-input-field");t&&(t.style.display=e?"none":""),this.element.querySelectorAll(".tag-remove").forEach(t=>{t.style.display=e?"none":""})}escapeHtml(e){if(null==e)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}getFormValue(){return this.getTagString()}async setFormValue(e){await this.setTags(e)}static create(e={}){return new TagInputView(e)}}class CollectionDropdownView extends e.View{constructor(e={}){super({tagName:"div",className:"collection-dropdown-view dropdown-menu show w-100 position-absolute",style:"max-height: 250px; overflow-y: auto; z-index: 1000;",template:'\n {{#data.loading}}\n <div class="dropdown-item text-center">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n </div>\n {{/data.loading}}\n\n {{^data.loading}}\n {{#data.items}}\n <button type="button"\n class="dropdown-item {{#isSelected}}active{{/isSelected}} {{#isFocused}}bg-light{{/isFocused}}"\n data-action="select-item"\n data-value="{{valueField}}"\n data-label="{{labelField}}"\n data-index="{{index}}">\n {{labelField}}\n </button>\n {{/data.items}}\n\n {{#data.showNoResults}}\n <div class="dropdown-item text-muted">\n {{#data.hasSearched}}No results found{{/data.hasSearched}}\n {{^data.hasSearched}}Start typing to search...{{/data.hasSearched}}\n </div>\n {{/data.showNoResults}}\n {{/data.loading}}\n ',...e}),this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.selectedValue=e.selectedValue||"",this.loading=e.loading||!1,this.hasSearched=e.hasSearched||!1,this.focusedIndex=e.focusedIndex||-1}async getViewData(){const e=this.collection?this.collection.toJSON().map((e,i)=>{const s=t.MOJOUtils.getNestedValue(e,this.labelField),n=t.MOJOUtils.getNestedValue(e,this.valueField);return{...e,labelField:s,valueField:n,isSelected:n==this.selectedValue,isFocused:i===this.focusedIndex,index:i}}):[];return{loading:this.loading,hasSearched:this.hasSearched,showNoResults:!this.loading&&this.hasSearched&&0===e.length,items:e}}async handleActionSelectItem(e,t){e.preventDefault();const i=t.getAttribute("data-value"),s=t.getAttribute("data-label");this.emit("item-selected",{value:i,label:s})}updateState(e){Object.assign(this,e)}updateFocusedItem(e){this.focusedIndex=e;const t=this.element?.querySelectorAll('.dropdown-item[data-action="select-item"]');t?.forEach((e,t)=>{e.classList.toggle("bg-light",t===this.focusedIndex)})}getItemCount(){return this.collection?this.collection.length():0}getFocusedItem(){return this.focusedIndex>=0&&this.collection&&this.collection.toJSON()[this.focusedIndex]||null}}class CollectionSelectView extends e.View{constructor(e={}){super({className:"collection-select-view",template:'\n <div class="position-relative">\n <input type="text"\n class="form-control {{#data.hasError}}is-invalid{{/data.hasError}} {{#data.showClear}}pe-5{{/data.showClear}}"\n placeholder="{{data.placeholder}}"\n value="{{data.displayValue}}"\n autocomplete="off" />\n\n <input type="hidden"\n name="{{data.name}}"\n value="{{data.selectedValue}}" />\n\n {{#data.showClear}}\n <button type="button"\n class="btn btn-link position-absolute top-50 end-0 translate-middle-y me-2 p-0 border-0"\n style="z-index: 10; color: #6c757d;"\n data-action="clear-selection"\n title="Clear selection">\n <i class="bi bi-x-circle"></i>\n </button>\n {{/data.showClear}}\n\n <div class="dropdown-container"></div>\n\n {{#data.hasError}}\n <div class="invalid-feedback">{{data.errorMessage}}</div>\n {{/data.hasError}}\n </div>\n ',...e}),this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.maxItems=e.maxItems||10,this.placeholder=e.placeholder||"Search...",this.debounceMs=e.debounceMs||400,this.name=e.name||"collection_select",this.emptyFetch=!1!==e.emptyFetch,this.requiresActiveGroup=e.requiresActiveGroup||!1,this.selectedValue=e.value||"0",this.selectedLabel="",this.searchValue="",this.showDropdown=!1,this.loading=!1,this.hasSearched=!1,this.focusedIndex=-1,this.hasError=!1,this.errorMessage="",this.selectedValue&&"object"==typeof this.selectedValue&&(this.selectedLabel=t.MOJOUtils.getNestedValue(this.selectedValue,this.labelField)||"",this.selectedValue=t.MOJOUtils.getNestedValue(this.selectedValue,this.valueField)||"0"),this.searchTimer=null,this.dropdownView=null,this.defaultParams={},this.defaultParamsOption=e.defaultParams||null,this.handleDocumentClick=this.handleDocumentClick.bind(this),this.handleKeyDown=this.handleKeyDown.bind(this),this.handleInputEvents=this.handleInputEvents.bind(this)}onInit(){this.collection&&this.setupCollection()}setupCollection(){if(this.defaultParams={...this.collection.params},this.collection.params.size=this.maxItems,this.defaultParams.size=this.maxItems,this.defaultParamsOption){const e="function"==typeof this.defaultParamsOption?this.defaultParamsOption():this.defaultParamsOption;e&&"object"==typeof e&&(Object.assign(this.defaultParams,e),Object.assign(this.collection.params,e))}if(this.requiresActiveGroup){const e=this.getApp();e&&e.activeGroup&&e.activeGroup.id&&(this.collection.params.group=e.activeGroup.id,this.defaultParams.group=e.activeGroup.id)}this.collection.on("fetch:start",()=>{this.loading=!0,this.showDropdown=!0,this.updateDropdown()}),this.collection.on("fetch:end",()=>{this.loading=!1,this.showDropdown=!0,this.updateDropdown()}),this.selectedValue&&this.loadSelectedItem(),this.emptyFetch&&this.collection.isEmpty()&&this.performInitialFetch()}async performInitialFetch(){if(this.collection)try{const e={...this.defaultParams};delete e.search,await this.collection.updateParams(e,!0)}catch(e){console.error("Initial fetch error:",e)}}async loadSelectedItem(){try{if(!this.selectedValue||"0"==this.selectedValue)return;if(this.selectedLabel)return;const e=this.collection?.get(this.selectedValue);if(e)return this.selectedLabel=this.getFieldValue(e,this.labelField),void this.render(!1);let t=await this.collection.fetchOne(this.selectedValue);t&&(this.selectedLabel=this.getFieldValue(t,this.labelField)||`${t.constructor.name} #${t.id}`,this.render(!1))}catch(e){console.error("Error loading selected item:",e)}}async getViewData(){let e="";return this.showDropdown&&this.hasSearched?e=this.searchValue:this.selectedValue&&this.selectedLabel&&(e=this.selectedLabel),{name:this.name,placeholder:this.placeholder,displayValue:e,selectedValue:this.selectedValue,showClear:!(!this.selectedValue||"0"===this.selectedValue||!this.selectedLabel),hasError:this.hasError,errorMessage:this.errorMessage}}async onAfterRender(){await super.onAfterRender();const e=this.getInput();e&&(e.addEventListener("input",this.handleInputEvents),e.addEventListener("focus",this.handleInputEvents),e.addEventListener("keydown",this.handleKeyDown)),document.addEventListener("click",this.handleDocumentClick),this.createDropdownView()}async onBeforeDestroy(){await super.onBeforeDestroy();const e=this.getInput();e&&(e.removeEventListener("input",this.handleInputEvents),e.removeEventListener("focus",this.handleInputEvents),e.removeEventListener("keydown",this.handleKeyDown)),document.removeEventListener("click",this.handleDocumentClick),this.searchTimer&&clearTimeout(this.searchTimer),this.dropdownView&&this.dropdownView.destroy()}createDropdownView(){this.dropdownView&&this.dropdownView.destroy(),this.dropdownView=new CollectionDropdownView({collection:this.collection,labelField:this.labelField,valueField:this.valueField,selectedValue:this.selectedValue,loading:this.loading,hasSearched:this.hasSearched,focusedIndex:this.focusedIndex}),this.dropdownView.on("item-selected",e=>{this.selectItem(e.value,e.label)})}async handleInputEvents(e){const t=e.target;"focus"===e.type?(this.showDropdown=!0,!this.hasSearched&&this.emptyFetch&&this.collection?.isEmpty()&&this.performInitialFetch(),this.updateDropdown()):"input"===e.type&&(this.searchValue=t.value,this.showDropdown=!0,this.hasSearched=!0,this.focusedIndex=-1,this.searchValue!==this.selectedLabel&&(this.selectedValue="0",this.selectedLabel="",this.emit("change",{value:"0",label:""})),this.searchTimer&&clearTimeout(this.searchTimer),this.searchTimer=setTimeout(()=>{this.performSearch()},this.debounceMs),this.updateDropdown())}async handleActionClearSelection(e,t){e.preventDefault(),e.stopPropagation(),this.clearSelection()}clearSelection(){this.selectedValue="0",this.selectedLabel="",this.searchValue="",this.showDropdown=!1,this.hasError=!1,this.focusedIndex=-1,this.hasSearched=!1;const e=this.getInput();e&&(e.value="",e.focus());const t=this.getHiddenInput();t&&(t.value="0"),this.updateDropdown(),this.render(),this.emit("change",{value:"0",label:""})}async performSearch(){if(this.collection)try{const e={...this.defaultParams};this.searchValue&&this.searchValue.trim()&&(e.search=this.searchValue.trim()),await this.collection.updateParams(e,!0)}catch(e){console.error("Search error:",e),this.loading=!1,this.updateDropdown()}}updateDropdown(){if(this.dropdownView)if(this.dropdownView.updateState({selectedValue:this.selectedValue,loading:this.loading,hasSearched:this.hasSearched,focusedIndex:this.focusedIndex}),this.showDropdown)if(this.dropdownView.isMounted())this.dropdownView.render();else{const e=this.element?.querySelector(".dropdown-container");e&&this.dropdownView.render(!0,e)}else this.dropdownView.isMounted()&&(this.dropdownView.destroy(),this.createDropdownView())}selectItem(e,t){this.selectedValue=e,this.selectedLabel=t,this.searchValue="",this.showDropdown=!1,this.hasError=!1,this.focusedIndex=-1,this.hasSearched=!1;const i=this.getInput();i&&(i.value=t);const s=this.getHiddenInput();s&&(s.value=e),this.updateDropdown(),this.emit("change",{value:e,label:t})}handleDocumentClick(e){this.element?.contains(e.target)||(this.showDropdown=!1,this.focusedIndex=-1,this.updateDropdown())}handleKeyDown(e){if(!this.showDropdown||!this.collection)return;const t=this.dropdownView?.getItemCount()||0;switch(e.key){case"ArrowDown":e.preventDefault(),this.focusedIndex=Math.min(this.focusedIndex+1,t-1),this.dropdownView?.updateFocusedItem(this.focusedIndex);break;case"ArrowUp":e.preventDefault(),this.focusedIndex=Math.max(this.focusedIndex-1,0),this.dropdownView?.updateFocusedItem(this.focusedIndex);break;case"Enter":{e.preventDefault();const t=this.dropdownView?.getFocusedItem();t&&this.selectItem(t[this.valueField],t[this.labelField]);break}case"Escape":e.preventDefault(),this.showDropdown=!1,this.focusedIndex=-1,this.updateDropdown()}}getInput(){return this.element?.querySelector('input[type="text"]')}getHiddenInput(){return this.element?.querySelector('input[type="hidden"]')}setValue(e,t=""){this.selectedValue=e,this.selectedLabel=t,this.searchValue="",this.hasError=!1,this.hasSearched=!1;const i=this.getInput();i&&(i.value=t);const s=this.getHiddenInput();s&&(s.value=e)}getValue(){return 0===this.selectedValue||"0"===this.selectedValue?null:this.selectedValue}getLabel(){return this.selectedLabel}setError(e){this.hasError=!0,this.errorMessage=e,this.render()}clearError(){this.hasError=!1,this.errorMessage="",this.render()}focus(){const e=this.getInput();e&&e.focus()}getFormValue(){return 0===this.selectedValue||"0"===this.selectedValue?null:this.selectedValue}setFormValue(e){let i=e,s="";i&&"object"==typeof i&&(s=t.MOJOUtils.getNestedValue(i,this.labelField)||"",i=t.MOJOUtils.getNestedValue(i,this.valueField)),i=i||"0",i!=this.selectedValue&&(this.selectedValue=i,this.selectedLabel=s,this.searchValue="",this.hasSearched=!1,this.showDropdown=!1,this.hasError=!1,this.selectedValue&&"0"!==this.selectedValue?(this.selectedLabel||(this.selectedLabel=`${this.collection.getModelName()} #${this.selectedValue}`),this.loadSelectedItem()):this.render())}getFieldValue(e,i){if(e&&i){if("function"==typeof e.get){const s=e.get(i);return void 0===s&&i.includes(".")?t.MOJOUtils.getNestedValue(e,i):s}return t.MOJOUtils.getNestedValue(e,i)}}}class SearchView extends e.View{constructor(e={}){super({tagName:"div",className:"collection-multiselect-search",template:'\n <input type="text" \n class="form-control form-control-sm mb-2" \n placeholder="{{placeholder}}"\n data-change-action="search"\n data-filter="live-search"\n data-filter-debounce="{{debounce}}" />\n ',...e}),this.placeholder=e.placeholder||"Search...",this.debounce=e.debounce||400}async onChangeSearch(e,t){const i=t.value.trim();this.emit("search",i)}getValue(){return this.element?.querySelector("input")?.value||""}clear(){const e=this.element?.querySelector("input");e&&(e.value="")}}class ListItemsView extends e.View{constructor(e={}){super({tagName:"div",className:"collection-multiselect-items",template:`\n {{#loading}}\n <div class="text-center py-3">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n </div>\n {{/loading}}\n\n {{^loading}}\n {{#items.length}}\n {{#showSelectAll}}\n <div class="collection-multiselect-actions d-flex justify-content-between align-items-center mb-2 py-1">\n <button type="button" \n class="btn btn-link btn-sm text-decoration-none p-0 {{#allSelected}}text-muted{{/allSelected}}" \n data-action="select-all"\n {{#allSelected}}disabled{{/allSelected}}>\n <i class="bi bi-check-square me-1"></i>\n SELECT {{#unselectedCount}}({{unselectedCount}}){{/unselectedCount}}\n </button>\n <button type="button" \n class="btn btn-link btn-sm text-decoration-none p-0 {{#noneSelected}}text-muted{{/noneSelected}}" \n data-action="deselect-all"\n {{#noneSelected}}disabled{{/noneSelected}}>\n DESELECT {{#selectedCount}}({{selectedCount}}){{/selectedCount}}\n <i class="bi bi-square ms-1"></i>\n </button>\n </div>\n {{/showSelectAll}}\n \n <div class="collection-multiselect-list border rounded" \n style="max-height: {{maxHeight}}px; overflow-y: auto;">\n {{#items}}\n <div class="collection-multiselect-item d-flex align-items-center py-2 px-3 {{^disabled}}clickable{{/disabled}}" \n data-action="{{^disabled}}toggle{{/disabled}}"\n data-value="{{value}}"\n data-index="{{index}}">\n <i class="bi {{#selected}}bi-check-square-fill text-primary{{/selected}}{{^selected}}bi-square{{/selected}} me-2" \n style="font-size: 1.1rem;"></i>\n ${e.customItemTemplate?"{{{customContent}}}":'<span {{#disabled}}class="text-muted"{{/disabled}}>{{label}}</span>'}\n </div>\n {{/items}}\n </div>\n {{/items.length}}\n\n {{^items.length}}\n <div class="collection-multiselect-empty text-muted text-center py-4 border rounded">\n <i class="bi bi-inbox fs-3 d-block mb-2 opacity-50"></i>\n <div>No items available</div>\n </div>\n {{/^items.length}}\n {{/loading}}\n `,...e}),this.items=e.items||[],this.loading=e.loading||!1,this.maxHeight=e.maxHeight||336,this.showSelectAll=!1!==e.showSelectAll,this.selectedCount=e.selectedCount||0,this.totalCount=e.totalCount||0,this.unselectedCount=e.unselectedCount||0,this.allSelected=e.allSelected||!1,this.noneSelected=e.noneSelected||!0,this.customItemTemplate=e.customItemTemplate||null,this.lastClickedIndex=-1}handleActionToggle(e,t){const i=t.getAttribute("data-value"),s=parseInt(t.getAttribute("data-index"),10);this.emit("toggle",{value:i,index:s,shiftKey:e.shiftKey,element:t}),this.lastClickedIndex=s}updateItemCheckbox(e,t){const i=e.querySelector("i.bi");i&&(t?(i.classList.remove("bi-square"),i.classList.add("bi-check-square-fill","text-primary")):(i.classList.remove("bi-check-square-fill","text-primary"),i.classList.add("bi-square")))}updateActionButtons(){const e=this.element?.querySelector('[data-action="select-all"]'),t=this.element?.querySelector('[data-action="deselect-all"]');e&&(e.querySelector("span"),this.allSelected?(e.classList.add("text-muted"),e.disabled=!0):(e.classList.remove("text-muted"),e.disabled=!1)),t&&(this.noneSelected?(t.classList.add("text-muted"),t.disabled=!0):(t.classList.remove("text-muted"),t.disabled=!1))}async handleActionSelectAll(e){e.preventDefault(),this.emit("select-all")}async handleActionDeselectAll(e){e.preventDefault(),this.emit("deselect-all")}updateState(e){Object.assign(this,e)}}class CollectionMultiSelectView extends e.View{constructor(e={}){super({tagName:"div",className:"collection-multiselect-view",template:'\n <div class="mojo-form-control">\n {{#label}}\n <label class="form-label">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}\n </label>\n {{/label}}\n \n <div class="collection-multiselect-search-container"></div>\n <div class="collection-multiselect-list-container"></div>\n\n {{#help}}\n <div class="form-text">{{help}}</div>\n {{/help}}\n {{#error}}\n <div class="invalid-feedback d-block">{{error}}</div>\n {{/error}}\n </div>\n ',...e}),this.name=e.name||"collection_multiselect",this.label=e.label||"",this.help=e.help||"",this.error=e.error||"",this.required=e.required||!1,this.disabled=e.disabled||!1,this.collection=e.collection,this.labelField=e.labelField||"name",this.valueField=e.valueField||"id",this.excludeIds=e.excludeIds||[],this.ignoreIds=e.ignoreIds||[],this.itemTemplate=e.itemTemplate||null,this.collectionParams=e.collectionParams||{},this.defaultParamsOption=e.defaultParams||null,this.baseParams={},this.requiresActiveGroup=e.requiresActiveGroup||!1,this.size=e.size||8,this.maxHeight=e.maxHeight||42*this.size,this.showSelectAll=!1!==e.showSelectAll,this.enableSearch=e.enableSearch||!1,this.searchPlaceholder=e.searchPlaceholder||"Search...",this.searchDebounce=e.searchDebounce||400,this.selectedValues=Array.isArray(e.value)?e.value:[],this.loading=!1,this.items=[],this.searchView=null,this.listView=null}onInit(){this.collection&&this.setupCollection()}setupCollection(){if(this.baseParams={...this.collection.params},Object.keys(this.collectionParams).length>0&&(Object.assign(this.baseParams,this.collectionParams),Object.assign(this.collection.params,this.collectionParams)),this.defaultParamsOption){const e="function"==typeof this.defaultParamsOption?this.defaultParamsOption():this.defaultParamsOption;e&&(Object.assign(this.baseParams,e),Object.assign(this.collection.params,e))}if(this.requiresActiveGroup){const e=this.getApp();e?.activeGroup?.id&&(this.baseParams.group=e.activeGroup.id,this.collection.params.group=e.activeGroup.id)}this.collection.on("fetch:start",()=>{this.loading=!0,this.updateListView()}),this.collection.on("fetch:end",()=>{this.loading=!1,this.buildItems(),this.updateListView()}),this.collection.isEmpty()||this.buildItems()}async onAfterRender(){await super.onAfterRender(),this.enableSearch&&this.createSearchView(),this.createListView(),this.collection?.isEmpty()&&this.collection.fetch()}createSearchView(){const e=this.element?.querySelector(".collection-multiselect-search-container");e&&(this.searchView=new SearchView({placeholder:this.searchPlaceholder,debounce:this.searchDebounce}),this.searchView.on("search",e=>{this.handleSearch(e)}),this.searchView.render(!0,e))}createListView(){const e=this.element?.querySelector(".collection-multiselect-list-container");if(!e)return;const t=this.selectedValues.length,i=this.items.length,s=i-t;this.listView=new ListItemsView({items:this.items,loading:this.loading,maxHeight:this.maxHeight,showSelectAll:this.showSelectAll,selectedCount:t,totalCount:i,unselectedCount:s,allSelected:t===i&&i>0,noneSelected:0===t,customItemTemplate:this.itemTemplate}),this.listView.on("toggle",e=>{this.handleToggle(e)}),this.listView.on("select-all",()=>{this.selectAll()}),this.listView.on("deselect-all",()=>{this.deselectAll()}),this.listView.render(!0,e)}updateListView(){if(this.listView){const e=this.selectedValues.length,t=this.items.length,i=t-e;this.listView.updateState({items:this.items,loading:this.loading,selectedCount:e,totalCount:t,unselectedCount:i,allSelected:e===t&&t>0,noneSelected:0===e}),this.listView.render(!1)}}buildItems(){const e=this.collection.models.filter(e=>{const t=this.getFieldValue(e,this.valueField);return null!=t&&!this.excludeIds.includes(t)&&!this.ignoreIds.some(e=>e==t)});this.items=e.map((e,t)=>{const i=e.toJSON?e.toJSON():e,s=this.getFieldValue(e,this.valueField),n={label:this.getFieldValue(e,this.labelField),value:s,index:t,selected:this.selectedValues.some(e=>e==s),disabled:this.disabled,model:i};return this.itemTemplate&&(n.customContent=this.renderItemTemplate(n)),n})}renderItemTemplate(e){if(!this.itemTemplate)return"";try{return this.renderTemplateString(this.itemTemplate,e)}catch(t){return console.error("Error rendering item template:",t),e.label}}getFieldValue(e,i){if(e&&i)return"function"==typeof e.get?e.get(i)??t.MOJOUtils.getNestedValue(e,i):t.MOJOUtils.getNestedValue(e,i)}handleSearch(e){const t={...this.baseParams};e&&(t.search=e),this.collection.updateParams(t,!0)}handleToggle({value:e,index:t,shiftKey:i,element:s}){if(i&&this.listView.lastClickedIndex>=0){const e=Math.min(this.listView.lastClickedIndex,t),i=Math.max(this.listView.lastClickedIndex,t),s=!this.items[t].selected;for(let t=e;t<=i;t++){const e=this.items[t];e.disabled||(s?this.selectedValues.includes(e.value)||this.selectedValues.push(e.value):this.selectedValues=this.selectedValues.filter(t=>t!=e.value),e.selected=s)}this.updateListView()}else{const i=this.items[t];i.selected?(this.selectedValues=this.selectedValues.filter(t=>t!=e),i.selected=!1):(this.selectedValues.push(e),i.selected=!0),s&&this.listView&&(this.listView.updateItemCheckbox(s,i.selected),this.listView.selectedCount=this.selectedValues.length,this.listView.unselectedCount=this.items.length-this.selectedValues.length,this.listView.allSelected=this.selectedValues.length===this.items.length&&this.items.length>0,this.listView.noneSelected=0===this.selectedValues.length,this.listView.updateActionButtons())}this.emit("change",{value:this.selectedValues,name:this.name})}selectAll(){this.selectedValues=this.items.filter(e=>!e.disabled).map(e=>e.value),this.items.forEach(e=>{e.disabled||(e.selected=!0)}),this.updateListView(),this.emit("change",{value:this.selectedValues,name:this.name})}deselectAll(){this.selectedValues=[],this.items.forEach(e=>e.selected=!1),this.updateListView(),this.emit("change",{value:this.selectedValues,name:this.name})}async onBeforeDestroy(){await super.onBeforeDestroy(),this.searchView&&this.searchView.destroy(),this.listView&&this.listView.destroy()}getValue(){return this.selectedValues}setValue(e){this.selectedValues=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}setExcludeIds(e){this.excludeIds=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}setIgnoreIds(e){this.ignoreIds=Array.isArray(e)?e:[],this.buildItems(),this.updateListView()}async refresh(){await this.collection.fetch()}getFormValue(){return this.selectedValues}setFormValue(e){this.setValue(e)}}class MultiSelectItemsView extends e.View{constructor(e={}){super({tagName:"div",className:"multiselect-items",template:'\n {{#items.length}}\n <div class="multiselect-list" style="max-height: {{maxHeight}}px; overflow-y: auto;">\n {{#items}}\n <div class="multiselect-item form-check px-3 py-2" \n data-action="toggle"\n data-value="{{value}}"\n data-index="{{index}}">\n <input type="checkbox" \n class="form-check-input" \n id="{{id}}"\n {{#selected}}checked{{/selected}}\n {{#disabled}}disabled{{/disabled}}>\n <label class="form-check-label w-100" for="{{id}}">\n {{label}}\n </label>\n </div>\n {{/items}}\n </div>\n <div class="multiselect-footer border-top p-2">\n <button type="button" class="btn btn-sm btn-primary w-100" data-action="close-dropdown">\n Done\n </button>\n </div>\n {{/items.length}}\n \n {{^items.length}}\n <div class="multiselect-empty text-muted text-center py-3">\n <small>No options available</small>\n </div>\n {{/items.length}}\n ',...e}),this.items=e.items||[],this.maxHeight=e.maxHeight||300}handleActionToggle(e,t){const i=t.getAttribute("data-value"),s=parseInt(t.getAttribute("data-index"),10),n=this.items[s];if(!n||n.disabled)return;n.selected=!n.selected;const a=t.querySelector('input[type="checkbox"]');a&&(a.checked=n.selected),this.emit("toggle",{value:i,index:s,selected:n.selected})}handleActionCloseDropdown(e,t){this.emit("close-dropdown")}getValue(){return this.items.filter(e=>e.selected).map(e=>e.value)}setValue(e){const t=new Set(Array.isArray(e)?e:[e]);this.items.forEach(e=>{e.selected=t.has(e.value)}),this.render(!1)}updateItems(e){this.items=e,this.render(!1)}}class MultiSelectDropdown extends e.View{constructor(e={}){super({tagName:"div",className:"multiselect-dropdown",template:'\n <div class="mojo-form-control">\n {{#label}}\n <label class="form-label">\n {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}\n </label>\n {{/label}}\n \n <div class="dropdown w-100">\n <button class="btn btn-outline-secondary dropdown-toggle w-100 text-start d-flex justify-content-between align-items-center" \n type="button" \n data-bs-toggle="dropdown" \n aria-expanded="false"\n {{#disabled}}disabled{{/disabled}}>\n <span class="multiselect-button-text">{{buttonText}}</span>\n <i class="bi bi-chevron-down"></i>\n </button>\n <div class="dropdown-menu w-100" data-bs-auto-close="outside" data-container="items"></div>\n </div>\n \n {{#help}}\n <div class="form-text">{{help}}</div>\n {{/help}}\n {{#error}}\n <div class="invalid-feedback d-block">{{error}}</div>\n {{/error}}\n </div>\n ',...e}),this.name=e.name||"multiselect",this.label=e.label||"",this.help=e.help||"",this.error=e.error||"",this.required=e.required||!1,this.disabled=e.disabled||!1,this.placeholder=e.placeholder||e.placeHolder||"Select...",this.maxHeight=e.maxHeight||300,this.showSelectedLabels=!1!==e.showSelectedLabels,this.maxLabelsToShow=e.maxLabelsToShow||3,this.options=e.options||[],this.selectedValues=Array.isArray(e.value)?e.value:[],this.buttonText=this.computeButtonText(),this.listView=null}computeButtonText(){const e=this.selectedValues.length;return 0===e?this.placeholder||"Select...":this.showSelectedLabels&&e<=this.maxLabelsToShow?this.selectedValues.map(e=>{const t=this.options.find(t=>("string"==typeof t?t:t.value)===e);return"string"==typeof t?t:t?.label||t?.value||e}).join(", "):`${e} selected`}async onAfterRender(){await super.onAfterRender(),this.createListView()}createListView(){const e=this.element?.querySelector('[data-container="items"]');if(!e)return;const t=this.options.map((e,t)=>{const i="string"==typeof e?e:e.value,s="string"==typeof e?e:e.label||e.text||e.value,n="object"==typeof e&&e.disabled;return{id:`${this.name}_${t}`,value:i,label:s,index:t,selected:this.selectedValues.includes(i),disabled:n}});this.listView=new MultiSelectItemsView({items:t,maxHeight:this.maxHeight}),this.listView.on("toggle",e=>{this.handleToggle(e)}),this.listView.on("close-dropdown",()=>{this.closeDropdown()}),this.listView.render(!0,e)}closeDropdown(){const e=this.element?.querySelector(".dropdown-toggle");if(e&&window.bootstrap?.Dropdown){const t=window.bootstrap.Dropdown.getInstance(e);t&&t.hide()}}handleToggle(e){const{value:t,selected:i}=e;i?this.selectedValues.includes(t)||this.selectedValues.push(t):this.selectedValues=this.selectedValues.filter(e=>e!==t),this.updateButtonText(),this.emit("change",{value:this.selectedValues,name:this.name})}updateButtonText(){const e=this.element?.querySelector(".multiselect-button-text");if(!e)return;const t=this.selectedValues.length;this.buttonText=this.computeButtonText(),e.textContent=this.buttonText,0===t?e.classList.add("text-muted"):e.classList.remove("text-muted")}getValue(){return this.selectedValues}setValue(e){this.selectedValues=Array.isArray(e)?e:e?[e]:[],this.listView&&this.listView.setValue(this.selectedValues),this.updateButtonText()}setOptions(e){if(this.options=e,this.listView){const e=this.options.map((e,t)=>{const i="string"==typeof e?e:e.value,s="string"==typeof e?e:e.label||e.text||e.value,n="object"==typeof e&&e.disabled;return{id:`${this.name}_${t}`,value:i,label:s,index:t,selected:this.selectedValues.includes(i),disabled:n}});this.listView.updateItems(e)}}clear(){this.setValue([])}getFormValue(){return this.getValue()}setFormValue(e){this.setValue(e)}async onBeforeDestroy(){await super.onBeforeDestroy(),this.listView&&this.listView.destroy()}}const a=["January","February","March","April","May","June","July","August","September","October","November","December"],l=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function r(e){if(null==e||""===e)return null;const t=parseInt(String(e).slice(0,4),10);return Number.isFinite(t)?{y:t}:null}function o(e){if(null==e||""===e)return null;const t=String(e).split("-"),i=parseInt(t[0],10),s=parseInt(t[1],10);return!Number.isFinite(i)||!Number.isFinite(s)||s<1||s>12?null:{y:i,m:s}}function d(e){if(null==e||""===e)return null;if(e instanceof Date&&!isNaN(e.getTime()))return{y:e.getFullYear(),m:e.getMonth()+1,d:e.getDate()};const t=String(e).split("-"),i=parseInt(t[0],10),s=parseInt(t[1],10),n=parseInt(t[2],10);return Number.isFinite(i)&&Number.isFinite(s)&&Number.isFinite(n)?s<1||s>12||n<1||n>31?null:{y:i,m:s,d:n}:null}function c(e){const t="object"==typeof e?e:r(e);return t?String(t.y):""}function h(e){const t="object"==typeof e?e:o(e);return t?`${t.y}-${k(t.m)}`:""}function u(e){const t="object"==typeof e?e:d(e);return t?`${t.y}-${k(t.m)}-${k(t.d)}`:""}function p(e,t){return"year"===t?c(e):"month"===t?h(e):u(e)}function m(e,t){return"year"===t?r(e):"month"===t?o(e):d(e)}const g=/YYYY|YY|MMMM|MMM|MM|M|DD|D/g;function b(e,t){if(!e)return"";const i=e.y,s=e.m,n=e.d;return String(t).replace(g,e=>{switch(e){case"YYYY":return String(i);case"YY":return String(i).slice(-2);case"MMMM":return s?a[s-1]:"";case"MMM":return s?l[s-1]:"";case"MM":return s?k(s):"";case"M":return s?String(s):"";case"DD":return n?k(n):"";case"D":return n?String(n):"";default:return e}})}function f(e,t){return new Date(e,t,0).getDate()}function v(e,t){if(!e)return null;let i=e.y,s=e.m+t;for(;s>12;)s-=12,i+=1;for(;s<1;)s+=12,i-=1;if(null==e.d)return{y:i,m:s};const n=f(i,s);return{y:i,m:s,d:Math.min(e.d,n)}}function y(e,t){return e&&t?e.y!==t.y?e.y<t.y?-1:1:(e.m||0)!==(t.m||0)?(e.m||0)<(t.m||0)?-1:1:(e.d||0)!==(t.d||0)?(e.d||0)<(t.d||0)?-1:1:0:0}function w(e,t){return e&&t?e.y!==t.y?e.y<t.y?-1:1:(e.m||0)!==(t.m||0)?(e.m||0)<(t.m||0)?-1:1:0:0}function C(e,t,i){return"year"===i?function(e,t){return e&&t?e.y===t.y?0:e.y<t.y?-1:1:0}(e,t):"month"===i?w(e,t):y(e,t)}function _(e){if(null==e||""===e)return null;if("object"==typeof e&&null!==e){const t=parseInt(e.hours??e.h,10),i=parseInt(e.minutes??e.m,10);return Number.isFinite(t)&&Number.isFinite(i)?t<0||t>23||i<0||i>59?null:{hours:t,minutes:i}:null}const t=String(e).trim(),i=t.indexOf(" "),s=i>-1?t.slice(0,i):t,n=(i>-1?t.slice(i+1).trim():"").match(/^(am|pm)$/i)||s.match(/(am|pm)$/i),a=s.replace(/(am|pm)$/i,"").trim().split(":");if(a.length<2)return null;let l=parseInt(a[0],10);const r=parseInt(a[1],10);if(!Number.isFinite(l)||!Number.isFinite(r))return null;if(r<0||r>59)return null;if(n){const e="pm"===n[1].toLowerCase();if(l<1||l>12)return null;12===l?l=e?12:0:e&&(l+=12)}return l<0||l>23?null:{hours:l,minutes:r}}function x(e,t="24h"){if(!e)return"";const i=e.hours,s=e.minutes;if(!Number.isFinite(i)||!Number.isFinite(s))return"";if("12h"===t){const e=i>=12?"PM":"AM";let t=i%12;return 0===t&&(t=12),`${t}:${k(s)} ${e}`}return`${k(i)}:${k(s)}`}function S(e,t){return e&&t?e.hours!==t.hours?e.hours<t.hours?-1:1:e.minutes!==t.minutes?e.minutes<t.minutes?-1:1:0:0}function F(e,t){if(!e)return null;try{const i=t instanceof Date?t:/* @__PURE__ */new Date,s=new Intl.DateTimeFormat("en-US",{timeZone:e,timeZoneName:"shortOffset"}).formatToParts(i).find(e=>"timeZoneName"===e.type);if(!s)return null;let n=s.value;if("GMT"===n||"UTC"===n)return"+00:00";n=n.replace(/^(GMT|UTC)/,"");const a=n.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!a)return null;const l=a[1];return`${l}${a[2].padStart(2,"0")}:${a[3]||"00"}`}catch(i){return null}}function D(e){if(null==e||""===e)return null;if(!("object"!=typeof e||Array.isArray(e)||e instanceof Date)){const t=e.date?d(e.date):null,i=e.time?_(e.time):null;return t?{date:t,time:i||{hours:0,minutes:0},timezone:e.timezone||null}:null}let t=String(e).trim();const i=t.match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})(?::\d{2}(?:\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?$/);if(i){const[,e,t,s,n,a,l]=i;let r=null;return l&&(r="Z"===l?"+00:00":/^[+-]\d{4}$/.test(l)?`${l.slice(0,3)}:${l.slice(3)}`:l),{date:{y:+e,m:+t,d:+s},time:{hours:+n,minutes:+a},timezone:r}}let s,n;if(t.length>=11&&"T"===t.charAt(10))s=t.slice(0,10),n=t.slice(11);else{const e=t.indexOf(" ");if(-1===e){const e=d(t);return e?{date:e,time:{hours:0,minutes:0},timezone:null}:null}s=t.slice(0,e),n=t.slice(e+1)}const a=d(s);if(!a)return null;const l=n.trim();let r=null,o=l;const c=l.match(/\s+([A-Za-z][A-Za-z_+\-]*\/[A-Za-z][A-Za-z_+\-]*|UTC|GMT)$/);c&&(r=c[1],o=l.slice(0,c.index).trim());const h=_(o);return h?{date:a,time:h,timezone:r}:null}function $(){const e=/* @__PURE__ */new Date;return{y:e.getFullYear(),m:e.getMonth()+1,d:e.getDate()}}let T=null,V=null,I=null;function A(e="en-US",t="short"){if((!e||"en-US"===e||"en"===e)&&"short"===t)return l.slice();if((!e||"en-US"===e||"en"===e)&&"long"===t)return a.slice();if("undefined"==typeof Intl||!Intl.DateTimeFormat)return"long"===t?a.slice():l.slice();if(T===e+"/"+t&&V)return V.slice();const i=new Intl.DateTimeFormat(e,{month:t}),s=[];for(let n=0;n<12;n++)s.push(i.format(new Date(2024,n,15)));return T=e+"/"+t,V=s,s.slice()}function k(e){return e<10?"0"+e:String(e)}function E(e,t){const i=(t%e.length+e.length)%e.length;return e.slice(i).concat(e.slice(0,i))}class Calendar extends e.View{constructor(e={}){const{precision:t="day",mode:i="single",months:s=1,value:n=null,startValue:a=null,endValue:l=null,min:r=null,max:o=null,disabledDates:c=[],firstDay:h=1,locale:p="en-US",excludeDisabledFromRange:g=!1,year:b=null,month:f=null,class:v="",...y}=e;super({tagName:"div",className:`mojo-calendar mojo-calendar-${t} ${v}`.trim(),...y}),this.precision=t,this.mode=i,this.months=Math.max(1,Math.min(2,0|s)),this.firstDay=h,this.locale=p,this.excludeDisabledFromRange=g,this.min=m(r,t)||(r?d(r):null),this.max=m(o,t)||(o?d(o):null),this.disabledDates=(c||[]).map(e=>u(d(e)||null)).filter(Boolean),"single"===i?this.selected=m(n,t):(this.start=m(a,t),this.end=m(l,t),this._anchor=null),this._hover=null,this.view=t;const w=$(),C=("single"===i?this.selected:this.start||this.end)||w;this.pageY=null!=b?Number(b):C.y??w.y,this.pageM=null!=f?Number(f):C.m??w.m,this._onCellMouseEnter=this._onCellMouseEnter.bind(this),this._onCellMouseLeave=this._onCellMouseLeave.bind(this)}setMin(e){this.min=m(e,this.precision),this._rerender()}setMax(e){this.max=m(e,this.precision),this._rerender()}setValue(e){this.selected=m(e,this.precision),this.selected&&(this.pageY=this.selected.y,this.pageM=this.selected.m||this.pageM),this._rerender()}setRange(e,t){this.start=m(e,this.precision),this.end=m(t,this.precision),this._anchor=null,this._rerender()}getValue(){return this.selected?p(this.selected,this.precision):""}getRange(){return{start:this.start?p(this.start,this.precision):"",end:this.end?p(this.end,this.precision):""}}async renderTemplate(){return""}async onAfterRender(){this._eventsWired||(this._wireEvents(this.element),this._eventsWired=!0),this._renderInto(this.element)}_rerender(){this.element&&this._renderInto(this.element)}_renderInto(e){e.innerHTML="";const t=document.createElement("div");if(t.className=this.months>1&&"day"===this.view?"mojo-calendar-multi":"mojo-calendar-single","day"===this.view){const e=this.months;for(let i=0;i<e;i++){let s=this.pageY,n=this.pageM+i;for(;n>12;)n-=12,s+=1;t.appendChild(this._buildDayPane(s,n,0===i,i===e-1))}}else"month"===this.view?t.appendChild(this._buildMonthPane(this.pageY)):"year"===this.view&&t.appendChild(this._buildYearPane(this._decadeStart(this.pageY)));e.appendChild(t)}_decadeStart(e){return 10*Math.floor(e/10)}_buildDayPane(e,t,i,s){const n=document.createElement("div");return n.className="mojo-calendar-pane",n.appendChild(this._buildHead(this._dayHeadLabel(e,t),"day",i,s,e,t)),n.appendChild(this._buildWeekdayHeader()),n.appendChild(this._buildDayGrid(e,t)),n}_dayHeadLabel(e,t){return{kind:"day",year:e,month:t}}_buildWeekdayHeader(){const e=document.createElement("div");return e.className="mojo-calendar-grid mojo-calendar-grid-day",function(e="en-US",t=1,i="short"){if("undefined"==typeof Intl||!Intl.DateTimeFormat)return E(["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],t);const s=e+"/"+t+"/"+i;if(T===s&&I)return I.slice();const n=new Intl.DateTimeFormat(e,{weekday:i}),a=[];for(let r=0;r<7;r++)a.push(n.format(new Date(2024,0,7+r)));const l=E(a,t);return T=s,I=l,l.slice()}(this.locale,this.firstDay,"short").forEach(t=>{const i=document.createElement("div");i.className="mojo-calendar-weekday",i.textContent=t,e.appendChild(i)}),e}_buildDayGrid(e,t){const i=document.createElement("div");i.className="mojo-calendar-grid mojo-calendar-grid-day";const s=function(e,t,i,s=1){return((new Date(e,t-1,i).getDay()-s)%7+7)%7}(e,t,1,this.firstDay),n=f(e,t),a=$();for(let l=0;l<s;l++){const e=document.createElement("div");e.className="mojo-calendar-cell mojo-calendar-cell-blank",i.appendChild(e)}for(let l=1;l<=n;l++){const s={y:e,m:t,d:l},n=document.createElement("button");n.type="button",n.className="mojo-calendar-cell",n.dataset.ymd=u(s),s.y===a.y&&s.m===a.m&&s.d===a.d&&n.classList.add("mojo-calendar-cell-today"),this._isDisabledAt(s,"day")&&(n.classList.add("mojo-calendar-cell-disabled"),n.disabled=!0),"range"===this.mode?this._applyRangeClasses(n,s,"day"):this.selected&&0===y(s,this.selected)&&n.classList.add("mojo-calendar-cell-selected");const r=document.createElement("span");r.className="mojo-calendar-cell-inner",r.textContent=String(l),n.appendChild(r),i.appendChild(n)}return i}_buildMonthPane(e){const t=document.createElement("div");return t.className="mojo-calendar-pane",t.appendChild(this._buildHead(String(e),"month",!0,!0,e,1)),t.appendChild(this._buildMonthGrid(e)),t}_buildMonthGrid(e){const t=document.createElement("div");t.className="mojo-calendar-grid mojo-calendar-grid-month";const i=A(this.locale,"short");for(let s=1;s<=12;s++){const n={y:e,m:s},a=document.createElement("button");a.type="button",a.className="mojo-calendar-cell",a.dataset.ym=h(n),this._isDisabledAt(n,"month")&&(a.classList.add("mojo-calendar-cell-disabled"),a.disabled=!0),"month"===this.precision&&"range"===this.mode?this._applyRangeClasses(a,n,"month"):"month"===this.precision&&"single"===this.mode&&this.selected&&0===w(n,this.selected)&&a.classList.add("mojo-calendar-cell-selected");const l=document.createElement("span");l.className="mojo-calendar-cell-inner",l.textContent=i[s-1],a.appendChild(l),t.appendChild(a)}return t}_buildYearPane(e){const t=document.createElement("div");return t.className="mojo-calendar-pane",t.appendChild(this._buildHead(`${e} – ${e+11}`,"year",!0,!0,e,1)),t.appendChild(this._buildYearGrid(e)),t}_buildYearGrid(e){const t=document.createElement("div");t.className="mojo-calendar-grid mojo-calendar-grid-year";for(let i=0;i<12;i++){const s=e+i,n={y:s},a=document.createElement("button");a.type="button",a.className="mojo-calendar-cell",a.dataset.year=String(s),this._isDisabledAt(n,"year")&&(a.classList.add("mojo-calendar-cell-disabled"),a.disabled=!0),"year"===this.precision&&"range"===this.mode?this._applyRangeClasses(a,n,"year"):"year"===this.precision&&"single"===this.mode&&this.selected&&this.selected.y===s&&a.classList.add("mojo-calendar-cell-selected");const l=document.createElement("span");l.className="mojo-calendar-cell-inner",l.textContent=String(s),a.appendChild(l),t.appendChild(a)}return t}_applyRangeClasses(e,t,i){let s=this.start,n=this.end;if(this._anchor){const e=this._hover||this._anchor,t=C(this._anchor,e,i);s=t<=0?this._anchor:e,n=t<=0?e:this._anchor}if(!s||!n)return void(this._anchor&&0===C(t,this._anchor,i)&&e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-solo"));const a=C(t,s,i),l=C(t,n,i);a>0&&l<0&&e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range"),0===a&&(e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-start"),0===C(s,n,i)?e.classList.add("mojo-calendar-cell-anchor-solo"):e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range")),0===l&&0!==C(s,n,i)&&(e.classList.add("mojo-calendar-cell-anchor","mojo-calendar-cell-anchor-end"),e.classList.add(this._anchor?"mojo-calendar-cell-in-preview":"mojo-calendar-cell-in-range"))}_buildHead(e,t,i,s){const n=document.createElement("div");n.className="mojo-calendar-head";const a=document.createElement("button");if(a.type="button",a.className="mojo-calendar-head-label",a.dataset.level=t,a.dataset.action="zoom-out","string"==typeof e)a.textContent=e;else if(e&&"day"===e.kind){const t=A(this.locale,"long");a.appendChild(document.createTextNode(`${t[e.month-1]} `));const i=document.createElement("span");i.className="mojo-calendar-year",i.textContent=String(e.year),a.appendChild(i)}n.appendChild(a);const l=document.createElement("div");return l.className="mojo-calendar-nav",i&&l.appendChild(this._navBtn("prev")),s&&l.appendChild(this._navBtn("next")),n.appendChild(l),n}_navBtn(e){const t=document.createElement("button");return t.type="button",t.className="mojo-calendar-nav-btn",t.dataset.action=`nav-${e}`,t.setAttribute("aria-label","prev"===e?"Previous":"Next"),t.innerHTML="prev"===e?"‹":"›",t}_wireEvents(e){e.addEventListener("click",e=>this._onClick(e)),e.addEventListener("mouseover",this._onCellMouseEnter),e.addEventListener("mouseleave",this._onCellMouseLeave),e.addEventListener("keydown",e=>this._onKeyDown(e))}_onClick(e){const t=e.target.closest("[data-action], .mojo-calendar-cell");if(!t||t.classList.contains("mojo-calendar-cell-blank"))return;if(t.disabled)return;const i=t.dataset.action;return"nav-prev"===i?this._navigate(-1):"nav-next"===i?this._navigate(1):"zoom-out"===i?this._zoomOut(t.dataset.level):void(t.classList.contains("mojo-calendar-cell")&&this._onCellClick(t))}_onCellClick(e){if("year"===this.view){const t=parseInt(e.dataset.year,10);if(!Number.isFinite(t))return;return"year"===this.precision?this._commitValue({y:t}):(this.pageY=t,this.view="month",this.emit("view:change",{view:this.view}),void this._rerender())}if("month"===this.view){const t=o(e.dataset.ym);if(!t)return;return"month"===this.precision?this._commitValue(t):(this.pageY=t.y,this.pageM=t.m,this.view="day",this.emit("view:change",{view:this.view}),void this._rerender())}if("day"===this.view){const t=d(e.dataset.ymd);if(!t)return;this._commitValue(t)}}_commitValue(e){if("single"===this.mode)return this.selected=e,this.emit("select",{value:p(e,this.precision),parsed:e}),void this._rerender();if(!this._anchor)return this._anchor=e,this.start=null,this.end=null,this._hover=null,this.emit("range:start",{anchor:p(e,this.precision)}),void this._rerender();const t=this._anchor,i=e,s=C(t,i,this.precision);this.start=s<=0?t:i,this.end=s<=0?i:t,this._anchor=null,this._hover=null,this.emit("range:select",{start:p(this.start,this.precision),end:p(this.end,this.precision)}),this._rerender()}_onCellMouseEnter(e){if("range"!==this.mode||!this._anchor)return;const t=e.target.closest(".mojo-calendar-cell");if(!t||t.classList.contains("mojo-calendar-cell-blank")||t.disabled)return;let i=null;"day"===this.view&&t.dataset.ymd?i=d(t.dataset.ymd):"month"===this.view&&t.dataset.ym?i=o(t.dataset.ym):"year"===this.view&&t.dataset.year&&(i={y:parseInt(t.dataset.year,10)}),i&&(this._hover&&0===C(this._hover,i,this.view)||(this._hover=i,this._rerender()))}_onCellMouseLeave(){"range"===this.mode&&this._anchor&&this._hover&&(this._hover=null,this._rerender())}_navigate(e){if("day"===this.view){const t=v({y:this.pageY,m:this.pageM},e);this.pageY=t.y,this.pageM=t.m}else"month"===this.view?this.pageY+=e:"year"===this.view&&(this.pageY=this._decadeStart(this.pageY)+10*e);this.emit("navigate",{delta:e}),this._rerender()}_zoomOut(e){if("day"===e)return this.view="month",this.emit("view:change",{view:this.view}),void this._rerender();"month"===e&&(this.view="year",this.emit("view:change",{view:this.view}),this._rerender())}_onKeyDown(e){const t=e.key;if("Escape"!==t)return"PageUp"===t?(this._navigate(-1),void e.preventDefault()):"PageDown"===t?(this._navigate(1),void e.preventDefault()):void 0;this._anchor&&(this._anchor=null,this._hover=null,this.emit("range:cancel"),this._rerender(),e.preventDefault())}_isDisabledAt(e,t){if(this.min&&C(e,this.min,t)<0)return!0;if(this.max&&C(e,this.max,t)>0)return!0;if("day"===t&&this.disabledDates.length){const t=u(e);if(this.disabledDates.includes(t))return!0}return!1}async onBeforeDestroy(){this.element&&(this.element.removeEventListener("mouseover",this._onCellMouseEnter),this.element.removeEventListener("mouseleave",this._onCellMouseLeave)),await super.onBeforeDestroy()}}class CalendarPopover{constructor(e={}){const{anchor:t=null,placement:i="bottom-start",gap:s=6,portal:n=!0,onOutsideClick:a=null,classNames:l=""}=e;this.anchor=t,this.placement=i,this.gap=s,this.portal=n,this.onOutsideClick=a,this.element=document.createElement("div"),this.element.className=`mojo-calendar-popover ${l}`.trim(),this.element.style.position="absolute",this.element.style.zIndex="10000",this.element.setAttribute("role","dialog"),this._open=!1,this._onDocClick=this._onDocClick.bind(this),this._onScroll=this._onScroll.bind(this),this._onResize=this._onResize.bind(this),this._onKey=this._onKey.bind(this)}setAnchor(e){this.anchor=e,this._open&&this._reposition()}setContent(e){this.element.innerHTML="",e&&this.element.appendChild(e)}open(){this._open||(this._open=!0,this.portal&&this.element.parentNode!==document.body&&document.body.appendChild(this.element),this.element.classList.add("is-open"),this._reposition(),setTimeout(()=>{document.addEventListener("mousedown",this._onDocClick,!0),document.addEventListener("keydown",this._onKey,!0),window.addEventListener("scroll",this._onScroll,!0),window.addEventListener("resize",this._onResize)},0))}close(){this._open&&(this._open=!1,this.element.classList.remove("is-open"),document.removeEventListener("mousedown",this._onDocClick,!0),document.removeEventListener("keydown",this._onKey,!0),window.removeEventListener("scroll",this._onScroll,!0),window.removeEventListener("resize",this._onResize),this.portal&&this.element.parentNode===document.body&&document.body.removeChild(this.element))}isOpen(){return this._open}destroy(){this.close(),this.element=null}_onDocClick(e){this.element.contains(e.target)||this.anchor&&this.anchor.contains(e.target)||("function"==typeof this.onOutsideClick?this.onOutsideClick(e):this.close())}_onKey(e){"Escape"===e.key&&this.close()}_onScroll(){this._open&&this._reposition()}_onResize(){this._open&&this._reposition()}_reposition(){if(!this.anchor)return;const e=this.anchor.getBoundingClientRect(),t=this.element.getBoundingClientRect(),i=window.scrollX||window.pageXOffset||0,s=window.scrollY||window.pageYOffset||0;let n=e.bottom+s+this.gap,a=e.left+i;"bottom-end"===this.placement?a=e.right+i-t.width:"top-start"===this.placement?n=e.top+s-t.height-this.gap:"top-end"===this.placement&&(n=e.top+s-t.height-this.gap,a=e.right+i-t.width);const l=document.documentElement.clientWidth||window.innerWidth;a+t.width>i+l-8&&(a=i+l-t.width-8),a<i+8&&(a=i+8);const r=document.documentElement.clientHeight||window.innerHeight;n-s+t.height>r-8&&e.top-t.height-this.gap>8&&(n=e.top+s-t.height-this.gap),this.element.style.top=`${n}px`,this.element.style.left=`${a}px`}}const q={day:"MMM DD, YYYY",month:"MMM YYYY",year:"YYYY"};class DatePicker extends e.View{constructor(e={}){const{name:t,value:i="",precision:s="day",format:n=null,displayFormat:a=null,min:l=null,max:r=null,placeholder:o=null,disabled:d=!1,readonly:c=!1,required:h=!1,class:u="",inputClass:p="form-control",inline:m=!1,disabledDates:g=[],firstDay:b=1,lang:f="en-US",autoApply:v=!0,...y}=e;super({tagName:"div",className:`mojo-date-picker mojo-date-picker-${s} ${u}`.trim(),...y}),this.name=t,this.precision=s,this.format=n,this.displayFormat=a||q[s]||q.day,this.min=l,this.max=r,this.placeholder=o??this._defaultPlaceholder(s),this.disabled=d,this.readonly=c,this.required=h,this.inputClass=p,this.inline=m,this.disabledDates=g,this.firstDay=b,this.lang=f,this.autoApply=v,this.currentValue=i||"",this._calendar=null,this._popover=null}_defaultPlaceholder(e){return"year"===e?"Select year...":"month"===e?"Select month...":"Select date..."}async renderTemplate(){const e=this._inputId(),t=this._displayText(this.currentValue),i=!this.currentValue;return this.inline?`\n <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(this.currentValue)}" data-hidden-value />\n <div data-cal-host class="mojo-date-picker-inline${this.hasError()?" is-invalid":""}"></div>\n `:`\n <button type="button" id="${e}" class="mojo-date-trigger${this.hasError()?" is-invalid":""}"\n ${this.disabled?"disabled":""}\n data-trigger>\n <i class="bi bi-calendar3"></i>\n <span class="mojo-date-trigger-text${i?" is-empty":""}" data-trigger-text>${this._attr(t||this.placeholder)}</span>\n ${this.required||this.disabled||this.readonly?"":'<button type="button" class="mojo-date-trigger-clear" data-clear aria-label="Clear" tabindex="-1">✕</button>'}\n </button>\n <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(this.currentValue)}" data-hidden-value />\n `}async onAfterRender(){this.inline?this._mountCalendarInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",t=>{t.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",e=>{e.stopPropagation(),this._setValue("")}))}_togglePopover(e){this.disabled||this.readonly||(this._popover?this._popover.setAnchor(e):this._popover=new CalendarPopover({anchor:e}),this._popover.isOpen()?this._popover.close():(this._calendar||(this._calendar=this._buildCalendar()),this._popover.setContent(this._calendar.element),this._popover.open(),this._calendar.render(!1)))}_mountCalendarInline(){const e=this.element.querySelector("[data-cal-host]");e&&(this._calendar||(this._calendar=this._buildCalendar()),e.appendChild(this._calendar.element),this._calendar.render(!1))}_buildCalendar(){const e=new Calendar({precision:this.precision,mode:"single",months:1,value:this.currentValue||null,min:this.min,max:this.max,disabledDates:this.disabledDates,firstDay:this.firstDay,locale:this.lang});return e.on("select",({value:e})=>{this._setValue(e),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e}_setValue(e){const t=this.currentValue;let i="";if(e){const t=m(e,this.precision);t&&(i=p(t,this.precision))}this.currentValue=i;const s=this._displayText(i),n=this.element.querySelector("[data-trigger-text]");n&&(n.textContent=s||this.placeholder,n.classList.toggle("is-empty",!i));const a=this.element.querySelector("[data-hidden-value]");a&&(a.value=i),this._calendar&&this._calendar.setValue(i),t!==i&&(this.emit("change",{value:i,formatted:s,oldValue:t}),this.emit("date:changed",{value:i,oldValue:t}))}_displayText(e){if(!e)return"";const t=m(e,this.precision);return t?b(t,this._stripIncompatibleTokens(this.displayFormat)):""}_stripIncompatibleTokens(e){return"day"===this.precision?e:"month"===this.precision?e.replace(/\bDD\b|\bD\b/g,"").replace(/[\s\-\/]+$/,"").trim():"year"===this.precision?e.replace(/MMMM|MMM|MM|M|DD|D/g,"").replace(/[\s\-\/]+$/,"").trim()||"YYYY":e}setValue(e){this._setValue(e)}getValue(){return this.currentValue}getFormattedValue(){return this._displayText(this.currentValue)}clear(){this._setValue("")}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(e)}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(e)}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this._setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-date-${this.name}-${this.id}`:`mojo-date-${this.id}`}_attr(e){return null==e?"":String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}async onBeforeDestroy(){this._popover&&(this._popover.destroy(),this._popover=null),this._calendar=null,await super.onBeforeDestroy()}static create(e={}){return new DatePicker(e)}}function M(e,t){if(!e)return null;const i=new Date(e.y,e.m-1,e.d+t);return{y:i.getFullYear(),m:i.getMonth()+1,d:i.getDate()}}function L(e){return"year"===e?[{label:"This year",range:()=>{const e=$();return{start:{y:e.y},end:{y:e.y}}}},{label:"Last year",range:()=>{const e=$();return{start:{y:e.y-1},end:{y:e.y-1}}}},{label:"Last 3 years",range:()=>{const e=$();return{start:{y:e.y-2},end:{y:e.y}}}},{label:"Last 5 years",range:()=>{const e=$();return{start:{y:e.y-4},end:{y:e.y}}}},{label:"Last 10 years",range:()=>{const e=$();return{start:{y:e.y-9},end:{y:e.y}}}}]:"month"===e?[{label:"This month",range:()=>{const e=$();return{start:{y:e.y,m:e.m},end:{y:e.y,m:e.m}}}},{label:"Last month",range:()=>{const e=$(),t=v({y:e.y,m:e.m},-1);return{start:t,end:t}}},{label:"Last 3 months",range:()=>{const e=$();return{start:v({y:e.y,m:e.m},-2),end:{y:e.y,m:e.m}}}},{label:"Last 6 months",range:()=>{const e=$();return{start:v({y:e.y,m:e.m},-5),end:{y:e.y,m:e.m}}}},{label:"YTD",range:()=>{const e=$();return{start:{y:e.y,m:1},end:{y:e.y,m:e.m}}}},{label:"Last 12 months",range:()=>{const e=$();return{start:v({y:e.y,m:e.m},-11),end:{y:e.y,m:e.m}}}}]:[{label:"Today",range:()=>{const e=$();return{start:e,end:e}}},{label:"Yesterday",range:()=>{const e=M($(),-1);return{start:e,end:e}}},{label:"Last 7 days",range:()=>{const e=$();return{start:M(e,-6),end:e}}},{label:"Last 30 days",range:()=>{const e=$();return{start:M(e,-29),end:e}}},{label:"Last 90 days",range:()=>{const e=$();return{start:M(e,-89),end:e}}},{divider:!0},{label:"This month",range:()=>{const e=$();return{start:{y:e.y,m:e.m,d:1},end:e}}},{label:"Last month",range:()=>{const e=$(),t=v({y:e.y,m:e.m,d:1},-1),i=v(t,1);i.d=0;const s=new Date(i.y,i.m,0).getDate();return{start:{...t,d:1},end:{...t,d:s}}}},{label:"This year",range:()=>{const e=$();return{start:{y:e.y,m:1,d:1},end:e}}}]}class PresetSidebar extends e.View{constructor(e={}){const{precision:t="day",presets:i="default",eyebrow:s="Quick range",...n}=e;super({tagName:"div",className:"mojo-calendar-presets",...n}),this.precision=t,this.eyebrow=s,this.activeIndex=-1,this.presets=!0===i||"default"===i?L(t):Array.isArray(i)?i:L(t)}setActive(e){this.activeIndex=e,this._highlight()}async renderTemplate(){return""}async onAfterRender(){this._renderInto(this.element)}_renderInto(e){if(e.innerHTML="",this.eyebrow){const t=document.createElement("div");t.className="mojo-calendar-presets-eyebrow",t.textContent=this.eyebrow,e.appendChild(t)}this.presets.forEach((t,i)=>{if(t.divider){const t=document.createElement("div");return t.className="mojo-calendar-presets-divider",void e.appendChild(t)}const s=document.createElement("button");s.type="button",s.className="mojo-calendar-preset"+(this.activeIndex===i?" is-active":""),s.dataset.presetIndex=String(i),s.textContent=t.label,e.appendChild(s)}),e.addEventListener("click",e=>{const t=e.target.closest(".mojo-calendar-preset");if(!t)return;const i=parseInt(t.dataset.presetIndex,10),s=this.presets[i];if(!s||"function"!=typeof s.range)return;const n=s.range();this.activeIndex=i,this._highlight();const a="year"===this.precision?c:"month"===this.precision?h:u;this.emit("preset:select",{index:i,label:s.label,start:a(n.start),end:a(n.end),parsed:n})})}_highlight(){this.element&&this.element.querySelectorAll(".mojo-calendar-preset").forEach(e=>{const t=parseInt(e.dataset.presetIndex,10);e.classList.toggle("is-active",t===this.activeIndex)})}}const O={day:"MMM DD, YYYY",month:"MMM YYYY",year:"YYYY"};class DateRangePicker extends e.View{constructor(e={}){const{name:t,startName:i,endName:s,fieldName:n,startDate:a="",endDate:l="",precision:r="day",format:o=null,displayFormat:d=null,outputFormat:c="date",min:h=null,max:u=null,placeholder:p=null,disabled:m=!1,readonly:g=!1,required:b=!1,class:f="",inputClass:v="form-control",inline:y=!1,separator:w=" – ",autoApply:C=!0,months:_=null,presets:x=null,...S}=e;super({tagName:"div",className:`mojo-date-picker mojo-date-range-picker mojo-date-picker-${r} ${f}`.trim(),...S}),this.name=t,this.startName=i,this.endName=s,this.fieldName=n,this.precision=r,this.format=o,this.displayFormat=d||O[r]||O.day,this.outputFormat=c,this.min=h,this.max=u,this.placeholder=p??this._defaultPlaceholder(r),this.disabled=m,this.readonly=g,this.required=b,this.inputClass=v,this.inline=y,this.separator=w,this.autoApply=C,this.months=_??("day"===r?2:1),this.presets=x,this.currentStartDate=a||"",this.currentEndDate=l||"",this._calendar=null,this._popover=null,this._presetSidebar=null}_defaultPlaceholder(e){return"year"===e?"Select year range...":"month"===e?"Select month range...":"Select date range..."}async renderTemplate(){const e=this._inputId(),t=this._displayText(),i=!this.currentStartDate,s=this.startName||(this.name?`${this.name}_start`:""),n=this.endName||(this.name?`${this.name}_end`:""),a=`\n ${this.name?`<input type="hidden" name="${this._attr(this.name)}" value="${this._attr(this.getCombinedValue())}" data-combined-value />`:""}\n ${s?`<input type="hidden" name="${this._attr(s)}" value="${this._attr(this.currentStartDate)}" data-start-value />`:""}\n ${n?`<input type="hidden" name="${this._attr(n)}" value="${this._attr(this.currentEndDate)}" data-end-value />`:""}\n `;return this.inline?`\n ${a}\n <div data-cal-host class="mojo-date-picker-inline${this.hasError()?" is-invalid":""}"></div>\n `:`\n <button type="button" id="${e}" class="mojo-date-trigger${this.hasError()?" is-invalid":""}"\n ${this.disabled?"disabled":""}\n data-trigger>\n <i class="bi bi-calendar3-range"></i>\n <span class="mojo-date-trigger-text${i?" is-empty":""}" data-trigger-text>${this._attr(t||this.placeholder)}</span>\n ${this.required||this.disabled||this.readonly?"":'<button type="button" class="mojo-date-trigger-clear" data-clear aria-label="Clear" tabindex="-1">✕</button>'}\n </button>\n ${a}\n `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",t=>{t.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",e=>{e.stopPropagation(),this._setRange("","")}))}_togglePopover(e){if(this.disabled||this.readonly)return;if(this._popover)this._popover.setAnchor(e);else{const t=this._hasPresets();this._popover=new CalendarPopover({anchor:e,classNames:t?"mojo-calendar-popover-with-presets":""})}if(this._popover.isOpen())return void this._popover.close();this._calendar||(this._calendar=this._buildCalendar()),this._hasPresets()&&!this._presetSidebar&&(this._presetSidebar=this._buildPresetSidebar());const t=this._buildPopoverContent();this._popover.setContent(t),this._popover.open(),this._calendar.render(!1),this._presetSidebar&&this._presetSidebar.render(!1)}_mountInline(){const e=this.element.querySelector("[data-cal-host]");e&&(this._calendar||(this._calendar=this._buildCalendar()),this._hasPresets()&&!this._presetSidebar&&(this._presetSidebar=this._buildPresetSidebar()),e.appendChild(this._buildPopoverContent()),this._calendar.render(!1),this._presetSidebar&&this._presetSidebar.render(!1))}_buildPopoverContent(){const e=document.createElement("div");e.className="mojo-calendar-popover-inner",e.style.display="contents",this._presetSidebar&&e.appendChild(this._presetSidebar.element);const t=document.createElement("div");return t.className="mojo-calendar-cal-wrap",t.appendChild(this._calendar.element),e.appendChild(t),e}_buildCalendar(){const e=new Calendar({precision:this.precision,mode:"range",months:this.months,startValue:this.currentStartDate||null,endValue:this.currentEndDate||null,min:this.min,max:this.max,firstDay:1,locale:"en-US"});return e.on("range:select",({start:e,end:t})=>{this._setRange(e,t),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e.on("range:start",()=>{this._presetSidebar&&this._presetSidebar.setActive(-1)}),e}_hasPresets(){return!0===this.presets||"default"===this.presets||Array.isArray(this.presets)&&this.presets.length>0}_buildPresetSidebar(){const e=new PresetSidebar({precision:this.precision,presets:this.presets});return e.on("preset:select",({start:e,end:t})=>{this._setRange(e,t),this._calendar&&this._calendar.setRange(e,t),this.autoApply&&this._popover&&this._popover.isOpen()&&this._popover.close()}),e}_setRange(e,t){const i=this.currentStartDate,s=this.currentEndDate;let n="",a="";if(e){const t=m(e,this.precision);t&&(n=p(t,this.precision))}if(t){const e=m(t,this.precision);e&&(a=p(e,this.precision))}this.currentStartDate=n,this.currentEndDate=a;const l=this.element.querySelector("[data-trigger-text]");if(l){const e=this._displayText();l.textContent=e||this.placeholder,l.classList.toggle("is-empty",!n)}this._updateHidden(),i===n&&s===a||(this.emit("change",{startDate:n,endDate:a,combined:this.getCombinedValue(),formatted:this._displayText(),oldStartDate:i,oldEndDate:s}),this.emit("range:changed",{startDate:n,endDate:a,oldStartDate:i,oldEndDate:s}))}_updateHidden(){const e=this.element.querySelector("[data-start-value]"),t=this.element.querySelector("[data-end-value]"),i=this.element.querySelector("[data-combined-value]");e&&(e.value=this.currentStartDate),t&&(t.value=this.currentEndDate),i&&(i.value=this.getCombinedValue())}_displayText(){const e=this.currentStartDate?m(this.currentStartDate,this.precision):null,t=this.currentEndDate?m(this.currentEndDate,this.precision):null;if(!e&&!t)return"";const i=this._stripIncompatibleTokens(this.displayFormat);return e&&t?`${b(e,i)}${this.separator}${b(t,i)}`:b(e||t,i)}_stripIncompatibleTokens(e){return"day"===this.precision?e:"month"===this.precision?e.replace(/\bDD\b|\bD\b/g,"").replace(/[\s\-\/]+$/,"").trim():"year"===this.precision?e.replace(/MMMM|MMM|MM|M|DD|D/g,"").replace(/[\s\-\/]+$/,"").trim()||"YYYY":e}getCombinedValue(){return this.currentStartDate||this.currentEndDate?"string"===this.outputFormat?`${this.currentStartDate}${this.separator}${this.currentEndDate}`:"object"===this.outputFormat?JSON.stringify({start:this.currentStartDate,end:this.currentEndDate}):`${this.currentStartDate}${this.separator}${this.currentEndDate}`:""}setRange(e,t){this._setRange(e,t),this._calendar&&this._calendar.setRange(e,t)}setStartDate(e){this._setRange(e,this.currentEndDate)}setEndDate(e){this._setRange(this.currentStartDate,e)}getStartDate(){return this.currentStartDate}getEndDate(){return this.currentEndDate}getRange(){return{start:this.currentStartDate,end:this.currentEndDate}}clear(){this._setRange("","")}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(e)}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(e)}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getCombinedValue()}async setFormValue(e){if(e)if("object"==typeof e&&e.start)this._setRange(e.start,e.end);else if("string"==typeof e&&e.includes(this.separator.trim())){const[t,i]=e.split(this.separator.trim()).map(e=>e.trim());this._setRange(t,i)}else this._setRange(e,this.currentEndDate);else this._setRange("","")}hasError(){return!1}_inputId(){return this.name?`mojo-daterange-${this.name}-${this.id}`:`mojo-daterange-${this.id}`}_attr(e){return null==e?"":String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}async onBeforeDestroy(){this._popover&&(this._popover.destroy(),this._popover=null),this._calendar=null,this._presetSidebar=null,await super.onBeforeDestroy()}static create(e={}){return new DateRangePicker(e)}}class ComboBox extends e.View{constructor(e={}){super(e),this.name=e.name||"combo",this.placeholder=e.placeholder||e.placeHolder||"Type or select...",this.value=e.value||"",this.options=(e.options||[]).map(e=>"string"==typeof e?{label:e,value:e}:"object"==typeof e&&null!==e?e:{label:e,value:e}),this.allowCustom=!1!==e.allowCustom,this.disabled=e.disabled||!1,this.required=e.required||!1,this.maxHeight=e.maxHeight||300,this.filteredOptions=[...this.options],this.highlightedIndex=-1,this.isOpen=!1,this.template='\n <div class="combobox-container">\n <div class="input-group">\n <input type="text"\n class="form-control combobox-input"\n placeholder="{{placeholder}}"\n value="{{value}}"\n {{#disabled}}disabled{{/disabled}}\n {{#required}}required{{/required}}\n data-action="combobox-input"\n autocomplete="off">\n <button class="btn btn-outline-secondary combobox-toggle"\n type="button"\n data-action="combobox-toggle"\n {{#disabled}}disabled{{/disabled}}>\n <i class="bi bi-chevron-down"></i>\n </button>\n </div>\n <div class="dropdown-menu combobox-dropdown"\n style="max-height: {{maxHeight}}px; overflow-y: auto; width: 100%;">\n <div data-region="dropdown-items"></div>\n {{^allowCustom}}\n <div class="combobox-no-match dropdown-item text-muted" style="display: none;">\n No matches found\n </div>\n {{/allowCustom}}\n </div>\n </div>\n ',this.itemTemplate='\n {{#items}}\n <button type="button"\n class="dropdown-item combobox-item {{#highlighted}}active{{/highlighted}}"\n data-action="select-item"\n data-value="{{value}}"\n data-index="{{index}}">\n {{label}}\n </button>\n {{/items}}\n '}async onInit(){await super.onInit()}async onAfterRender(){if(await super.onAfterRender(),this.input=this.element.querySelector(".combobox-input"),this.dropdown=this.element.querySelector(".combobox-dropdown"),this.dropdownItems=this.element.querySelector('[data-region="dropdown-items"]'),this.noMatchDiv=this.element.querySelector(".combobox-no-match"),this.value&&this.input){const e=this.options.find(e=>e.value===this.value);e?this.input.value=e.label||e.value:this.allowCustom&&(this.input.value=this.value)}this.renderItems(),this.setupEventListeners()}setupEventListeners(){this.input.addEventListener("focus",()=>this.openDropdown()),this.input.addEventListener("input",e=>this.handleInput(e)),this.input.addEventListener("keydown",e=>this.handleKeydown(e)),document.addEventListener("click",e=>{this.element.contains(e.target)||this.closeDropdown()})}handleInput(e){const t=e.target.value.toLowerCase();this.filteredOptions=this.options.filter(e=>(e.label||e.value).toLowerCase().includes(t)),this.highlightedIndex=-1,this.renderItems(),this.openDropdown(),!this.allowCustom&&this.noMatchDiv&&(this.noMatchDiv.style.display=0===this.filteredOptions.length?"block":"none"),this.value=e.target.value,this.emit("change",{value:this.value})}handleKeydown(e){if(!this.isOpen&&("ArrowDown"===e.key||"ArrowUp"===e.key))return this.openDropdown(),void e.preventDefault();if(this.isOpen)switch(e.key){case"ArrowDown":e.preventDefault(),this.highlightedIndex=Math.min(this.highlightedIndex+1,this.filteredOptions.length-1),this.renderItems(),this.scrollToHighlighted();break;case"ArrowUp":e.preventDefault(),this.highlightedIndex=Math.max(this.highlightedIndex-1,-1),this.renderItems(),this.scrollToHighlighted();break;case"Enter":e.preventDefault(),this.highlightedIndex>=0&&this.selectItem(this.filteredOptions[this.highlightedIndex]);break;case"Escape":e.preventDefault(),this.closeDropdown();break;case"Tab":this.closeDropdown()}}scrollToHighlighted(){if(this.highlightedIndex<0)return;const e=this.dropdownItems.querySelectorAll(".combobox-item")[this.highlightedIndex];e&&e.scrollIntoView({block:"nearest"})}openDropdown(){this.disabled||this.isOpen||(this.isOpen=!0,this.dropdown.classList.add("show"),""===this.input.value&&(this.filteredOptions=[...this.options],this.renderItems()))}closeDropdown(){this.isOpen&&(this.isOpen=!1,this.dropdown.classList.remove("show"),this.highlightedIndex=-1,!this.allowCustom)&&(this.options.find(e=>e.value===this.input.value||e.label===this.input.value)||""===this.input.value||(this.input.value=this.value))}selectItem(e){const t=e.value,i=e.label||e.value;this.input.value=i,this.value=t,this.closeDropdown(),this.filteredOptions=[...this.options],this.highlightedIndex=-1,this.emit("change",{value:this.value,label:i})}renderItems(){const t=this.filteredOptions.map((e,t)=>({value:e.value,label:e.label||e.value,index:t,highlighted:t===this.highlightedIndex})),i=e.Mustache.render(this.itemTemplate,{items:t});this.dropdownItems.innerHTML=i}async onActionComboboxInput(e,t){}async onActionComboboxToggle(e,t){this.isOpen?this.closeDropdown():(this.input.focus(),this.openDropdown())}async onActionSelectItem(e,t){const i=t.getAttribute("data-value"),s=this.options.find(e=>e.value===i);s&&this.selectItem(s)}getValue(){return this.value}setValue(e){if(this.value=e,!this.input)return;const t=this.options.find(t=>t.value===e);t?this.input.value=t.label||t.value:this.allowCustom&&(this.input.value=e)}setFormValue(e){this.setValue(e)}getTemplateData(){return{placeholder:this.placeholder,value:this.input?this.input.value:this.value,disabled:this.disabled,required:this.required,maxHeight:this.maxHeight,allowCustom:this.allowCustom}}}const j=["UTC","GMT","America/New_York","America/Chicago","America/Denver","America/Los_Angeles","America/Anchorage","America/Honolulu","America/Phoenix","America/Toronto","America/Vancouver","America/Mexico_City","America/Sao_Paulo","America/Buenos_Aires","America/Bogota","Europe/London","Europe/Dublin","Europe/Paris","Europe/Berlin","Europe/Madrid","Europe/Rome","Europe/Amsterdam","Europe/Stockholm","Europe/Athens","Europe/Moscow","Europe/Istanbul","Africa/Cairo","Africa/Johannesburg","Africa/Lagos","Africa/Nairobi","Asia/Dubai","Asia/Tehran","Asia/Karachi","Asia/Kolkata","Asia/Bangkok","Asia/Singapore","Asia/Hong_Kong","Asia/Shanghai","Asia/Tokyo","Asia/Seoul","Asia/Jakarta","Asia/Manila","Australia/Perth","Australia/Sydney","Australia/Melbourne","Pacific/Auckland","Pacific/Fiji","Pacific/Honolulu"];let z=!1;class TimezoneSelect extends e.View{constructor(e={}){const{name:t="timezone",value:i=null,timezones:s=null,disabled:n=!1,required:a=!1,placeholder:l="Search timezone...",...r}=e;super({tagName:"div",className:"mojo-timezone-select",...r}),this.name=t,this.disabled=n,this.required=a,this.placeholder=l,this.timezones=s,this.currentValue=i||function(){try{return(new Intl.DateTimeFormat).resolvedOptions().timeZone||"UTC"}catch(e){return"UTC"}}(),this._combo=null,this.template='<div data-region="combo-host"></div>'}async onAfterRender(){const e=this.element.querySelector('[data-region="combo-host"]');if(!e)return;const t=this._buildZoneList().map(e=>({value:e,label:this._labelFor(e)}));this._combo=new ComboBox({name:this.name,value:this.currentValue,placeholder:this.placeholder,options:t,allowCustom:!1,disabled:this.disabled,required:this.required,maxHeight:280}),await this._combo.render(!0,e),this._combo.on("change",e=>{const t=e&&e.value?e.value:"";if(t!==this.currentValue){const e=this.currentValue;this.currentValue=t,this.emit("change",{value:t,oldValue:e})}})}_buildZoneList(){if(Array.isArray(this.timezones)&&this.timezones.length)return this.timezones.slice();try{if("undefined"!=typeof Intl&&"function"==typeof Intl.supportedValuesOf){const e=Intl.supportedValuesOf("timeZone");if(Array.isArray(e)&&e.length)return e.slice()}}catch(e){}return z||(z=!0,console.warn('[TimezoneSelect] Intl.supportedValuesOf("timeZone") unavailable; falling back to curated list.')),j.slice()}_labelFor(e){const t=function(e){try{const t=/* @__PURE__ */new Date,i=new Intl.DateTimeFormat("en-US",{timeZone:e,timeZoneName:"shortOffset"}).formatToParts(t).find(e=>"timeZoneName"===e.type);if(!i)return null;let s=i.value;if("GMT"===s)return"+00:00";s=s.replace(/^GMT/,"");const n=s.match(/^([+-])(\d{1,2})(?::(\d{2}))?$/);if(!n)return s||null;const a=n[1];return`${"-"===a?"−":"+"}${n[2].padStart(2,"0")}:${n[3]||"00"}`}catch(t){return null}}(e);return t?`${e} (UTC${t})`:e}getValue(){return this.currentValue}getFormValue(){return this.currentValue}setValue(e){if(e!==this.currentValue&&(this.currentValue=e||"",this._combo)){this._combo.value=this.currentValue;const e=this._combo.element&&this._combo.element.querySelector(".combobox-input");e&&(e.value=this.currentValue)}}setEnabled(e){this.disabled=!e;const t=this.element.querySelector(".combobox-input"),i=this.element.querySelector(".combobox-toggle");t&&(t.disabled=!e),i&&(i.disabled=!e)}async onBeforeDestroy(){if(this._combo&&"function"==typeof this._combo.destroy)try{await this._combo.destroy()}catch(e){}this._combo=null,await super.onBeforeDestroy()}}class TimePicker extends e.View{constructor(e={}){const{name:t,value:i="",format:s="24h",step:n=1,min:a=null,max:l=null,placeholder:r=null,disabled:o=!1,readonly:d=!1,required:c=!1,class:h="",inline:u=!1,autoApply:p=!1,timezone:m=!1,timezones:g=null,outputFormat:b="iso",showFooter:f=!0,...v}=e;super({tagName:"div",className:`mojo-time-picker ${h}`.trim(),...v}),this.name=t,this.format="12h"===s?"12h":"24h",this.step=Math.max(1,parseInt(n,10)||1),this.min=a,this.max=l,this.placeholder=r??("12h"===this.format?"h:mm AM/PM":"HH:MM"),this.disabled=o,this.readonly=d,this.required=c,this.inline=u,this.autoApply=p,this.showFooter=!1!==f,this.timezone=!0===m||Array.isArray(m),this.timezoneList=Array.isArray(m)?m:g,this.outputFormat=["object","iana","iso"].includes(b)?b:"iso";const y=this._parseInitial(i);this.currentTime=y.time,this.currentTimezone=y.timezone||(this.timezone?function(){try{return(new Intl.DateTimeFormat).resolvedOptions().timeZone||"UTC"}catch(e){return"UTC"}}():null),this._popover=null,this._tzSelect=null,this._spinner=null}_parseInitial(e){if(null==e||""===e)return{time:null,timezone:null};if("object"==typeof e&&!Array.isArray(e))return{time:e.time?_(e.time):null,timezone:e.timezone||null};const t=String(e).trim(),i=t.match(/^(\d{1,2}:\d{2})(Z|[+-]\d{2}:?\d{2})$/);if(i){const e=i[2];let t=null;return t="Z"===e?"+00:00":/^[+-]\d{4}$/.test(e)?`${e.slice(0,3)}:${e.slice(3)}`:e,{time:_(i[1]),timezone:t}}const s=t.indexOf(" ");if(s>-1){const e=t.slice(s+1).trim();return/^(am|pm)$/i.test(e)?{time:_(t),timezone:null}:{time:_(t.slice(0,s)),timezone:e||null}}return{time:_(t),timezone:null}}async renderTemplate(){const e=this._inputId(),t=this._displayText(),i=!this.currentTime,s=this._serialize();return this.inline?`\n <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(s)}" data-hidden-value />\n <div data-time-host class="mojo-time-picker-inline${this.hasError()?" is-invalid":""}"></div>\n `:`\n <button type="button" id="${e}" class="mojo-time-trigger${this.hasError()?" is-invalid":""}"\n ${this.disabled?"disabled":""}\n data-trigger>\n <i class="bi bi-clock"></i>\n <span class="mojo-time-trigger-text${i?" is-empty":""}" data-trigger-text>${this._attr(t||this.placeholder)}</span>\n ${this.required||this.disabled||this.readonly?"":'<button type="button" class="mojo-time-trigger-clear" data-clear aria-label="Clear" tabindex="-1">✕</button>'}\n </button>\n <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(s)}" data-hidden-value />\n `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",t=>{t.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",e=>{e.stopPropagation(),this.clear()}))}_togglePopover(e){if(this.disabled||this.readonly)return;if(this._popover?this._popover.setAnchor(e):this._popover=new CalendarPopover({anchor:e,classNames:"mojo-time-popover"}),this._popover.isOpen())return void this._popover.close();const t=this._buildSpinnerContent();this._popover.setContent(t),this._popover.open(),this.timezone&&this._mountTimezoneSelect()}_mountInline(){const e=this.element.querySelector("[data-time-host]");if(!e)return;const t=this._buildSpinnerContent();e.appendChild(t),this.timezone&&this._mountTimezoneSelect()}_buildSpinnerContent(){const e=document.createElement("div");e.className="mojo-time-popover-inner";const t=document.createElement("div");t.className="mojo-time-stepper-row";const i=this.currentTime||{hours:0,minutes:0},s=this._hourDisplay(i.hours);t.appendChild(this._buildStepper("hour",s,"Hour"));const n=document.createElement("div");if(n.className="mojo-time-stepper-sep",n.textContent=":",t.appendChild(n),t.appendChild(this._buildStepper("minute",H(i.minutes),"Minute")),"12h"===this.format&&t.appendChild(this._buildAmPmToggle(i.hours)),e.appendChild(t),this.timezone){const t=document.createElement("div");t.className="mojo-time-tz-host",t.setAttribute("data-tz-host",""),e.appendChild(t)}if(this.showFooter){const t=document.createElement("div");t.className="mojo-time-foot";const i=document.createElement("button");i.type="button",i.className="btn btn-link btn-sm mojo-time-now",i.textContent="Now",i.addEventListener("click",e=>{e.preventDefault();const t=/* @__PURE__ */new Date;this._commitTime({hours:t.getHours(),minutes:t.getMinutes()}),this._refreshSpinnerDisplay()}),t.appendChild(i);const s=document.createElement("button");s.type="button",s.className="btn btn-primary btn-sm mojo-time-apply",s.textContent="Set",s.addEventListener("click",e=>{e.preventDefault(),this.currentTime||this._commitTime({hours:0,minutes:0}),this._popover&&this._popover.isOpen()&&this._popover.close()}),t.appendChild(s),e.appendChild(t)}return this._spinner=e,e}_buildStepper(e,t,i){const s=document.createElement("div");s.className=`mojo-time-stepper mojo-time-stepper-${e}`;const n=document.createElement("button");n.type="button",n.className="mojo-time-stepper-btn",n.setAttribute("aria-label",`Increase ${i.toLowerCase()}`),n.innerHTML='<i class="bi bi-chevron-up" aria-hidden="true"></i>',n.addEventListener("click",t=>{t.preventDefault(),this._step(e,1)});const a=document.createElement("input");a.type="text",a.className="mojo-time-stepper-value",a.value=t,a.setAttribute("inputmode","numeric"),a.setAttribute("aria-label",i),a.maxLength=2,a.addEventListener("focus",()=>a.select()),a.addEventListener("keydown",t=>this._onValueKey(e,a,t)),a.addEventListener("blur",()=>this._onValueBlur(e,a));const l=document.createElement("button");l.type="button",l.className="mojo-time-stepper-btn",l.setAttribute("aria-label",`Decrease ${i.toLowerCase()}`),l.innerHTML='<i class="bi bi-chevron-down" aria-hidden="true"></i>',l.addEventListener("click",t=>{t.preventDefault(),this._step(e,-1)});const r=document.createElement("div");return r.className="mojo-time-stepper-label",r.textContent=i,s.appendChild(n),s.appendChild(a),s.appendChild(l),s.appendChild(r),s}_buildAmPmToggle(e){const t=document.createElement("div");t.className="mojo-time-ampm";const i=e>=12,s=document.createElement("button");s.type="button",s.className="mojo-time-ampm-btn"+(i?"":" is-active"),s.textContent="AM",s.addEventListener("click",e=>{e.preventDefault(),this._setAmPm("am")});const n=document.createElement("button");return n.type="button",n.className="mojo-time-ampm-btn"+(i?" is-active":""),n.textContent="PM",n.addEventListener("click",e=>{e.preventDefault(),this._setAmPm("pm")}),t.appendChild(s),t.appendChild(n),t}_mountTimezoneSelect(){if(!this.timezone)return;const e=this.inline?this.element.querySelector("[data-time-host] [data-tz-host]"):this._spinner&&this._spinner.querySelector("[data-tz-host]");if(e){if(this._tzSelect)try{this._tzSelect.destroy&&this._tzSelect.destroy()}catch(t){}e.innerHTML="",this._tzSelect=new TimezoneSelect({name:"timezone",value:this.currentTimezone,timezones:this.timezoneList}),this._tzSelect.render(!0,e),this._tzSelect.on("change",({value:e})=>{const t=this.currentTimezone;this.currentTimezone=e||null,t!==this.currentTimezone&&this._syncOutputs()})}}_step(e,t){const i=this.currentTime||{hours:0,minutes:0};let{hours:s,minutes:n}=i;if("hour"===e)s=((s+t)%24+24)%24;else{const e=((60*s+n+t*this.step)%1440+1440)%1440;s=Math.floor(e/60),n=e%60}const a=this._clampToBounds({hours:s,minutes:n});this._commitTime(a),this._refreshSpinnerDisplay()}_setAmPm(e){if(this.currentTime){const{hours:t,minutes:i}=this.currentTime;let s=t;"am"===e&&s>=12?s-=12:"pm"===e&&s<12&&(s+=12),this._commitTime(this._clampToBounds({hours:s,minutes:i}))}else this._commitTime({hours:"pm"===e?12:0,minutes:0});this._refreshSpinnerDisplay()}_onValueKey(e,t,i){"ArrowUp"===i.key?(i.preventDefault(),this._step(e,1),t.focus(),t.select()):"ArrowDown"===i.key?(i.preventDefault(),this._step(e,-1),t.focus(),t.select()):"Enter"===i.key?(i.preventDefault(),t.blur()):"Tab"===i.key||/^[0-9]$/.test(i.key)||["Backspace","Delete","ArrowLeft","ArrowRight","Home","End"].includes(i.key)||i.preventDefault()}_onValueBlur(e,t){const i=(t.value||"").replace(/\D/g,"");if(""===i)return void this._refreshSpinnerDisplay();let s=parseInt(i,10);const n=this.currentTime||{hours:0,minutes:0};let{hours:a,minutes:l}=n;if("hour"===e)if("12h"===this.format){s<1&&(s=1),s>12&&(s=12);const e=n.hours>=12;a=12===s?e?12:0:e?s+12:s}else s<0&&(s=0),s>23&&(s=23),a=s;else s<0&&(s=0),s>59&&(s=59),l=s;this._commitTime(this._clampToBounds({hours:a,minutes:l})),this._refreshSpinnerDisplay()}_hourDisplay(e){if("12h"===this.format){let t=e%12;return 0===t&&(t=12),String(t)}return H(e)}_refreshSpinnerDisplay(){if(!this._spinner)return;const e=this.currentTime||{hours:0,minutes:0},t=this._spinner.querySelector(".mojo-time-stepper-hour .mojo-time-stepper-value"),i=this._spinner.querySelector(".mojo-time-stepper-minute .mojo-time-stepper-value");if(t&&(t.value=this._hourDisplay(e.hours)),i&&(i.value=H(e.minutes)),"12h"===this.format){const t=e.hours>=12,i=this._spinner.querySelector(".mojo-time-ampm-btn:nth-child(1)"),s=this._spinner.querySelector(".mojo-time-ampm-btn:nth-child(2)");i&&i.classList.toggle("is-active",!t),s&&s.classList.toggle("is-active",t)}}_clampToBounds(e){const t=this.min?_(this.min):null,i=this.max?_(this.max):null;return t&&S(e,t)<0?t:i&&S(e,i)>0?i:e}_commitTime(e){const t=this._serialize();this.currentTime=e?{hours:e.hours,minutes:e.minutes}:null,this._syncOutputs(t)}_syncOutputs(e){const t=this._serialize(),i=this._displayText(),s=this.element&&this.element.querySelector("[data-trigger-text]");s&&(s.textContent=i||this.placeholder,s.classList.toggle("is-empty",!this.currentTime));const n=this.element&&this.element.querySelector("[data-hidden-value]");n&&(n.value=t),void 0!==e&&e!==t&&(this.emit("change",{value:this.getValue(),formatted:i,oldValue:e}),this.emit("time:changed",{value:this.getValue()}))}_serialize(){if(!this.currentTime)return"";const e=x(this.currentTime,"24h");if(!this.timezone||!this.currentTimezone)return e;if("iana"===this.outputFormat)return`${e} ${this.currentTimezone}`;const t=F(this.currentTimezone,/* @__PURE__ */new Date);return t?`${e}${t}`:e}_displayText(){if(!this.currentTime)return"";const e=x(this.currentTime,this.format);return this.timezone&&this.currentTimezone?`${e} ${this.currentTimezone}`:e}getValue(){return this.currentTime?this.timezone&&"object"===this.outputFormat?{time:x(this.currentTime,"24h"),timezone:this.currentTimezone||null}:this._serialize():"object"===this.outputFormat?null:""}setValue(e){const t=this._serialize(),i=this._parseInitial(e);this.currentTime=i.time,i.timezone&&(this.currentTimezone=i.timezone),this._refreshSpinnerDisplay(),this._syncOutputs(t)}getFormattedValue(){return this._displayText()}clear(){if(!this.currentTime&&!this.element.querySelector("[data-hidden-value]")?.value)return;const e=this._serialize();this.currentTime=null,this._syncOutputs(e)}setMin(e){this.min=e}setMax(e){this.max=e}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-time-${this.name}-${this.id}`:`mojo-time-${this.id}`}_attr(e){return null==e?"":String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}async onBeforeDestroy(){if(this._popover){try{this._popover.destroy()}catch(e){}this._popover=null}if(this._tzSelect){try{await this._tzSelect.destroy()}catch(e){}this._tzSelect=null}this._spinner=null,await super.onBeforeDestroy()}static addMinutes(e,t){return function(e,t){if(!e)return null;let i=60*e.hours+e.minutes+t;return i=(i%1440+1440)%1440,{hours:Math.floor(i/60),minutes:i%60}}(e,t)}static create(e={}){return new TimePicker(e)}}function H(e){return e<10?"0"+e:String(e)}class DateTimePicker extends e.View{constructor(e={}){const{name:t,value:i="",format:s=null,displayFormat:n=null,timeFormat:a="24h",timeStep:l=1,min:r=null,max:o=null,placeholder:d=null,disabled:c=!1,readonly:h=!1,required:u=!1,class:p="",inline:m=!1,disabledDates:g=[],firstDay:b=1,lang:f="en-US",autoApply:v=!1,timezone:y=!1,timezones:w=null,outputFormat:C="iso",..._}=e;super({tagName:"div",className:`mojo-datetime-picker ${p}`.trim(),..._}),this.name=t,this.format=s,this.displayFormat=n||"MMM DD, YYYY",this.timeFormat="12h"===a?"12h":"24h",this.timeStep=Math.max(1,parseInt(l,10)||1),this.min=r,this.max=o,this.placeholder=d??"Pick date & time...",this.disabled=c,this.readonly=h,this.required=u,this.inline=m,this.disabledDates=g,this.firstDay=b,this.lang=f,this.autoApply=v,this.timezone=!0===y||Array.isArray(y),this.timezoneList=Array.isArray(y)?y:w,this.outputFormat=["object","iana","iso"].includes(C)?C:"iso";const x=this._parseInitial(i);this.currentDate=x.date,this.currentTime=x.time,this.currentTimezone=x.timezone||(this.timezone?P():null),this._calendar=null,this._timePicker=null,this._tzSelect=null,this._popover=null,this._popoverContent=null}_parseInitial(e){return null==e||""===e?{date:null,time:null,timezone:null}:("object"!=typeof e||Array.isArray(e)||Date,D(e)||{date:null,time:null,timezone:null})}async renderTemplate(){const e=this._inputId(),t=this._displayText(),i=!this.currentDate,s=this._serialize();return this.inline?`\n <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(s)}" data-hidden-value />\n <div data-dt-host class="mojo-datetime-picker-inline${this.hasError()?" is-invalid":""}"></div>\n `:`\n <button type="button" id="${e}" class="mojo-datetime-trigger${this.hasError()?" is-invalid":""}"\n ${this.disabled?"disabled":""}\n data-trigger>\n <i class="bi bi-calendar3"></i>\n <span class="mojo-datetime-trigger-text${i?" is-empty":""}" data-trigger-text>${this._attr(t||this.placeholder)}</span>\n ${this.required||this.disabled||this.readonly?"":'<button type="button" class="mojo-datetime-trigger-clear" data-clear aria-label="Clear" tabindex="-1">✕</button>'}\n </button>\n <input type="hidden" name="${this._attr(this.name||"")}" value="${this._attr(s)}" data-hidden-value />\n `}async onAfterRender(){this.inline?this._mountInline():this._wireTrigger()}_wireTrigger(){const e=this.element.querySelector("[data-trigger]"),t=this.element.querySelector("[data-clear]");e&&(e.addEventListener("click",t=>{t.target.closest("[data-clear]")||this._togglePopover(e)}),t&&t.addEventListener("click",e=>{e.stopPropagation(),this.clear()}))}_togglePopover(e){this.disabled||this.readonly||(this._popover?this._popover.setAnchor(e):this._popover=new CalendarPopover({anchor:e,classNames:"mojo-datetime-popover"}),this._popover.isOpen()?this._popover.close():(this._popoverContent||(this._popoverContent=this._buildContent()),this._popover.setContent(this._popoverContent),this._popover.open(),this._calendar&&this._calendar.render(!1)))}_mountInline(){const e=this.element.querySelector("[data-dt-host]");e&&(this._popoverContent||(this._popoverContent=this._buildContent()),e.appendChild(this._popoverContent),this._calendar&&this._calendar.render(!1))}_buildContent(){const e=document.createElement("div");e.className="mojo-datetime-popover-inner";const t=document.createElement("div");t.className="mojo-datetime-row";const i=document.createElement("div");i.className="mojo-datetime-cal-col",t.appendChild(i);const s=document.createElement("div");s.className="mojo-datetime-time-col",t.appendChild(s),e.appendChild(t),this._calendar=new Calendar({precision:"day",mode:"single",months:1,value:this.currentDate?u(this.currentDate):null,min:this._dateBound(this.min),max:this._dateBound(this.max),disabledDates:this.disabledDates,firstDay:this.firstDay,locale:this.lang}),i.appendChild(this._calendar.element),this._calendar.on("select",({value:e})=>{const t=d(e);this.currentDate=t,this.currentTime||(this.currentTime={hours:0,minutes:0}),this._refreshTimezoneDefault(),this._syncOutputs()}),this._timePicker=new TimePicker({name:null,value:this.currentTime?x(this.currentTime,"24h"):"",format:this.timeFormat,step:this.timeStep,timezone:!1,inline:!0,autoApply:!1,showFooter:!1});const n=document.createElement("div");if(n.className="mojo-datetime-time-head",n.textContent="Time",s.appendChild(n),s.appendChild(this._timePicker.element),this._timePicker.on("change",()=>{const e=this._timePicker.currentTime;if(this.currentTime=e?{...e}:null,this.currentTime&&!this.currentDate){const e=/* @__PURE__ */new Date;this.currentDate={y:e.getFullYear(),m:e.getMonth()+1,d:e.getDate()},this._calendar&&this._calendar.setValue(u(this.currentDate))}this._syncOutputs()}),this._timePicker.render(!1),this.timezone){const t=document.createElement("div");t.className="mojo-datetime-tz-row";const i=document.createElement("div");i.className="mojo-datetime-tz-label",i.textContent="Timezone",t.appendChild(i);const s=document.createElement("div");s.className="mojo-datetime-tz-host",t.appendChild(s),e.appendChild(t),this._tzSelect=new TimezoneSelect({name:"timezone",value:this.currentTimezone,timezones:Array.isArray(this.timezoneList)?this.timezoneList:null}),this._tzSelect.render(!0,s),this._tzSelect.on("change",({value:e})=>{const t=this.currentTimezone;this.currentTimezone=e||null,t!==this.currentTimezone&&this._syncOutputs()})}const a=document.createElement("div");a.className="mojo-datetime-foot";const l=document.createElement("button");l.type="button",l.className="btn btn-link btn-sm",l.textContent="Now",l.addEventListener("click",e=>{e.preventDefault();const t=/* @__PURE__ */new Date;this.currentDate={y:t.getFullYear(),m:t.getMonth()+1,d:t.getDate()},this.currentTime={hours:t.getHours(),minutes:t.getMinutes()},this._calendar&&this._calendar.setValue(u(this.currentDate)),this._timePicker&&this._timePicker.setValue(x(this.currentTime,"24h")),this._syncOutputs()}),a.appendChild(l);const r=document.createElement("button");return r.type="button",r.className="btn btn-primary btn-sm",r.textContent="Done",r.addEventListener("click",e=>{e.preventDefault(),this._popover&&this._popover.isOpen()&&this._popover.close()}),a.appendChild(r),e.appendChild(a),e}_refreshTimezoneDefault(){this.timezone&&!this.currentTimezone&&this._timePicker&&(this.currentTimezone=this._timePicker.currentTimezone||P())}_timePickerValue(){if(!this.currentTime&&!this.currentTimezone)return"";const e=this.currentTime?x(this.currentTime,"24h"):"00:00";return this.timezone&&this.currentTimezone?`${e} ${this.currentTimezone}`:e}_dateBound(e){return e?String(e).trim().split(/[ T]/)[0]:null}_syncOutputs(e){const t=this._serialize(),i=this._displayText(),s=this.element&&this.element.querySelector("[data-trigger-text]");s&&(s.textContent=i||this.placeholder,s.classList.toggle("is-empty",!this.currentDate));const n=this.element&&this.element.querySelector("[data-hidden-value]");n&&(n.value=t),void 0!==e&&e!==t?(this.emit("change",{value:this.getValue(),formatted:i,oldValue:e}),this.emit("datetime:changed",{value:this.getValue()})):void 0===e&&this.emit("change",{value:this.getValue(),formatted:i,oldValue:null})}_serialize(){if(!this.currentDate)return"";const e=u(this.currentDate),t=this.currentTime?x(this.currentTime,"24h"):"00:00";if("iana"===this.outputFormat){let i=`${e} ${t}`;return this.timezone&&this.currentTimezone&&(i+=` ${this.currentTimezone}`),i}let i=`${e}T${t}:00`;if(this.timezone&&this.currentTimezone){const e=new Date(this.currentDate.y,this.currentDate.m-1,this.currentDate.d,this.currentTime?.hours||0,this.currentTime?.minutes||0),t=F(this.currentTimezone,e);t&&(i+=t)}return i}_displayText(){if(!this.currentDate)return"";let e=`${b(this.currentDate,this.displayFormat)} ${this.currentTime?x(this.currentTime,this.timeFormat):"12h"===this.timeFormat?"12:00 AM":"00:00"}`;return this.timezone&&this.currentTimezone&&(e+=` ${this.currentTimezone}`),e}getValue(){if(!this.currentDate)return"object"===this.outputFormat?null:"";if("object"===this.outputFormat){const e={date:u(this.currentDate),time:this.currentTime?x(this.currentTime,"24h"):"00:00"};return this.timezone&&(e.timezone=this.currentTimezone||null),e}return this._serialize()}setValue(e){const t=this._parseInitial(e);this.currentDate=t.date,this.currentTime=t.time,t.timezone&&(this.currentTimezone=t.timezone),this._calendar&&this.currentDate&&this._calendar.setValue(u(this.currentDate)),this._timePicker&&this._timePicker.setValue(this._timePickerValue()),this._syncOutputs()}getFormattedValue(){return this._displayText()}clear(){const e=this._serialize();this.currentDate=null,this.currentTime=null,this._calendar&&this._calendar.setValue(null),this._timePicker&&this._timePicker.clear(),this._syncOutputs(e)}setMin(e){this.min=e,this._calendar&&this._calendar.setMin(this._dateBound(e))}setMax(e){this.max=e,this._calendar&&this._calendar.setMax(this._dateBound(e))}setEnabled(e){this.disabled=!e;const t=this.element.querySelector("[data-trigger]");t&&(t.disabled=!e),!e&&this._popover&&this._popover.isOpen()&&this._popover.close()}setReadonly(e){this.readonly=e,e&&this._popover&&this._popover.isOpen()&&this._popover.close()}focus(){const e=this.element.querySelector("[data-trigger]");e&&e.focus()}show(){const e=this.element.querySelector("[data-trigger]");e&&this._togglePopover(e)}hide(){this._popover&&this._popover.close()}getFormValue(){return this.getValue()}async setFormValue(e){this.setValue(e)}hasError(){return!1}_inputId(){return this.name?`mojo-datetime-${this.name}-${this.id}`:`mojo-datetime-${this.id}`}_attr(e){return null==e?"":String(e).replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}async onBeforeDestroy(){if(this._popover){try{this._popover.destroy()}catch(e){}this._popover=null}if(this._timePicker){try{await this._timePicker.destroy()}catch(e){}this._timePicker=null}if(this._tzSelect){try{await this._tzSelect.destroy()}catch(e){}this._tzSelect=null}this._calendar=null,this._popoverContent=null,await super.onBeforeDestroy()}static create(e={}){return new DateTimePicker(e)}}function P(){try{return(new Intl.DateTimeFormat).resolvedOptions().timeZone||"UTC"}catch(e){return"UTC"}}class ComboInput extends e.View{constructor(e={}){const{name:t,value:i="",placeholder:s="Select or type...",options:n=[],allowCustom:a=!0,showDescription:l=!0,minChars:r=0,maxSuggestions:o=10,disabled:d=!1,readonly:c=!1,required:h=!1,class:u="",inputClass:p="form-control",onSelect:m=null,onChange:g=null,...b}=e;super({tagName:"div",className:`combo-input ${u}`,...b}),this.name=t,this.placeholder=s,this.options=this.normalizeOptions(n),this.allowCustom=a,this.showDescription=l,this.minChars=r,this.maxSuggestions=o,this.disabled=d,this.readonly=c,this.required=h,this.inputClass=p,this.onSelectCallback=m,this.onChangeCallback=g,this.currentValue=i,this.inputValue=this.getDisplayValue(i),this.filteredOptions=[],this.highlightedIndex=-1,this.isOpen=!1,this.selectedOption=this.findOptionByValue(i)}normalizeOptions(e){return Array.isArray(e)?e.map(e=>"string"==typeof e?{value:e,label:e}:"object"==typeof e&&void 0!==e.value?{value:e.value,label:e.label||String(e.value),description:e.description||e.label||"",meta:e.meta||{}}:null).filter(e=>null!==e):[]}findOptionByValue(e){return this.options.find(t=>t.value===e)||null}getDisplayValue(e){const t=this.findOptionByValue(e);return t?t.label:e}async renderTemplate(){return`\n <div class="combo-input-container position-relative">\n <div class="input-wrapper position-relative">\n ${this.renderInput()}\n ${this.renderDropdownToggle()}\n </div>\n ${this.renderHiddenInput()}\n ${this.renderDropdown()}\n </div>\n `}renderInput(){return`\n <input type="text"\n class="${this.inputClass} combo-input-field"\n placeholder="${this.escapeHtml(this.placeholder)}"\n value="${this.escapeHtml(this.inputValue)}"\n ${this.disabled?"disabled":""}\n ${this.readonly?"readonly":""}\n ${this.required?"required":""}\n data-change-action="input-change"\n data-action="input-keydown"\n autocomplete="off"\n role="combobox"\n aria-expanded="${this.isOpen}"\n aria-autocomplete="list"\n aria-controls="combo-dropdown-${this.cid}">\n `}renderDropdownToggle(){return this.readonly||this.disabled?"":'\n <button type="button"\n class="btn btn-sm combo-toggle position-absolute top-50 end-0 translate-middle-y border-0"\n data-action="toggle-dropdown"\n tabindex="-1"\n aria-label="Toggle dropdown"\n style="padding: 0.25rem 0.5rem;">\n <i class="bi bi-chevron-down"></i>\n </button>\n '}renderHiddenInput(){return this.name?`\n <input type="hidden"\n name="${this.name}"\n value="${this.escapeHtml(this.currentValue)}"\n class="combo-input-hidden">\n `:""}renderDropdown(){return`\n <div id="combo-dropdown-${this.cid}"\n class="combo-dropdown dropdown-menu position-absolute w-100 ${this.isOpen?"show":""}"\n role="listbox"\n style="max-height: 300px; overflow-y: auto; z-index: 1050;">\n ${this.renderDropdownContent()}\n </div>\n `}renderDropdownContent(){return 0===this.filteredOptions.length?this.renderNoResults():this.filteredOptions.slice(0,this.maxSuggestions).map((e,t)=>this.renderOption(e,t)).join("")}renderOption(e,t){const i=t===this.highlightedIndex,s=e.value===this.currentValue;return`\n <div class="dropdown-item combo-option ${i?"active":""} ${s?"selected":""}"\n data-action="select-option"\n data-option-index="${t}"\n role="option"\n aria-selected="${s}"\n style="cursor: pointer;">\n <div class="d-flex justify-content-between align-items-start">\n <div class="flex-grow-1">\n <div class="combo-option-label fw-semibold">${this.highlightMatch(e.label)}</div>\n ${this.showDescription&&e.description?`\n <div class="combo-option-description small text-muted">${this.escapeHtml(e.description)}</div>\n `:""}\n </div>\n ${s?'<i class="bi bi-check text-primary ms-2"></i>':""}\n </div>\n </div>\n `}renderNoResults(){return this.allowCustom&&this.inputValue.length>=this.minChars?`\n <div class="dropdown-item-text text-muted small">\n <i class="bi bi-info-circle me-1"></i>\n ${this.inputValue?"No matches found. Press Enter to use custom value.":"Start typing to see suggestions..."}\n </div>\n `:'\n <div class="dropdown-item-text text-muted small">\n <i class="bi bi-search me-1"></i>\n No matching options found.\n </div>\n '}highlightMatch(e){if(!this.inputValue)return this.escapeHtml(e);const t=this.escapeHtml(e),i=new RegExp(`(${this.escapeRegex(this.inputValue)})`,"gi");return t.replace(i,'<mark class="bg-warning bg-opacity-25">$1</mark>')}async onAfterRender(){await super.onAfterRender(),this.updateFilteredOptions(),this.handleOutsideClick=e=>{this.element&&!this.element.contains(e.target)&&this.closeDropdown()},document.addEventListener("click",this.handleOutsideClick)}async onChangeInputChange(e,t){this.inputValue=t.value,this.updateFilteredOptions(),this.inputValue.length>=this.minChars?this.openDropdown():this.closeDropdown(),this.highlightedIndex=-1,await this.updateDropdownDisplay()}async onActionInputKeydown(e,t){switch(e.key){case"ArrowDown":e.preventDefault(),this.isOpen?this.highlightNext():this.openDropdown(),await this.updateDropdownDisplay();break;case"ArrowUp":e.preventDefault(),this.isOpen&&(this.highlightPrevious(),await this.updateDropdownDisplay());break;case"Enter":e.preventDefault(),this.isOpen&&this.highlightedIndex>=0?await this.selectHighlightedOption():this.allowCustom&&this.inputValue&&await this.selectCustomValue(this.inputValue);break;case"Escape":e.preventDefault(),this.closeDropdown();const t=this.element.querySelector(".combo-input-field");t&&(t.value=this.getDisplayValue(this.currentValue),this.inputValue=t.value);break;case"Tab":this.isOpen&&this.closeDropdown()}}async onActionToggleDropdown(e,t){if(e.preventDefault(),e.stopPropagation(),this.isOpen)this.closeDropdown();else{this.inputValue="";const e=this.element.querySelector(".combo-input-field");e&&(e.value="",e.focus()),this.updateFilteredOptions(),this.openDropdown(),await this.updateDropdownDisplay()}}async onActionSelectOption(e,t){e.preventDefault(),e.stopPropagation();const i=parseInt(t.getAttribute("data-option-index"));i>=0&&i<this.filteredOptions.length&&await this.selectOption(this.filteredOptions[i])}openDropdown(){this.isOpen=!0;const e=this.element?.querySelector(".combo-dropdown");e&&e.classList.add("show");const t=this.element?.querySelector(".combo-input-field");t&&t.setAttribute("aria-expanded","true")}closeDropdown(){this.isOpen=!1,this.highlightedIndex=-1;const e=this.element?.querySelector(".combo-dropdown");e&&e.classList.remove("show");const t=this.element?.querySelector(".combo-input-field");t&&t.setAttribute("aria-expanded","false")}updateFilteredOptions(){const e=this.inputValue.toLowerCase().trim();e?(this.filteredOptions=this.options.filter(t=>{const i=t.label.toLowerCase().includes(e),s=String(t.value).toLowerCase().includes(e),n=t.description?.toLowerCase().includes(e);return i||s||n}),this.filteredOptions.sort((t,i)=>{const s=t.label.toLowerCase()===e,n=i.label.toLowerCase()===e;if(s&&!n)return-1;if(!s&&n)return 1;const a=t.label.toLowerCase().startsWith(e),l=i.label.toLowerCase().startsWith(e);return a&&!l?-1:!a&&l?1:0})):this.filteredOptions=[...this.options]}async updateDropdownDisplay(){const e=this.element?.querySelector(".combo-dropdown");if(e&&(e.innerHTML=this.renderDropdownContent(),this.highlightedIndex>=0)){const t=e.querySelector(".combo-option.active");t&&t.scrollIntoView({block:"nearest"})}}highlightNext(){0!==this.filteredOptions.length&&(this.highlightedIndex=(this.highlightedIndex+1)%Math.min(this.filteredOptions.length,this.maxSuggestions))}highlightPrevious(){0!==this.filteredOptions.length&&(this.highlightedIndex=this.highlightedIndex<=0?Math.min(this.filteredOptions.length,this.maxSuggestions)-1:this.highlightedIndex-1)}async selectHighlightedOption(){this.highlightedIndex>=0&&this.highlightedIndex<this.filteredOptions.length&&await this.selectOption(this.filteredOptions[this.highlightedIndex])}async selectOption(e){this.currentValue=e.value,this.inputValue=e.label,this.selectedOption=e;const t=this.element?.querySelector(".combo-input-field");t&&(t.value=e.label);const i=this.element?.querySelector(".combo-input-hidden");i&&(i.value=e.value),this.closeDropdown(),this.emit("select",{option:e,value:e.value,meta:e.meta}),this.emit("change",{value:e.value,option:e,meta:e.meta}),"function"==typeof this.onSelectCallback&&this.onSelectCallback(e),"function"==typeof this.onChangeCallback&&this.onChangeCallback(e.value)}async selectCustomValue(e){if(!this.allowCustom)return;this.currentValue=e,this.inputValue=e,this.selectedOption=null;const t=this.element?.querySelector(".combo-input-hidden");t&&(t.value=e),this.closeDropdown(),this.emit("custom",{value:e}),this.emit("change",{value:e,custom:!0}),"function"==typeof this.onChangeCallback&&this.onChangeCallback(e)}getValue(){return this.currentValue}async setValue(e){this.currentValue=e,this.selectedOption=this.findOptionByValue(e),this.inputValue=this.getDisplayValue(e);const t=this.element?.querySelector(".combo-input-field");t&&(t.value=this.inputValue);const i=this.element?.querySelector(".combo-input-hidden");i&&(i.value=e),this.updateFilteredOptions()}getSelectedOption(){return this.selectedOption}async setOptions(e){this.options=this.normalizeOptions(e),this.updateFilteredOptions(),this.isOpen&&await this.updateDropdownDisplay()}setEnabled(e){this.disabled=!e;const t=this.element?.querySelector(".combo-input-field");t&&(t.disabled=this.disabled);const i=this.element?.querySelector(".combo-toggle");i&&(i.disabled=this.disabled)}setReadonly(e){this.readonly=e;const t=this.element?.querySelector(".combo-input-field");t&&(e?t.setAttribute("readonly",""):t.removeAttribute("readonly"))}focus(){const e=this.element?.querySelector(".combo-input-field");e&&e.focus()}async clear(){await this.setValue(""),this.inputValue="";const e=this.element?.querySelector(".combo-input-field");e&&(e.value=""),this.emit("clear")}getFormValue(){return this.allowCustom&&this.inputValue&&this.inputValue!==this.getDisplayValue(this.currentValue)?this.inputValue:this.currentValue}async setFormValue(e){await this.setValue(e)}escapeHtml(e){if(null==e)return"";const t=document.createElement("div");return t.textContent=String(e),t.innerHTML}escapeRegex(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}async onBeforeDestroy(){this.handleOutsideClick&&document.removeEventListener("click",this.handleOutsideClick),await super.onBeforeDestroy()}static create(e={}){return new ComboInput(e)}}class FormView extends e.View{constructor(e={}){const{formConfig:t=e.config,fields:s,model:n=null,data:a={},defaults:l=null,errors:r={},fileHandling:o="base64",autosaveModelField:d=!1,...c}=e;super({tagName:"div",className:"form-view",enableTooltips:!0,...c}),i.FormPlugins.onFormViewInit?.(this),this.model=n,this.defaults=l||a,this._originalData=a,this.errors=r,this.loading=!1,this.fileHandling=o,this.autosaveModelField=d,this.customComponents=/* @__PURE__ */new Map,this.fieldStatusManagers=/* @__PURE__ */new Map,this.saveTimeouts=/* @__PURE__ */new Map,this.pendingSaveFields=/* @__PURE__ */new Map,this.batchSaveTimeout=null,this.isSaving=!1,this.data=this.prepareFormData(),this.formConfig=t||{fields:s||[]},this.formBuilder=new FormBuilder({...this.getFormConfig(),data:this.data,errors:r})}prepareFormData(){const e={...this.defaults};if(this.model)if(this.model.attributes&&"object"==typeof this.model.attributes)Object.assign(e,this.model.attributes);else if("function"==typeof this.model.toJSON){const t=this.model.toJSON();Object.assign(e,t)}else"object"==typeof this.model&&this.model.constructor===Object&&Object.assign(e,this.model);return this._originalData&&Object.assign(e,this._originalData),e}getFormConfig(){const e={...this.formConfig},t=this.getApp();return this.formConfig.fields&&Array.isArray(this.formConfig.fields)?e.fields=this.formConfig.fields.filter(e=>!e.permissions||t.activeUser?.hasPermission(e.permissions)):e.fields=[],e}async renderTemplate(){return this.formBuilder.buildFormHTML()}async onAfterRender(){await super.onAfterRender(),this.data=this.prepareFormData(),this.populateFormValues(),this.initializeFormComponents(),this.initializeChangeHandlers();const e=this.getFormElement();e&&e.addEventListener("submit",e=>(e.preventDefault(),!1)),this._initShowWhen(),i.FormPlugins.onFormViewAfterRender?.(this)}populateFormValues(){if(this.element&&this.formConfig?.fields){this._isPopulating=!0;try{this.formConfig.fields.forEach(e=>{this.populateFieldRecursive(e)})}finally{this._isPopulating=!1}}}populateFieldRecursive(e){"group"===e.type&&e.fields?e.fields.forEach(e=>{this.populateFieldRecursive(e)}):"tabset"===e.type&&e.tabs?e.tabs.forEach(e=>{e.fields&&Array.isArray(e.fields)&&e.fields.forEach(e=>{this.populateFieldRecursive(e)})}):this.populateFieldValue(e)}populateFieldValue(e){if(!e.name||!this.element)return;const i=this.element.querySelector(`[name="${e.name}"]`);if(!i)return;const s=t.MOJOUtils.getContextData(this.data,e.name);null!=s&&this.setFieldValue(i,e,s)}initializeFormComponents(){this.initializeImageFields(),this.initializeCustomComponents(),this.initializeTagInputs(),this.initializeMultiSelectDropdowns(),this.initializeComboBoxes(),this.initializeCollectionSelects(),this.initializeCollectionMultiSelects(),this.initializeDatePickers(),this.initializeDateRangePickers(),this.initializeTimePickers(),this.initializeDateTimePickers(),this.initializePasswordFields()}initializeImageFields(){this.element.querySelectorAll(".image-drop-zone.droppable").length>0&&this.enableFileDrop({acceptedTypes:["image/*"],maxFileSize:10485760,multiple:!1,dropZoneSelector:".image-drop-zone.droppable",visualFeedback:!0,dragOverClass:"drag-over",dragActiveClass:"drag-active"})}initializeCustomComponents(){this.initializeTagInputs(),this.initializeCollectionSelects(),this.initializeCollectionMultiSelects(),this.initializeDatePickers(),this.initializeDateRangePickers(),this.initializeTimePickers(),this.initializeDateTimePickers(),this.initializeComboInputs();try{const e=(t=[])=>{t.forEach(t=>{if(t&&"group"===t.type&&Array.isArray(t.fields))e(t.fields);else if(t&&t.name){const e=this.element.querySelector(`[name="${t.name}"], #${t.id||t.name}`);e&&i.FormPlugins.onFieldInit?.(this,e,t)}})};e(this.formConfig?.fields||[])}catch(e){console.warn("FormPlugins.onFieldInit error:",e)}this.element.querySelectorAll("[data-component]").forEach(e=>{e.getAttribute("data-component"),e.getAttribute("data-field")})}initializeChangeHandlers(){if(!this.element)return;const e=this.element.querySelectorAll("input:not([data-action]), select:not([data-action]), textarea:not([data-action])");e.length,e.forEach(e=>{e.type,e.name,e.getAttribute("data-change-action"),e.hasAttribute("data-component")||e.hasAttribute("data-change-action")||e.classList.contains("form-check-input")||(e.addEventListener("change",t=>{if(this._isPopulating)return;const i=e.name;if(i){let s=e.value;if("checkbox"===e.type)s=e.checked;else if("radio"===e.type){if(!e.checked)return}else if(e.multiple&&e.selectedOptions)s=Array.from(e.selectedOptions).map(e=>e.value);else if("file"===e.type){const i=e.getAttribute("data-change-action");if("image-selected"===i)return void this.onChangeImageSelected(t,e);if("file-selected"===i)return void this.onChangeFileSelected(t,e)}this.handleFieldChange(i,s)}}),"text"!==e.type&&"email"!==e.type&&"url"!==e.type&&"TEXTAREA"!==e.tagName||e.addEventListener("input",t=>{if(this._isPopulating)return;const i=e.name;i&&this.handleFieldChange(i,e.value)}))})}initializeTagInputs(){this.element.querySelectorAll('[data-field-type="tag"]').forEach(e=>{try{const t=e.getAttribute("data-field-name"),i=e.getAttribute("data-field-config"),s=JSON.parse(i),n=new TagInputView({...s,containerId:null});n.render(!0,e),this.customComponents.set(t,n),n.on("change",e=>{this.handleFieldChange(t,e.value)})}catch(t){}})}initializeMultiSelectDropdowns(){this.element.querySelectorAll('[data-field-type="multiselect"]').forEach(e=>{try{const i=e.getAttribute("data-field-name"),s=e.getAttribute("data-field-config"),n=JSON.parse(s),a=this.getFormFieldConfig(i);if(!a)return;const l=new MultiSelectDropdown({...n,options:a.options||[],placeholder:a.placeholder||n.placeholder||"Select...",label:a.label,containerId:null});let r=n.value??t.MOJOUtils.getContextData(this.data,i);r&&l.setFormValue(r),l.render(!0,e),this.customComponents.set(i,l),l.on("change",e=>{this.handleFieldChange(i,e.value)})}catch(i){console.error("MultiSelectDropdown initialization failed:",i)}})}initializeComboBoxes(){this.element.querySelectorAll('[data-field-type="combobox"]').forEach(e=>{try{const i=e.getAttribute("data-field-name"),s=e.getAttribute("data-field-config"),n=JSON.parse(s),a=this.getFormFieldConfig(i);if(!a)return;const l=new ComboBox({...n,options:a.options||[],placeholder:a.placeholder||n.placeholder||"Type or select...",containerId:null});let r=n.value??t.MOJOUtils.getContextData(this.data,i);r&&l.setFormValue(r),l.render(!0,e),this.customComponents.set(i,l),l.on("change",e=>{this.handleFieldChange(i,e.value)})}catch(i){console.error("ComboBox initialization failed:",i)}})}initializeCollectionSelects(){this.element.querySelectorAll('[data-field-type="collection"]').forEach(e=>{try{const i=e.getAttribute("data-field-name"),s=e.getAttribute("data-field-config"),n=JSON.parse(s),a=this.getFormFieldConfig(i);if(!a||!a.Collection)return;const l=new a.Collection;a.collectionParams&&(l.params={...l.params,...a.collectionParams});const r=new CollectionSelectView({...n,collection:l,defaultParams:a.defaultParams||null,containerId:null});let o=t.MOJOUtils.getContextData(this.data,i);o&&r.setFormValue(o),r.render(!0,e),this.customComponents.set(i,r),r.on("change",e=>{this.handleFieldChange(i,e.value)})}catch(i){}})}initializeCollectionMultiSelects(){this.element.querySelectorAll('[data-field-type="collectionmultiselect"]').forEach(e=>{try{const i=e.getAttribute("data-field-name"),s=e.getAttribute("data-field-config"),n=JSON.parse(s),a=this.getFormFieldConfig(i);if(!a||!a.Collection)return;const l=new a.Collection;a.collectionParams&&(l.params={...l.params,...a.collectionParams});const r=new CollectionMultiSelectView({...n,collection:l,defaultParams:a.defaultParams||null,itemTemplate:a.itemTemplate||null,containerId:null});let o=t.MOJOUtils.getContextData(this.data,i);o&&r.setFormValue(o),r.render(!0,e),this.customComponents.set(i,r),r.on("change",e=>{this.handleFieldChange(i,e.value)})}catch(i){console.error("CollectionMultiSelect initialization failed:",i)}})}initializeDatePickers(){this.element.querySelectorAll('[data-field-type="datepicker"]').forEach(e=>{try{const t=e.getAttribute("data-field-name"),i=e.getAttribute("data-field-config"),s=JSON.parse(i),n=new DatePicker({...s,containerId:null});n.render(!0,e),this.customComponents.set(t,n),n.on("change",e=>{this.handleFieldChange(t,e.value)})}catch(t){}})}initializeDateRangePickers(){this.element.querySelectorAll('[data-field-type="daterange"]').forEach(e=>{try{const t=e.getAttribute("data-field-name"),i=e.getAttribute("data-field-config"),s=JSON.parse(i),n=new DateRangePicker({...s,containerId:null});n.render(!0,e),this.customComponents.set(t,n),n.on("change",e=>{this.handleFieldChange(t,e.combined)})}catch(t){}})}initializeTimePickers(){this.element.querySelectorAll('[data-field-type="timepicker"]').forEach(e=>{try{const t=e.getAttribute("data-field-name"),i=e.getAttribute("data-field-config"),s=JSON.parse(i),n=new TimePicker({...s,containerId:null});n.render(!0,e),this.customComponents.set(t,n),n.on("change",e=>{this.handleFieldChange(t,e.value)})}catch(t){}})}initializeDateTimePickers(){this.element.querySelectorAll('[data-field-type="datetimepicker"]').forEach(e=>{try{const t=e.getAttribute("data-field-name"),i=e.getAttribute("data-field-config"),s=JSON.parse(i),n=new DateTimePicker({...s,containerId:null});n.render(!0,e),this.customComponents.set(t,n),n.on("change",e=>{this.handleFieldChange(t,e.value)})}catch(t){}})}initializeComboInputs(){this.element.querySelectorAll('[data-field-type="combo"]').forEach(e=>{try{const i=e.getAttribute("data-field-name"),s=e.getAttribute("data-field-config"),n=JSON.parse(s),a=new ComboInput({...n,containerId:null});let l=t.MOJOUtils.getContextData(this.data,i);l&&a.setValue(l),a.render(!0,e),this.customComponents.set(i,a),a.on("change",e=>{this.handleFieldChange(i,e.value)}),a.on("select",e=>{this.emit("field:select",{field:i,value:e.value,option:e.option,meta:e.meta})})}catch(i){console.error("ComboInput initialization failed:",i)}})}handleFieldChange(e,t){this._isPopulating||(this.data[e]=t,this.autosaveModelField&&this.model?this.handleFieldSave(e,t):this.model&&this.options.allowModelChange&&(this._isFormDrivenChange=!0,this.model.set(e,t)),this.emit("field:change",{field:e,value:t}),this._updateShowWhen(e,t),i.FormPlugins.onFieldChange?.(this,e,t))}_initShowWhen(){this._showWhenMap={},this.element&&this.element.querySelectorAll("[data-show-when-field]").forEach(e=>{const t=e.getAttribute("data-show-when-field");this._showWhenMap[t]||(this._showWhenMap[t]=[]),this._showWhenMap[t].push(e),"none"===e.style.display?e.querySelectorAll("input, select, textarea").forEach(e=>{e.required&&(e.dataset.wasRequired="true",e.required=!1)}):e.querySelectorAll("input, select, textarea").forEach(e=>{e.required&&(e.dataset.wasRequired="true")})})}_updateShowWhen(e,t){const i=this._showWhenMap?.[e];if(!i)return;const s=String(t??"");i.forEach(e=>{const t=e.getAttribute("data-show-when-value").split(","),i="true"===e.getAttribute("data-show-when-negate"),n=t.includes(s),a=i?!n:n;e.style.display=a?"":"none",e.querySelectorAll("input, select, textarea").forEach(e=>{a?"true"===e.dataset.wasRequired&&(e.required=!0):(e.required&&(e.dataset.wasRequired="true"),e.required=!1)})})}async handleFieldSave(e,t){this.model&&(this.pendingSaveFields.set(e,t),this.getFieldStatusManager(e).showStatus("saving"),this.batchSaveTimeout&&clearTimeout(this.batchSaveTimeout),this.batchSaveTimeout=setTimeout(async()=>{await this.executeBatchSave()},300))}async executeBatchSave(){if(this.isSaving||0===this.pendingSaveFields.size)return;const e=Object.fromEntries(this.pendingSaveFields),t=Array.from(this.pendingSaveFields.keys());try{if(this.isSaving=!0,this.pendingSaveFields.clear(),this.batchSaveTimeout=null,this._isFormDrivenChange=!0,"function"==typeof this.model.save){const i=await this.model.save(e);if(!i||!i.success||i.data&&!i.data.status){const e=i?.data?.error||i?.error||i?.message||"Save failed";return this.getApp()?.toast?.error(e),this.revertFields(t),void t.forEach(t=>{this.getFieldStatusManager(t).showStatus("error",{message:e})})}}else Object.entries(e).forEach(([e,t])=>{this.model.set(e,t)});t.forEach(e=>{this.getFieldStatusManager(e).showStatus("saved")})}catch(i){console.error("Batch save error:",i),this.getApp()?.toast?.error(i.message||"An error occurred while saving"),this.revertFields(t),t.forEach(e=>{this.getFieldStatusManager(e).showStatus("error",{message:i.message})})}finally{this.isSaving=!1}}revertFields(e){if(!this.model)return;const t=this._isPopulating;this._isPopulating=!0;try{e.forEach(e=>{const t=this.model.get(e);this.data[e]=t;const i=this.element?.querySelector(`[name="${e}"]`);if(i){const s=this.getFormFieldConfig(e);s?this.setFieldValue(i,s,t):"checkbox"===i.type?i.checked=Boolean(t):i.value=t??""}})}finally{this._isPopulating=t}}getFieldStatusManager(e){if(!this.fieldStatusManagers.has(e)){const t=this.element.querySelector(`[name="${e}"]`);if(t){const i=new FieldStatusManager(t);this.fieldStatusManagers.set(e,i)}}return this.fieldStatusManagers.get(e)}refreshForm(){this.data=this.prepareFormData(),this.element&&this.populateFormValues()}getChangeReason(e,t){if(e instanceof File)return 0===e.size||""===e.name||"blob"===e.name?"empty file, no change":`file upload: ${e.name}, ${e.size} bytes`;if("string"==typeof e&&e.startsWith("data:image/"))return"base64 image upload";if("boolean"==typeof e||"boolean"==typeof t){const i=Boolean(e);return`boolean: ${null!=t&&Boolean(t)} → ${i}`}return null!=e&&String(e).trim(),null!=t&&String(t).trim(),null==t?"was null/undefined, now has value":null==e?"was value, now null/undefined":"text content changed"}setFormData(e){this._originalData={...this._originalData,...e},this.refreshForm()}async onActionSubmitForm(e,t){e.preventDefault();const i=await this.handleSubmit();i.success?(this.data=i.data,this.emit("submit",{data:i.data,result:i.result,form:this,event:e}),!this.model&&this.formConfig.onSubmit&&"function"==typeof this.formConfig.onSubmit&&await this.formConfig.onSubmit(i.data,this)):this.emit("error",{error:i.error,result:i,form:this})}async onActionResetForm(e,t){const i=this.getFormElement();i&&(i.reset(),this.data={},this.clearAllErrors(),this.emit("reset",{form:this,event:e}))}async onActionClickImageUpload(e,t){const i=t.getAttribute("data-field-id");if(!i)return void console.error("FormView: No fieldId attribute found");const s=this.element.querySelector(`#${i}`);s&&!s.disabled?s.click():s||console.error("FormView: fileInput not found for fieldId:",i)}async onActionRemoveImage(e,t){const i=t.getAttribute("data-field");if(!i)return;const s=this.element.querySelector(`input[name="${i}"]`);s&&(s.value="",s.dispatchEvent(new Event("change",{bubbles:!0}))),delete this.data[i],this.emit("change",{field:i,value:null,form:this}),await this.updateField(i)}async onActionClearColor(e,t){const i=t.getAttribute("data-field");if(!i)return;const s=this.element.querySelector(`input[name="${i}"]`);s&&(s.value="",this.handleFieldChange(i,""),await this.updateField(i))}async onActionPreviewHtml(e,t){e.preventDefault();const i=t.getAttribute("data-target");if(!i)return;const s=this.element.querySelector(`#${i}`);if(!s)return;const n=s.value||"";(await Promise.resolve().then(()=>require("./Modal-BRKy85bz.js")).then(e=>e.Modal$1)).default.htmlPreview({html:n,title:"HTML Preview"})}async onActionSelectButtonOption(e,t){const i=t.getAttribute("data-field"),s=t.getAttribute("data-value");if(!i||!s)return;this.data[i]=s;const n=t.closest(".btn-group");n&&(n.querySelectorAll("button").forEach(e=>{e.classList.remove("active"),e.classList.add("btn-outline-primary"),e.classList.remove("btn-primary")}),t.classList.add("active"),t.classList.remove("btn-outline-primary"),t.classList.add("btn-primary")),this.emit("field:changed",{field:i,value:s,form:this}),this.emit("change",{field:i,value:s,form:this}),this.emit("form:changed",await this.getFormData())}async onActionApplyFilter(e,t){const i=t.closest(".dropdown"),s=i?.querySelectorAll('input[type="checkbox"]');if(!s||0===s.length)return;const n=s[0].getAttribute("data-field");if(!n)return;const a=[];s.forEach(e=>{e.checked&&a.push(e.value)}),this.data[n]=a;const l=i.querySelector('[data-bs-toggle="dropdown"]');if(l&&window.bootstrap?.Dropdown){const e=window.bootstrap.Dropdown.getInstance(l);e?.hide()}this.emit("field:changed",{field:n,value:a,form:this}),this.emit("change",{field:n,value:a,form:this}),this.emit("form:changed",await this.getFormData())}async onChangeValidateField(e,t){const i=t.name;if(i){const e=t.value;this.handleFieldChange(i,e),this.validateField(i)}}async onChangeToggleSwitch(e,t){const i=t.getAttribute("data-field");if(i){const e=t.checked;this.handleFieldChange(i,e),this.emit("switch:toggle",{field:i,checked:e,form:this})}}async onChangeImageSelected(e,t){t.files;const i=t.getAttribute("data-field"),s=t.files[0];if(i&&s){const e=this.findFieldConfig(i),a=URL.createObjectURL(s);if(e&&e.imageSize){e.imageSize;try{const n=window.MOJO?.plugins?.ImageCropView;if(!n)return this.data[i]=s,await this.updateImagePreview(i,a),void this.emit("image:selected",{field:i,file:s,form:this});const l=await n.showDialog(a,{title:`Crop ${e.label||i}`,cropAndScale:e.imageSize,size:"lg"});if("crop"===l.action&&l.data){const e=await fetch(l.data),t=await e.blob(),n=new File([t],s.name,{type:s.type||"image/png"});this.data[i]=n,await this.updateImagePreview(i,l.data),this.emit("image:selected",{field:i,file:n,originalFile:s,cropped:!0,cropData:l.cropData,form:this}),this.emit("change",{field:i,value:n,form:this})}else t.value=""}catch(n){console.error("FormView: Error during image cropping:",n),this.data[i]=s,await this.updateImagePreview(i,a),this.emit("image:selected",{field:i,file:s,form:this}),this.emit("change",{field:i,value:s,form:this})}}else this.data[i]=s,await this.updateImagePreview(i,a),this.emit("image:selected",{field:i,file:s,form:this})}}async onChangeFileSelected(e,t){const i=Array.from(t.files);t.multiple?this.data[t.name]=t.files:this.data[t.name]=i[0]||null,this.emit("file:selected",{field:t.name,files:i,form:this}),this.emit("change",{field:t.name,value:i,form:this})}async onChangeRangeChanged(e,t){const i=t.name,s=t.value,n=t.getAttribute("data-target");if(n){const e=this.element.querySelector(`#${n}`);e&&(e.textContent=s)}i&&this.handleFieldChange(i,s),this.emit("range:changed",{field:i,value:s,form:this})}async onChangeFilterSearch(e,t){const i=t.value;this.emit("search",{query:i,field:t.name,form:this})}async onChangeFilterSelectOptions(e,t){const i=t.value.toLowerCase(),s=t.getAttribute("data-target"),n=s?this.element.querySelector(`#${s}`):null;n&&n.querySelectorAll("option").forEach(e=>{const t=e.textContent.toLowerCase();e.style.display=t.includes(i)?"":"none"})}async onFileDrop(e,t,i){const s=t.target.closest(".image-drop-zone");if(!s)return;const n=s.getAttribute("data-field");if(!n)return;const a=e[0],l=this.element.querySelector(`input[name="${n}"]`);if(l){const e=new DataTransfer;e.items.add(a),l.files=e.files,l.dispatchEvent(new Event("change",{bubbles:!0}))}this.data[n]=a;const r=URL.createObjectURL(a);await this.updateImagePreview(n,r),this.emit("image:dropped",{field:n,file:a,form:this})}async onFileDropError(e,t,i){this.showError(`File upload error: ${e.message}`),this.emit("file:error",{error:e,files:i,form:this})}getFormElement(){return this.element?this.element.querySelector("form"):null}getFormFieldConfig(e){const t=i=>{for(const s of i){if(s.name===e)return s;if(s.fields&&Array.isArray(s.fields)){const e=t(s.fields);if(e)return e}}return null};return t(this.formConfig.fields||[])}async getFormData(){const e=this.getFormElement();if(!e)return"multipart"===this.fileHandling?new FormData:{};if("multipart"===this.fileHandling){const t=new FormData(e);for(const[e,i]of Object.entries(this.data))if(i instanceof File)t.set(e,i);else if(i instanceof FileList)for(let s=0;s<i.length;s++)t.append(`${e}[${s}]`,i[s]);return t}{const i=new FormData(e),s={};for(const[e,t]of i.entries())s[e]?(Array.isArray(s[e])||(s[e]=[s[e]]),s[e].push(t)):s[e]=t;e.querySelectorAll('input[type="checkbox"]').forEach(e=>{s[e.name]=e.checked}),e.querySelectorAll('input[type="number"]').forEach(e=>{if(e.name&&void 0!==s[e.name]&&""!==s[e.name]){const t=Number(s[e.name]);isNaN(t)||(s[e.name]=t)}}),this.formConfig.fields?.forEach(e=>{if("select"===e.type&&e.name&&void 0!==s[e.name]){const t=this.getFormFieldConfig(e.name);if(t?.options&&Array.isArray(t.options)&&t.options.every(e=>{const t="object"==typeof e?e.value:e;return""===t||!isNaN(Number(t))})&&""!==s[e.name]){const t=Number(s[e.name]);isNaN(t)||(s[e.name]=t)}}}),e.querySelectorAll('[data-field-type="json"]').forEach(e=>{try{s[e.name]=JSON.parse(e.value)}catch(t){s[e.name]=e.value}}),this.customComponents.forEach((e,t)=>{e.getFormValue?s[t]=e.getFormValue():e.getValue&&(s[t]=e.getValue())}),this.element&&this.element.querySelectorAll("[data-show-when-field]").forEach(e=>{"none"===e.style.display&&e.querySelectorAll("[name]").forEach(e=>{delete s[e.name]})});for(const[e,n]of Object.entries(this.data))if(n instanceof File)try{s[e]=await this.fileToBase64(n)}catch(t){s[e]=null}else if(n instanceof FileList){const i=[];for(let e=0;e<n.length;e++)try{i.push(await this.fileToBase64(n[e]))}catch(t){i.push(null)}s[e]=i}return s}}_onModelChange(){this.isSaving||(this.data=this.prepareFormData(),this.isMounted()&&(this._isFormDrivenChange||this.syncFormWithModel(),this._isFormDrivenChange=!1))}syncFormWithModel(){this.model&&this.element&&(this.formDataMatchesModelData(this.data)||this.populateFormValues())}formDataMatchesModelData(e){if(!this.formConfig?.fields||!this.element)return!0;for(const t of this.formConfig.fields)if("group"===t.type&&t.fields){for(const i of t.fields)if(!this.fieldValueMatchesModel(i,e))return!1}else if(!this.fieldValueMatchesModel(t,e))return!1;return!0}fieldValueMatchesModel(e,i){if(!e.name)return!0;const s=this.element.querySelector(`[name="${e.name}"]`);if(!s)return!0;const n=this.getFieldCurrentValue(s,e),a=t.MOJOUtils.getContextData(i,e.name);return!1===this.valuesAreDifferent(n,a)}getFieldCurrentValue(e,t){switch(t.type){case"checkbox":case"toggle":case"switch":return e.checked;case"radio":const s=this.element.querySelector(`[name="${t.name}"]:checked`);return s?s.value:"";case"select":return e.multiple?Array.from(e.selectedOptions).map(e=>e.value):e.value;case"file":case"image":return null;case"json":try{return e.value?JSON.parse(e.value):null}catch(i){return e.value}default:return e.value}}setFieldValue(e,t,i){switch(t.type){case"checkbox":case"toggle":case"switch":e.checked=Boolean(i);break;case"radio":const n=this.element.querySelector(`[name="${t.name}"][value="${i}"]`);n&&(n.checked=!0);break;case"select":e.multiple&&Array.isArray(i)?Array.from(e.options).forEach(e=>{e.selected=i.includes(e.value)}):e.value=i??"";break;case"file":case"image":break;case"json":if("object"==typeof i&&null!==i)try{e.value=JSON.stringify(i,null,2)}catch(s){e.value="{}"}else e.value="string"==typeof i?i:String(i||"");break;default:e.value=i||""}e.dispatchEvent(new Event("change",{bubbles:!0}))}setDefaults(e){this.defaults={...this.defaults,...e},this.refreshForm()}async handleSubmit(){try{const e=await this.getFormData();if(!1!==this.formConfig.validateOnSubmit&&!this.validate())return this.focusFirstError(),{success:!1,data:e,error:"Form validation failed"};if(this.model&&"function"==typeof this.model.save){const t=await this.saveModel(e);return t&&!1!==t.success?{success:!0,data:e,result:t}:{success:!1,data:e,result:t,error:t?.message||t?.error||"Save failed. Please try again."}}return e}catch(e){return{success:!1,error:e.message||"An error occurred while submitting the form"}}}async saveModel(e=null){if(!this.model||"function"!=typeof this.model.save)throw new Error("No model available for saving");e||(e=await this.getFormData());const t=this.getChangedData(e);if(!t||0===Object.keys(t).length)return{success:!0,message:"No changes to save",data:e};try{return this._isFormDrivenChange=!0,await this.model.save(t)}catch(i){throw i}}getChangedData(e){if(!this.model)return e;const t=this.getOriginalModelData();let i;return i=e instanceof FormData?this.getChangedFormData(e,t):this.getChangedObjectData(e,t),i}getOriginalModelData(){return this.model.attributes?this.model.attributes:"function"==typeof this.model.toJSON?this.model.toJSON():{}}getChangedFormData(e,t){const i=new FormData;let s=!1;for(const[n,a]of e.entries())if(a instanceof File)0===a.size||""===a.name||"blob"===a.name||(i.set(n,a),s=!0);else{const e=t[n];a!==e&&a!==String(e)&&(i.set(n,a),s=!0)}return s?i:null}getChangedObjectData(e,t){const i={};let s=!1;const n=/* @__PURE__ */new Set([...Object.keys(t),...Object.keys(e)]),a=(e,t)=>t.split(".").reduce((e,t)=>e&&"object"==typeof e?e[t]:void 0,e);for(const l of n){const n=this.findFieldConfig(l);if(!n)continue;const r=e[l],o=a(t,l),d=n.type||"text";this.valuesAreDifferent(r,o,d,n)&&(i[l]=r,s=!0)}return s?i:null}valuesAreDifferent(e,t,i="text",s={}){if(e instanceof File)return e.size>0&&""!==e.name&&"blob"!==e.name;if("string"==typeof e&&e.startsWith("data:image/"))return!0;if("collection"===i&&"object"==typeof t&&null!=t&&"string"==typeof e){if("0"===e)return null!==t;if(t[s.valueField||"id"]==e)return!1}return"switch"===i||"checkbox"===i||"toggle"===i?!!e!=!!t:(null==e?"":String(e).trim())!==(null==t?"":String(t).trim())}validate(){const e=this.getFormElement();if(!e)return!1;const t=e.checkValidity();return t||e.classList.add("was-validated"),t}validateField(e){const t=this.getFormElement();if(!t)return!1;const i=t.elements[e];if(!i)return!1;const s=i.checkValidity();return s?(i.classList.remove("is-invalid"),i.classList.add("is-valid"),delete this.errors[e]):(i.classList.remove("is-valid"),i.classList.add("is-invalid"),this.errors[e]=i.validationMessage),s}focusFirstError(){const e=this.getFormElement();if(!e)return;const t=e.querySelector(":invalid");if(!t)return;const i=t.closest(".tab-pane");if(i&&!i.classList.contains("active")){const t=i.id,s=e.querySelector(`[role="tab"][aria-controls="${t}"], [data-bs-target="#${t}"]`);if(s){const t=window.bootstrap?.Tab?.getOrCreateInstance?window.bootstrap.Tab.getOrCreateInstance(s):null;t&&"function"==typeof t.show?t.show():(e.querySelectorAll('[role="tab"].nav-link').forEach(e=>{const t=e===s;e.classList.toggle("active",t),e.setAttribute("aria-selected",t?"true":"false")}),e.querySelectorAll(".tab-pane").forEach(e=>e.classList.remove("show","active")),i.classList.add("show","active"))}}t.focus(),t.scrollIntoView({behavior:"smooth",block:"center"})}clearAllErrors(){const e=this.getFormElement();e&&(this.errors={},e.classList.remove("was-validated"),e.querySelectorAll(".is-invalid").forEach(e=>e.classList.remove("is-invalid")),e.querySelectorAll(".is-valid").forEach(e=>e.classList.remove("is-valid")))}setLoading(e){this.loading=e;const t=this.getFormElement();if(!t)return;const i=t.querySelectorAll("input, select, textarea, button"),s=t.querySelector('button[type="submit"]');if(e)i.forEach(e=>e.disabled=!0),s&&(s.innerHTML='<span class="spinner-border spinner-border-sm me-2"></span>Loading...');else if(i.forEach(e=>e.disabled=!1),s){const e=this.formConfig.options?.submitButton||"Submit";s.innerHTML="string"==typeof e?e:"Submit"}}showError(e){if(this.emit("error",{message:e,form:this}),this.element){this.element.querySelectorAll(".alert").forEach(e=>e.remove());const t=document.createElement("div");t.className="alert alert-danger alert-dismissible fade show",t.innerHTML=`\n ${e}\n <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>\n `,this.element.insertBefore(t,this.element.firstChild),setTimeout(()=>{t.parentNode&&t.remove()},5e3)}}async updateField(e){this.formBuilder=new FormBuilder({...this.getFormConfig(),data:this.data,errors:this.errors}),await this.render()}async updateImagePreview(e,t){const i=this.element.querySelector(`[data-field="${e}"].image-drop-zone`);if(!i)return;let s=i.querySelector("img");const n=i.querySelector(".bi-image")?.parentElement,a=i.getAttribute("data-field-id");if(t){if(s)s.src=t;else{const s=`${a}_preview`;i.innerHTML=`\n <img id="${s}"\n src="${t}"\n alt="Preview"\n class="img-thumbnail w-100 h-100"\n style="object-fit: cover;">\n <button type="button"\n class="btn btn-sm btn-danger position-absolute top-0 end-0 m-1"\n data-action="remove-image"\n data-field-id="${a}"\n data-field="${e}"\n style="opacity: 0.8;">\n <i class="bi bi-x"></i>\n </button>\n `}n&&(n.style.display="none")}}findFieldConfig(e){const t=i=>{for(const s of i){if(s.name===e)return s;if(s.fields&&Array.isArray(s.fields)){const e=t(s.fields);if(e)return e}if(s.tabs&&Array.isArray(s.tabs))for(const e of s.tabs)if(e.fields&&Array.isArray(e.fields)){const i=t(e.fields);if(i)return i}}return null};return t(this.formConfig.fields||[])}async fileToBase64(e){return new Promise((t,i)=>{const s=new FileReader;s.onload=()=>t(s.result),s.onerror=i,s.readAsDataURL(e)})}hasFiles(e){if(e instanceof FormData){for(const[t,i]of e.entries())if(i instanceof File)return!0;return!1}for(const t of Object.values(e)){if(t instanceof File)return!0;if(Array.isArray(t)&&t.some(e=>e instanceof File))return!0}return!1}reset(){const e=this.getFormElement();e&&e.reset(),this.data={},this.errors={},this.clearAllErrors(),this.emit("reset",{form:this})}async updateConfig(e){this.formConfig={...this.formConfig,...e},this.formBuilder=new FormBuilder({...this.getFormConfig(),data:this.data,errors:this.errors}),await this.render()}async onBeforeDestroy(){const e=[];for(const t of this.customComponents.values())t.destroy&&e.push(t.destroy());await Promise.all(e),this.customComponents.clear(),Object.values(this.data).forEach(e=>{"string"==typeof e&&e.startsWith("blob:")&&URL.revokeObjectURL(e)}),await super.onBeforeDestroy()}initializePasswordFields(){this.element&&this.element.querySelectorAll('input[data-field-type="password"], input[type="password"]').forEach(e=>{this.updatePasswordStrengthUI(e),e.addEventListener("input",e=>{this.updatePasswordStrengthUI(e.target)});const t=t=>{if("function"==typeof t.getModifierState){const i=t.getModifierState("CapsLock");this.updateCapsLockWarning(e,!!i)}};e.addEventListener("keydown",t),e.addEventListener("keyup",t),this.updateCapsLockWarning(e,!1)})}async onActionTogglePassword(e,t){e.preventDefault();const i=t.getAttribute("data-target");let s=null;if(i&&(s=this.element.querySelector("#"+i)),!s){const e=t.closest(".input-group");e&&(s=e.querySelector('input[type="password"], input[data-field-type="password"], input[type="text"]'))}if(!s)return;const n="password"===s.type;s.type=n?"text":"password",t.setAttribute("aria-pressed",n?"true":"false"),t.setAttribute("aria-label",n?"Hide password":"Show password");const a=t.querySelector("i");a&&(a.classList.toggle("bi-eye",!n),a.classList.toggle("bi-eye-slash",n)),s.focus();try{const e=s.value?.length??0;s.setSelectionRange(e,e)}catch(l){}}async onActionCopyToClipboard(e,t){e.preventDefault();const i=t.getAttribute("data-target");if(!i)return;const s=this.element.querySelector("#"+i);if(s)try{await navigator.clipboard.writeText(s.value);const e=t.querySelector("i");if(e){const i=e.className;e.className="bi bi-check2",t.classList.add("btn-success"),t.classList.remove("btn-outline-secondary"),setTimeout(()=>{e.className=i,t.classList.remove("btn-success"),t.classList.add("btn-outline-secondary")},1500)}this.app&&this.app.toast&&this.app.toast.success("Copied to clipboard!")}catch(n){console.error("Failed to copy to clipboard:",n),this.app&&this.app.toast&&this.app.toast.error("Failed to copy to clipboard")}}computePasswordStrength(e=""){const t=e.length;let i=0;t>=6&&i++,t>=8&&i++,t>=12&&i++;const s=[/[a-z]/.test(e),/[A-Z]/.test(e),/\d/.test(e),/[^A-Za-z0-9]/.test(e)].filter(Boolean).length;return s>=2&&i++,s>=3&&i++,i=Math.max(0,Math.min(4,i)),[{percent:0,label:"Too short",barClass:"bg-secondary"},{percent:25,label:"Weak",barClass:"bg-danger"},{percent:50,label:"Fair",barClass:"bg-warning"},{percent:75,label:"Good",barClass:"bg-info"},{percent:100,label:"Strong",barClass:"bg-success"}][i]}updatePasswordStrengthUI(e){if(!e||!e.id)return;const t=this.element.querySelector(`#${e.id}_strength_bar`),i=this.element.querySelector(`#${e.id}_strength_text`);if(!t&&!i)return;const{percent:s,label:n,barClass:a}=this.computePasswordStrength(e.value||"");t&&(t.className=`progress-bar ${a}`,t.style.width=`${s}%`,t.setAttribute("aria-valuenow",String(s))),i&&(i.textContent=n)}updateCapsLockWarning(e,t){if(!e||!e.id)return;const i=this.element.querySelector(`#${e.id}_caps_warning`);i&&(t?i.classList.remove("d-none"):i.classList.add("d-none"))}}class FieldStatusManager{constructor(e){this.fieldElement=e,this.statusContainer=this.findOrCreateStatusContainer(),this.timeouts=/* @__PURE__ */new Map}findOrCreateStatusContainer(){let e=this.fieldElement.parentElement.querySelector(".field-status-label-inline");if(!e){const t=this.findFieldLabel();t&&(e=t.querySelector(".field-status-label-inline"))}return e||(e=this.createStatusContainer()),e}createStatusContainer(){const e=this.getFieldType();this.getPlacementStrategy(e);const t=document.createElement("div");return this.createLabelInlineContainer(t)}getFieldType(){const e=this.fieldElement.tagName.toLowerCase(),t=this.fieldElement.type?.toLowerCase(),i=this.fieldElement.className;return"checkbox"===t||i.includes("form-check-input")||i.includes("form-switch")?"toggle":"select"===e?"select":"textarea"===e?"textarea":"input"}getPlacementStrategy(e){return"label-inline"}createLabelInlineContainer(e){e.className="field-status-label-inline",e.innerHTML=this.getStatusHTML();const t=this.findFieldLabel();return t?t.appendChild(e):this.fieldElement.parentElement.appendChild(e),e}findFieldLabel(){if(this.fieldElement.id){const e=document.querySelector(`label[for="${this.fieldElement.id}"]`);if(e)return e}const e=this.fieldElement.parentElement.querySelector("label");if(e)return e;return this.fieldElement.closest("label")||null}createInputOverlayContainer(e){e.className="field-status-overlay",e.innerHTML=this.getStatusHTML();const t=this.fieldElement.parentElement;return"static"===getComputedStyle(t).position&&(t.style.position="relative"),t.appendChild(e),e}createFullOverlayContainer(e){e.className="field-status-full-overlay d-none",e.innerHTML='\n <div class="saving-indicator">\n <div class="spinner-border spinner-border-sm text-primary" role="status">\n <span class="visually-hidden">Saving...</span>\n </div>\n <span class="ms-2">Saving...</span>\n </div>\n <div class="success-indicator d-none">\n <i class="bi bi-check-circle text-success"></i>\n <span class="ms-2">Saved</span>\n </div>\n <div class="error-indicator d-none">\n <i class="bi bi-exclamation-circle text-danger"></i>\n <span class="ms-2">Error saving</span>\n </div>\n ';const t=this.fieldElement.parentElement;return"static"===getComputedStyle(t).position&&(t.style.position="relative"),t.appendChild(e),e}getStatusHTML(){return'\n <div class="spinner-border spinner-border-sm text-primary d-none" data-status="saving" role="status">\n <span class="visually-hidden">Saving...</span>\n </div>\n <i class="bi bi-check-circle text-success d-none" data-status="saved"></i>\n <i class="bi bi-exclamation-circle text-danger d-none" data-status="error"></i>\n '}showStatus(e,t={}){this.clearTimeout(e),this.showStandardStatus(e,t)}showStandardStatus(e,t={}){this.hideAllStatuses();const i=this.statusContainer.querySelector(`[data-status="${e}"]`);i&&(i.classList.remove("d-none"),i.classList.add("d-inline-block","show"),"saved"===e?this.setTimeout(e,()=>this.hideStatus(e),2500):"error"===e&&(t.message&&(i.title=t.message),this.setTimeout(e,()=>this.hideStatus(e),6e3)))}showFullOverlayStatus(e,t={}){let i;switch(this.statusContainer.querySelectorAll(".saving-indicator, .success-indicator, .error-indicator").forEach(e=>e.classList.add("d-none")),this.statusContainer.classList.remove("d-none"),e){case"saving":i=".saving-indicator";break;case"saved":i=".success-indicator",this.setTimeout(e,()=>this.hideStatus(e),2500);break;case"error":if(i=".error-indicator",t.message){const e=this.statusContainer.querySelector(".error-indicator span");e&&(e.textContent=t.message)}this.setTimeout(e,()=>this.hideStatus(e),6e3)}if(i){const e=this.statusContainer.querySelector(i);e&&e.classList.remove("d-none")}}hideStatus(e){const t=this.statusContainer.querySelector(`[data-status="${e}"]`);t&&(t.classList.remove("show"),t.classList.add("hide"),setTimeout(()=>{t.classList.add("d-none"),t.classList.remove("d-inline-block","hide"),t.title=""},300))}hideAllStatuses(){this.statusContainer.querySelectorAll("[data-status]").forEach(e=>{e.classList.add("d-none"),e.classList.remove("d-inline-block","show","hide"),e.title=""})}setTimeout(e,t,i){const s=setTimeout(t,i);this.timeouts.set(e,s)}clearTimeout(e){this.timeouts.has(e)&&(clearTimeout(this.timeouts.get(e)),this.timeouts.delete(e))}destroy(){this.timeouts.forEach(e=>clearTimeout(e)),this.timeouts.clear()}}n(FormView);const N=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,FormView:FormView,default:FormView},Symbol.toStringTag,{value:"Module"}));exports.FormBuilder=FormBuilder,exports.FormView=FormView,exports.FormView$1=N,exports.applyFileDropMixin=n;
|
|
2
|
+
//# sourceMappingURL=FormView-LRb8scDI.js.map
|