121 lines
4.2 KiB
JavaScript
121 lines
4.2 KiB
JavaScript
/**
|
||
* Checkbox Select Multiple Widget
|
||
* Provides a multi-select dropdown with checkboxes and tag display
|
||
*/
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Initialize all checkbox multiselect widgets
|
||
document.querySelectorAll('.checkbox-multiselect-wrapper').forEach(function(wrapper) {
|
||
initCheckboxMultiselect(wrapper);
|
||
});
|
||
});
|
||
|
||
function initCheckboxMultiselect(wrapper) {
|
||
const widgetId = wrapper.dataset.widgetId;
|
||
const inputContainer = wrapper.querySelector('.multiselect-input-container');
|
||
const searchInput = wrapper.querySelector('.multiselect-search');
|
||
const dropdown = wrapper.querySelector('.multiselect-dropdown');
|
||
const tagsContainer = wrapper.querySelector('.multiselect-tags');
|
||
const clearButton = wrapper.querySelector('.multiselect-clear');
|
||
const checkboxes = wrapper.querySelectorAll('input[type="checkbox"]');
|
||
|
||
// Show dropdown when clicking on input container
|
||
inputContainer.addEventListener('click', function(e) {
|
||
if (e.target !== clearButton) {
|
||
positionDropdown();
|
||
dropdown.classList.add('show');
|
||
searchInput.focus();
|
||
}
|
||
});
|
||
|
||
// Position dropdown (up or down based on available space)
|
||
function positionDropdown() {
|
||
const rect = inputContainer.getBoundingClientRect();
|
||
const spaceAbove = rect.top;
|
||
const spaceBelow = window.innerHeight - rect.bottom;
|
||
const dropdownHeight = 300; // max-height from CSS
|
||
|
||
// If more space below and enough space, open downward
|
||
if (spaceBelow > spaceAbove && spaceBelow >= dropdownHeight) {
|
||
dropdown.classList.add('dropdown-below');
|
||
} else {
|
||
dropdown.classList.remove('dropdown-below');
|
||
}
|
||
}
|
||
|
||
// Hide dropdown when clicking outside
|
||
document.addEventListener('click', function(e) {
|
||
if (!wrapper.contains(e.target)) {
|
||
dropdown.classList.remove('show');
|
||
}
|
||
});
|
||
|
||
// Search functionality
|
||
searchInput.addEventListener('input', function() {
|
||
const searchTerm = this.value.toLowerCase();
|
||
const options = wrapper.querySelectorAll('.multiselect-option');
|
||
|
||
options.forEach(function(option) {
|
||
const label = option.querySelector('.option-label').textContent.toLowerCase();
|
||
if (label.includes(searchTerm)) {
|
||
option.classList.remove('hidden');
|
||
} else {
|
||
option.classList.add('hidden');
|
||
}
|
||
});
|
||
});
|
||
|
||
// Handle checkbox changes
|
||
checkboxes.forEach(function(checkbox) {
|
||
checkbox.addEventListener('change', function() {
|
||
updateTags();
|
||
});
|
||
});
|
||
|
||
// Clear all button
|
||
clearButton.addEventListener('click', function(e) {
|
||
e.stopPropagation();
|
||
checkboxes.forEach(function(checkbox) {
|
||
checkbox.checked = false;
|
||
});
|
||
updateTags();
|
||
});
|
||
|
||
// Update tags display
|
||
function updateTags() {
|
||
tagsContainer.innerHTML = '';
|
||
let hasSelections = false;
|
||
|
||
checkboxes.forEach(function(checkbox) {
|
||
if (checkbox.checked) {
|
||
hasSelections = true;
|
||
const tag = document.createElement('div');
|
||
tag.className = 'multiselect-tag';
|
||
tag.innerHTML = `
|
||
<span>${checkbox.dataset.label}</span>
|
||
<button type="button" class="multiselect-tag-remove" data-value="${checkbox.value}">×</button>
|
||
`;
|
||
|
||
// Remove tag on click
|
||
tag.querySelector('.multiselect-tag-remove').addEventListener('click', function(e) {
|
||
e.stopPropagation();
|
||
checkbox.checked = false;
|
||
updateTags();
|
||
});
|
||
|
||
tagsContainer.appendChild(tag);
|
||
}
|
||
});
|
||
|
||
// Show/hide clear button
|
||
if (hasSelections) {
|
||
inputContainer.classList.add('has-selections');
|
||
} else {
|
||
inputContainer.classList.remove('has-selections');
|
||
}
|
||
}
|
||
|
||
// Initialize tags on load
|
||
updateTags();
|
||
}
|