import { createElement, render } from 'preact'; /** @jsx createElement */
import Autocomplete from './autocomplete';
let renderer = null;
let observer = null;
function accessibleAutocomplete(options) {
let currentOptions = { ...options };
if (!currentOptions.element) {
throw new Error('element is not defined');
}
if (!currentOptions.id) {
throw new Error('id is not defined');
}
if (!currentOptions.source) {
throw new Error('source is not defined');
}
if (Array.isArray(currentOptions.source)) {
currentOptions.source = createSimpleEngine(currentOptions.source);
}
renderer = render(, currentOptions.element);
if (typeof currentOptions.selectElement === 'undefined') {
return renderer;
}
// create MutationObserver and re-render
observer = new MutationObserver(mutationsList => {
for (const mutation of mutationsList) {
if (mutation.type == 'childList') {
currentOptions.source = createSimpleEngine(getSourceArray(currentOptions));
}
if (mutation.type == 'attributes') {
currentOptions.inputClassName = mutation.target.classList;
}
}
render(, currentOptions.element, renderer);
});
observer.observe(currentOptions.selectElement, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['class'],
});
return {
setOptions: (newOptions) => {
const mergedOptions = {...currentOptions, ...newOptions};
currentOptions = mergedOptions;
render(, mergedOptions.element, renderer);
}
}
}
const createSimpleEngine = values => (query, syncResults) => {
const matches = values.filter(
r => r.toLowerCase().indexOf(query.toLowerCase()) !== -1
);
syncResults(matches);
};
const getSourceArray = configurationOptions => {
let availableOptions = [].filter.call(
configurationOptions.selectElement.options,
option => option.value || configurationOptions.preserveNullOptions
);
return availableOptions.map(option => option.textContent || option.innerText);
};
accessibleAutocomplete.enhanceSelectElement = configurationOptions => {
if (!configurationOptions.selectElement) {
throw new Error('selectElement is not defined');
}
// Set defaults.
if (!configurationOptions.source) {
configurationOptions.source = getSourceArray(configurationOptions);
}
configurationOptions.onConfirm =
configurationOptions.onConfirm ||
(query => {
const requestedOption = [].filter.call(
configurationOptions.selectElement.options,
option => (option.textContent || option.innerText) === query
)[0];
if (requestedOption) {
requestedOption.selected = true;
}
});
if (
configurationOptions.selectElement.value ||
configurationOptions.defaultValue === undefined
) {
const option =
configurationOptions.selectElement.options[
configurationOptions.selectElement.options.selectedIndex
];
if (option) {
configurationOptions.defaultValue =
option.textContent || option.innerText;
}
}
if (configurationOptions.name === undefined) configurationOptions.name = '';
if (configurationOptions.id === undefined) {
if (configurationOptions.selectElement.id === undefined) {
configurationOptions.id = '';
} else {
configurationOptions.id = configurationOptions.selectElement.id;
}
}
if (configurationOptions.autoselect === undefined)
configurationOptions.autoselect = true;
configurationOptions.inputClassName =
configurationOptions.selectElement.className;
const element = document.createElement('span');
element.classList.add('autocomplete__enhanced-select');
configurationOptions.selectElement.parentNode.insertBefore(
element,
configurationOptions.selectElement
);
configurationOptions.selectElement.style.display = 'none';
configurationOptions.selectElement.id =
configurationOptions.selectElement.id + '-select';
return accessibleAutocomplete({
...configurationOptions,
element: element
});
};
accessibleAutocomplete.destroy = () => {
if (observer) observer.disconnect();
};
export default accessibleAutocomplete;