element-plus
Version:
A Component Library for Vue3.0
1,596 lines (1,578 loc) • 50.7 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var vue = require('vue');
var ElCollapseTransition = require('../el-collapse-transition');
var ElCheckbox = require('../el-checkbox');
var mitt = require('mitt');
var dom = require('../utils/dom');
var aria = require('../utils/aria');
var locale = require('../locale');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var ElCollapseTransition__default = /*#__PURE__*/_interopDefaultLegacy(ElCollapseTransition);
var ElCheckbox__default = /*#__PURE__*/_interopDefaultLegacy(ElCheckbox);
var mitt__default = /*#__PURE__*/_interopDefaultLegacy(mitt);
/**
* 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 = vue.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 = vue.defineComponent({
name: "ElTreeNodeContent",
props: {
node: {
type: Object,
required: true
},
renderContent: Function
},
setup(props) {
const nodeInstance = vue.inject("NodeInstance");
const tree = vue.inject("RootTree");
return () => {
const node = props.node;
const { data, store } = node;
return props.renderContent ? props.renderContent(vue.h, { _self: nodeInstance, node, data, store }) : tree.ctx.slots.default ? tree.ctx.slots.default({ node, data }) : vue.h("span", { class: "el-tree-node__label" }, [node.label]);
};
}
});
script.__file = "packages/tree/src/tree-node-content.vue";
function useNodeExpandEventBroadcast(props) {
const parentNodeMap = vue.inject("TreeNodeMap", null);
const currentNodeMap = {
treeNodeExpand: (node) => {
if (props.node !== node) {
props.node.collapse();
}
},
children: []
};
if (parentNodeMap) {
parentNodeMap.children.push(currentNodeMap);
}
vue.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__default['default']();
vue.provide("DragNodeEmitter", emitter);
const dragState = vue.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) {
dom.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") {
dom.addClass(dropNode.$el, "is-drop-inner");
} else {
dom.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);
}
dom.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 = vue.inject("DragNodeEmitter");
return {
emitter
};
}
var script$1 = vue.defineComponent({
name: "ElTreeNode",
components: {
ElCollapseTransition: ElCollapseTransition__default['default'],
ElCheckbox: ElCheckbox__default['default'],
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 = vue.inject("RootTree");
const expanded = vue.ref(false);
const childNodeRendered = vue.ref(false);
const oldChecked = vue.ref(null);
const oldIndeterminate = vue.ref(null);
const node$ = vue.ref(null);
const { emitter } = useDragNodeEmitter();
const instance = vue.getCurrentInstance();
vue.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";
vue.watch(() => {
const children = props.node.data[childrenKey];
return children && [...children];
}, () => {
props.node.updateChildren();
});
vue.watch(() => props.node.indeterminate, (val) => {
handleSelectChange(props.node.checked, val);
});
vue.watch(() => props.node.checked, (val) => {
handleSelectChange(val, props.node.indeterminate);
});
vue.watch(() => props.node.expanded, (val) => {
vue.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);
vue.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 = vue.resolveComponent("el-checkbox");
const _component_node_content = vue.resolveComponent("node-content");
const _component_el_tree_node = vue.resolveComponent("el-tree-node");
const _component_el_collapse_transition = vue.resolveComponent("el-collapse-transition");
return vue.withDirectives((vue.openBlock(), vue.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] = vue.withModifiers((...args) => _ctx.handleClick && _ctx.handleClick(...args), ["stop"])),
onContextmenu: _cache[4] || (_cache[4] = (...args) => _ctx.handleContextMenu && _ctx.handleContextMenu(...args)),
onDragstart: _cache[5] || (_cache[5] = vue.withModifiers((...args) => _ctx.handleDragStart && _ctx.handleDragStart(...args), ["stop"])),
onDragover: _cache[6] || (_cache[6] = vue.withModifiers((...args) => _ctx.handleDragOver && _ctx.handleDragOver(...args), ["stop"])),
onDragend: _cache[7] || (_cache[7] = vue.withModifiers((...args) => _ctx.handleDragEnd && _ctx.handleDragEnd(...args), ["stop"])),
onDrop: _cache[8] || (_cache[8] = vue.withModifiers((...args) => _ctx.handleDrop && _ctx.handleDrop(...args), ["stop"]))
}, [
vue.createVNode("div", {
class: "el-tree-node__content",
style: { "padding-left": (_ctx.node.level - 1) * _ctx.tree.props.indent + "px" }
}, [
vue.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] = vue.withModifiers((...args) => _ctx.handleExpandIconClick && _ctx.handleExpandIconClick(...args), ["stop"]))
}, null, 2),
_ctx.showCheckbox ? (vue.openBlock(), vue.createBlock(_component_el_checkbox, {
key: 0,
"model-value": _ctx.node.checked,
indeterminate: _ctx.node.indeterminate,
disabled: !!_ctx.node.disabled,
onClick: _cache[2] || (_cache[2] = vue.withModifiers(() => {
}, ["stop"])),
onChange: _ctx.handleCheckChange
}, null, 8, ["model-value", "indeterminate", "disabled", "onChange"])) : vue.createCommentVNode("v-if", true),
_ctx.node.loading ? (vue.openBlock(), vue.createBlock("span", _hoisted_1)) : vue.createCommentVNode("v-if", true),
vue.createVNode(_component_node_content, {
node: _ctx.node,
"render-content": _ctx.renderContent
}, null, 8, ["node", "render-content"])
], 4),
vue.createVNode(_component_el_collapse_transition, null, {
default: vue.withCtx(() => [
!_ctx.renderAfterExpand || _ctx.childNodeRendered ? vue.withDirectives((vue.openBlock(), vue.createBlock("div", {
key: 0,
class: "el-tree-node__children",
role: "group",
"aria-expanded": _ctx.expanded
}, [
(vue.openBlock(true), vue.createBlock(vue.Fragment, null, vue.renderList(_ctx.node.childNodes, (child) => {
return vue.openBlock(), vue.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"])), [
[vue.vShow, _ctx.expanded]
]) : vue.createCommentVNode("v-if", true)
]),
_: 1
})
], 42, ["aria-expanded", "aria-disabled", "aria-checked", "draggable", "data-key"])), [
[vue.vShow, _ctx.node.visible]
]);
}
script$1.render = render;
script$1.__file = "packages/tree/src/tree-node.vue";
function useKeydown({ el$ }, store) {
const treeItems = vue.ref([]);
const checkboxItems = vue.ref([]);
vue.onMounted(() => {
initTabIndex();
dom.on(el$.value, "keydown", handleKeydown);
});
vue.onBeforeUnmount(() => {
dom.off(el$.value, "keydown", handleKeydown);
});
vue.onUpdated(() => {
treeItems.value = Array.from(el$.value.querySelectorAll("[role=treeitem]"));
checkboxItems.value = Array.from(el$.value.querySelectorAll("input[type=checkbox]"));
});
vue.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 ([aria.EVENT_CODE.up, aria.EVENT_CODE.down].indexOf(code) > -1) {
ev.preventDefault();
if (code === aria.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 ([aria.EVENT_CODE.left, aria.EVENT_CODE.right].indexOf(code) > -1) {
ev.preventDefault();
currentItem.click();
}
const hasInput = currentItem.querySelector('[type="checkbox"]');
if ([aria.EVENT_CODE.enter, aria.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 = vue.defineComponent({
name: "ElTree",
components: { ElTreeNode: script$1 },
props: {
data: {
type: Array
},
emptyText: {
type: String,
default() {
return locale.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 = vue.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 = vue.ref(store.value.root);
const currentNode = vue.ref(null);
const el$ = vue.ref(null);
const dropIndicator$ = vue.ref(null);
const { broadcastExpanded } = useNodeExpandEventBroadcast(props);
const { dragState } = useDragNodeHandler({
props,
ctx,
el$,
dropIndicator$,
store
});
useKeydown({ el$ }, store);
const isEmpty = vue.computed(() => {
const { childNodes } = root.value;
return !childNodes || childNodes.length === 0 || childNodes.every(({ visible }) => !visible);
});
vue.watch(() => props.defaultCheckedKeys, (newVal) => {
store.value.setDefaultCheckedKey(newVal);
});
vue.watch(() => props.defaultExpandedKeys, (newVal) => {
store.value.defaultExpandedKeys = newVal;
store.value.setDefaultExpandedKeys(newVal);
});
vue.watch(() => props.data, (newVal) => {
store.value.setData(newVal);
}, { deep: true });
vue.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);
};
vue.provide("RootTree", {
ctx,
props,
store,
root,
currentNode,
instance: vue.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 = vue.resolveComponent("el-tree-node");
return vue.openBlock(), vue.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"
}, [
(vue.openBlock(true), vue.createBlock(vue.Fragment, null, vue.renderList(_ctx.root.childNodes, (child) => {
return vue.openBlock(), vue.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.renderCo