%PDF- %PDF-
Direktori : /home/opti/workflow/src/public/app-assets/vendors/formBuilder-master/src/js/control/ |
Current File : /home/opti/workflow/src/public/app-assets/vendors/formBuilder-master/src/js/control/autocomplete.js |
import control from '../control' import { filter } from '../dom' /** * Autocomplete class * Output an autocomplete form element */ export default class controlAutocomplete extends control { /** * definition * @return {Object} select control definition */ static get definition() { return { mi18n: { requireValidOption: 'requireValidOption', }, } } /** * build a text DOM element, supporting other jquery text form-control's * @return {Object} DOM Element to be injected into the form. */ build() { const { values, type, ...data } = this.config const keyboardNav = e => { const list = e.target.nextSibling.nextSibling const hiddenField = e.target.nextSibling const activeOption = this.getActiveOption(list) const keyCodeMapVals = [ // up [ 38, () => { const previous = this.getPreviousOption(activeOption) if (previous) { this.selectOption(list, previous) } }, ], // down [ 40, () => { const next = this.getNextOption(activeOption) if (next) { this.selectOption(list, next) } }, ], // enter [ 13, () => { if (activeOption) { e.target.value = activeOption.innerHTML hiddenField.value = activeOption.getAttribute('value') if (list.style.display === 'none') { this.showList(list, activeOption) } else { this.hideList(list) } } else { // Don't allow a value not in the list if (this.config.requireValidOption) { if (!this.isOptionValid(list, e.target.value)) { e.target.value = '' e.target.nextSibling.value = '' } } } e.preventDefault() }, ], // escape [ 27, () => { this.hideList(list) }, ], ] const keyCodeMap = new Map(keyCodeMapVals) let direction = keyCodeMap.get(e.keyCode) if (!direction) { direction = () => false } return direction() } const fauxEvents = { focus: evt => { const list = evt.target.nextSibling.nextSibling const filteredOptions = filter(list.querySelectorAll('li'), evt.target.value) evt.target.addEventListener('keydown', keyboardNav) if (evt.target.value.length > 0) { const selectedOption = filteredOptions.length > 0 ? filteredOptions[filteredOptions.length - 1] : null this.showList(list, selectedOption) } }, blur: evt => { evt.target.removeEventListener('keydown', keyboardNav) setTimeout(() => { evt.target.nextSibling.nextSibling.style.display = 'none' }, 200) // Validate the option entered exists if (this.config.requireValidOption) { const list = evt.target.nextSibling.nextSibling if (!this.isOptionValid(list, evt.target.value)) { evt.target.value = '' evt.target.nextSibling.value = '' } } }, input: evt => { const list = evt.target.nextSibling.nextSibling const hiddenField = evt.target.nextSibling hiddenField.value = evt.target.value const filteredOptions = filter(list.querySelectorAll('li'), evt.target.value) if (filteredOptions.length == 0) { this.hideList(list) } else { let activeOption = this.getActiveOption(list) if (!activeOption) { activeOption = filteredOptions[filteredOptions.length - 1] } this.showList(list, activeOption) } }, } const fauxAttrs = Object.assign({}, data, { id: `${data.id}-input`, autocomplete: 'off', events: fauxEvents, }) const hiddenAttrs = Object.assign({}, data, { type: 'hidden' }) delete fauxAttrs.name const field = [this.markup('input', null, fauxAttrs), this.markup('input', null, hiddenAttrs)] const options = values.map(optionData => { const label = optionData.label const config = { events: { click: evt => { const list = evt.target.parentElement const field = list.previousSibling.previousSibling field.value = optionData.label field.nextSibling.value = optionData.value this.hideList(list) }, }, value: optionData.value, } return this.markup('li', label, config) }) field.push(this.markup('ul', options, { id: `${data.id}-list`, className: `fb-${type}-list` })) return field } /** * Hides autocomplete list and deselects all the options * @param {Object} list - list of autocomplete options */ hideList(list) { this.selectOption(list, null) list.style.display = 'none' } /** * Shows autocomplete list. Automatically selects 'selectedOption' * @param {Object} list - list of autocomplete options * @param {Object} selectedOption - option to be selected */ showList(list, selectedOption) { this.selectOption(list, selectedOption) list.style.display = 'block' list.style.width = list.parentElement.offsetWidth + 'px' } /** * Returns first option from autocomplete list with 'active-option' class * @param {Object} list - list of autocomplete options * @return {Object} first list option with 'active-option' class */ getActiveOption(list) { const activeOption = list.getElementsByClassName('active-option')[0] if (activeOption && activeOption.style.display !== 'none') { return activeOption } return null } /** * Previous next option to the current option * @param {Object} current - currently selected option * @return {Object} previous option to the current option or null if previous doesn't exist */ getPreviousOption(current) { let previous = current do { previous = previous ? previous.previousSibling : null } while (previous != null && previous.style.display === 'none') return previous } /** * Returns next option to the current option * @param {Object} current - currently selected option * @return {Object} next option to the current option or null if next doesn't exist */ getNextOption(current) { let next = current do { next = next ? next.nextSibling : null } while (next != null && next.style.display === 'none') return next } /** * Selects option in autocomplete list. Removes class 'active-option' from all options * and then adds that class to 'selected' option. If 'selected' is null then no option is selected * @param {Object} list - list of autocomplete options * @param {Object} selectedOption - option - 'li' element - to be selected in autocomplete list */ selectOption(list, selectedOption) { const options = list.querySelectorAll('li') // --Fix for IE11 for (let i = 0; i < options.length; i++) { options[i].classList.remove('active-option') } if (selectedOption) { selectedOption.classList.add('active-option') } } /** * Is the value in the autocomplete field in the pre-defined Options list? * @param {Object} list - list of autocomplete options * @param {Object} value -value trying to be set * @return {Object} - is the option in the pre defined list */ isOptionValid(list, value) { const options = list.querySelectorAll('li') let validValue = false for (let i = 0; i < options.length; i++) { if (options[i].innerHTML === value) { validValue = true break } } return validValue } /** * onRender callback * @param {Object} evt */ onRender(evt) { // Set userData if available if (this.config.userData) { const $el = $('#' + this.config.name) const $options = $el.next() const preSelectedOption = this.config.userData[0] let selectedOption = null $options.find('li').each(function() { // eslint-disable-next-line no-invalid-this if ($(this).attr('value') === preSelectedOption) { // eslint-disable-next-line no-invalid-this selectedOption = $(this).get(0) return } }) // If the option was not set, and configuration says it doesn't have to be pre-defined, set the value if (selectedOption === null) { if (this.config.requireValidOption) { // Don't allow return } else { // Set it to whatever the value is $el.prev().val(this.config.userData[0]) return } } $el.prev().val(selectedOption.innerHTML) $el.val(selectedOption.getAttribute('value')) const list = $el.next().get(0) if (list.style.display === 'none') { this.showList(list, selectedOption) } else { this.hideList(list) } } } } control.register('autocomplete', controlAutocomplete)