Initial import
This commit is contained in:
@@ -0,0 +1,281 @@
|
||||
class SearchBox {
|
||||
container
|
||||
box = document.createElement('div')
|
||||
list = document.createElement('div')
|
||||
listItems = document.createElement('div')
|
||||
selected = document.createElement('div')
|
||||
searchField = document.createElement('input')
|
||||
cloneListItems = this.listItems
|
||||
callback
|
||||
dynamic = {}
|
||||
constructor(selector) {
|
||||
if (typeof selector === "string") {
|
||||
this.container = document.querySelector(selector)
|
||||
} else {
|
||||
this.container = selector;
|
||||
}
|
||||
if(this.container) {
|
||||
if (this.container.nodeName === 'SELECT') {
|
||||
this.dataRetrieve()
|
||||
} else {
|
||||
alert('Html element SELECT is required')
|
||||
}
|
||||
addEventListener('keydown', ({keyCode}) => {
|
||||
if (keyCode === 27) {
|
||||
this.clear()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.box.classList.remove('open')
|
||||
this.searchField.value = ''
|
||||
this.listItems.querySelectorAll('.list-item').forEach(e => {
|
||||
e.classList.add('visible')
|
||||
e.classList.remove('hover')
|
||||
e.style.display = 'block'
|
||||
})
|
||||
}
|
||||
|
||||
getNextSibling(elem, selector) {
|
||||
var sibling = elem.nextElementSibling;
|
||||
while (sibling) {
|
||||
if (sibling.matches(selector)) return sibling;
|
||||
sibling = sibling.nextElementSibling
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getPreviousSibling(elem, selector) {
|
||||
var sibling = elem.previousElementSibling;
|
||||
if (!selector) return sibling;
|
||||
while (sibling) {
|
||||
if (sibling.matches(selector)) return sibling;
|
||||
sibling = sibling.previousElementSibling;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
keyDown() {
|
||||
this.searchField.addEventListener('keydown', ({keyCode}) => {
|
||||
if (keyCode === 38 || keyCode === 40) {
|
||||
event.preventDefault()
|
||||
const visibleList = this.listItems.querySelectorAll('.visible:not(.hover)');
|
||||
const firstItem = visibleList[0];
|
||||
const lastItem = this.listItems.querySelectorAll('.visible:not(.hover)')[visibleList.length - 1];
|
||||
if (this.listItems.querySelectorAll('.visible.hover').length === 0) {
|
||||
if (keyCode === 38 && lastItem)
|
||||
lastItem.classList.add('hover')
|
||||
if (keyCode === 40 && firstItem)
|
||||
firstItem.classList.add('hover')
|
||||
} else {
|
||||
const hoverElement = this.listItems.querySelector('.visible.hover')
|
||||
hoverElement.classList.remove('hover')
|
||||
//up
|
||||
if (keyCode === 38) {
|
||||
const prev = this.getPreviousSibling(hoverElement, '.visible')
|
||||
if (prev && prev.classList.contains('visible')) {
|
||||
prev.classList.add('hover')
|
||||
console.log(prev.offsetTop)
|
||||
this.listItems.scrollTo({
|
||||
top: prev.offsetTop - 160,
|
||||
})
|
||||
} else {
|
||||
lastItem.classList.add('hover')
|
||||
this.listItems.scrollTo({
|
||||
top: lastItem.offsetTop - 160,
|
||||
})
|
||||
}
|
||||
}
|
||||
//down
|
||||
if (keyCode === 40) {
|
||||
const next = this.getNextSibling(hoverElement, '.visible')
|
||||
if (next && next.classList.contains('visible')) {
|
||||
next.classList.add('hover')
|
||||
this.listItems.scrollTo({
|
||||
top: next.offsetTop - 160
|
||||
})
|
||||
} else {
|
||||
firstItem.classList.add('hover')
|
||||
this.listItems.scrollTo({
|
||||
top: firstItem.offsetTop - 160,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keyCode === 13) {
|
||||
event.preventDefault()
|
||||
const currentSelected = this.listItems.querySelector('.hover');
|
||||
if (currentSelected) {
|
||||
const selected = this.listItems.querySelector('.selected');
|
||||
if (!this.container.hasAttribute('multiple')) {
|
||||
if (selected) {
|
||||
selected.classList.remove('selected')
|
||||
}
|
||||
currentSelected.classList.add('selected')
|
||||
this.selected.innerText = currentSelected.innerHTML
|
||||
this.container.value = currentSelected.dataset.select
|
||||
if (this.dynamic.change) {
|
||||
this.dynamic.change(this.container.value)
|
||||
}
|
||||
} else {
|
||||
this.multipleSelected(currentSelected, this.container.querySelector(`option[value="${currentSelected.dataset.select}"]`))
|
||||
}
|
||||
this.container.parentNode.classList.remove('form-error')
|
||||
this.clear()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
multipleSelected(listItem, e) {
|
||||
if (!this.selected.querySelector(`.selected-box[data-id="${e.value}"]`)) {
|
||||
const sb = document.createElement('div')
|
||||
const close = document.createElement('div')
|
||||
sb.className = 'selected-box'
|
||||
close.className = 'close'
|
||||
sb.innerText = e.innerText
|
||||
sb.setAttribute('data-id', e.value)
|
||||
const sbExists = this.selected.querySelector('.selected-box')
|
||||
if (!sbExists) {
|
||||
this.selected.innerHTML = '';
|
||||
}
|
||||
sb.appendChild(close)
|
||||
this.selected.appendChild(sb)
|
||||
listItem.classList.add('selected')
|
||||
e.setAttribute('selected', true)
|
||||
sb.addEventListener('click', () => {
|
||||
event.preventDefault()
|
||||
e.removeAttribute('selected')
|
||||
const listItemSelected = this.listItems.querySelector(`.list-item[data-select="${e.value}"]`)
|
||||
listItemSelected.classList.remove('selected')
|
||||
sb.remove()
|
||||
const sbExists = this.selected.querySelector('.selected-box')
|
||||
if (!sbExists) {
|
||||
var s = this.container.querySelector('option:first-child')
|
||||
if (s)
|
||||
this.selected.innerHTML = s.innerText;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
dataRetrieve() {
|
||||
this.box.classList.add('search-box')
|
||||
this.list.classList.add('list')
|
||||
this.selected.classList.add('selected')
|
||||
this.listItems.classList.add('list-items')
|
||||
this.list.appendChild(this.searchField)
|
||||
this.list.appendChild(this.listItems)
|
||||
this.box.appendChild(this.selected)
|
||||
this.box.appendChild(this.list)
|
||||
if (this.container.hasClass('disabled')) {
|
||||
this.box.classList.add('disabled')
|
||||
}
|
||||
this.box.addEventListener('click', e => {
|
||||
if (
|
||||
!event.target.classList.contains('selected-box') &&
|
||||
!event.target.classList.contains('close')
|
||||
) {
|
||||
if (this.box.classList.contains('open')) {
|
||||
this.clear()
|
||||
} else {
|
||||
document.querySelectorAll('.search-box').forEach(b => {
|
||||
b.classList.remove('open')
|
||||
})
|
||||
this.box.classList.add('open')
|
||||
this.searchField.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.keyDown()
|
||||
this.updateFromOptionList()
|
||||
this.searchField.addEventListener('keyup', e => {
|
||||
this.listItems.querySelectorAll('.list-item').forEach((e, i) => {
|
||||
if (e.innerText.toLowerCase().indexOf(this.searchField.value.toLowerCase()) !== -1 || this.searchField.value === '') {
|
||||
e.style.display = 'block'
|
||||
e.classList.add('visible')
|
||||
} else {
|
||||
e.style.display = 'none'
|
||||
e.classList.remove('visible')
|
||||
e.classList.remove('hover')
|
||||
}
|
||||
})
|
||||
})
|
||||
this.container.parentNode.appendChild(this.box);
|
||||
}
|
||||
|
||||
updateFromOptionList() {
|
||||
this.listItems.innerHTML = '';
|
||||
this.container.querySelectorAll('option').forEach((e, i) => {
|
||||
if (i === 0) {
|
||||
//if (this.selected.innerText !== '')
|
||||
this.selected.innerText = e.innerText
|
||||
}
|
||||
if (e.value) {
|
||||
const listItem = document.createElement('div');
|
||||
listItem.className = 'list-item visible'
|
||||
listItem.setAttribute('data-select', e.value)
|
||||
listItem.innerText = e.innerText;
|
||||
this.listItems.appendChild(listItem)
|
||||
if (e.hasAttribute('selected') && !this.container.hasAttribute('multiple')) {
|
||||
this.selected.innerText = e.innerText
|
||||
listItem.classList.add('selected')
|
||||
this.listItems.scrollTo({
|
||||
top: listItem.offsetTop - 160,
|
||||
})
|
||||
}
|
||||
if (e.hasAttribute('selected') && this.container.hasAttribute('multiple')) {
|
||||
this.multipleSelected(listItem, e)
|
||||
}
|
||||
listItem.addEventListener('click', l => {
|
||||
if (!this.container.hasAttribute('multiple')) {
|
||||
this.container.value = e.value
|
||||
this.selected.innerText = e.innerText
|
||||
if (this.dynamic.change) {
|
||||
this.dynamic.change(this.container.value)
|
||||
}
|
||||
} else {
|
||||
this.multipleSelected(listItem, e)
|
||||
}
|
||||
this.container.parentNode.classList.remove('form-error')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
updateFromObject(object) {
|
||||
const $this = this;
|
||||
object.searchBox.dynamic.change = function (value) {
|
||||
$this.request(object.url, `${object.queryId}=${value}`, data => {
|
||||
//console.log(data);
|
||||
$this.container.innerHTML = $this.container.querySelector('option:first-child').outerHTML
|
||||
data.forEach(o => {
|
||||
if (o[object.data.id] && o[object.data.name]) {
|
||||
const option = document.createElement('option')
|
||||
option.value = o[object.data.id];
|
||||
option.innerText = o[object.data.name]
|
||||
$this.container.appendChild(option)
|
||||
}
|
||||
})
|
||||
if (data.length > 0) {
|
||||
$this.updateFromOptionList()
|
||||
$this.container.classList.remove('disabled')
|
||||
$this.box.classList.remove('disabled')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
request(url, query, callback) {
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.responseType = 'json'
|
||||
xhr.open('get', `${url}?${query}`)
|
||||
xhr.onload = () => {
|
||||
callback(xhr.response)
|
||||
}
|
||||
xhr.send()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user