@coreui/coreui-pro
Version:
The most popular front-end framework for developing responsive, mobile-first projects on the web rewritten by the CoreUI Team
891 lines (863 loc) • 32.7 kB
JavaScript
/*!
* CoreUI autocomplete.js v5.23.0 (https://coreui.io)
* Copyright 2025 The CoreUI Team (https://github.com/orgs/coreui/people)
* Licensed under MIT (https://github.com/coreui/coreui/blob/main/LICENSE)
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core'), require('./base-component.js'), require('./dom/data.js'), require('./dom/event-handler.js'), require('./dom/selector-engine.js'), require('./util/sanitizer.js'), require('./util/index.js')) :
typeof define === 'function' && define.amd ? define(['@popperjs/core', './base-component', './dom/data', './dom/event-handler', './dom/selector-engine', './util/sanitizer', './util/index'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Autocomplete = factory(global["@popperjs/core"], global.BaseComponent, global.Data, global.EventHandler, global.SelectorEngine, global.Sanitizer, global.Index));
})(this, (function (Popper, BaseComponent, Data, EventHandler, SelectorEngine, sanitizer_js, index_js) { 'use strict';
function _interopNamespaceDefault(e) {
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
if (e) {
for (const k in e) {
if (k !== 'default') {
const d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
n.default = e;
return Object.freeze(n);
}
const Popper__namespace = /*#__PURE__*/_interopNamespaceDefault(Popper);
/**
* --------------------------------------------------------------------------
* CoreUI PRO autocomplete.js
* License (https://coreui.io/pro/license/)
* --------------------------------------------------------------------------
*/
/**
* ------------------------------------------------------------------------
* Constants
* ------------------------------------------------------------------------
*/
const NAME = 'autocomplete';
const DATA_KEY = 'coreui.autocomplete';
const EVENT_KEY = `.${DATA_KEY}`;
const DATA_API_KEY = '.data-api';
const ARROW_UP_KEY = 'ArrowUp';
const ARROW_DOWN_KEY = 'ArrowDown';
const BACKSPACE_KEY = 'Backspace';
const DELETE_KEY = 'Delete';
const ENTER_KEY = 'Enter';
const ESCAPE_KEY = 'Escape';
const TAB_KEY = 'Tab';
const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button
const EVENT_BLUR = `blur${EVENT_KEY}`;
const EVENT_CHANGED = `changed${EVENT_KEY}`;
const EVENT_CLICK = `click${EVENT_KEY}`;
const EVENT_HIDE = `hide${EVENT_KEY}`;
const EVENT_HIDDEN = `hidden${EVENT_KEY}`;
const EVENT_INPUT = `input${EVENT_KEY}`;
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`;
const EVENT_KEYUP = `keyup${EVENT_KEY}`;
const EVENT_SHOW = `show${EVENT_KEY}`;
const EVENT_SHOWN = `shown${EVENT_KEY}`;
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`;
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`;
const CLASS_NAME_AUTOCOMPLETE = 'autocomplete';
const CLASS_NAME_BUTTONS = 'autocomplete-buttons';
const CLASS_NAME_CLEANER = 'autocomplete-cleaner';
const CLASS_NAME_DISABLED = 'disabled';
const CLASS_NAME_DROPDOWN = 'autocomplete-dropdown';
const CLASS_NAME_INDICATOR = 'autocomplete-indicator';
const CLASS_NAME_INPUT = 'autocomplete-input';
const CLASS_NAME_INPUT_HINT = 'autocomplete-input-hint';
const CLASS_NAME_INPUT_GROUP = 'autocomplete-input-group';
const CLASS_NAME_LABEL = 'label';
const CLASS_NAME_OPTGROUP = 'autocomplete-optgroup';
const CLASS_NAME_OPTGROUP_LABEL = 'autocomplete-optgroup-label';
const CLASS_NAME_OPTION = 'autocomplete-option';
const CLASS_NAME_OPTIONS = 'autocomplete-options';
const CLASS_NAME_OPTIONS_EMPTY = 'autocomplete-options-empty';
const CLASS_NAME_SELECTED = 'selected';
const CLASS_NAME_SHOW = 'show';
const SELECTOR_DATA_TOGGLE = '[data-coreui-toggle="autocomplete"]:not(.disabled)';
const SELECTOR_DATA_TOGGLE_SHOWN = `.autocomplete:not(.disabled).${CLASS_NAME_SHOW}`;
const SELECTOR_INDICATOR = '.autocomplete-indicator';
const SELECTOR_OPTGROUP = '.autocomplete-optgroup';
const SELECTOR_OPTION = '.autocomplete-option';
const SELECTOR_OPTIONS = '.autocomplete-options';
const SELECTOR_OPTIONS_EMPTY = '.autocomplete-options-empty';
const SELECTOR_VISIBLE_ITEMS = '.autocomplete-options .autocomplete-option:not(.disabled):not(:disabled)';
const Default = {
allowList: sanitizer_js.DefaultAllowlist,
allowOnlyDefinedOptions: false,
ariaCleanerLabel: 'Clear selection',
ariaIndicatorLabel: 'Toggle visibility of options menu',
cleaner: false,
clearSearchOnSelect: true,
container: false,
disabled: false,
highlightOptionsOnSearch: false,
id: null,
indicator: false,
invalid: false,
name: null,
options: false,
optionsGroupsTemplate: null,
optionsMaxHeight: 'auto',
optionsTemplate: null,
placeholder: null,
required: false,
sanitize: true,
sanitizeFn: null,
search: null,
searchNoResultsLabel: false,
showHints: false,
valid: false,
value: null
};
const DefaultType = {
allowList: 'object',
allowOnlyDefinedOptions: 'boolean',
ariaCleanerLabel: 'string',
ariaIndicatorLabel: 'string',
cleaner: 'boolean',
clearSearchOnSelect: 'boolean',
container: '(string|element|boolean)',
disabled: 'boolean',
highlightOptionsOnSearch: 'boolean',
id: '(string|null)',
indicator: 'boolean',
invalid: 'boolean',
name: '(string|null)',
options: '(array|null)',
optionsGroupsTemplate: '(function|null)',
optionsMaxHeight: '(number|string)',
optionsTemplate: '(function|null)',
placeholder: '(string|null)',
required: 'boolean',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
search: '(array|string|null)',
searchNoResultsLabel: 'boolean|string',
showHints: 'boolean',
valid: 'boolean',
value: '(number|string|null)'
};
/**
* ------------------------------------------------------------------------
* Class Definition
* ------------------------------------------------------------------------
*/
class Autocomplete extends BaseComponent {
constructor(element, config) {
var _this$_config$id;
super(element, config);
this._uniqueId = (_this$_config$id = this._config.id) != null ? _this$_config$id : index_js.getUID(`${this.constructor.NAME}`);
this._indicatorElement = null;
this._inputElement = null;
this._inputHintElement = null;
this._togglerElement = null;
this._optionsElement = null;
this._menu = null;
this._selected = [];
this._options = this._getOptionsFromConfig();
this._popper = null;
this._search = '';
this._createAutocomplete();
this._addEventListeners();
Data.set(this._element, DATA_KEY, this);
}
// Getters
static get Default() {
return Default;
}
static get DefaultType() {
return DefaultType;
}
static get NAME() {
return NAME;
}
// Public
toggle() {
return this._isShown() ? this.hide() : this.show();
}
show() {
if (this._config.disabled || this._isShown()) {
return;
}
if (!this._config.searchNoResultsLabel && this._flattenOptions().filter(option => option.label.toLowerCase().includes(this._search.toLowerCase())).length === 0) {
return;
}
EventHandler.trigger(this._element, EVENT_SHOW);
this._element.classList.add(CLASS_NAME_SHOW);
this._inputElement.setAttribute('aria-expanded', 'true');
if (this._config.container) {
this._menu.style.minWidth = `${this._element.offsetWidth}px`;
this._menu.classList.add(CLASS_NAME_SHOW);
}
EventHandler.trigger(this._element, EVENT_SHOWN);
this._createPopper();
}
hide() {
EventHandler.trigger(this._element, EVENT_HIDE);
if (this._popper) {
this._popper.destroy();
}
this._element.classList.remove(CLASS_NAME_SHOW);
this._inputElement.setAttribute('aria-expanded', 'false');
if (this._config.container) {
this._menu.classList.remove(CLASS_NAME_SHOW);
}
if (this._inputHintElement) {
this._inputHintElement.value = '';
}
EventHandler.trigger(this._element, EVENT_HIDDEN);
}
dispose() {
if (this._popper) {
this._popper.destroy();
}
super.dispose();
}
clear() {
this.deselectAll();
this.search('');
this._filterOptionsList();
this._inputElement.value = '';
EventHandler.trigger(this._element, EVENT_CHANGED, {
value: this._selected
});
}
search(label) {
this._search = label.length > 0 ? label.toLowerCase() : '';
if (!this._isExternalSearch()) {
this._filterOptionsList();
}
EventHandler.trigger(this._element, EVENT_INPUT, {
value: label
});
}
update(config) {
if (config.value) {
this.deselectAll();
}
this._config = {
...this._config,
...this._configAfterMerge(config)
};
this._options = this._getOptionsFromConfig();
this._optionsElement.innerHTML = '';
this._createOptions(this._optionsElement, this._options);
}
deselectAll(options = this._selected) {
if (this._selected.length === 0) {
return;
}
for (const option of options) {
if (option.disabled) {
continue;
}
if (Array.isArray(option.options)) {
this.deselectAll(option.options);
continue;
}
this._deselectOption(option.value);
this._updateCleaner();
}
}
// Helpers
_flattenOptions(options = this._options, flat = []) {
for (const opt of options) {
if (opt && Array.isArray(opt.options)) {
this._flattenOptions(opt.options, flat);
continue;
}
flat.push(opt);
}
return flat;
}
_getClassNames() {
return this._element.classList.value.split(' ');
}
_highlightOption(label) {
const regex = new RegExp(this._search, 'gi');
return label.replace(regex, string => `<strong>${string}</strong>`);
}
_isExternalSearch() {
return Array.isArray(this._config.search) && this._config.search.includes('external');
}
_isGlobalSearch() {
return Array.isArray(this._config.search) && this._config.search.includes('global');
}
_isVisible(element) {
const style = window.getComputedStyle(element);
return style.display !== 'none';
}
_isShown() {
return this._element.classList.contains(CLASS_NAME_SHOW);
}
// Private
_addEventListeners() {
EventHandler.on(this._element, EVENT_CLICK, event => {
if (!this._config.disabled && !event.target.closest(SELECTOR_INDICATOR)) {
this.show();
}
});
EventHandler.on(this._element, EVENT_KEYDOWN, event => {
if (event.key === ESCAPE_KEY) {
this.hide();
if (this._config.allowOnlyDefinedOptions && this._selected.length === 0) {
this.search('');
this._inputElement.value = '';
}
return;
}
if (this._isGlobalSearch() && (event.key.length === 1 || event.key === BACKSPACE_KEY || event.key === DELETE_KEY)) {
this._inputElement.focus();
}
});
EventHandler.on(this._menu, EVENT_KEYDOWN, event => {
if (this._isGlobalSearch() && (event.key.length === 1 || event.key === BACKSPACE_KEY || event.key === DELETE_KEY)) {
this._inputElement.focus();
}
});
EventHandler.on(this._togglerElement, EVENT_KEYDOWN, event => {
if (!this._isShown() && (event.key === ENTER_KEY || event.key === ARROW_DOWN_KEY)) {
event.preventDefault();
this.show();
return;
}
if (this._isShown() && event.key === ARROW_DOWN_KEY) {
event.preventDefault();
this._selectMenuItem(event);
}
});
EventHandler.on(this._indicatorElement, EVENT_CLICK, event => {
event.preventDefault();
this.toggle();
});
EventHandler.on(this._inputElement, EVENT_BLUR, () => {
const options = this._flattenOptions().filter(option => option.label.toLowerCase().startsWith(this._inputElement.value.toLowerCase()));
if (this._config.allowOnlyDefinedOptions && this._selected.length === 0 && options.length === 0) {
this.clear();
}
});
EventHandler.on(this._inputElement, EVENT_KEYDOWN, event => {
if (!this._isShown() && event.key !== TAB_KEY) {
this.show();
}
if (event.key === ARROW_DOWN_KEY && this._inputElement.value.length === this._inputElement.selectionStart) {
this._selectMenuItem(event);
return;
}
if (event.key === TAB_KEY && this._config.showHints && this._inputElement.value.length > 0) {
if (this._inputHintElement.value) {
event.preventDefault();
event.stopPropagation();
}
const options = this._flattenOptions().filter(option => option.label.toLowerCase().startsWith(this._inputElement.value.toLowerCase()));
if (options.length > 0) {
this._selectOption(options[0]);
}
}
if (event.key === ENTER_KEY) {
event.preventDefault();
event.stopPropagation();
if (this._inputElement.value.length === 0) {
return;
}
const options = this._flattenOptions().filter(option => option.label.toLowerCase() === this._inputElement.value.toLowerCase());
if (options.length > 0) {
this._selectOption(options[0]);
}
if (options.length === 0 && !this._config.allowOnlyDefinedOptions) {
EventHandler.trigger(this._element, EVENT_CHANGED, {
value: this._inputElement.value
});
this.hide();
if (this._config.clearSearchOnSelect) {
this.search('');
}
}
}
});
EventHandler.on(this._inputElement, EVENT_KEYUP, event => {
if (event.key.length === 1 || event.key === BACKSPACE_KEY || event.key === DELETE_KEY) {
const {
value
} = event.target;
this.search(value);
if (this._config.showHints) {
const options = value ? this._flattenOptions().filter(option => option.label.toLowerCase().startsWith(value.toLowerCase())) : [];
this._inputHintElement.value = options.length > 0 ? `${value}${options[0].label.slice(value.length)}` : '';
}
if (this._selected.length > 0) {
this.deselectAll();
EventHandler.trigger(this._element, EVENT_CHANGED, {
value: this._selected
});
}
}
});
EventHandler.on(this._optionsElement, EVENT_CLICK, event => {
event.preventDefault();
event.stopPropagation();
this._onOptionsClick(event.target);
});
EventHandler.on(this._cleanerElement, EVENT_CLICK, event => {
if (!this._config.disabled) {
event.preventDefault();
event.stopPropagation();
this.clear();
}
});
EventHandler.on(this._cleanerElement, EVENT_KEYDOWN, event => {
if (!this._config.disabled && event.key === ENTER_KEY) {
event.preventDefault();
event.stopPropagation();
this.clear();
}
});
EventHandler.on(this._optionsElement, EVENT_KEYDOWN, event => {
if (event.key === ENTER_KEY) {
this._onOptionsClick(event.target);
}
if ([ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)) {
event.preventDefault();
this._selectMenuItem(event);
}
});
}
_getOptionsFromConfig(options = this._config.options) {
if (!options || !Array.isArray(options)) {
return [];
}
const _options = [];
for (const option of options) {
var _option$value;
if (option.options && Array.isArray(option.options)) {
const customGroupProperties = {
...option
};
delete customGroupProperties.label;
delete customGroupProperties.options;
_options.push({
...customGroupProperties,
label: option.label,
options: this._getOptionsFromConfig(option.options)
});
continue;
}
const label = typeof option === 'string' ? option : option.label;
const value = (_option$value = option.value) != null ? _option$value : typeof option === 'string' ? option : option.label;
const isSelected = option.selected || this._config.value && this._config.value === value;
const customProperties = typeof option === 'object' ? {
...option
} : {};
delete customProperties.label;
delete customProperties.value;
delete customProperties.selected;
delete customProperties.disabled;
_options.push({
...customProperties,
label,
value: String(value),
...(isSelected && {
selected: true
}),
...(option.disabled && {
disabled: true
})
});
if (isSelected) {
this._selected.push({
label: option.label,
value: String(value)
});
}
}
return _options;
}
_createAutocomplete() {
this._element.classList.add(CLASS_NAME_AUTOCOMPLETE);
this._element.classList.toggle('is-invalid', this._config.invalid);
this._element.classList.toggle('is-valid', this._config.valid);
if (this._config.disabled) {
this._element.classList.add(CLASS_NAME_DISABLED);
}
for (const className of this._getClassNames()) {
this._element.classList.add(className);
}
this._createInputGroup();
this._createButtons();
this._createOptionsContainer();
this._updateOptionsList();
}
_createInputGroup() {
var _this$_config$placeho;
const togglerEl = document.createElement('div');
togglerEl.classList.add(CLASS_NAME_INPUT_GROUP);
this._togglerElement = togglerEl;
if (!this._config.search && !this._config.disabled) {
togglerEl.tabIndex = -1;
}
if (!this._config.disabled && this._config.showHints) {
const inputHintEl = document.createElement('input');
inputHintEl.classList.add(CLASS_NAME_INPUT, CLASS_NAME_INPUT_HINT);
inputHintEl.setAttribute('name', (this._config.name || `${this._uniqueId}-hint`).toString());
inputHintEl.autocomplete = 'off';
inputHintEl.readOnly = true;
inputHintEl.tabIndex = -1;
inputHintEl.setAttribute('aria-hidden', true);
togglerEl.append(inputHintEl);
this._inputHintElement = inputHintEl;
}
const inputEl = document.createElement('input');
inputEl.classList.add(CLASS_NAME_INPUT);
inputEl.id = this._uniqueId;
inputEl.setAttribute('name', (this._config.name || this._uniqueId).toString());
inputEl.autocomplete = 'off';
inputEl.placeholder = (_this$_config$placeho = this._config.placeholder) != null ? _this$_config$placeho : '';
inputEl.role = 'combobox';
inputEl.setAttribute('aria-autocomplete', 'list');
inputEl.setAttribute('aria-expanded', 'false');
inputEl.setAttribute('aria-haspopup', 'listbox');
if (this._config.disabled) {
inputEl.setAttribute('disabled', true);
inputEl.tabIndex = -1;
}
if (this._config.required) {
inputEl.setAttribute('required', true);
}
togglerEl.append(inputEl);
this._inputElement = inputEl;
this._element.append(togglerEl);
}
_createButtons() {
if (!this._config.cleaner && !this._config.indicator) {
return;
}
const buttons = document.createElement('div');
buttons.classList.add(CLASS_NAME_BUTTONS);
if (!this._config.disabled && this._config.cleaner) {
const cleaner = document.createElement('button');
cleaner.type = 'button';
cleaner.classList.add(CLASS_NAME_CLEANER);
cleaner.style.display = 'none';
cleaner.setAttribute('aria-label', this._config.ariaCleanerLabel);
buttons.append(cleaner);
this._cleanerElement = cleaner;
}
if (this._config.indicator) {
const indicator = document.createElement('button');
indicator.type = 'button';
indicator.classList.add(CLASS_NAME_INDICATOR);
indicator.setAttribute('aria-label', this._config.ariaIndicatorLabel);
if (this._config.disabled) {
indicator.tabIndex = -1;
}
buttons.append(indicator);
this._indicatorElement = indicator;
this._indicatorElement = indicator;
}
this._togglerElement.append(buttons);
this._updateCleaner();
}
_createPopper() {
if (typeof Popper__namespace === 'undefined') {
throw new TypeError('CoreUI\'s Auto Complete component require Popper (https://popper.js.org)');
}
const popperConfig = {
modifiers: [{
name: 'preventOverflow',
options: {
boundary: 'clippingParents'
}
}, {
name: 'offset',
options: {
offset: [0, 2]
}
}],
placement: index_js.isRTL() ? 'bottom-end' : 'bottom-start'
};
this._popper = Popper__namespace.createPopper(this._togglerElement, this._menu, popperConfig);
}
_createOptionsContainer() {
const dropdownDiv = document.createElement('div');
dropdownDiv.classList.add(CLASS_NAME_DROPDOWN);
dropdownDiv.role = 'listbox';
dropdownDiv.setAttribute('aria-labelledby', this._uniqueId);
dropdownDiv.setAttribute('id', `${this._uniqueId}-listbox`);
const optionsDiv = document.createElement('div');
optionsDiv.classList.add(CLASS_NAME_OPTIONS);
if (this._config.optionsMaxHeight !== 'auto') {
optionsDiv.style.maxHeight = `${this._config.optionsMaxHeight}px`;
optionsDiv.style.overflow = 'auto';
}
dropdownDiv.append(optionsDiv);
const {
container
} = this._config;
if (container) {
this._inputElement.setAttribute('aria-owns', `${this._uniqueId}-listbox`);
dropdownDiv.id = `${this._uniqueId}-listbox`;
container.append(dropdownDiv);
} else {
this._element.append(dropdownDiv);
}
this._createOptions(optionsDiv, this._options);
this._optionsElement = optionsDiv;
this._menu = dropdownDiv;
}
_createOptions(parentElement, options) {
for (const option of options) {
if (Array.isArray(option.options)) {
const optgroup = document.createElement('div');
optgroup.classList.add(CLASS_NAME_OPTGROUP);
optgroup.setAttribute('role', 'group');
const optgrouplabel = document.createElement('div');
if (this._config.optionsGroupsTemplate && typeof this._config.optionsGroupsTemplate === 'function') {
optgrouplabel.innerHTML = this._config.sanitize ? sanitizer_js.sanitizeHtml(this._config.optionsGroupsTemplate(option), this._config.allowList, this._config.sanitizeFn) : this._config.optionsGroupsTemplate(option);
} else {
optgrouplabel.textContent = option.label;
}
optgrouplabel.classList.add(CLASS_NAME_OPTGROUP_LABEL);
optgroup.append(optgrouplabel);
this._createOptions(optgroup, option.options);
parentElement.append(optgroup);
continue;
}
const optionDiv = document.createElement('div');
optionDiv.classList.add(CLASS_NAME_OPTION);
if (option.disabled) {
optionDiv.classList.add(CLASS_NAME_DISABLED);
optionDiv.setAttribute('aria-disabled', 'true');
}
optionDiv.dataset.value = option.value;
optionDiv.tabIndex = 0;
if (this._isExternalSearch() && this._config.highlightOptionsOnSearch && this._search) {
optionDiv.innerHTML = this._highlightOption(option.label);
} else if (this._config.optionsTemplate && typeof this._config.optionsTemplate === 'function') {
optionDiv.innerHTML = this._config.sanitize ? sanitizer_js.sanitizeHtml(this._config.optionsTemplate(option), this._config.allowList, this._config.sanitizeFn) : this._config.optionsTemplate(option);
} else {
optionDiv.textContent = option.label;
}
parentElement.append(optionDiv);
}
}
_onOptionsClick(element) {
if (element.classList.contains(CLASS_NAME_LABEL)) {
return;
}
if (!element.classList.contains(CLASS_NAME_OPTION)) {
element = element.closest(SELECTOR_OPTION);
if (!element) {
return;
}
}
const {
value
} = element.dataset;
const foundOption = this._findOptionByValue(value);
if (foundOption) {
this._selectOption(foundOption);
this._inputElement.focus();
}
}
_findOptionByValue(value, options = this._options) {
for (const option of options) {
if (option.value === value) {
return option;
}
if (option.options && Array.isArray(option.options)) {
const found = this._findOptionByValue(value, option.options);
if (found) {
return found;
}
}
}
return null;
}
_selectOption(option) {
this.deselectAll();
if (this._selected.filter(selectedOption => selectedOption.value === option.value).length === 0) {
this._selected.push(option);
}
const foundOption = SelectorEngine.findOne(`[data-value="${option.value}"]`, this._optionsElement);
if (foundOption) {
foundOption.classList.add(CLASS_NAME_SELECTED);
foundOption.setAttribute('aria-selected', true);
}
EventHandler.trigger(this._element, EVENT_CHANGED, {
value: option
});
this._inputElement.value = option.label;
if (this._config.showHints) {
this._inputHintElement.value = '';
}
this.hide();
if (this._config.clearSearchOnSelect) {
this.search('');
}
this._updateCleaner();
}
_deselectOption(value) {
this._selected = this._selected.filter(option => option.value !== value);
const option = SelectorEngine.findOne(`[data-value="${value}"]`, this._optionsElement);
if (option) {
option.classList.remove(CLASS_NAME_SELECTED);
option.setAttribute('aria-selected', false);
}
// EventHandler.trigger(this._element, EVENT_CHANGED, {
// value: this._selected
// })
}
_updateCleaner() {
if (!this._config.cleaner || this._cleanerElement === null) {
return;
}
if (this._selected.length > 0) {
this._cleanerElement.style.removeProperty('display');
return;
}
this._cleanerElement.style.display = 'none';
}
_updateOptionsList(options = this._options) {
for (const option of options) {
if (Array.isArray(option.options)) {
this._updateOptionsList(option.options);
continue;
}
if (option.selected) {
this._selectOption(option);
}
}
}
_filterOptionsList() {
const options = SelectorEngine.find(SELECTOR_OPTION, this._menu);
let visibleOptions = 0;
for (const option of options) {
// eslint-disable-next-line unicorn/prefer-includes
if (option.textContent.toLowerCase().indexOf(this._search) === -1) {
option.style.display = 'none';
} else {
if (this._config.highlightOptionsOnSearch && !this._config.optionsTemplate) {
option.innerHTML = this._highlightOption(option.textContent);
}
option.style.removeProperty('display');
visibleOptions++;
}
const optgroup = option.closest(SELECTOR_OPTGROUP);
if (optgroup) {
// eslint-disable-next-line unicorn/prefer-array-some
if (SelectorEngine.children(optgroup, SELECTOR_OPTION).filter(element => this._isVisible(element)).length > 0) {
optgroup.style.removeProperty('display');
} else {
optgroup.style.display = 'none';
}
}
}
if (visibleOptions > 0) {
if (SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._menu)) {
SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._menu).remove();
}
return;
}
if (visibleOptions === 0) {
if (this._config.searchNoResultsLabel) {
const placeholder = document.createElement('div');
placeholder.classList.add(CLASS_NAME_OPTIONS_EMPTY);
placeholder.innerHTML = this._config.searchNoResultsLabel;
if (!SelectorEngine.findOne(SELECTOR_OPTIONS_EMPTY, this._menu)) {
SelectorEngine.findOne(SELECTOR_OPTIONS, this._menu).append(placeholder);
}
return;
}
this.hide();
}
}
_selectMenuItem({
key,
target
}) {
const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => index_js.isVisible(element));
if (!items.length) {
return;
}
// if target isn't included in items (e.g. when expanding the dropdown)
// allow cycling to get the last item in case key equals ARROW_UP_KEY
index_js.getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus();
}
_configAfterMerge(config) {
if (config.container === true) {
config.container = document.body;
}
if (typeof config.container === 'object' || typeof config.container === 'string') {
config.container = index_js.getElement(config.container);
}
if (typeof config.options === 'string') {
config.options = config.options.split(/,\s*/).map(String);
}
if (typeof config.search === 'string') {
config.search = config.search.split(/,\s*/).map(String);
}
return config;
}
// Static
static autocompleteInterface(element, config) {
const data = Autocomplete.getOrCreateInstance(element, config);
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
throw new TypeError(`No method named "${config}"`);
}
data[config]();
}
}
static jQueryInterface(config) {
return this.each(function () {
Autocomplete.autocompleteInterface(this, config);
});
}
static clearMenus(event) {
if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY) {
return;
}
const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN);
for (const toggle of openToggles) {
const context = Autocomplete.getInstance(toggle);
if (!context) {
continue;
}
const composedPath = event.composedPath();
if (composedPath.includes(context._element)) {
continue;
}
({
relatedTarget: context._element
});
if (event.type === 'click') ;
context.hide();
context.search('');
if (context._config.allowOnlyDefinedOptions && context._selected.length === 0) {
context._inputElement.value = '';
}
}
}
}
/**
* Data API implementation
*/
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
for (const autocomplete of SelectorEngine.find(SELECTOR_DATA_TOGGLE)) {
Autocomplete.autocompleteInterface(autocomplete);
}
});
EventHandler.on(document, EVENT_CLICK_DATA_API, Autocomplete.clearMenus);
EventHandler.on(document, EVENT_KEYUP_DATA_API, Autocomplete.clearMenus);
/**
* jQuery
*/
index_js.defineJQueryPlugin(Autocomplete);
return Autocomplete;
}));
//# sourceMappingURL=autocomplete.js.map