2018-03-23 13:30:20 +00:00
|
|
|
import PropTypes from '../../_util/vue-types'
|
|
|
|
import classNames from 'classnames'
|
|
|
|
import warning from 'warning'
|
2018-09-05 13:28:54 +00:00
|
|
|
import { getPosition, getNodeChildren, isCheckDisabled, traverseTreeNodes, mapChildren } from './util'
|
2018-04-13 10:58:58 +00:00
|
|
|
import { initDefaultProps, getOptionProps, filterEmpty, getComponentFromProp } from '../../_util/props-util'
|
2018-03-24 09:12:22 +00:00
|
|
|
import BaseMixin from '../../_util/BaseMixin'
|
|
|
|
import getTransitionProps from '../../_util/getTransitionProps'
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-09-05 13:28:54 +00:00
|
|
|
function noop () {}
|
2018-03-23 13:30:20 +00:00
|
|
|
const ICON_OPEN = 'open'
|
|
|
|
const ICON_CLOSE = 'close'
|
|
|
|
|
|
|
|
const defaultTitle = '---'
|
|
|
|
|
|
|
|
let onlyTreeNodeWarned = false // Only accept TreeNode
|
|
|
|
|
|
|
|
const TreeNode = {
|
2018-03-24 09:12:22 +00:00
|
|
|
name: 'TreeNode',
|
|
|
|
mixins: [BaseMixin],
|
2018-07-11 09:51:20 +00:00
|
|
|
__ANT_TREE_NODE: true,
|
2018-03-23 13:30:20 +00:00
|
|
|
props: initDefaultProps({
|
|
|
|
eventKey: PropTypes.string, // Pass by parent `cloneElement`
|
|
|
|
prefixCls: PropTypes.string,
|
|
|
|
// className: PropTypes.string,
|
|
|
|
root: PropTypes.object,
|
|
|
|
// onSelect: PropTypes.func,
|
|
|
|
|
|
|
|
// By parent
|
|
|
|
expanded: PropTypes.bool,
|
|
|
|
selected: PropTypes.bool,
|
|
|
|
checked: PropTypes.bool,
|
2018-09-05 13:28:54 +00:00
|
|
|
loaded: PropTypes.bool,
|
|
|
|
loading: PropTypes.bool,
|
2018-03-23 13:30:20 +00:00
|
|
|
halfChecked: PropTypes.bool,
|
2018-03-24 09:12:22 +00:00
|
|
|
title: PropTypes.any,
|
2018-03-23 13:30:20 +00:00
|
|
|
pos: PropTypes.string,
|
|
|
|
dragOver: PropTypes.bool,
|
|
|
|
dragOverGapTop: PropTypes.bool,
|
|
|
|
dragOverGapBottom: PropTypes.bool,
|
|
|
|
|
|
|
|
// By user
|
|
|
|
isLeaf: PropTypes.bool,
|
|
|
|
selectable: PropTypes.bool,
|
|
|
|
disabled: PropTypes.bool,
|
|
|
|
disableCheckbox: PropTypes.bool,
|
|
|
|
icon: PropTypes.any,
|
2018-04-13 10:58:58 +00:00
|
|
|
dataRef: PropTypes.object,
|
|
|
|
}, {}),
|
2018-03-23 13:30:20 +00:00
|
|
|
|
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
dragNodeHighlight: false,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
inject: {
|
2018-03-24 09:12:22 +00:00
|
|
|
vcTree: { default: {}},
|
2018-04-11 13:25:16 +00:00
|
|
|
vcTreeNode: { default: {}},
|
2018-03-23 13:30:20 +00:00
|
|
|
},
|
2018-03-24 09:12:22 +00:00
|
|
|
provide () {
|
|
|
|
return {
|
|
|
|
vcTreeNode: this,
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
// Isomorphic needn't load data in server side
|
|
|
|
mounted () {
|
2018-03-24 09:12:22 +00:00
|
|
|
this.syncLoadData(this.$props)
|
2018-03-23 13:30:20 +00:00
|
|
|
},
|
2018-03-24 09:12:22 +00:00
|
|
|
watch: {
|
|
|
|
expanded (val) {
|
|
|
|
this.syncLoadData({ expanded: val })
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
},
|
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
methods: {
|
2018-09-05 13:28:54 +00:00
|
|
|
onUpCheckConduct (treeNode, nodeChecked, nodeHalfChecked, e) {
|
2018-03-24 09:12:22 +00:00
|
|
|
const { pos: nodePos } = getOptionProps(treeNode)
|
|
|
|
const { eventKey, pos, checked, halfChecked } = this
|
|
|
|
const {
|
|
|
|
vcTree: { checkStrictly, isKeyChecked, onBatchNodeCheck, onCheckConductFinished },
|
|
|
|
vcTreeNode: { onUpCheckConduct } = {},
|
|
|
|
} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Stop conduct when current node is disabled
|
|
|
|
if (isCheckDisabled(this)) {
|
2018-09-05 13:28:54 +00:00
|
|
|
onCheckConductFinished(e)
|
2018-03-23 13:30:20 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
const children = this.getNodeChildren()
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
let checkedCount = nodeChecked ? 1 : 0
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Statistic checked count
|
|
|
|
children.forEach((node, index) => {
|
|
|
|
const childPos = getPosition(pos, index)
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (nodePos === childPos || isCheckDisabled(node)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (isKeyChecked(node.key || childPos)) {
|
|
|
|
checkedCount += 1
|
|
|
|
}
|
|
|
|
})
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Static enabled children count
|
|
|
|
const enabledChildrenCount = children
|
|
|
|
.filter(node => !isCheckDisabled(node))
|
|
|
|
.length
|
|
|
|
|
|
|
|
// checkStrictly will not conduct check status
|
|
|
|
const nextChecked = checkStrictly ? checked : enabledChildrenCount === checkedCount
|
|
|
|
const nextHalfChecked = checkStrictly // propagated or child checked
|
|
|
|
? halfChecked : (nodeHalfChecked || (checkedCount > 0 && !nextChecked))
|
|
|
|
|
|
|
|
// Add into batch update
|
|
|
|
if (checked !== nextChecked || halfChecked !== nextHalfChecked) {
|
|
|
|
onBatchNodeCheck(eventKey, nextChecked, nextHalfChecked)
|
|
|
|
|
|
|
|
if (onUpCheckConduct) {
|
2018-09-05 13:28:54 +00:00
|
|
|
onUpCheckConduct(this, nextChecked, nextHalfChecked, e)
|
2018-03-24 09:12:22 +00:00
|
|
|
} else {
|
|
|
|
// Flush all the update
|
2018-09-05 13:28:54 +00:00
|
|
|
onCheckConductFinished(e)
|
2018-03-24 09:12:22 +00:00
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
} else {
|
|
|
|
// Flush all the update
|
2018-09-05 13:28:54 +00:00
|
|
|
onCheckConductFinished(e)
|
2018-03-23 13:30:20 +00:00
|
|
|
}
|
2018-03-24 09:12:22 +00:00
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onDownCheckConduct (nodeChecked) {
|
|
|
|
const { $slots } = this
|
|
|
|
const children = $slots.default || []
|
|
|
|
const { vcTree: { checkStrictly, isKeyChecked, onBatchNodeCheck }} = this
|
|
|
|
if (checkStrictly) return
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
traverseTreeNodes(children, ({ node, key }) => {
|
|
|
|
if (isCheckDisabled(node)) return false
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (nodeChecked !== isKeyChecked(key)) {
|
|
|
|
onBatchNodeCheck(key, nodeChecked, false)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onSelectorClick (e) {
|
2018-09-05 13:28:54 +00:00
|
|
|
// Click trigger before select/check operation
|
|
|
|
const { vcTree: { onNodeClick }} = this
|
|
|
|
onNodeClick(e, this)
|
2018-03-24 09:12:22 +00:00
|
|
|
if (this.isSelectable()) {
|
|
|
|
this.onSelect(e)
|
|
|
|
} else {
|
|
|
|
this.onCheck(e)
|
|
|
|
}
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-09-05 13:28:54 +00:00
|
|
|
onSelectorDoubleClick (e) {
|
|
|
|
const { vcTree: { onNodeDoubleClick }} = this
|
|
|
|
onNodeDoubleClick(e, this)
|
|
|
|
},
|
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onSelect (e) {
|
|
|
|
if (this.isDisabled()) return
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
const { vcTree: { onNodeSelect }} = this
|
|
|
|
e.preventDefault()
|
|
|
|
onNodeSelect(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onCheck (e) {
|
|
|
|
if (this.isDisabled()) return
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
const { disableCheckbox, checked, eventKey } = this
|
|
|
|
const {
|
|
|
|
vcTree: { checkable, onBatchNodeCheck, onCheckConductFinished },
|
|
|
|
vcTreeNode: { onUpCheckConduct } = {},
|
|
|
|
} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (!checkable || disableCheckbox) return
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
e.preventDefault()
|
|
|
|
const targetChecked = !checked
|
|
|
|
onBatchNodeCheck(eventKey, targetChecked, false, this)
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Children conduct
|
|
|
|
this.onDownCheckConduct(targetChecked)
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Parent conduct
|
|
|
|
if (onUpCheckConduct) {
|
2018-09-05 13:28:54 +00:00
|
|
|
onUpCheckConduct(this, targetChecked, false, e)
|
2018-03-24 09:12:22 +00:00
|
|
|
} else {
|
2018-09-05 13:28:54 +00:00
|
|
|
onCheckConductFinished(e)
|
2018-03-24 09:12:22 +00:00
|
|
|
}
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onMouseEnter (e) {
|
|
|
|
const { vcTree: { onNodeMouseEnter }} = this
|
|
|
|
onNodeMouseEnter(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onMouseLeave (e) {
|
|
|
|
const { vcTree: { onNodeMouseLeave }} = this
|
|
|
|
onNodeMouseLeave(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onContextMenu (e) {
|
|
|
|
const { vcTree: { onNodeContextMenu }} = this
|
|
|
|
onNodeContextMenu(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onDragStart (e) {
|
|
|
|
const { vcTree: { onNodeDragStart }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
e.stopPropagation()
|
|
|
|
this.setState({
|
|
|
|
dragNodeHighlight: true,
|
|
|
|
})
|
|
|
|
onNodeDragStart(e, this)
|
|
|
|
|
|
|
|
try {
|
|
|
|
// ie throw error
|
|
|
|
// firefox-need-it
|
|
|
|
e.dataTransfer.setData('text/plain', '')
|
|
|
|
} catch (error) {
|
|
|
|
// empty
|
|
|
|
}
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onDragEnter (e) {
|
|
|
|
const { vcTree: { onNodeDragEnter }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
e.preventDefault()
|
|
|
|
e.stopPropagation()
|
|
|
|
onNodeDragEnter(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onDragOver (e) {
|
|
|
|
const { vcTree: { onNodeDragOver }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
e.preventDefault()
|
|
|
|
e.stopPropagation()
|
|
|
|
onNodeDragOver(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onDragLeave (e) {
|
|
|
|
const { vcTree: { onNodeDragLeave }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
e.stopPropagation()
|
|
|
|
onNodeDragLeave(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onDragEnd (e) {
|
|
|
|
const { vcTree: { onNodeDragEnd }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
e.stopPropagation()
|
|
|
|
this.setState({
|
|
|
|
dragNodeHighlight: false,
|
|
|
|
})
|
|
|
|
onNodeDragEnd(e, this)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
onDrop (e) {
|
|
|
|
const { vcTree: { onNodeDrop }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
e.preventDefault()
|
|
|
|
e.stopPropagation()
|
|
|
|
this.setState({
|
|
|
|
dragNodeHighlight: false,
|
2018-03-23 13:30:20 +00:00
|
|
|
})
|
2018-03-24 09:12:22 +00:00
|
|
|
onNodeDrop(e, this)
|
|
|
|
},
|
|
|
|
|
|
|
|
// Disabled item still can be switch
|
|
|
|
onExpand (e) {
|
|
|
|
const { vcTree: { onNodeExpand }} = this
|
2018-09-05 13:28:54 +00:00
|
|
|
onNodeExpand(e, this)
|
2018-03-24 09:12:22 +00:00
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
getNodeChildren () {
|
|
|
|
const { $slots: { default: children }} = this
|
|
|
|
const originList = filterEmpty(children)
|
|
|
|
const targetList = getNodeChildren(originList)
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (originList.length !== targetList.length && !onlyTreeNodeWarned) {
|
|
|
|
onlyTreeNodeWarned = true
|
|
|
|
warning(false, 'Tree only accept TreeNode as children.')
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return targetList
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
getNodeState () {
|
|
|
|
const { expanded } = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (this.isLeaf2()) {
|
|
|
|
return null
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return expanded ? ICON_OPEN : ICON_CLOSE
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
isLeaf2 () {
|
2018-09-05 13:28:54 +00:00
|
|
|
const { isLeaf, loaded } = this
|
2018-03-24 09:12:22 +00:00
|
|
|
const { vcTree: { loadData }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
const hasChildren = this.getNodeChildren().length !== 0
|
2018-09-05 13:28:54 +00:00
|
|
|
if (isLeaf === false) {
|
|
|
|
return false
|
|
|
|
}
|
2018-03-24 09:12:22 +00:00
|
|
|
return (
|
|
|
|
isLeaf ||
|
|
|
|
(!loadData && !hasChildren) ||
|
2018-09-05 13:28:54 +00:00
|
|
|
(loadData && loaded && !hasChildren)
|
2018-03-24 09:12:22 +00:00
|
|
|
)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
isDisabled () {
|
|
|
|
const { disabled } = this
|
|
|
|
const { vcTree: { disabled: treeDisabled }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Follow the logic of Selectable
|
|
|
|
if (disabled === false) {
|
|
|
|
return false
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return !!(treeDisabled || disabled)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
isSelectable () {
|
|
|
|
const { selectable } = this
|
|
|
|
const { vcTree: { selectable: treeSelectable }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Ignore when selectable is undefined or null
|
|
|
|
if (typeof selectable === 'boolean') {
|
|
|
|
return selectable
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return treeSelectable
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Load data to avoid default expanded tree without data
|
|
|
|
syncLoadData (props) {
|
2018-04-11 13:25:16 +00:00
|
|
|
const { expanded } = this
|
2018-09-05 13:28:54 +00:00
|
|
|
const { vcTree: { onNodeLoad }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-04-11 13:25:16 +00:00
|
|
|
// read from state to avoid loadData at same time
|
2018-09-05 13:28:54 +00:00
|
|
|
if (expanded && !this.isLeaf2()) {
|
|
|
|
// We needn't reload data when has children in sync logic
|
|
|
|
// It's only needed in node expanded
|
|
|
|
const hasChildren = this.getNodeChildren().length !== 0
|
|
|
|
if (!hasChildren) {
|
|
|
|
onNodeLoad(this)
|
2018-04-11 13:25:16 +00:00
|
|
|
}
|
2018-09-05 13:28:54 +00:00
|
|
|
}
|
2018-03-24 09:12:22 +00:00
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Switcher
|
|
|
|
renderSwitcher () {
|
|
|
|
const { expanded } = this
|
|
|
|
const { vcTree: { prefixCls }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (this.isLeaf2()) {
|
|
|
|
return <span class={`${prefixCls}-switcher ${prefixCls}-switcher-noop`} />
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return (
|
|
|
|
<span
|
|
|
|
class={classNames(
|
|
|
|
`${prefixCls}-switcher`,
|
|
|
|
`${prefixCls}-switcher_${expanded ? ICON_OPEN : ICON_CLOSE}`,
|
|
|
|
)}
|
|
|
|
onClick={this.onExpand}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Checkbox
|
|
|
|
renderCheckbox () {
|
|
|
|
const { checked, halfChecked, disableCheckbox } = this
|
|
|
|
const { vcTree: { prefixCls, checkable }} = this
|
|
|
|
const disabled = this.isDisabled()
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (!checkable) return null
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// [Legacy] Custom element should be separate with `checkable` in future
|
|
|
|
const $custom = typeof checkable !== 'boolean' ? checkable : null
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return (
|
|
|
|
<span
|
|
|
|
class={classNames(
|
|
|
|
`${prefixCls}-checkbox`,
|
|
|
|
checked && `${prefixCls}-checkbox-checked`,
|
|
|
|
!checked && halfChecked && `${prefixCls}-checkbox-indeterminate`,
|
|
|
|
(disabled || disableCheckbox) && `${prefixCls}-checkbox-disabled`,
|
|
|
|
)}
|
|
|
|
onClick={this.onCheck}
|
|
|
|
>
|
|
|
|
{$custom}
|
|
|
|
</span>
|
|
|
|
)
|
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
renderIcon () {
|
2018-09-05 13:28:54 +00:00
|
|
|
const { loading } = this
|
2018-03-24 09:12:22 +00:00
|
|
|
const { vcTree: { prefixCls }} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return (
|
|
|
|
<span
|
|
|
|
class={classNames(
|
|
|
|
`${prefixCls}-iconEle`,
|
|
|
|
`${prefixCls}-icon__${this.getNodeState() || 'docu'}`,
|
2018-09-05 13:28:54 +00:00
|
|
|
loading && `${prefixCls}-icon_loading`,
|
2018-03-24 09:12:22 +00:00
|
|
|
)}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
},
|
|
|
|
|
|
|
|
// Icon + Title
|
|
|
|
renderSelector () {
|
2018-09-05 13:28:54 +00:00
|
|
|
const { selected, icon, loading, dragNodeHighlight, $scopedSlots } = this
|
2018-04-13 10:58:58 +00:00
|
|
|
const { vcTree: { prefixCls, showIcon, draggable, loadData }} = this
|
2018-03-24 09:12:22 +00:00
|
|
|
const disabled = this.isDisabled()
|
2018-04-13 10:58:58 +00:00
|
|
|
const title = getComponentFromProp(this, 'title') || defaultTitle
|
|
|
|
const treeIcon = getComponentFromProp(this, 'icon') || $scopedSlots.icon
|
2018-03-24 09:12:22 +00:00
|
|
|
const wrapClass = `${prefixCls}-node-content-wrapper`
|
|
|
|
|
|
|
|
// Icon - Still show loading icon when loading without showIcon
|
|
|
|
let $icon
|
|
|
|
|
|
|
|
if (showIcon) {
|
2018-04-11 13:25:16 +00:00
|
|
|
const currentIcon = icon || treeIcon
|
|
|
|
$icon = currentIcon ? (
|
2018-03-24 09:12:22 +00:00
|
|
|
<span
|
|
|
|
class={classNames(
|
|
|
|
`${prefixCls}-iconEle`,
|
|
|
|
`${prefixCls}-icon__customize`,
|
|
|
|
)}
|
|
|
|
>
|
2018-04-11 13:25:16 +00:00
|
|
|
{typeof currentIcon === 'function'
|
2018-09-05 13:28:54 +00:00
|
|
|
? currentIcon({ ...this.$props }) : currentIcon}
|
2018-03-24 09:12:22 +00:00
|
|
|
</span>
|
|
|
|
) : this.renderIcon()
|
2018-09-05 13:28:54 +00:00
|
|
|
} else if (loadData && loading) {
|
2018-03-24 09:12:22 +00:00
|
|
|
$icon = this.renderIcon()
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Title
|
|
|
|
const $title = <span class={`${prefixCls}-title`}>{title}</span>
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return (
|
2018-03-23 13:30:20 +00:00
|
|
|
<span
|
2018-03-24 09:12:22 +00:00
|
|
|
ref='selectHandle'
|
|
|
|
title={typeof title === 'string' ? title : ''}
|
2018-03-23 13:30:20 +00:00
|
|
|
class={classNames(
|
2018-03-24 09:12:22 +00:00
|
|
|
`${wrapClass}`,
|
|
|
|
`${wrapClass}-${this.getNodeState() || 'normal'}`,
|
|
|
|
(!disabled && (selected || dragNodeHighlight)) && `${prefixCls}-node-selected`,
|
|
|
|
(!disabled && draggable) && 'draggable'
|
2018-03-23 13:30:20 +00:00
|
|
|
)}
|
2018-03-24 09:12:22 +00:00
|
|
|
draggable={(!disabled && draggable) || undefined}
|
|
|
|
aria-grabbed={(!disabled && draggable) || undefined}
|
|
|
|
onMouseenter={this.onMouseEnter}
|
|
|
|
onMouseleave={this.onMouseLeave}
|
2018-04-12 14:04:55 +00:00
|
|
|
onContextmenu={this.onContextMenu}
|
2018-03-24 09:12:22 +00:00
|
|
|
onClick={this.onSelectorClick}
|
2018-09-05 13:28:54 +00:00
|
|
|
onDoubleclick={this.onSelectorDoubleClick}
|
|
|
|
onDragstart={draggable ? this.onDragStart : noop}
|
2018-03-23 13:30:20 +00:00
|
|
|
>
|
2018-03-24 09:12:22 +00:00
|
|
|
{$icon}{$title}
|
2018-03-23 13:30:20 +00:00
|
|
|
</span>
|
2018-03-24 09:12:22 +00:00
|
|
|
)
|
|
|
|
},
|
|
|
|
|
|
|
|
// Children list wrapped with `Animation`
|
|
|
|
renderChildren () {
|
|
|
|
const { expanded, pos } = this
|
|
|
|
const { vcTree: {
|
|
|
|
prefixCls,
|
|
|
|
openTransitionName, openAnimation,
|
|
|
|
renderTreeNode,
|
|
|
|
}} = this
|
|
|
|
|
|
|
|
// [Legacy] Animation control
|
|
|
|
const renderFirst = this.renderFirst
|
|
|
|
this.renderFirst = 1
|
|
|
|
let transitionAppear = true
|
|
|
|
if (!renderFirst && expanded) {
|
|
|
|
transitionAppear = false
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
let animProps = {}
|
|
|
|
if (openTransitionName) {
|
|
|
|
animProps = getTransitionProps(openTransitionName, { appear: transitionAppear })
|
|
|
|
} else if (typeof openAnimation === 'object') {
|
|
|
|
animProps = { ...openAnimation }
|
2018-04-11 13:25:16 +00:00
|
|
|
animProps.props = { css: false, ...animProps.props }
|
2018-03-24 09:12:22 +00:00
|
|
|
if (!transitionAppear) {
|
|
|
|
delete animProps.props.appear
|
|
|
|
}
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
// Children TreeNode
|
|
|
|
const nodeList = this.getNodeChildren()
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
if (nodeList.length === 0) {
|
|
|
|
return null
|
2018-03-23 13:30:20 +00:00
|
|
|
}
|
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
let $children
|
|
|
|
if (expanded) {
|
|
|
|
$children = (
|
|
|
|
<ul
|
|
|
|
class={classNames(
|
|
|
|
`${prefixCls}-child-tree`,
|
|
|
|
expanded && `${prefixCls}-child-tree-open`,
|
|
|
|
)}
|
|
|
|
data-expanded={expanded}
|
|
|
|
>
|
2018-09-05 13:28:54 +00:00
|
|
|
{mapChildren(nodeList, (node, index) => (
|
2018-03-24 09:12:22 +00:00
|
|
|
renderTreeNode(node, index, pos)
|
|
|
|
))}
|
|
|
|
</ul>
|
|
|
|
)
|
|
|
|
}
|
2018-03-23 13:30:20 +00:00
|
|
|
|
2018-03-24 09:12:22 +00:00
|
|
|
return (
|
|
|
|
<transition
|
|
|
|
{...animProps}
|
2018-03-23 13:30:20 +00:00
|
|
|
>
|
2018-03-24 09:12:22 +00:00
|
|
|
{$children}
|
|
|
|
</transition>
|
2018-03-23 13:30:20 +00:00
|
|
|
)
|
2018-03-24 09:12:22 +00:00
|
|
|
},
|
2018-03-23 13:30:20 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
render () {
|
|
|
|
const {
|
|
|
|
dragOver, dragOverGapTop, dragOverGapBottom,
|
2018-09-05 13:28:54 +00:00
|
|
|
isLeaf,
|
|
|
|
expanded, selected, checked, halfChecked, loading,
|
|
|
|
} = this.$props
|
2018-03-24 09:12:22 +00:00
|
|
|
const { vcTree: {
|
2018-03-23 13:30:20 +00:00
|
|
|
prefixCls,
|
|
|
|
filterTreeNode,
|
2018-09-05 13:28:54 +00:00
|
|
|
draggable,
|
2018-03-24 09:12:22 +00:00
|
|
|
}} = this
|
2018-03-23 13:30:20 +00:00
|
|
|
const disabled = this.isDisabled()
|
|
|
|
return (
|
|
|
|
<li
|
|
|
|
class={{
|
|
|
|
[`${prefixCls}-treenode-disabled`]: disabled,
|
2018-09-05 13:28:54 +00:00
|
|
|
[`${prefixCls}-treenode-switcher-${expanded ? 'open' : 'close'}`]: !isLeaf,
|
|
|
|
[`${prefixCls}-treenode-checkbox-checked`]: checked,
|
|
|
|
[`${prefixCls}-treenode-checkbox-indeterminate`]: halfChecked,
|
|
|
|
[`${prefixCls}-treenode-selected`]: selected,
|
|
|
|
[`${prefixCls}-treenode-loading`]: loading,
|
2018-03-23 13:30:20 +00:00
|
|
|
'drag-over': !disabled && dragOver,
|
|
|
|
'drag-over-gap-top': !disabled && dragOverGapTop,
|
|
|
|
'drag-over-gap-bottom': !disabled && dragOverGapBottom,
|
|
|
|
'filter-node': filterTreeNode && filterTreeNode(this),
|
|
|
|
}}
|
2018-09-05 13:28:54 +00:00
|
|
|
onDragenter={draggable ? this.onDragEnter : noop}
|
|
|
|
onDragover={draggable ? this.onDragOver : noop}
|
|
|
|
onDragleave={draggable ? this.onDragLeave : noop}
|
|
|
|
onDrop={draggable ? this.onDrop : noop}
|
|
|
|
onDragend={draggable ? this.onDragEnd : noop}
|
2018-03-23 13:30:20 +00:00
|
|
|
>
|
|
|
|
{this.renderSwitcher()}
|
|
|
|
{this.renderCheckbox()}
|
|
|
|
{this.renderSelector()}
|
|
|
|
{this.renderChildren()}
|
|
|
|
</li>
|
|
|
|
)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
TreeNode.isTreeNode = 1
|
|
|
|
|
|
|
|
export default TreeNode
|