UNPKG

@jgjergj/vuetify-toolkit

Version:
325 lines (322 loc) 11.3 kB
import { VNodeData, VNode, VNodeChildren } from 'vue' import { VChipA } from '../../shims-vuetify' import { getObjectValueByPath, getPropertyFromItem } from '../../vuetify-import' import VCascaderSelectList from './VCascaderSelectList' import commonSelect from '../mixin/commonSelect' /* @vue/component */ export default commonSelect.extend({ name: 'v-cascader', props: { itemKey: { type: String, default: 'id' }, itemChildren: { type: [String, Function], default: 'children' }, itemText: { type: [String, Array, Function], default: 'text' }, showFullPath: { type: Boolean, default: true }, delimeter: { type: [String], default: ',' } }, data: (vm: any) => ({ currentNode: null, parents: new Map(), childNodes: new Map(), treeviewCashe: new Map(), itemCashe: new Map(), currentParents: [] as any[], currentParentKey: undefined }), computed: { computedItems (): any[] { return (this as any).$data.childNodes.get((this as any).currentParentKey) // return (this as any).buildTree((this as any).$props.items) }, computedChildren (): any[] { if (!(this as any).$data.currentParentKey) return (this as any).computedItems const localChildren = (this as any).$data.treeviewCashe.get((this as any).$data.currentParentKey) return localChildren }, listData (): VNodeData { const scopeId = this.$vnode && (this.$vnode as any).context.$options._scopeId return { attrs: scopeId ? { [scopeId]: true } : undefined, props: { action: this.multiple && !this.isHidingSelected, dark: this.dark, color: this.color, dense: this.dense, hideSelected: this.hideSelected, items: this.computedChildren, noDataText: this.noDataText, selectedItems: this.selectedItems, itemAvatar: this.itemAvatar, itemDisabled: this.itemDisabled, itemValue: this.itemValue, itemText: (this as any).$props.itemText, parents: this.currentParents }, on: { select: (item: object) => { (this as any).selectItem(item) }, 'select-parent': (item: object) => { (this as any).selectParent(item) }, 'update-dimensions': () => ((this as any).$refs.menu as any).updateDimensions() }, scopedSlots: { item: (this.$scopedSlots as any).item } } }, staticList (): VNode { // if (this.$slots['no-data'] || this.$slots['prepend-item'] || this.$slots['append-item']) { // consoleError('assert: staticList should not be called if slots are used') // } const slots: VNodeChildren = [] slots.push((this.$scopedSlots as any).items) return (this as any).$createElement(VCascaderSelectList, this.listData, slots) } }, watch: { value: { immediate: true, handler (val) { if (val) { if (Array.isArray(val)) { (this as any).$data.selectedItems = [] val.map(v => { const itemKey = getObjectValueByPath(v, (this as any).$props.itemKey, []) const itemToAdd = { text: (this as any).textItem(itemKey), key: itemKey }; (this as any).$data.selectedItems.push(itemToAdd) }) } else { (this as any).$data.selectedItems = [] // this.currentItem = null } } } }, items: { immediate: true, handler (val) { (this as any).buildTree(val, undefined) } }, internalSearch: { immediate: true, handler (val) { (this as any).buildTree(val, undefined) } }, showFullPath: { immediate: true, handler (val) { (this as any).updateSelectedItems() } }, delimeter: { immediate: true, handler (val) { (this as any).updateSelectedItems() } } }, methods: { itemMatchFilter (item: any): boolean { if (this.internalSearch && this.internalSearch != null) { const comparedVal = getPropertyFromItem(item, this.$props.itemText) return this.$props.filter(item, this.internalSearch, comparedVal) } else return true }, buildTree (items: any, parentkey?: any, forceInclude?: false): any[] { if (this.$data.childNodes.has(parentkey)) return this.$data.childNodes.get(parentkey) const newItems: any[] = [] items.map((item: any) => { const localChildren = getObjectValueByPath(item, this.$props.itemChildren, []) const itemKey = getObjectValueByPath(item, this.$props.itemKey, []); (this as any).$data.itemCashe.set(itemKey, item) const itemForceInclude = forceInclude || (this as any).itemMatchFilter(item) if (localChildren.length > 0) { const newChildren = (this as any).buildTree(localChildren, itemKey, itemForceInclude) const clone = Object.assign({}, item) clone[this.$props.itemChildren] = newChildren clone.hasChildren = true newItems.push(clone) this.$data.treeviewCashe.set(itemKey, localChildren) this.$data.parents.set(itemKey, parentkey) } else { this.$data.parents.set(itemKey, parentkey) } }) this.$data.childNodes.set(parentkey, newItems) return newItems }, getParents (key: number|string): any[] { const result = [] const parent = this.$data.parents.get(key) if (parent) { result.push(parent) const p = (this as any).getParents(parent) result.push(...p) } return result }, genChipSelection (item: object, index: number) { const isDisabled = false // ( // !(this as any).isInteractive || // (this as any).getDisabled(item) // ) return this.$createElement(VChipA, { staticClass: 'v-chip--select', attrs: { tabindex: -1 }, props: { close: this.$props.deletableChips && !isDisabled, disabled: isDisabled, inputValue: (item as any).text, small: this.$props.smallChips, value: (item as any).text }, on: { click: (e: MouseEvent) => { if (isDisabled) return this.currentItem = item as any const currentKey = (item as any).key; (this as any).updateParents(currentKey); (this as any).selectedIndex = index }, 'click:close': () => { this.selectedItems = this.selectedItems.filter(v => v.key !== (item as any).key); (this as any).emitInput() } }, key: (item as any).key }, (item as any).text) }, genCommaSelection (item: object, index: number, last: boolean) { const color = index === (this as any).selectedIndex && (this as any).computedColor const isDisabled = false // ( // !(this as any).isInteractive || // (this as any).getDisabled(item) // ) return this.$createElement('div', (this as any).setTextColor(color, { staticClass: 'v-select__selection v-select__selection--comma', class: { 'v-select__selection--disabled': isDisabled }, on: { click: (e: MouseEvent) => { if (isDisabled) return this.currentItem = item as any const currentKey = (item as any).key; (this as any).updateParents(currentKey); (this as any).selectedIndex = index } }, key: (item as any).key }), `${(item as any).text}${last ? '' : ', '}`) }, genListWithSlot (): VNode { const slots = ['prepend-item', 'no-data', 'append-item'] .filter(slotName => this.$slots[slotName]) .map(slotName => this.$createElement('template', { slot: slotName }, this.$slots[slotName])) return this.$createElement(VCascaderSelectList, ({ ...this.listData }) as VNodeData, slots) }, textItem (itemkey: any): string { let txt = '' if (this.$props.showFullPath) { const p = (this as any).retriveParents(itemkey) p.map((v:any) => { txt += (this as any).getText(v) + this.$props.delimeter }) } txt += (this as any).getText((this as any).itemCashe.get(itemkey)) return txt }, selectItem (item: object) { const itemKey = getObjectValueByPath(item, this.$props.itemKey, []) const chld = (this as any).$data.treeviewCashe.get(itemKey) if (chld) { this.$data.currentParentKey = itemKey this.$data.currentParents.push(item) const itemToAdd = { text: (this as any).textItem(itemKey), key: itemKey } this.$data.selectedItems = [itemToAdd] } else { // selected item if (!this.$props.multiple) { this.$data.isMenuActive = false } const itemToAdd = { text: (this as any).textItem(itemKey), key: itemKey } if (this.$props.multiple && this.$data.selectedItems.filter((v: any) => v.key === itemKey).length === 0) { this.$data.selectedItems.push(itemToAdd) } else if (!this.$props.multiple) { this.$data.selectedItems = [itemToAdd] } this.$data.currentParentKey = undefined this.$data.currentParents = [] } (this as any).emitInput() }, emitInput () { const result: any[] = [] this.$data.selectedItems.map((v: any) => { result.push(this.$data.itemCashe.get(v.key)) }) this.$emit('input', result) }, updateSelectedItems () { this.$nextTick(() => { this.$data.selectedItems.map((v: any) => { v.text = (this as any).textItem(v.key) }) }) }, retriveParents (itemKey: any): any[] { const result: any[] = [] let parentKey = this.$data.parents.get(itemKey) while (parentKey) { result.unshift((this as any).$data.itemCashe.get(parentKey)) parentKey = this.$data.parents.get(parentKey) } return result }, updateParents (itemKey: any) { this.$data.currentParentKey = this.$data.parents.get(itemKey) this.$data.currentParents = [] while (true) { const p = this.$data.parents.get(itemKey) if (p) { this.$data.currentParents.unshift(p) itemKey = p } else break } }, selectParent (item: object) { let itemKey = getObjectValueByPath(item, this.$props.itemKey, []) this.$data.currentParentKey = this.$data.parents.get(itemKey) this.$data.currentParents = [] while (true) { const p = this.$data.parents.get(itemKey) if (p) { this.$data.currentParents.unshift(p) itemKey = p } else break } } } })