$(document).ready(function() { $('[ms-code-select-wrapper]').each(function() { const $wrapper = $(this); const isMulti = $wrapper.attr('ms-code-select-wrapper') === 'multi'; const $input = $wrapper.find('[ms-code-select="input"]'); const $list = $wrapper.find('[ms-code-select="list"]'); const $selectedWrapper = $wrapper.find('[ms-code-select="selected-wrapper"]'); const $emptyState = $wrapper.find('[ms-code-select="empty-state"]'); const options = $input.attr('ms-code-select-options').split(',').map(opt => opt.trim()); let selectedOptions = []; let highlightedIndex = -1; const $templateSelectedTag = $selectedWrapper.find('[ms-code-select="tag"]'); const templateSelectedTagHTML = $templateSelectedTag.prop('outerHTML'); $templateSelectedTag.remove(); const $templateNewTag = $list.find('[ms-code-select="tag-name-new"]'); const templateNewTagHTML = $templateNewTag.prop('outerHTML'); $templateNewTag.remove(); function createSelectedTag(value) { const $newTag = $(templateSelectedTagHTML); $newTag.find('[ms-code-select="tag-name-selected"]').text(value); $newTag.find('[ms-code-select="tag-close"]').on('click', function(e) { e.stopPropagation(); removeTag(value); }); return $newTag; } function addTag(value) { if (!selectedOptions.includes(value) && options.includes(value)) { selectedOptions.push(value); $selectedWrapper.append(createSelectedTag(value)); updateInput(); filterOptions(); } } function removeTag(value) { selectedOptions = selectedOptions.filter(option => option !== value); $selectedWrapper.find(`[ms-code-select="tag-name-selected"]:contains("${value}")`).closest('[ms-code-select="tag"]').remove(); updateInput(); if (isMulti && selectedOptions.length > 0) { $input.val($input.val() + ', '); } filterOptions(); } function updateInput() { $input.val(selectedOptions.join(', ')); } function toggleList(show) { $list.toggle(show); } function createOptionElement(value) { const $option = $(templateNewTagHTML); $option.text(value); $option.on('click', function() { selectOption(value); }); return $option; } function selectOption(value) { if (isMulti) { addTag(value); $input.val(selectedOptions.join(', ') + (selectedOptions.length > 0 ? ', ' : '')); $input.focus(); } else { selectedOptions = [value]; $selectedWrapper.empty().append(createSelectedTag(value)); updateInput(); toggleList(false); } filterOptions(); } function filterOptions() { const inputValue = $input.val(); const searchTerm = isMulti ? inputValue.split(',').pop().trim() : inputValue.trim(); let visibleOptionsCount = 0; $list.find('[ms-code-select="tag-name-new"]').each(function() { const $option = $(this); const optionText = $option.text().toLowerCase(); const matches = optionText.includes(searchTerm.toLowerCase()); const isSelected = selectedOptions.includes($option.text()); $option.toggle(matches && !isSelected); if (matches && !isSelected) visibleOptionsCount++; }); $emptyState.toggle(visibleOptionsCount === 0 && searchTerm !== ''); highlightedIndex = -1; updateHighlight(); } function cleanInput() { const inputValues = $input.val().split(',').map(v => v.trim()).filter(v => v); const validValues = inputValues.filter(v => options.includes(v)); selectedOptions = validValues; $selectedWrapper.empty(); selectedOptions.forEach(value => $selectedWrapper.append(createSelectedTag(value))); updateInput(); filterOptions(); } function handleInputChange() { const inputValue = $input.val(); const inputValues = inputValue.split(',').map(v => v.trim()); const lastValue = inputValues[inputValues.length - 1]; if (inputValue.endsWith(',') || inputValue.endsWith(', ')) { inputValues.pop(); const newValidValues = inputValues.filter(v => options.includes(v) && !selectedOptions.includes(v)); newValidValues.forEach(addTag); $input.val(selectedOptions.join(', ') + (selectedOptions.length > 0 ? ', ' : '')); } else if (options.includes(lastValue) && !selectedOptions.includes(lastValue)) { addTag(lastValue); $input.val(selectedOptions.join(', ') + ', '); } filterOptions(); } function initializeWithValue() { const initialValue = $input.val(); if (initialValue) { const initialValues = initialValue.split(',').map(v => v.trim()); initialValues.forEach(value => { if (options.includes(value)) { addTag(value); } }); updateInput(); filterOptions(); } } function updateHighlight() { $list.find('[ms-code-select="tag-name-new"]').removeClass('highlighted').css('background-color', ''); if (highlightedIndex >= 0) { $list.find('[ms-code-select="tag-name-new"]:visible').eq(highlightedIndex) .addClass('highlighted') .css('background-color', '#e0e0e0'); } } function handleKeyDown(e) { const visibleOptions = $list.find('[ms-code-select="tag-name-new"]:visible'); const optionCount = visibleOptions.length; switch (e.key) { case 'ArrowDown': e.preventDefault(); highlightedIndex = (highlightedIndex + 1) % optionCount; updateHighlight(); break; case 'ArrowUp': e.preventDefault(); highlightedIndex = (highlightedIndex - 1 + optionCount) % optionCount; updateHighlight(); break; case 'Enter': e.preventDefault(); if (highlightedIndex >= 0) { const selectedValue = visibleOptions.eq(highlightedIndex).text(); selectOption(selectedValue); } break; } } $.each(options, function(i, option) { $list.append(createOptionElement(option)); }); $input.on('focus', function() { toggleList(true); if (isMulti) { const currentVal = $input.val().trim(); if (currentVal !== '' && !currentVal.endsWith(',')) { $input.val(currentVal + ', '); } this.selectionStart = this.selectionEnd = this.value.length; } filterOptions(); }); $input.on('click', function(e) { e.preventDefault(); this.selectionStart = this.selectionEnd = this.value.length; }); $input.on('blur', function() { setTimeout(function() { if (!$list.is(':hover')) { toggleList(false); cleanInput(); } }, 100); }); $input.on('input', handleInputChange); $input.on('keydown', handleKeyDown); $list.on('mouseenter', '[ms-code-select="tag-name-new"]', function() { $(this).css('background-color', '#e0e0e0'); }); $list.on('mouseleave', '[ms-code-select="tag-name-new"]', function() { if (!$(this).hasClass('highlighted')) { $(this).css('background-color', ''); } }); initializeWithValue(); toggleList(false); }); });