function dselectUpdate(button, classElement, classToggler) { const value = button.dataset.dselectValue const target = button.closest(`.${classElement}`).previousElementSibling const toggler = target.nextElementSibling.getElementsByClassName(classToggler)[0] const input = target.nextElementSibling.querySelector('input') if (target.multiple) { Array.from(target.options).filter(option => option.value === value)[0].selected = true } else { target.value = value } if (target.multiple) { toggler.click() } target.dispatchEvent(new Event('change')) toggler.focus() if (input) { input.value = '' } } function dselectRemoveTag(button, classElement, classToggler) { const value = button.parentNode.dataset.dselectValue const target = button.closest(`.${classElement}`).previousElementSibling const toggler = target.nextElementSibling.getElementsByClassName(classToggler)[0] const input = target.nextElementSibling.querySelector('input') Array.from(target.options).filter(option => option.value === value)[0].selected = false target.dispatchEvent(new Event('change')) toggler.click() if (input) { input.value = '' } } function dselectSearch(event, input, classElement, classToggler, creatable) { const filterValue = input.value.toLowerCase().trim() const itemsContainer = input.nextElementSibling const headers = itemsContainer.querySelectorAll('.dropdown-header') const items = itemsContainer.querySelectorAll('.dropdown-item') const noResults = itemsContainer.nextElementSibling headers.forEach(i => i.classList.add('d-none')) for (const item of items) { const filterText = item.textContent if (filterText.toLowerCase().indexOf(filterValue) > -1) { item.classList.remove('d-none') let header = item while(header = header.previousElementSibling) { if (header.classList.contains('dropdown-header')) { header.classList.remove('d-none') break } } } else { item.classList.add('d-none') } } const found = Array.from(items).filter(i => !i.classList.contains('d-none') && !i.hasAttribute('hidden')) if (found.length < 1) { noResults.classList.remove('d-none') itemsContainer.classList.add('d-none') if (creatable) { noResults.innerHTML = `Press Enter to add "${input.value}"` if (event.key === 'Enter') { const target = input.closest(`.${classElement}`).previousElementSibling const toggler = target.nextElementSibling.getElementsByClassName(classToggler)[0] target.insertAdjacentHTML('afterbegin', ``) target.dispatchEvent(new Event('change')) input.value = '' input.dispatchEvent(new Event('keyup')) toggler.click() toggler.focus() } } } else { noResults.classList.add('d-none') itemsContainer.classList.remove('d-none') } } function dselectClear(button, classElement) { const target = button.closest(`.${classElement}`).previousElementSibling Array.from(target.options).forEach(option => option.selected = false) target.dispatchEvent(new Event('change')) } function dselect(el, option = {}) { el.style.display = 'none' const classElement = 'dselect-wrapper' const classNoResults = 'dselect-no-results' const classTag = 'dselect-tag' const classTagRemove = 'dselect-tag-remove' const classPlaceholder = 'dselect-placeholder' const classClearBtn = 'dselect-clear' const classTogglerClearable = 'dselect-clearable' const defaultSearch = false const defaultCreatable = false const defaultClearable = false const defaultMaxHeight = '360px' const defaultSize = '' const search = attrBool('search') || option.search || defaultSearch const creatable = attrBool('creatable') || option.creatable || defaultCreatable const clearable = attrBool('clearable') || option.clearable || defaultClearable const maxHeight = el.dataset.dselectMaxHeight || option.maxHeight || defaultMaxHeight let size = el.dataset.dselectSize || option.size || defaultSize size = size !== '' ? ` form-select-${size}` : '' const classToggler = `form-select${size}` const searchInput = search ? `` : '' function attrBool(attr) { const attribute = `data-dselect-${attr}` if (!el.hasAttribute(attribute)) return null const value = el.getAttribute(attribute) return value.toLowerCase() === 'true' } function removePrev() { if (el.nextElementSibling && el.nextElementSibling.classList && el.nextElementSibling.classList.contains(classElement)) { el.nextElementSibling.remove() } } function isPlaceholder(option) { return option.getAttribute('value') === '' } function selectedTag(options, multiple) { if (multiple) { const selectedOptions = Array.from(options).filter(option => option.selected && !isPlaceholder(option)) const placeholderOption = Array.from(options).filter(option => isPlaceholder(option)) let tag = [] if (selectedOptions.length === 0) { const text = placeholderOption.length ? placeholderOption[0].textContent : ' ' tag.push(`${text}`) } else { for (const option of selectedOptions) { tag.push(`
${option.text}
`) } } return tag.join('') } else { const selectedOption = options[options.selectedIndex] return isPlaceholder(selectedOption) ? `${selectedOption.innerHTML}` : selectedOption.innerHTML } } function selectedText(options) { const selectedOption = options[options.selectedIndex] return isPlaceholder(selectedOption) ? '' : selectedOption.textContent } function itemTags(options) { let items = [] for (const option of options) { if (option.tagName === 'OPTGROUP') { items.push(``) } else { const hidden = isPlaceholder(option) ? ' hidden' : '' const active = option.selected ? ' active' : '' const disabled = el.multiple && option.selected ? ' disabled' : '' const value = option.value const text = option.textContent items.push(`${text}`) } } items = items.join('') return items } function createDom() { const autoclose = el.multiple ? ' data-bs-auto-close="outside"' : '' const additionalClass = Array.from(el.classList).filter(className => { return className !== 'form-select' && className !== 'form-select-sm' && className !== 'form-select-lg' }).join(' ') const clearBtn = clearable && !el.multiple ? ` ` : '' const template = ` ` removePrev() el.insertAdjacentHTML('afterend', template) // insert template after element } createDom() function updateDom() { const dropdown = el.nextElementSibling const toggler = dropdown.getElementsByClassName(classToggler)[0] const dSelectItems = dropdown.getElementsByClassName('dselect-items')[0] toggler.innerHTML = selectedTag(el.options, el.multiple) dSelectItems.innerHTML = itemTags(el.querySelectorAll('*')) if (!el.multiple) { toggler.dataset.dselectText = selectedText(el.options) } } el.addEventListener('change', updateDom) }