UNPKG

bootstrap-italia

Version:

Bootstrap Italia è un tema Bootstrap 5 per la creazione di applicazioni web nel pieno rispetto delle linee guida di design per i siti internet e i servizi digitali della PA

150 lines (122 loc) 4.16 kB
/** * -------------------------------------------------------------------------- * Bootstrap Italia (https://italia.github.io/bootstrap-italia/) * Authors: https://github.com/italia/bootstrap-italia/blob/main/AUTHORS * Licensed under BSD-3-Clause license (https://github.com/italia/bootstrap-italia/blob/main/LICENSE) * -------------------------------------------------------------------------- */ import BaseComponent from './base-component' import EventHandler from './dom/event-handler' import InputLabel from './input-label' const NAME = 'inputsearchautocomplete' const DATA_KEY = 'bs.inputsearchautocomplete' const EVENT_KEY = `.${DATA_KEY}` const Default = { autocomplete: [], } const EVENT_KEYUP = `keyup${EVENT_KEY}` const CLASS_NAME_SHOW = 'autocomplete-list-show' const CLASS_NAME_AUTOCOMPLETE = 'autocomplete' const DATA_AUTOCOMPLETE = 'data-bs-autocomplete' const SELECTOR_SEARCH = 'input[' + DATA_AUTOCOMPLETE + '][type="search"]' class InputSearch extends BaseComponent { constructor(element, config) { super(element) this._config = this._getConfig(config) this._items = [] this._autocompleteElement = null this._label = new InputLabel(element) this._init() this._bindEvents() } // Getters static get NAME() { return NAME } // Public search() { const value = this._element.value //!!! $autocomplete.empty() this._autocompleteElement.innerHTML = '' if (value) { this._items.forEach((item) => { let markText = new RegExp('(' + value + ')', 'gi') let optionText = item.text.replace(markText, '<mark>$1</mark>') let optionLabel = item.label ? '<em>' + item.label + '</em>' : '' let optionIcon = item.icon ? item.icon : '' let optionLink = item.link ? item.link : '#' if (optionText.toLowerCase().indexOf(value.toLowerCase()) !== -1) { this._autocompleteElement.classList.add(CLASS_NAME_SHOW) this._autocompleteElement.appendChild(this._createOption(optionLink, optionText, optionLabel, optionIcon)) } }) } else { this._autocompleteElement.classList.remove(CLASS_NAME_SHOW) } } // Private _getConfig(config) { config = { ...Default, ...(typeof config === 'object' ? config : {}), } return config } _getItems() { try { return JSON.parse(this._element.getAttribute(DATA_AUTOCOMPLETE)) } catch (error) { console.error('[InputSearchAutocomplete] invalid data provided for ' + DATA_AUTOCOMPLETE + ' attribute', error) return [] } } _init() { if (this._element.classList.contains(CLASS_NAME_AUTOCOMPLETE)) { if (typeof document === 'undefined') { return } this._items = this._getItems() this._autocompleteElement = document.createElement('ul') this._autocompleteElement.classList.add('autocomplete-list') this._element.parentNode.insertBefore(this._autocompleteElement, this._element.nextSibling) } } _bindEvents() { EventHandler.on(this._element, EVENT_KEYUP, () => this.search()) } _createOption(link, text, label, icon) { if (typeof document === 'undefined') { return } const option = document.createElement('li') option.innerHTML = `<a href="${link}"> ${icon} <span class="autocomplete-list-text"> <span>${text}</span> ${label} </span> </a>` return option } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ const createInput = (element) => { if (element && element.matches(SELECTOR_SEARCH)) { return InputSearch.getOrCreateInstance(element) } return null } if (typeof document !== 'undefined') { document.addEventListener('DOMContentLoaded', function () { var frmel = document.querySelectorAll(SELECTOR_SEARCH + ', label') frmel.forEach(function (item) { const target = InputLabel.getInputFromLabel(item) || item createInput(target) }) }) } export default InputSearch