UNPKG

@jgjergj/vuetify-toolkit

Version:
403 lines (398 loc) 13.4 kB
import Vue, { VNode } from 'vue' import { VTreeviewNodeProps, getObjectValueByPath } from '../../vuetify-import' import { VCardA, VDividerA, VTreeviewA, VPaginationA, VRowA, VIconA } from '../../shims-vuetify' import VAdvDataTable from '../VAdvDataTable' import treeviewScopedSlots from '../../utils/TreeviewScopedSlots' import tableScopedSlots from '../../utils/TableScopedSlots' import { ScopedSlot } from 'vue/types/vnode' // eslint-disable-next-line @typescript-eslint/no-explicit-any const VDataTableProps = ((VAdvDataTable as any).options as any).props type ScopedSlotType = { [key: string]: ScopedSlot | undefined } /* @vue/component */ export default Vue.extend({ name: 'v-md-view', props: { ...VDataTableProps, ...VTreeviewNodeProps, multiple: { type: Boolean, default: false }, hierarchy: { type: Boolean, default: true }, folderIcon: { type: [String, Function], default: undefined }, folderOpenIcon: { type: [String, Function], default: undefined }, itemIcon: { type: [String, Function], default: undefined }, folderIconColor: { type: [String, Function], default: undefined }, itemIconColor: { type: [String, Function], default: undefined } }, data: () => ({ currentNode: null, openNodes: [] as any[], treeviewCashe: new Map(), parents: new Map(), currentPage: 1, x: 0, clientwidth: 0, treeWidth: 300, filteredTableItemsCount: 0 }), computed: { treeItems (): any[] { return this.buildTree(this.$props.items) }, tableHeaders (): any[] { if (this.$props.folderIcon || this.$props.folderOpenIcon || this.$props.itemIcon) { const iconHeader = { text: '', value: 'itemIcon', align: 'start', sortable: false, filterable: false, divider: false, width: 20 } return [iconHeader, ...this.$props.headers] } return this.$props.headers }, tableItems (): any[] { if (this.$props.hierarchy) { const currentItem = this.treeviewCashe.get(this.currentNode) return getObjectValueByPath(currentItem, this.$props.itemChildren, []) } else { const allItems: any[] = [] this.getAllItems(this.$props.items, allItems) return allItems } }, pageCount (): number { if (this.$props.itemsPerPage && Array.isArray(this.tableItems)) { if (this.$props.itemsPerPage < this.filteredTableItemsCount) { let res = Math.floor(this.filteredTableItemsCount / this.$props.itemsPerPage) res += (this.filteredTableItemsCount % this.$props.itemsPerPage) > 0 ? 1 : 0 return res } } return 0 }, tableWidth (): number { return this.clientwidth - 10 - this.treeWidth } }, methods: { buildTree (items: any, parentkey?: any): any[] { const newItems: any[] = [] items.map((item: any) => { const localChildren = getObjectValueByPath(item, this.$props.itemChildren, []) const itemKey = getObjectValueByPath(item, this.$props.itemKey, []) if (localChildren.length > 0) { const newChildren = this.buildTree(localChildren, itemKey) const clone = Object.assign({}, item) clone[this.$props.itemChildren] = newChildren newItems.push(clone) this.treeviewCashe.set(itemKey, item) this.parents.set(itemKey, parentkey) } else { this.parents.set(itemKey, parentkey) } }) return newItems }, getAllItems (items: any[], allItems: any[]) { items.map(item => { const localChildren = getObjectValueByPath(item, this.$props.itemChildren, []) if (localChildren.length > 0) { this.getAllItems(localChildren, allItems) } else { allItems.push(item) } }) }, updateTable (e: any[]) { if (this.$props.hierarchy) { this.currentNode = e[0] } }, genDivider (): VNode { return this.$createElement(VDividerA, { props: { vertical: true }, style: { cursor: 'col-resize', width: '10px' }, on: { mousedown: this.startResizing } }) }, /* resising parts of component */ updateDimensions () { const rect = this.$el.getBoundingClientRect() this.x = rect.x this.clientwidth = rect.width this.treeWidth = Math.min(this.clientwidth - 10, this.treeWidth) this.$nextTick() }, startResizing () { this.updateDimensions(); (this.$el as HTMLBaseElement).addEventListener('mousemove', this.Resizing) }, Resizing (e: MouseEvent) { (this.$el as HTMLBaseElement).style.cursor = 'col-resize' this.$el.addEventListener('mouselive', this.endResizing) this.$el.addEventListener('mouseup', this.endResizing) this.treeWidth = e.x - this.x }, endResizing () { (this.$el as HTMLBaseElement).removeEventListener('mousemove', this.Resizing); (this.$el as HTMLBaseElement).removeEventListener('mouselive', this.endResizing); (this.$el as HTMLBaseElement).removeEventListener('mouseup', this.endResizing); (this.$el as HTMLBaseElement).style.cursor = '' }, /* resising parts of component */ genPagination (): VNode| VNode[]| undefined { if (this.$props.itemsPerPage && Array.isArray(this.tableItems)) { // if (this.$props.itemsPerPage < this.tableItems.length) { if (this.$props.itemsPerPage < this.filteredTableItemsCount) { return [ this.$createElement(VDividerA, { props: { vertical: false } }), this.$createElement(VPaginationA, { ref: 'data-table-pagination', props: { length: this.pageCount, dark: this.$props.dark, value: this.currentPage }, style: { 'vertical-align': 'bottom' }, on: { input: (e: number) => { this.currentPage = e } } }) ] } } return undefined }, genItemIcon (item: any): VNode { const itemKey = getObjectValueByPath(item.item, this.$props.itemKey, []) let fn let color if (this.treeviewCashe.get(itemKey)) { if (this.openNodes.indexOf(itemKey) >= 0) { fn = this.$props.folderOpenIcon } else { fn = this.$props.folderIcon } color = this.$props.folderIconColor } else { fn = this.$props.itemIcon color = this.$props.itemIconColor } return this.$createElement(VIconA, { props: { color: color } }, fn) }, genTableScopedSlots (): ScopedSlotType { let slots = tableScopedSlots(this.$scopedSlots) if (this.$props.folderIcon || this.$props.folderOpenIcon || this.$props.itemIcon) { slots = Object.assign(slots, { 'item.itemIcon': this.genItemIcon }) } return slots as ScopedSlotType }, genTable (): VNode { const slots = [ 'body', 'body.append', 'body.prepend', 'footer', 'loading', 'no-data', 'no-results', 'header', 'progress', 'top' ] .filter(slotName => this.$slots[slotName]) .map(slotName => this.$createElement('template', { slot: slotName }, this.$slots[slotName])) const TableScopedSlots = this.genTableScopedSlots() return this.$createElement(VAdvDataTable, { ref: 'data-table', props: { selected: this.$props.selectable, dense: this.$props.dense, headers: this.tableHeaders, items: this.tableItems, itemsPerPage: this.$props.itemsPerPage, page: this.currentPage, hideDefaultFooter: true, showSelect: this.$props.selectable, singleSelect: !this.$props.multiple, headerIcon: this.$props.headerIcon, headerIconColor: this.$props.headerIconColor, upIcon: this.$props.upIcon, downIcon: this.$props.downIcon, filterIcon: this.$props.filterIcon, filterActiveIcon: this.$props.filterActiveIcon, filterSelectionIcon: this.$props.filterSelectionIcon, filterActiveIconColor: this.$props.filterActiveIconColor, sortIcon: this.$props.sortIcon }, style: { width: this.tableWidth + 'px' }, scopedSlots: TableScopedSlots, on: { 'click:row': (e: any) => this.synchronyzeActiveNode(e), 'items-count-change': (e: number) => { this.filteredTableItemsCount = e } } }, slots) }, getParents (key: number|string): any[] { const result = [] const parent = this.parents.get(key) if (parent) { result.push(parent) const p = this.getParents(parent) result.push(...p) } return result }, synchronyzeActiveNode (e: object) { const itemKey = getObjectValueByPath(e, this.$props.itemKey, []) this.currentNode = this.parents.get(itemKey) const parents = this.getParents(itemKey) this.openNodes.push(...parents) this.$nextTick(() => {}) }, genCombinedTreeViewSlot (props: any): VNode { if (this.$scopedSlots.prependTree) { return this.$createElement('div', {}, [this.genItemIcon(props), this.$scopedSlots.prependTree(props)] ) } else { return this.$createElement('div', {}, [this.genItemIcon(props)] ) } }, genTreeViewScopedSlots (): ScopedSlotType { let slots if (this.$scopedSlots.prependTree && (this.$props.folderIcon || this.$props.folderOpenIcon)) { // needs combined scoped slot slots = Object.assign({}, { prepend: this.genCombinedTreeViewSlot }) if (this.$scopedSlots.appendTree) { const slotAppend = this.$scopedSlots.appendTree slots = Object.assign({}, { append: (props: any) => slotAppend(props) }) } if (this.$scopedSlots.labelTree) { const slotLabel = this.$scopedSlots.labelTree slots = Object.assign({}, { label: (props: any) => slotLabel(props) }) } } else { slots = treeviewScopedSlots(this.$scopedSlots) } if (this.$props.folderIcon || this.$props.folderOpenIcon) { // if (!slots.prependTree) { // const slotPrepend = this.$scopedSlots.labelTree // slots = Object.assign(slots, { prepend: this.genItemIcon }) // } } return slots as ScopedSlotType }, genTreeView (): VNode { return this.$createElement(VTreeviewA, { ref: 'treeview', props: { dense: this.$props.dense, hoverable: this.$props.hoverable, multipleActive: false, search: this.$props.search, items: this.treeItems, active: [this.currentNode], activatable: true, activeClass: this.$props.activeClass, color: this.$props.color, expandIcon: this.$props.expandIcon, itemChildren: this.$props.itemChildren, itemDisabled: this.$props.itemDisabled, itemKey: this.$props.itemKey, itemText: this.$props.itemText, loadChildren: this.$props.loadChildren, loadingIcon: this.$props.loadingIcon, offIcon: this.$props.offIcon, onIcon: this.$props.onIcon, open: this.openNodes, openOnClick: this.$props.openOnClick, rounded: this.$props.rounded, selectable: false, selectedColor: this.$props.selectedColor, shaped: this.$props.shaped, transition: this.$props.transition }, style: { width: this.treeWidth + 'px', padding: '16px' }, scopedSlots: this.genTreeViewScopedSlots(), on: { 'update:active': this.updateTable, 'update:open': (e: any) => { this.openNodes = e } } }) } }, mounted () { window.addEventListener('resize', this.updateDimensions) window.addEventListener('load', this.updateDimensions) this.updateDimensions() }, beforeDestroy () { window.removeEventListener('resize', this.updateDimensions) window.removeEventListener('load', this.updateDimensions) }, render (): VNode { return this.$createElement(VCardA, {}, [ this.$createElement(VRowA, { props: { align: 'stretch' } }, [ this.genTreeView(), this.genDivider(), this.genTable() ]), this.genPagination() ]) } })