UNPKG

element-plus

Version:

A Component Library for Vue3.0

1,603 lines (1,587 loc) 50.1 kB
import { reactive, defineComponent, inject, h, provide, ref, getCurrentInstance, watch, nextTick, resolveComponent, withDirectives, openBlock, createBlock, withModifiers, createVNode, createCommentVNode, withCtx, Fragment, renderList, vShow, onMounted, onBeforeUnmount, onUpdated, computed, toDisplayString } from 'vue'; import ElCollapseTransition from '../el-collapse-transition'; import ElCheckbox from '../el-checkbox'; import mitt from 'mitt'; import { removeClass, addClass, on, off } from '../utils/dom'; import { EVENT_CODE } from '../utils/aria'; import { t } from '../locale'; /** * Make a map and return a function for checking if a key * is in that map. * IMPORTANT: all calls of this function must be prefixed with * \/\*#\_\_PURE\_\_\*\/ * So that rollup can tree-shake them if necessary. */ const EMPTY_OBJ = (process.env.NODE_ENV !== 'production') ? Object.freeze({}) : {}; const EMPTY_ARR = (process.env.NODE_ENV !== 'production') ? Object.freeze([]) : []; const hasOwnProperty = Object.prototype.hasOwnProperty; const hasOwn = (val, key) => hasOwnProperty.call(val, key); const NODE_KEY = "$treeNodeId"; const markNodeData = function(node, data) { if (!data || data[NODE_KEY]) return; Object.defineProperty(data, NODE_KEY, { value: node.id, enumerable: false, configurable: false, writable: false }); }; const getNodeKey = function(key, data) { if (!key) return data[NODE_KEY]; return data[key]; }; const getChildState = (node) => { let all = true; let none = true; let allWithoutDisable = true; for (let i = 0, j = node.length; i < j; i++) { const n = node[i]; if (n.checked !== true || n.indeterminate) { all = false; if (!n.disabled) { allWithoutDisable = false; } } if (n.checked !== false || n.indeterminate) { none = false; } } return { all, none, allWithoutDisable, half: !all && !none }; }; const reInitChecked = function(node) { if (node.childNodes.length === 0) return; const { all, none, half } = getChildState(node.childNodes); if (all) { node.checked = true; node.indeterminate = false; } else if (half) { node.checked = false; node.indeterminate = true; } else if (none) { node.checked = false; node.indeterminate = false; } const parent = node.parent; if (!parent || parent.level === 0) return; if (!node.store.checkStrictly) { reInitChecked(parent); } }; const getPropertyFromData = function(node, prop) { const props = node.store.props; const data = node.data || {}; const config = props[prop]; if (typeof config === "function") { return config(data, node); } else if (typeof config === "string") { return data[config]; } else if (typeof config === "undefined") { const dataProp = data[prop]; return dataProp === void 0 ? "" : dataProp; } }; let nodeIdSeed = 0; class Node { constructor(options) { this.id = nodeIdSeed++; this.text = null; this.checked = false; this.indeterminate = false; this.data = null; this.expanded = false; this.parent = null; this.visible = true; this.isCurrent = false; this.canFocus = false; for (const name in options) { if (hasOwn(options, name)) { this[name] = options[name]; } } this.level = 0; this.loaded = false; this.childNodes = []; this.loading = false; if (this.parent) { this.level = this.parent.level + 1; } } initialize() { const store = this.store; if (!store) { throw new Error("[Node]store is required!"); } store.registerNode(this); const props = store.props; if (props && typeof props.isLeaf !== "undefined") { const isLeaf = getPropertyFromData(this, "isLeaf"); if (typeof isLeaf === "boolean") { this.isLeafByUser = isLeaf; } } if (store.lazy !== true && this.data) { this.setData(this.data); if (store.defaultExpandAll) { this.expanded = true; this.canFocus = true; } } else if (this.level > 0 && store.lazy && store.defaultExpandAll) { this.expand(); } if (!Array.isArray(this.data)) { markNodeData(this, this.data); } if (!this.data) return; const defaultExpandedKeys = store.defaultExpandedKeys; const key = store.key; if (key && defaultExpandedKeys && defaultExpandedKeys.indexOf(this.key) !== -1) { this.expand(null, store.autoExpandParent); } if (key && store.currentNodeKey !== void 0 && this.key === store.currentNodeKey) { store.currentNode = this; store.currentNode.isCurrent = true; } if (store.lazy) { store._initDefaultCheckedNode(this); } this.updateLeafState(); if (this.parent && (this.level === 1 || this.parent.expanded === true)) this.canFocus = true; } setData(data) { if (!Array.isArray(data)) { markNodeData(this, data); } this.data = data; this.childNodes = []; let children; if (this.level === 0 && this.data instanceof Array) { children = this.data; } else { children = getPropertyFromData(this, "children") || []; } for (let i = 0, j = children.length; i < j; i++) { this.insertChild({ data: children[i] }); } } get label() { return getPropertyFromData(this, "label"); } get key() { const nodeKey = this.store.key; if (this.data) return this.data[nodeKey]; return null; } get disabled() { return getPropertyFromData(this, "disabled"); } get nextSibling() { const parent = this.parent; if (parent) { const index = parent.childNodes.indexOf(this); if (index > -1) { return parent.childNodes[index + 1]; } } return null; } get previousSibling() { const parent = this.parent; if (parent) { const index = parent.childNodes.indexOf(this); if (index > -1) { return index > 0 ? parent.childNodes[index - 1] : null; } } return null; } contains(target, deep = true) { return (this.childNodes || []).some((child) => child === target || deep && child.contains(target)); } remove() { const parent = this.parent; if (parent) { parent.removeChild(this); } } insertChild(child, index, batch) { if (!child) throw new Error("insertChild error: child is required."); if (!(child instanceof Node)) { if (!batch) { const children = this.getChildren(true); if (children.indexOf(child.data) === -1) { if (typeof index === "undefined" || index < 0) { children.push(child.data); } else { children.splice(index, 0, child.data); } } } Object.assign(child, { parent: this, store: this.store }); child = reactive(new Node(child)); if (child instanceof Node) { child.initialize(); } } child.level = this.level + 1; if (typeof index === "undefined" || index < 0) { this.childNodes.push(child); } else { this.childNodes.splice(index, 0, child); } this.updateLeafState(); } insertBefore(child, ref) { let index; if (ref) { index = this.childNodes.indexOf(ref); } this.insertChild(child, index); } insertAfter(child, ref) { let index; if (ref) { index = this.childNodes.indexOf(ref); if (index !== -1) index += 1; } this.insertChild(child, index); } removeChild(child) { const children = this.getChildren() || []; const dataIndex = children.indexOf(child.data); if (dataIndex > -1) { children.splice(dataIndex, 1); } const index = this.childNodes.indexOf(child); if (index > -1) { this.store && this.store.deregisterNode(child); child.parent = null; this.childNodes.splice(index, 1); } this.updateLeafState(); } removeChildByData(data) { let targetNode = null; for (let i = 0; i < this.childNodes.length; i++) { if (this.childNodes[i].data === data) { targetNode = this.childNodes[i]; break; } } if (targetNode) { this.removeChild(targetNode); } } expand(callback, expandParent) { const done = () => { if (expandParent) { let parent = this.parent; while (parent.level > 0) { parent.expanded = true; parent = parent.parent; } } this.expanded = true; if (callback) callback(); this.childNodes.forEach((item) => { item.canFocus = true; }); }; if (this.shouldLoadData()) { this.loadData((data) => { if (Array.isArray(data)) { if (this.checked) { this.setChecked(true, true); } else if (!this.store.checkStrictly) { reInitChecked(this); } done(); } }); } else { done(); } } doCreateChildren(array, defaultProps = {}) { array.forEach((item) => { this.insertChild(Object.assign({ data: item }, defaultProps), void 0, true); }); } collapse() { this.expanded = false; this.childNodes.forEach((item) => { item.canFocus = false; }); } shouldLoadData() { return this.store.lazy === true && this.store.load && !this.loaded; } updateLeafState() { if (this.store.lazy === true && this.loaded !== true && typeof this.isLeafByUser !== "undefined") { this.isLeaf = this.isLeafByUser; return; } const childNodes = this.childNodes; if (!this.store.lazy || this.store.lazy === true && this.loaded === true) { this.isLeaf = !childNodes || childNodes.length === 0; return; } this.isLeaf = false; } setChecked(value, deep, recursion, passValue) { this.indeterminate = value === "half"; this.checked = value === true; if (this.store.checkStrictly) return; if (!(this.shouldLoadData() && !this.store.checkDescendants)) { const { all, allWithoutDisable } = getChildState(this.childNodes); if (!this.isLeaf && (!all && allWithoutDisable)) { this.checked = false; value = false; } const handleDescendants = () => { if (deep) { const childNodes = this.childNodes; for (let i = 0, j = childNodes.length; i < j; i++) { const child = childNodes[i]; passValue = passValue || value !== false; const isCheck = child.disabled ? child.checked : passValue; child.setChecked(isCheck, deep, true, passValue); } const { half, all: all2 } = getChildState(childNodes); if (!all2) { this.checked = all2; this.indeterminate = half; } } }; if (this.shouldLoadData()) { this.loadData(() => { handleDescendants(); reInitChecked(this); }, { checked: value !== false }); return; } else { handleDescendants(); } } const parent = this.parent; if (!parent || parent.level === 0) return; if (!recursion) { reInitChecked(parent); } } getChildren(forceInit = false) { if (this.level === 0) return this.data; const data = this.data; if (!data) return null; const props = this.store.props; let children = "children"; if (props) { children = props.children || "children"; } if (data[children] === void 0) { data[children] = null; } if (forceInit && !data[children]) { data[children] = []; } return data[children]; } updateChildren() { const newData = this.getChildren() || []; const oldData = this.childNodes.map((node) => node.data); const newDataMap = {}; const newNodes = []; newData.forEach((item, index) => { const key = item[NODE_KEY]; const isNodeExists = !!key && oldData.findIndex((data) => data[NODE_KEY] === key) >= 0; if (isNodeExists) { newDataMap[key] = { index, data: item }; } else { newNodes.push({ index, data: item }); } }); if (!this.store.lazy) { oldData.forEach((item) => { if (!newDataMap[item[NODE_KEY]]) this.removeChildByData(item); }); } newNodes.forEach(({ index, data }) => { this.insertChild({ data }, index); }); this.updateLeafState(); } loadData(callback, defaultProps = {}) { if (this.store.lazy === true && this.store.load && !this.loaded && (!this.loading || Object.keys(defaultProps).length)) { this.loading = true; const resolve = (children) => { this.loaded = true; this.loading = false; this.childNodes = []; this.doCreateChildren(children, defaultProps); this.updateLeafState(); if (callback) { callback.call(this, children); } }; this.store.load(this, resolve); } else { if (callback) { callback.call(this); } } } } class TreeStore { constructor(options) { this.currentNode = null; this.currentNodeKey = null; for (const option in options) { if (hasOwn(options, option)) { this[option] = options[option]; } } this.nodesMap = {}; } initialize() { this.root = new Node({ data: this.data, store: this }); this.root.initialize(); if (this.lazy && this.load) { const loadFn = this.load; loadFn(this.root, (data) => { this.root.doCreateChildren(data); this._initDefaultCheckedNodes(); }); } else { this._initDefaultCheckedNodes(); } } filter(value) { const filterNodeMethod = this.filterNodeMethod; const lazy = this.lazy; const traverse = function(node) { const childNodes = node.root ? node.root.childNodes : node.childNodes; childNodes.forEach((child) => { child.visible = filterNodeMethod.call(child, value, child.data, child); traverse(child); }); if (!node.visible && childNodes.length) { let allHidden = true; allHidden = !childNodes.some((child) => child.visible); if (node.root) { node.root.visible = allHidden === false; } else { node.visible = allHidden === false; } } if (!value) return; if (node.visible && !node.isLeaf && !lazy) node.expand(); }; traverse(this); } setData(newVal) { const instanceChanged = newVal !== this.root.data; if (instanceChanged) { this.root.setData(newVal); this._initDefaultCheckedNodes(); } else { this.root.updateChildren(); } } getNode(data) { if (data instanceof Node) return data; const key = typeof data !== "object" ? data : getNodeKey(this.key, data); return this.nodesMap[key] || null; } insertBefore(data, refData) { const refNode = this.getNode(refData); refNode.parent.insertBefore({ data }, refNode); } insertAfter(data, refData) { const refNode = this.getNode(refData); refNode.parent.insertAfter({ data }, refNode); } remove(data) { const node = this.getNode(data); if (node && node.parent) { if (node === this.currentNode) { this.currentNode = null; } node.parent.removeChild(node); } } append(data, parentData) { const parentNode = parentData ? this.getNode(parentData) : this.root; if (parentNode) { parentNode.insertChild({ data }); } } _initDefaultCheckedNodes() { const defaultCheckedKeys = this.defaultCheckedKeys || []; const nodesMap = this.nodesMap; defaultCheckedKeys.forEach((checkedKey) => { const node = nodesMap[checkedKey]; if (node) { node.setChecked(true, !this.checkStrictly); } }); } _initDefaultCheckedNode(node) { const defaultCheckedKeys = this.defaultCheckedKeys || []; if (defaultCheckedKeys.indexOf(node.key) !== -1) { node.setChecked(true, !this.checkStrictly); } } setDefaultCheckedKey(newVal) { if (newVal !== this.defaultCheckedKeys) { this.defaultCheckedKeys = newVal; this._initDefaultCheckedNodes(); } } registerNode(node) { const key = this.key; if (!node || !node.data) return; if (!key) { this.nodesMap[node.id] = node; } else { const nodeKey = node.key; if (nodeKey !== void 0) this.nodesMap[node.key] = node; } } deregisterNode(node) { const key = this.key; if (!key || !node || !node.data) return; node.childNodes.forEach((child) => { this.deregisterNode(child); }); delete this.nodesMap[node.key]; } getCheckedNodes(leafOnly = false, includeHalfChecked = false) { const checkedNodes = []; const traverse = function(node) { const childNodes = node.root ? node.root.childNodes : node.childNodes; childNodes.forEach((child) => { if ((child.checked || includeHalfChecked && child.indeterminate) && (!leafOnly || leafOnly && child.isLeaf)) { checkedNodes.push(child.data); } traverse(child); }); }; traverse(this); return checkedNodes; } getCheckedKeys(leafOnly = false) { return this.getCheckedNodes(leafOnly).map((data) => (data || {})[this.key]); } getHalfCheckedNodes() { const nodes = []; const traverse = function(node) { const childNodes = node.root ? node.root.childNodes : node.childNodes; childNodes.forEach((child) => { if (child.indeterminate) { nodes.push(child.data); } traverse(child); }); }; traverse(this); return nodes; } getHalfCheckedKeys() { return this.getHalfCheckedNodes().map((data) => (data || {})[this.key]); } _getAllNodes() { const allNodes = []; const nodesMap = this.nodesMap; for (const nodeKey in nodesMap) { if (hasOwn(nodesMap, nodeKey)) { allNodes.push(nodesMap[nodeKey]); } } return allNodes; } updateChildren(key, data) { const node = this.nodesMap[key]; if (!node) return; const childNodes = node.childNodes; for (let i = childNodes.length - 1; i >= 0; i--) { const child = childNodes[i]; this.remove(child.data); } for (let i = 0, j = data.length; i < j; i++) { const child = data[i]; this.append(child, node.data); } } _setCheckedKeys(key, leafOnly = false, checkedKeys) { const allNodes = this._getAllNodes().sort((a, b) => b.level - a.level); const cache = Object.create(null); const keys = Object.keys(checkedKeys); allNodes.forEach((node) => node.setChecked(false, false)); for (let i = 0, j = allNodes.length; i < j; i++) { const node = allNodes[i]; const nodeKey = node.data[key].toString(); const checked = keys.indexOf(nodeKey) > -1; if (!checked) { if (node.checked && !cache[nodeKey]) { node.setChecked(false, false); } continue; } let parent = node.parent; while (parent && parent.level > 0) { cache[parent.data[key]] = true; parent = parent.parent; } if (node.isLeaf || this.checkStrictly) { node.setChecked(true, false); continue; } node.setChecked(true, true); if (leafOnly) { node.setChecked(false, false); const traverse = function(node2) { const childNodes = node2.childNodes; childNodes.forEach((child) => { if (!child.isLeaf) { child.setChecked(false, false); } traverse(child); }); }; traverse(node); } } } setCheckedNodes(array, leafOnly = false) { const key = this.key; const checkedKeys = {}; array.forEach((item) => { checkedKeys[(item || {})[key]] = true; }); this._setCheckedKeys(key, leafOnly, checkedKeys); } setCheckedKeys(keys, leafOnly = false) { this.defaultCheckedKeys = keys; const key = this.key; const checkedKeys = {}; keys.forEach((key2) => { checkedKeys[key2] = true; }); this._setCheckedKeys(key, leafOnly, checkedKeys); } setDefaultExpandedKeys(keys) { keys = keys || []; this.defaultExpandedKeys = keys; keys.forEach((key) => { const node = this.getNode(key); if (node) node.expand(null, this.autoExpandParent); }); } setChecked(data, checked, deep) { const node = this.getNode(data); if (node) { node.setChecked(!!checked, deep); } } getCurrentNode() { return this.currentNode; } setCurrentNode(currentNode) { const prevCurrentNode = this.currentNode; if (prevCurrentNode) { prevCurrentNode.isCurrent = false; } this.currentNode = currentNode; this.currentNode.isCurrent = true; } setUserCurrentNode(node, shouldAutoExpandParent = true) { const key = node[this.key]; const currNode = this.nodesMap[key]; this.setCurrentNode(currNode); if (shouldAutoExpandParent && this.currentNode.level > 1) { this.currentNode.parent.expand(null, true); } } setCurrentNodeKey(key, shouldAutoExpandParent = true) { if (key === null || key === void 0) { this.currentNode && (this.currentNode.isCurrent = false); this.currentNode = null; return; } const node = this.getNode(key); if (node) { this.setCurrentNode(node); if (shouldAutoExpandParent && this.currentNode.level > 1) { this.currentNode.parent.expand(null, true); } } } } var script = defineComponent({ name: "ElTreeNodeContent", props: { node: { type: Object, required: true }, renderContent: Function }, setup(props) { const nodeInstance = inject("NodeInstance"); const tree = inject("RootTree"); return () => { const node = props.node; const { data, store } = node; return props.renderContent ? props.renderContent(h, { _self: nodeInstance, node, data, store }) : tree.ctx.slots.default ? tree.ctx.slots.default({ node, data }) : h("span", { class: "el-tree-node__label" }, [node.label]); }; } }); script.__file = "packages/tree/src/tree-node-content.vue"; function useNodeExpandEventBroadcast(props) { const parentNodeMap = inject("TreeNodeMap", null); const currentNodeMap = { treeNodeExpand: (node) => { if (props.node !== node) { props.node.collapse(); } }, children: [] }; if (parentNodeMap) { parentNodeMap.children.push(currentNodeMap); } provide("TreeNodeMap", currentNodeMap); return { broadcastExpanded: (node) => { if (!props.accordion) return; for (const childNode of currentNodeMap.children) { childNode.treeNodeExpand(node); } } }; } function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) { const emitter = mitt(); provide("DragNodeEmitter", emitter); const dragState = ref({ showDropIndicator: false, draggingNode: null, dropNode: null, allowDrop: true, dropType: null }); emitter.on("tree-node-drag-start", ({ event, treeNode }) => { if (typeof props.allowDrag === "function" && !props.allowDrag(treeNode.node)) { event.preventDefault(); return false; } event.dataTransfer.effectAllowed = "move"; try { event.dataTransfer.setData("text/plain", ""); } catch (e) { } dragState.value.draggingNode = treeNode; ctx.emit("node-drag-start", treeNode.node, event); }); emitter.on("tree-node-drag-over", ({ event, treeNode }) => { const dropNode = treeNode; const oldDropNode = dragState.value.dropNode; if (oldDropNode && oldDropNode !== dropNode) { removeClass(oldDropNode.$el, "is-drop-inner"); } const draggingNode = dragState.value.draggingNode; if (!draggingNode || !dropNode) return; let dropPrev = true; let dropInner = true; let dropNext = true; let userAllowDropInner = true; if (typeof props.allowDrop === "function") { dropPrev = props.allowDrop(draggingNode.node, dropNode.node, "prev"); userAllowDropInner = dropInner = props.allowDrop(draggingNode.node, dropNode.node, "inner"); dropNext = props.allowDrop(draggingNode.node, dropNode.node, "next"); } event.dataTransfer.dropEffect = dropInner ? "move" : "none"; if ((dropPrev || dropInner || dropNext) && oldDropNode !== dropNode) { if (oldDropNode) { ctx.emit("node-drag-leave", draggingNode.node, oldDropNode.node, event); } ctx.emit("node-drag-enter", draggingNode.node, dropNode.node, event); } if (dropPrev || dropInner || dropNext) { dragState.value.dropNode = dropNode; } if (dropNode.node.nextSibling === draggingNode.node) { dropNext = false; } if (dropNode.node.previousSibling === draggingNode.node) { dropPrev = false; } if (dropNode.node.contains(draggingNode.node, false)) { dropInner = false; } if (draggingNode.node === dropNode.node || draggingNode.node.contains(dropNode.node)) { dropPrev = false; dropInner = false; dropNext = false; } const targetPosition = dropNode.$el.getBoundingClientRect(); const treePosition = el$.value.getBoundingClientRect(); let dropType; const prevPercent = dropPrev ? dropInner ? 0.25 : dropNext ? 0.45 : 1 : -1; const nextPercent = dropNext ? dropInner ? 0.75 : dropPrev ? 0.55 : 0 : 1; let indicatorTop = -9999; const distance = event.clientY - targetPosition.top; if (distance < targetPosition.height * prevPercent) { dropType = "before"; } else if (distance > targetPosition.height * nextPercent) { dropType = "after"; } else if (dropInner) { dropType = "inner"; } else { dropType = "none"; } const iconPosition = dropNode.$el.querySelector(".el-tree-node__expand-icon").getBoundingClientRect(); const dropIndicator = dropIndicator$.value; if (dropType === "before") { indicatorTop = iconPosition.top - treePosition.top; } else if (dropType === "after") { indicatorTop = iconPosition.bottom - treePosition.top; } dropIndicator.style.top = indicatorTop + "px"; dropIndicator.style.left = iconPosition.right - treePosition.left + "px"; if (dropType === "inner") { addClass(dropNode.$el, "is-drop-inner"); } else { removeClass(dropNode.$el, "is-drop-inner"); } dragState.value.showDropIndicator = dropType === "before" || dropType === "after"; dragState.value.allowDrop = dragState.value.showDropIndicator || userAllowDropInner; dragState.value.dropType = dropType; ctx.emit("node-drag-over", draggingNode.node, dropNode.node, event); }); emitter.on("tree-node-drag-end", (event) => { const { draggingNode, dropType, dropNode } = dragState.value; event.preventDefault(); event.dataTransfer.dropEffect = "move"; if (draggingNode && dropNode) { const draggingNodeCopy = { data: draggingNode.node.data }; if (dropType !== "none") { draggingNode.node.remove(); } if (dropType === "before") { dropNode.node.parent.insertBefore(draggingNodeCopy, dropNode.node); } else if (dropType === "after") { dropNode.node.parent.insertAfter(draggingNodeCopy, dropNode.node); } else if (dropType === "inner") { dropNode.node.insertChild(draggingNodeCopy); } if (dropType !== "none") { store.value.registerNode(draggingNodeCopy); } removeClass(dropNode.$el, "is-drop-inner"); ctx.emit("node-drag-end", draggingNode.node, dropNode.node, dropType, event); if (dropType !== "none") { ctx.emit("node-drop", draggingNode.node, dropNode.node, dropType, event); } } if (draggingNode && !dropNode) { ctx.emit("node-drag-end", draggingNode.node, null, dropType, event); } dragState.value.showDropIndicator = false; dragState.value.draggingNode = null; dragState.value.dropNode = null; dragState.value.allowDrop = true; }); return { dragState }; } function useDragNodeEmitter() { const emitter = inject("DragNodeEmitter"); return { emitter }; } var script$1 = defineComponent({ name: "ElTreeNode", components: { ElCollapseTransition, ElCheckbox, NodeContent: script }, props: { node: { type: Node, default: () => ({}) }, props: { type: Object, default: () => ({}) }, accordion: Boolean, renderContent: Function, renderAfterExpand: Boolean, showCheckbox: { type: Boolean, default: false } }, emits: ["node-expand"], setup(props, ctx) { const { broadcastExpanded } = useNodeExpandEventBroadcast(props); const tree = inject("RootTree"); const expanded = ref(false); const childNodeRendered = ref(false); const oldChecked = ref(null); const oldIndeterminate = ref(null); const node$ = ref(null); const { emitter } = useDragNodeEmitter(); const instance = getCurrentInstance(); provide("NodeInstance", instance); if (!tree) { console.warn("Can not find node's tree."); } if (props.node.expanded) { expanded.value = true; childNodeRendered.value = true; } const childrenKey = tree.props["children"] || "children"; watch(() => { const children = props.node.data[childrenKey]; return children && [...children]; }, () => { props.node.updateChildren(); }); watch(() => props.node.indeterminate, (val) => { handleSelectChange(props.node.checked, val); }); watch(() => props.node.checked, (val) => { handleSelectChange(val, props.node.indeterminate); }); watch(() => props.node.expanded, (val) => { nextTick(() => expanded.value = val); if (val) { childNodeRendered.value = true; } }); const getNodeKey$1 = (node) => { return getNodeKey(tree.props.nodeKey, node.data); }; const handleSelectChange = (checked, indeterminate) => { if (oldChecked.value !== checked || oldIndeterminate.value !== indeterminate) { tree.ctx.emit("check-change", props.node.data, checked, indeterminate); } oldChecked.value = checked; oldIndeterminate.value = indeterminate; }; const handleClick = () => { const store = tree.store.value; store.setCurrentNode(props.node); tree.ctx.emit("current-change", store.currentNode ? store.currentNode.data : null, store.currentNode); tree.currentNode.value = props.node; if (tree.props.expandOnClickNode) { handleExpandIconClick(); } if (tree.props.checkOnClickNode && !props.node.disabled) { handleCheckChange(null, { target: { checked: !props.node.checked } }); } tree.ctx.emit("node-click", props.node.data, props.node, instance); }; const handleContextMenu = (event) => { if (tree.instance.vnode.props["onNodeContextmenu"]) { event.stopPropagation(); event.preventDefault(); } tree.ctx.emit("node-contextmenu", event, props.node.data, props.node, instance); }; const handleExpandIconClick = () => { if (props.node.isLeaf) return; if (expanded.value) { tree.ctx.emit("node-collapse", props.node.data, props.node, instance); props.node.collapse(); } else { props.node.expand(); ctx.emit("node-expand", props.node.data, props.node, instance); } }; const handleCheckChange = (value, ev) => { props.node.setChecked(ev.target.checked, !tree.props.checkStrictly); nextTick(() => { const store = tree.store.value; tree.ctx.emit("check", props.node.data, { checkedNodes: store.getCheckedNodes(), checkedKeys: store.getCheckedKeys(), halfCheckedNodes: store.getHalfCheckedNodes(), halfCheckedKeys: store.getHalfCheckedKeys() }); }); }; const handleChildNodeExpand = (nodeData, node, instance2) => { broadcastExpanded(node); tree.ctx.emit("node-expand", nodeData, node, instance2); }; const handleDragStart = (event) => { if (!tree.props.draggable) return; emitter.emit("tree-node-drag-start", { event, treeNode: props }); }; const handleDragOver = (event) => { if (!tree.props.draggable) return; emitter.emit("tree-node-drag-over", { event, treeNode: { $el: node$.value, node: props.node } }); event.preventDefault(); }; const handleDrop = (event) => { event.preventDefault(); }; const handleDragEnd = (event) => { if (!tree.props.draggable) return; emitter.emit("tree-node-drag-end", event); }; return { node$, tree, expanded, childNodeRendered, oldChecked, oldIndeterminate, emitter, parent, getNodeKey: getNodeKey$1, handleSelectChange, handleClick, handleContextMenu, handleExpandIconClick, handleCheckChange, handleChildNodeExpand, handleDragStart, handleDragOver, handleDrop, handleDragEnd }; } }); const _hoisted_1 = { key: 1, class: "el-tree-node__loading-icon el-icon-loading" }; function render(_ctx, _cache, $props, $setup, $data, $options) { const _component_el_checkbox = resolveComponent("el-checkbox"); const _component_node_content = resolveComponent("node-content"); const _component_el_tree_node = resolveComponent("el-tree-node"); const _component_el_collapse_transition = resolveComponent("el-collapse-transition"); return withDirectives((openBlock(), createBlock("div", { ref: "node$", class: ["el-tree-node", { "is-expanded": _ctx.expanded, "is-current": _ctx.node.isCurrent, "is-hidden": !_ctx.node.visible, "is-focusable": !_ctx.node.disabled, "is-checked": !_ctx.node.disabled && _ctx.node.checked }], role: "treeitem", tabindex: "-1", "aria-expanded": _ctx.expanded, "aria-disabled": _ctx.node.disabled, "aria-checked": _ctx.node.checked, draggable: _ctx.tree.props.draggable, "data-key": _ctx.getNodeKey(_ctx.node), onClick: _cache[3] || (_cache[3] = withModifiers((...args) => _ctx.handleClick && _ctx.handleClick(...args), ["stop"])), onContextmenu: _cache[4] || (_cache[4] = (...args) => _ctx.handleContextMenu && _ctx.handleContextMenu(...args)), onDragstart: _cache[5] || (_cache[5] = withModifiers((...args) => _ctx.handleDragStart && _ctx.handleDragStart(...args), ["stop"])), onDragover: _cache[6] || (_cache[6] = withModifiers((...args) => _ctx.handleDragOver && _ctx.handleDragOver(...args), ["stop"])), onDragend: _cache[7] || (_cache[7] = withModifiers((...args) => _ctx.handleDragEnd && _ctx.handleDragEnd(...args), ["stop"])), onDrop: _cache[8] || (_cache[8] = withModifiers((...args) => _ctx.handleDrop && _ctx.handleDrop(...args), ["stop"])) }, [ createVNode("div", { class: "el-tree-node__content", style: { "padding-left": (_ctx.node.level - 1) * _ctx.tree.props.indent + "px" } }, [ createVNode("span", { class: [ { "is-leaf": _ctx.node.isLeaf, expanded: !_ctx.node.isLeaf && _ctx.expanded }, "el-tree-node__expand-icon", _ctx.tree.props.iconClass ? _ctx.tree.props.iconClass : "el-icon-caret-right" ], onClick: _cache[1] || (_cache[1] = withModifiers((...args) => _ctx.handleExpandIconClick && _ctx.handleExpandIconClick(...args), ["stop"])) }, null, 2), _ctx.showCheckbox ? (openBlock(), createBlock(_component_el_checkbox, { key: 0, "model-value": _ctx.node.checked, indeterminate: _ctx.node.indeterminate, disabled: !!_ctx.node.disabled, onClick: _cache[2] || (_cache[2] = withModifiers(() => { }, ["stop"])), onChange: _ctx.handleCheckChange }, null, 8, ["model-value", "indeterminate", "disabled", "onChange"])) : createCommentVNode("v-if", true), _ctx.node.loading ? (openBlock(), createBlock("span", _hoisted_1)) : createCommentVNode("v-if", true), createVNode(_component_node_content, { node: _ctx.node, "render-content": _ctx.renderContent }, null, 8, ["node", "render-content"]) ], 4), createVNode(_component_el_collapse_transition, null, { default: withCtx(() => [ !_ctx.renderAfterExpand || _ctx.childNodeRendered ? withDirectives((openBlock(), createBlock("div", { key: 0, class: "el-tree-node__children", role: "group", "aria-expanded": _ctx.expanded }, [ (openBlock(true), createBlock(Fragment, null, renderList(_ctx.node.childNodes, (child) => { return openBlock(), createBlock(_component_el_tree_node, { key: _ctx.getNodeKey(child), "render-content": _ctx.renderContent, "render-after-expand": _ctx.renderAfterExpand, "show-checkbox": _ctx.showCheckbox, node: child, onNodeExpand: _ctx.handleChildNodeExpand }, null, 8, ["render-content", "render-after-expand", "show-checkbox", "node", "onNodeExpand"]); }), 128)) ], 8, ["aria-expanded"])), [ [vShow, _ctx.expanded] ]) : createCommentVNode("v-if", true) ]), _: 1 }) ], 42, ["aria-expanded", "aria-disabled", "aria-checked", "draggable", "data-key"])), [ [vShow, _ctx.node.visible] ]); } script$1.render = render; script$1.__file = "packages/tree/src/tree-node.vue"; function useKeydown({ el$ }, store) { const treeItems = ref([]); const checkboxItems = ref([]); onMounted(() => { initTabIndex(); on(el$.value, "keydown", handleKeydown); }); onBeforeUnmount(() => { off(el$.value, "keydown", handleKeydown); }); onUpdated(() => { treeItems.value = Array.from(el$.value.querySelectorAll("[role=treeitem]")); checkboxItems.value = Array.from(el$.value.querySelectorAll("input[type=checkbox]")); }); watch(checkboxItems, (val) => { val.forEach((checkbox) => { checkbox.setAttribute("tabindex", "-1"); }); }); const handleKeydown = (ev) => { const currentItem = ev.target; if (currentItem.className.indexOf("el-tree-node") === -1) return; const code = ev.code; treeItems.value = Array.from(el$.value.querySelectorAll(".is-focusable[role=treeitem]")); const currentIndex = treeItems.value.indexOf(currentItem); let nextIndex; if ([EVENT_CODE.up, EVENT_CODE.down].indexOf(code) > -1) { ev.preventDefault(); if (code === EVENT_CODE.up) { nextIndex = currentIndex === -1 ? 0 : currentIndex !== 0 ? currentIndex - 1 : treeItems.value.length - 1; const startIndex = nextIndex; while (true) { if (store.value.getNode(treeItems.value[nextIndex].dataset.key).canFocus) break; nextIndex--; if (nextIndex === startIndex) { nextIndex = -1; break; } if (nextIndex < 0) { nextIndex = treeItems.value.length - 1; } } } else { nextIndex = currentIndex === -1 ? 0 : currentIndex < treeItems.value.length - 1 ? currentIndex + 1 : 0; const startIndex = nextIndex; while (true) { if (store.value.getNode(treeItems.value[nextIndex].dataset.key).canFocus) break; nextIndex++; if (nextIndex === startIndex) { nextIndex = -1; break; } if (nextIndex >= treeItems.value.length) { nextIndex = 0; } } } nextIndex !== -1 && treeItems.value[nextIndex].focus(); } if ([EVENT_CODE.left, EVENT_CODE.right].indexOf(code) > -1) { ev.preventDefault(); currentItem.click(); } const hasInput = currentItem.querySelector('[type="checkbox"]'); if ([EVENT_CODE.enter, EVENT_CODE.space].indexOf(code) > -1 && hasInput) { ev.preventDefault(); hasInput.click(); } }; const initTabIndex = () => { var _a; treeItems.value = Array.from(el$.value.querySelectorAll(".is-focusable[role=treeitem]")); checkboxItems.value = Array.from(el$.value.querySelectorAll("input[type=checkbox]")); const checkedItem = el$.value.querySelectorAll(".is-checked[role=treeitem]"); if (checkedItem.length) { checkedItem[0].setAttribute("tabindex", "0"); return; } (_a = treeItems.value[0]) == null ? void 0 : _a.setAttribute("tabindex", "0"); }; } var script$2 = defineComponent({ name: "ElTree", components: { ElTreeNode: script$1 }, props: { data: { type: Array }, emptyText: { type: String, default() { return t("el.tree.emptyText"); } }, renderAfterExpand: { type: Boolean, default: true }, nodeKey: String, checkStrictly: Boolean, defaultExpandAll: Boolean, expandOnClickNode: { type: Boolean, default: true }, checkOnClickNode: Boolean, checkDescendants: { type: Boolean, default: false }, autoExpandParent: { type: Boolean, default: true }, defaultCheckedKeys: Array, defaultExpandedKeys: Array, currentNodeKey: [String, Number], renderContent: Function, showCheckbox: { type: Boolean, default: false }, draggable: { type: Boolean, default: false }, allowDrag: Function, allowDrop: Function, props: { type: Object, default() { return { children: "children", label: "label", disabled: "disabled" }; } }, lazy: { type: Boolean, default: false }, highlightCurrent: Boolean, load: Function, filterNodeMethod: Function, accordion: Boolean, indent: { type: Number, default: 18 }, iconClass: String }, emits: [ "check-change", "current-change", "node-click", "node-contextmenu", "node-collapse", "node-expand", "check", "node-drag-start", "node-drag-end", "node-drop", "node-drag-leave", "node-drag-enter", "node-drag-over" ], setup(props, ctx) { const store = ref(new TreeStore({ key: props.nodeKey, data: props.data, lazy: props.lazy, props: props.props, load: props.load, currentNodeKey: props.currentNodeKey, checkStrictly: props.checkStrictly, checkDescendants: props.checkDescendants, defaultCheckedKeys: props.defaultCheckedKeys, defaultExpandedKeys: props.defaultExpandedKeys, autoExpandParent: props.autoExpandParent, defaultExpandAll: props.defaultExpandAll, filterNodeMethod: props.filterNodeMethod })); store.value.initialize(); const root = ref(store.value.root); const currentNode = ref(null); const el$ = ref(null); const dropIndicator$ = ref(null); const { broadcastExpanded } = useNodeExpandEventBroadcast(props); const { dragState } = useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }); useKeydown({ el$ }, store); const isEmpty = computed(() => { const { childNodes } = root.value; return !childNodes || childNodes.length === 0 || childNodes.every(({ visible }) => !visible); }); watch(() => props.defaultCheckedKeys, (newVal) => { store.value.setDefaultCheckedKey(newVal); }); watch(() => props.defaultExpandedKeys, (newVal) => { store.value.defaultExpandedKeys = newVal; store.value.setDefaultExpandedKeys(newVal); }); watch(() => props.data, (newVal) => { store.value.setData(newVal); }, { deep: true }); watch(() => props.checkStrictly, (newVal) => { store.value.checkStrictly = newVal; }); const filter = (value) => { if (!props.filterNodeMethod) throw new Error("[Tree] filterNodeMethod is required when filter"); store.value.filter(value); }; const getNodeKey$1 = (node) => { return getNodeKey(props.nodeKey, node.data); }; const getNodePath = (data) => { if (!props.nodeKey) throw new Error("[Tree] nodeKey is required in getNodePath"); const node = store.value.getNode(data); if (!node) return []; const path = [node.data]; let parent = node.parent; while (parent && parent !== root.value) { path.push(parent.data); parent = parent.parent; } return path.reverse(); }; const getCheckedNodes = (leafOnly, includeHalfChecked) => { return store.value.getCheckedNodes(leafOnly, includeHalfChecked); }; const getCheckedKeys = (leafOnly) => { return store.value.getCheckedKeys(leafOnly); }; const getCurrentNode = () => { const currentNode2 = store.value.getCurrentNode(); return currentNode2 ? currentNode2.data : null; }; const getCurrentKey = () => { if (!props.nodeKey) throw new Error("[Tree] nodeKey is required in getCurrentKey"); const currentNode2 = getCurrentNode(); return currentNode2 ? currentNode2[props.nodeKey] : null; }; const setCheckedNodes = (nodes, leafOnly) => { if (!props.nodeKey) throw new Error("[Tree] nodeKey is required in setCheckedNodes"); store.value.setCheckedNodes(nodes, leafOnly); }; const setCheckedKeys = (keys, leafOnly) => { if (!props.nodeKey) throw new Error("[Tree] nodeKey is required in setCheckedKeys"); store.value.setCheckedKeys(keys, leafOnly); }; const setChecked = (data, checked, deep) => { store.value.setChecked(data, checked, deep); }; const getHalfCheckedNodes = () => { return store.value.getHalfCheckedNodes(); }; const getHalfCheckedKeys = () => { return store.value.getHalfCheckedKeys(); }; const setCurrentNode = (node, shouldAutoExpandParent = true) => { if (!props.nodeKey) throw new Error("[Tree] nodeKey is required in setCurrentNode"); store.value.setUserCurrentNode(node, shouldAutoExpandParent); }; const setCurrentKey = (key, shouldAutoExpandParent = true) => { if (!props.nodeKey) throw new Error("[Tree] nodeKey is required in setCurrentKey"); store.value.setCurrentNodeKey(key, shouldAutoExpandParent); }; const getNode = (data) => { return store.value.getNode(data); }; const remove = (data) => { store.value.remove(data); }; const append = (data, parentNode) => { store.value.append(data, parentNode); }; const insertBefore = (data, refNode) => { store.value.insertBefore(data, refNode); }; const insertAfter = (data, refNode) => { store.value.insertAfter(data, refNode); }; const handleNodeExpand = (nodeData, node, instance) => { broadcastExpanded(node); ctx.emit("node-expand", nodeData, node, instance); }; const updateKeyChildren = (key, data) => { if (!props.nodeKey) throw new Error("[Tree] nodeKey is required in updateKeyChild"); store.value.updateChildren(key, data); }; provide("RootTree", { ctx, props, store, root, currentNode, instance: getCurrentInstance() }); return { store, root, currentNode, dragState, el$, dropIndicator$, isEmpty, filter, getNodeKey: getNodeKey$1, getNodePath, getCheckedNodes, getCheckedKeys, getCurrentNode, getCurrentKey, setCheckedNodes, setCheckedKeys, setChecked, getHalfCheckedNodes, getHalfCheckedKeys, setCurrentNode, setCurrentKey, getNode, remove, append, insertBefore, insertAfter, handleNodeExpand, updateKeyChildren }; } }); const _hoisted_1$1 = { key: 0, class: "el-tree__empty-block" }; const _hoisted_2 = { class: "el-tree__empty-text" }; const _hoisted_3 = { ref: "dropIndicator$", class: "el-tree__drop-indicator" }; function render$1(_ctx, _cache, $props, $setup, $data, $options) { const _component_el_tree_node = resolveComponent("el-tree-node"); return openBlock(), createBlock("div", { ref: "el$", class: ["el-tree", { "el-tree--highlight-current": _ctx.highlightCurrent, "is-dragging": !!_ctx.dragState.draggingNode, "is-drop-not-allow": !_ctx.dragState.allowDrop, "is-drop-inner": _ctx.dragState.dropType === "inner" }], role: "tree" }, [ (openBlock(true), createBlock(Fragment, null, renderList(_ctx.root.childNodes, (child) => { return openBlock(), createBlock(_component_el_tree_node, { key: _ctx.getNodeKey(child), node: child, props: _ctx.props, accordion: _ctx.accordion, "render-after-expand": _ctx.renderAfterExpand, "show-checkbox": _ctx.showCheckbox, "render-content": _ctx.renderContent, onNodeExpand: _ctx.handleNodeExpand }, null, 8, ["node", "props", "accordion", "render-after-expand", "show-checkbox", "render-content", "onNodeExpand"]); }), 128)), _ctx.isEmpty ? (openBlock(), createBlock("div", _hoisted_1$1, [ createVNode("span", _hoisted_2, toDisplayString(_ctx.emptyText), 1) ])) : createCommentVNode("v-if", true), withDirectives(createVNode("div", _hoisted_3, null, 512), [ [vShow, _ctx.dragState.showDropIndicator] ]) ], 2); } script$2.render = render$1; script$2.__file = "packages/tree/src/tree.vue"; script$2.install = (app) => { app.component(sc