let multiSelectLoader = null; const resolveScriptUrl = (script) => { if (script) return script; const assetBase = window.APP_ASSET_BASE || document.baseURI; return new URL('vendor/multi-select/MultiSelect.js', assetBase).toString(); }; const ensureMultiSelect = async (script) => { if (typeof window.MultiSelect !== 'undefined') { return window.MultiSelect; } if (!multiSelectLoader) { multiSelectLoader = new Promise((resolve, reject) => { const tag = document.createElement('script'); tag.src = resolveScriptUrl(script); tag.async = true; tag.onload = () => resolve(window.MultiSelect); tag.onerror = (event) => reject(event); document.head.appendChild(tag); }); } return multiSelectLoader; }; export const initMultiSelect = async (target = '[data-multi-select]') => { const elements = typeof target === 'string' ? document.querySelectorAll(target) : [target]; if (!elements.length) return []; const MultiSelect = await ensureMultiSelect(); const instances = []; elements.forEach((element) => { if (!element || element.dataset.multiSelectInit === '1') return; const syncTarget = element.dataset.syncTarget; const syncInput = syncTarget ? document.querySelector(syncTarget) : null; const options = {}; const placeholder = element.dataset.placeholder; if (placeholder) options.placeholder = placeholder; if (element.dataset.search !== undefined) { options.search = element.dataset.search === 'true'; } if (element.dataset.selectAll !== undefined) { options.selectAll = element.dataset.selectAll === 'true'; } if (element.dataset.disabled !== undefined) { options.disabled = element.dataset.disabled === 'true'; } if (element.disabled) { options.disabled = true; } if (element.dataset.listAll !== undefined) { options.listAll = element.dataset.listAll === 'true'; } if (element.dataset.selectedLabel) { options.selectedLabel = element.dataset.selectedLabel; } if (element.dataset.searchPlaceholder) { options.searchPlaceholder = element.dataset.searchPlaceholder; } if (element.dataset.selectAllLabel) { options.selectAllLabel = element.dataset.selectAllLabel; } let isSyncing = false; let instance; try { instance = new MultiSelect(element, options); } catch (error) { console.error('[multi-select] init failed', element, error); return; } if (element.dataset.disabled === 'true' || element.disabled) { instance.disable(); } element.dataset.multiSelectInit = '1'; instances.push(instance); if (syncInput) { syncInput._multiSelectInstance = instance; const syncValues = () => { if (!syncInput || isSyncing) return; isSyncing = true; const values = instance.selectedValues || []; syncInput.value = Array.isArray(values) ? values.join(',') : ''; syncInput.dispatchEvent(new Event('change', { bubbles: true })); isSyncing = false; }; instance.element.addEventListener('multi-select:change', syncValues); const values = instance.selectedValues || []; syncInput.value = Array.isArray(values) ? values.join(',') : ''; syncInput.addEventListener('change', () => { if (isSyncing) return; const nextValues = syncInput.value ? syncInput.value.split(',').map((item) => item.trim()).filter(Boolean) : []; instance.setValues(nextValues); }); } }); return instances; }; const autoInit = () => { initMultiSelect().catch(() => {}); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', autoInit); } else { autoInit(); }