@jgjergj/vuetify-toolkit
Version:
Vuetify.js Additional components set
325 lines (322 loc) • 11.3 kB
text/typescript
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
}
}
}
})