baseline
This commit is contained in:
109
web/js/components/app-multiselect-init.js
Normal file
109
web/js/components/app-multiselect-init.js
Normal file
@@ -0,0 +1,109 @@
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user