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
JavaScript
/**
* --------------------------------------------------------------------------
* 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