|
| 1 | +import omit from 'omit.js' |
| 2 | +import debounce from 'lodash/debounce' |
| 3 | +import PropTypes from '../_util/vue-types' |
| 4 | +import { conductExpandParent, convertTreeToEntities } from '../vc-tree/src/util' |
| 5 | +import Tree, { TreeProps } from './Tree' |
| 6 | +import { calcRangeKeys, getFullKeyList } from './util' |
| 7 | +import Icon from '../icon' |
| 8 | +import { initDefaultProps, getOptionProps } from '../_util/props-util' |
| 9 | + |
| 10 | +// export type ExpandAction = false | 'click' | 'doubleClick'; |
| 11 | + |
| 12 | +// export interface DirectoryTreeProps extends TreeProps { |
| 13 | +// expandAction?: ExpandAction; |
| 14 | +// } |
| 15 | + |
| 16 | +// export interface DirectoryTreeState { |
| 17 | +// expandedKeys?: string[]; |
| 18 | +// selectedKeys?: string[]; |
| 19 | +// } |
| 20 | + |
| 21 | +function getIcon (h, props) { |
| 22 | + const { isLeaf, expanded } = props |
| 23 | + if (isLeaf) { |
| 24 | + return <Icon type='file' /> |
| 25 | + } |
| 26 | + return <Icon type={expanded ? 'folder-open' : 'folder'} /> |
| 27 | +} |
| 28 | + |
| 29 | +export default { |
| 30 | + name: 'ADirectoryTree', |
| 31 | + model: { |
| 32 | + prop: 'checkedKeys', |
| 33 | + event: 'check', |
| 34 | + }, |
| 35 | + props: initDefaultProps({ ...TreeProps(), expandAction: PropTypes.oneOf([false, 'click', 'doubleClick']) }, { |
| 36 | + prefixCls: 'ant-tree', |
| 37 | + showIcon: true, |
| 38 | + expandAction: 'click', |
| 39 | + }), |
| 40 | + |
| 41 | + // state: DirectoryTreeState; |
| 42 | + // onDebounceExpand: (event, node: AntTreeNode) => void; |
| 43 | + |
| 44 | + // // Shift click usage |
| 45 | + // lastSelectedKey?: string; |
| 46 | + // cachedSelectedKeys?: string[]; |
| 47 | + |
| 48 | + data () { |
| 49 | + const props = getOptionProps(this) |
| 50 | + const { defaultExpandAll, defaultExpandParent, expandedKeys, defaultExpandedKeys } = props |
| 51 | + const { keyEntities } = convertTreeToEntities(this.$slots.default) |
| 52 | + const state = {} |
| 53 | + // Selected keys |
| 54 | + state._selectedKeys = props.selectedKeys || props.defaultSelectedKeys || [] |
| 55 | + |
| 56 | + // Expanded keys |
| 57 | + if (defaultExpandAll) { |
| 58 | + state._expandedKeys = getFullKeyList(props.children) |
| 59 | + } else if (defaultExpandParent) { |
| 60 | + state._expandedKeys = conductExpandParent(expandedKeys || defaultExpandedKeys, keyEntities) |
| 61 | + } else { |
| 62 | + state._expandedKeys = defaultExpandedKeys |
| 63 | + } |
| 64 | + |
| 65 | + this.onDebounceExpand = debounce(this.expandFolderNode, 200, { |
| 66 | + leading: true, |
| 67 | + }) |
| 68 | + return { |
| 69 | + _selectedKeys: [], |
| 70 | + _expandedKeys: [], |
| 71 | + ...state, |
| 72 | + } |
| 73 | + }, |
| 74 | + watch: { |
| 75 | + expandedKeys (val) { |
| 76 | + this.setState({ _expandedKeys: val }) |
| 77 | + }, |
| 78 | + selectedKeys (val) { |
| 79 | + this.setState({ _selectedKeys: val }) |
| 80 | + }, |
| 81 | + }, |
| 82 | + methods: { |
| 83 | + onExpand (expandedKeys, info) { |
| 84 | + this.setUncontrolledState({ _expandedKeys: expandedKeys }) |
| 85 | + |
| 86 | + this.$emit('expand', expandedKeys, info) |
| 87 | + |
| 88 | + return undefined |
| 89 | + }, |
| 90 | + |
| 91 | + onClick (event, node) { |
| 92 | + const { expandAction } = this.$props |
| 93 | + |
| 94 | + // Expand the tree |
| 95 | + if (expandAction === 'click') { |
| 96 | + this.onDebounceExpand(event, node) |
| 97 | + } |
| 98 | + this.$emit('click', event, node) |
| 99 | + }, |
| 100 | + |
| 101 | + onDoubleClick (event, node) { |
| 102 | + const { expandAction } = this.$props |
| 103 | + |
| 104 | + // Expand the tree |
| 105 | + if (expandAction === 'doubleClick') { |
| 106 | + this.onDebounceExpand(event, node) |
| 107 | + } |
| 108 | + |
| 109 | + this.$emit('doubleclick', event, node) |
| 110 | + }, |
| 111 | + |
| 112 | + onSelect (keys, event) { |
| 113 | + const { multiple } = this.$props |
| 114 | + const children = this.$slots.default || [] |
| 115 | + const { _expandedKeys: expandedKeys = [], _selectedKeys: selectedKeys = [] } = this.$data |
| 116 | + const { node, nativeEvent } = event |
| 117 | + const { eventKey = '' } = node |
| 118 | + |
| 119 | + const newState = {} |
| 120 | + |
| 121 | + // Windows / Mac single pick |
| 122 | + const ctrlPick = nativeEvent.ctrlKey || nativeEvent.metaKey |
| 123 | + const shiftPick = nativeEvent.shiftKey |
| 124 | + |
| 125 | + // Generate new selected keys |
| 126 | + let newSelectedKeys = selectedKeys.slice() |
| 127 | + if (multiple && ctrlPick) { |
| 128 | + // Control click |
| 129 | + newSelectedKeys = keys |
| 130 | + this.lastSelectedKey = eventKey |
| 131 | + this.cachedSelectedKeys = newSelectedKeys |
| 132 | + } else if (multiple && shiftPick) { |
| 133 | + // Shift click |
| 134 | + newSelectedKeys = Array.from(new Set([ |
| 135 | + ...this.cachedSelectedKeys || [], |
| 136 | + ...calcRangeKeys(children, expandedKeys, eventKey, this.lastSelectedKey), |
| 137 | + ])) |
| 138 | + } else { |
| 139 | + // Single click |
| 140 | + newSelectedKeys = [eventKey] |
| 141 | + this.lastSelectedKey = eventKey |
| 142 | + this.cachedSelectedKeys = newSelectedKeys |
| 143 | + } |
| 144 | + newState._selectedKeys = newSelectedKeys |
| 145 | + |
| 146 | + this.$emit('select', newSelectedKeys, event) |
| 147 | + |
| 148 | + this.setUncontrolledState(newState) |
| 149 | + }, |
| 150 | + |
| 151 | + expandFolderNode (event, node) { |
| 152 | + const { _expandedKeys: expandedKeys = [] } = this.$data |
| 153 | + const { eventKey = '', expanded, isLeaf } = node |
| 154 | + |
| 155 | + if (isLeaf || event.shiftKey || event.metaKey || event.ctrlKey) { |
| 156 | + return |
| 157 | + } |
| 158 | + |
| 159 | + const newExpandedKeys = expandedKeys.slice() |
| 160 | + const index = newExpandedKeys.indexOf(eventKey) |
| 161 | + |
| 162 | + if (expanded && index >= 0) { |
| 163 | + newExpandedKeys.splice(index, 1) |
| 164 | + } else if (!expanded && index === -1) { |
| 165 | + newExpandedKeys.push(eventKey) |
| 166 | + } |
| 167 | + |
| 168 | + this.setUncontrolledState({ |
| 169 | + _expandedKeys: newExpandedKeys, |
| 170 | + }) |
| 171 | + this.$emit('expand', newExpandedKeys, { |
| 172 | + expanded: !expanded, |
| 173 | + node, |
| 174 | + nativeEvent: event.nativeEvent, |
| 175 | + }) |
| 176 | + }, |
| 177 | + |
| 178 | + setUncontrolledState (state) { |
| 179 | + const newState = omit(state, Object.keys(getOptionProps(this)).map(p => `_${p}`)) |
| 180 | + if (Object.keys(newState).length) { |
| 181 | + this.setState(newState) |
| 182 | + } |
| 183 | + }, |
| 184 | + }, |
| 185 | + |
| 186 | + render () { |
| 187 | + const { prefixCls, ...props } = getOptionProps(this) |
| 188 | + const { _expandedKeys: expandedKeys, _selectedKeys: selectedKeys } = this.$data |
| 189 | + const treeProps = { |
| 190 | + props: { |
| 191 | + icon: getIcon, |
| 192 | + ...props, |
| 193 | + prefixCls, |
| 194 | + expandedKeys, |
| 195 | + selectedKeys, |
| 196 | + }, |
| 197 | + class: `${prefixCls}-directory`, |
| 198 | + select: this.onSelect, |
| 199 | + click: this.onClick, |
| 200 | + doubleclick: this.onDoubleClick, |
| 201 | + expand: this.onExpand, |
| 202 | + } |
| 203 | + return ( |
| 204 | + <Tree {...treeProps}>{this.$slots.default}</Tree> |
| 205 | + ) |
| 206 | + }, |
| 207 | +} |
0 commit comments