function setupAutocomplete(id){
let currentFocus = -1;
let isScriptTriggered = false;
const autoCompleteDiv = document.getElementById(id);
autoCompleteDiv.position = "relative";
const spotfireInput = autoCompleteDiv.firstElementChild;
const autocompleteInput = document.createElement('input');
autocompleteInput.id = id + "Input";
autocompleteInput.style.display = 'none';
// Copy style from SpotfireControl to input
for (let style in spotfireInput.style) {
if (spotfireInput.style.hasOwnProperty(style) && spotfireInput.style[style]) {
autocompleteInput.style[style] = spotfireInput.style[style];
}
}
autoCompleteDiv.appendChild(autocompleteInput);
//popup for autocomplete items
const popup = document.createElement('div');
popup.style.width = `${spotfireInput.offsetWidth}px`;
popup.style.position = 'absolute';
popup.style.zIndex = '100';
popup.className = 'autocomplete-items';
popup.style.display = 'none';
autoCompleteDiv.appendChild(popup);
//observer for csv values as it comes from a calculated value
const csvObserver = new MutationObserver(() => {
csvValues = document.getElementById(id + '-data').innerText.split(',');
});
csvObserver.observe(document.getElementById(id + '-data'), {
childList: true,
characterData: true,
subtree: true
});
let csvValues = document.getElementById(id + '-data').innerText.split(',');
function toggleInputDisplay() {
spotfireInput.style.display = '';
autocompleteInput.style.display = 'none';
spotfireInput.value = autocompleteInput.value;
isScriptTriggered = true;
spotfireInput.focus();
spotfireInput.blur();
isScriptTriggered = false;
}
autocompleteInput.addEventListener('click', () => {
autocompleteInput.value = "";
});
autocompleteInput.addEventListener('input', () => {
const inputValue = autocompleteInput.value;
const filteredValues = csvValues.filter(name => name.toLowerCase().includes(inputValue.toLowerCase()));
popup.innerHTML = '';
filteredValues.forEach(value => {
const div = document.createElement('div');
div.className = "sf-element-dropdown-list-item";
div.innerHTML = value.replace(new RegExp(inputValue, 'gi'), match => "<span class='highlight'>" + match + "</span>");
// Copy style from src input to div
for (var style in autocompleteInput.style) {
if (autocompleteInput.style.hasOwnProperty(style) && autocompleteInput.style[style]) {
div.style[style] = autocompleteInput.style[style];
}
}
div.addEventListener('click', () => {
autocompleteInput.value = value;
popup.style.display = 'none';
spotfireInput.value = value;
currentFocus = -1;
toggleInputDisplay();
});
popup.appendChild(div);
});
popup.style.display = filteredValues.length ? 'block' : 'none';
});
autocompleteInput.addEventListener('keydown', (e) => {
const divs = popup.getElementsByTagName('div');
if (e.keyCode == 40) { // Down arrow
currentFocus++;
if (currentFocus >= divs.length) currentFocus = 0;
} else if (e.keyCode == 38) { // Up arrow
currentFocus--;
if (currentFocus < 0) currentFocus = divs.length - 1;
} else if (e.keyCode == 13) { // Enter
if (currentFocus > -1) {
divs[currentFocus].click();
} else {
spotfireInput.value = autocompleteInput.value;
isScriptTriggered = true;
toggleInputDisplay();
isScriptTriggered = false;
}
} else if (e.keyCode == 27) { // Escape key
isScriptTriggered = true;
toggleInputDisplay();
isScriptTriggered = false;
}
for (let i = 0; i < divs.length; i++) {
divs[i].classList.remove('over');
}
if (currentFocus > -1) {
divs[currentFocus].classList.add('over');
}
});
spotfireInput.addEventListener('focus', () => {
if (isScriptTriggered) return;
// When spotfireInput gets focus, hide it and show input
spotfireInput.style.display = 'none';
autocompleteInput.style.display = '';
autocompleteInput.value = "";
autocompleteInput.focus();
});
autocompleteInput.addEventListener('blur', () => {
setTimeout(() => {
popup.style.display = 'none';
toggleInputDisplay();
}, 200);
});
//styles
const styleTag = `
<style>
#autocompleteInput{
outline: none;
}
.autocomplete-items{
background-color: #fff;
border:1px solid #c6c8cc;
}
.autocomplete-items div:hover,
.autocomplete-items div.over {
color: #FFFFFF !important;
background-color: #7289F9;
cursor:default;
}
.highlight {
font-weight: bold;
text-decoration: underline;
}
</style>`
autoCompleteDiv.insertAdjacentHTML('afterEnd', styleTag)
}
setupAutocomplete("autocomplete")