UNPKG

vuetify

Version:

Vue.js 2 Semantic Component Framework

185 lines (155 loc) 5.21 kB
import { escapeHTML } from '../../../util/helpers' /** * Select autocomplete * * @mixin * * Handles logic when using the "autocomplete" prop */ export default { props: { filter: { type: Function, default: (item, queryText, itemText) => { const hasValue = val => val != null ? val : '' const text = hasValue(itemText) const query = hasValue(queryText) return text.toString() .toLowerCase() .indexOf(query.toString().toLowerCase()) > -1 } } }, methods: { filterSearch () { if (!this.isAutocomplete) return this.computedItems return this.computedItems.filter(i => this.filter( i, this.searchValue, this.getText(i)) ) }, genFiltered (text) { text = (text || '').toString() if (!this.isAutocomplete || !this.searchValue || this.filteredItems.length < 1 ) return escapeHTML(text) const { start, middle, end } = this.getMaskedCharacters(text) return `${escapeHTML(start)}${this.genHighlight(middle)}${escapeHTML(end)}` }, genHighlight (text) { if (this.isNotFiltering) return escapeHTML(text) return `<span class="list__tile__mask">${escapeHTML(text)}</span>` }, getMaskedCharacters (text) { const searchValue = (this.searchValue || '').toString().toLowerCase() const index = text.toLowerCase().indexOf(searchValue) if (index < 0) return { start: '', middle: text, end: '' } const start = text.slice(0, index) const middle = text.slice(index, index + searchValue.length) const end = text.slice(index + searchValue.length) return { start, middle, end } }, getCurrentTag () { return this.isMenuItemSelected() ? this.filteredItems[this.getMenuIndex()] : (this.isAnyValueAllowed ? this.searchValue : null) }, tabOut () { this.blur() }, onTabDown (e) { // If tabbing through inputs and // and there is no need for an // update, blur the v-select if (!this.isAutocomplete || !this.getCurrentTag() || this.combobox) return this.tabOut() // When adding tags, if searching and // there is not a filtered options, // add the value to the tags list if (this.tags && this.searchValue && !this.filteredItems.length ) { e.preventDefault() return this.updateTags(this.searchValue) } // An item that is selected by // menu-index should toggled if (this.menuIsActive) { e.preventDefault() this.selectListTile(this.getMenuIndex()) } }, onEnterDown () { this.updateTags(this.getCurrentTag()) }, onEscDown (e) { e.preventDefault() this.menuIsActive = false }, onKeyDown (e) { // If enter, space, up, or down is pressed, open menu if (!this.menuIsActive && [13, 32, 38, 40].includes(e.keyCode)) { e.preventDefault() return this.showMenu() } // If escape deactivate the menu if (e.keyCode === 27) return this.onEscDown(e) // If tab - select item or close menu if (e.keyCode === 9) return this.onTabDown(e) if (!this.isAutocomplete || ![32].includes(e.keyCode) // space ) this.$refs.menu.changeListIndex(e) // Up or down if ([38, 40].includes(e.keyCode)) this.selectedIndex = -1 if (this.isAutocomplete && !this.hideSelections && !this.searchValue ) this.changeSelectedIndex(e.keyCode) if (!this.isAnyValueAllowed || !this.searchValue) return // Enter if (e.keyCode === 13) return this.onEnterDown() // Left arrow if (e.keyCode === 37 && this.$refs.input.selectionStart === 0 && this.selectedItems.length) { this.updateTags(this.searchValue) this.$nextTick(() => { this.selectedIndex = Math.max(this.selectedItems.length - 2, 0) }) } // Right arrow if (e.keyCode === 39 && this.$refs.input.selectionEnd === this.searchValue.length) { this.resetMenuIndex() } }, selectListTile (index) { if (!this.$refs.menu.tiles[index]) return this.$refs.menu.tiles[index].click() }, updateTags (content) { // Avoid direct mutation // for vuex strict mode let selectedItems = this.selectedItems.slice() // If a duplicate item // exists, remove it if (selectedItems.includes(content)) { this.$delete(selectedItems, selectedItems.indexOf(content)) } // When updating tags ensure // that that the search text // is populated if needed let searchValue = null if (this.combobox) { selectedItems = [content] searchValue = this.chips ? null : content } else { selectedItems.push(content) } this.selectedItems = selectedItems this.$nextTick(() => { this.searchValue = searchValue this.$emit('input', this.combobox ? content : this.selectedItems) // Combobox should close its menu when tags are updated this.menuIsActive = !this.combobox }) } } }