395 lines
18 KiB
JavaScript
395 lines
18 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const vue_1 = require("vue");
|
|
const vooks_1 = require("vooks");
|
|
const seemly_1 = require("seemly");
|
|
const _utils_1 = require("../../_utils");
|
|
const TreeNodeSwitcher_1 = __importDefault(require("./TreeNodeSwitcher"));
|
|
const TreeNodeCheckbox_1 = __importDefault(require("./TreeNodeCheckbox"));
|
|
const TreeNodeContent_1 = __importDefault(require("./TreeNodeContent"));
|
|
const interface_1 = require("./interface");
|
|
const dnd_1 = require("./dnd");
|
|
const utils_1 = require("./utils");
|
|
const TreeNode = (0, vue_1.defineComponent)({
|
|
name: 'TreeNode',
|
|
props: {
|
|
clsPrefix: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
tmNode: {
|
|
type: Object,
|
|
required: true
|
|
}
|
|
},
|
|
setup(props) {
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
const NTree = (0, vue_1.inject)(interface_1.treeInjectionKey);
|
|
const { droppingNodeParentRef, droppingMouseNodeRef, draggingNodeRef, droppingPositionRef, droppingOffsetLevelRef, nodePropsRef, indentRef, blockLineRef, checkboxPlacementRef, checkOnClickRef, disabledFieldRef, showLineRef, renderSwitcherIconRef, overrideDefaultNodeClickBehaviorRef } = NTree;
|
|
const checkboxDisabledRef = (0, vooks_1.useMemo)(() => !!props.tmNode.rawNode.checkboxDisabled);
|
|
const nodeIsDisabledRef = (0, vooks_1.useMemo)(() => {
|
|
return (0, utils_1.isNodeDisabled)(props.tmNode, disabledFieldRef.value);
|
|
});
|
|
const disabledRef = (0, vooks_1.useMemo)(() => NTree.disabledRef.value || nodeIsDisabledRef.value);
|
|
const resolvedNodePropsRef = (0, vue_1.computed)(() => {
|
|
const { value: nodeProps } = nodePropsRef;
|
|
if (!nodeProps)
|
|
return undefined;
|
|
return nodeProps({
|
|
option: props.tmNode.rawNode
|
|
});
|
|
});
|
|
// used for drag and drop
|
|
const contentInstRef = (0, vue_1.ref)(null);
|
|
// must be non-reactive
|
|
const contentElRef = { value: null };
|
|
(0, vue_1.onMounted)(() => {
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
contentElRef.value = contentInstRef.value.$el;
|
|
});
|
|
function handleSwitcherClick() {
|
|
const callback = () => {
|
|
const { tmNode } = props;
|
|
if (!tmNode.isLeaf && !tmNode.shallowLoaded) {
|
|
if (!NTree.loadingKeysRef.value.has(tmNode.key)) {
|
|
NTree.loadingKeysRef.value.add(tmNode.key);
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
const { onLoadRef: { value: onLoad } } = NTree;
|
|
if (onLoad) {
|
|
void onLoad(tmNode.rawNode)
|
|
.then((value) => {
|
|
if (value !== false) {
|
|
NTree.handleSwitcherClick(tmNode);
|
|
}
|
|
})
|
|
.finally(() => {
|
|
NTree.loadingKeysRef.value.delete(tmNode.key);
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
NTree.handleSwitcherClick(tmNode);
|
|
}
|
|
};
|
|
if (renderSwitcherIconRef.value) {
|
|
// if renderSwitcherIcon is set, icon dom may be altered before event
|
|
// bubbles to parent dom, so that target check fails. Call it in next
|
|
// event loop so that event bubble phase is finishes.
|
|
setTimeout(callback, 0);
|
|
}
|
|
else {
|
|
callback();
|
|
}
|
|
}
|
|
const selectableRef = (0, vooks_1.useMemo)(() => !nodeIsDisabledRef.value &&
|
|
NTree.selectableRef.value &&
|
|
(NTree.internalTreeSelect
|
|
? NTree.mergedCheckStrategyRef.value !== 'child' ||
|
|
(NTree.multipleRef.value && NTree.cascadeRef.value) ||
|
|
props.tmNode.isLeaf
|
|
: true));
|
|
const checkableRef = (0, vooks_1.useMemo)(() => NTree.checkableRef.value &&
|
|
(NTree.cascadeRef.value ||
|
|
NTree.mergedCheckStrategyRef.value !== 'child' ||
|
|
props.tmNode.isLeaf));
|
|
const checkedRef = (0, vooks_1.useMemo)(() => NTree.displayedCheckedKeysRef.value.includes(props.tmNode.key));
|
|
const mergedCheckOnClickRef = (0, vooks_1.useMemo)(() => {
|
|
const { value: checkable } = checkableRef;
|
|
if (!checkable)
|
|
return false;
|
|
const { value: checkOnClick } = checkOnClickRef;
|
|
const { tmNode } = props;
|
|
if (typeof checkOnClick === 'boolean') {
|
|
return !tmNode.disabled && checkOnClick;
|
|
}
|
|
return checkOnClick(props.tmNode.rawNode);
|
|
});
|
|
function _handleClick(e) {
|
|
const { value: expandOnClick } = NTree.expandOnClickRef;
|
|
const { value: selectable } = selectableRef;
|
|
const { value: mergedCheckOnClick } = mergedCheckOnClickRef;
|
|
if (!selectable && !expandOnClick && !mergedCheckOnClick)
|
|
return;
|
|
if ((0, seemly_1.happensIn)(e, 'checkbox') || (0, seemly_1.happensIn)(e, 'switcher'))
|
|
return;
|
|
const { tmNode } = props;
|
|
if (selectable) {
|
|
NTree.handleSelect(tmNode);
|
|
}
|
|
if (expandOnClick && !tmNode.isLeaf) {
|
|
handleSwitcherClick();
|
|
}
|
|
if (mergedCheckOnClick) {
|
|
handleCheck(!checkedRef.value);
|
|
}
|
|
}
|
|
function handleNodeClick(e) {
|
|
var _a, _b;
|
|
if (!disabledRef.value) {
|
|
const overrideDefaultNodeClickBehavior = overrideDefaultNodeClickBehaviorRef.value;
|
|
let shouldOverride = false;
|
|
if (overrideDefaultNodeClickBehavior) {
|
|
switch (overrideDefaultNodeClickBehavior({ option: props.tmNode.rawNode })) {
|
|
case 'toggleCheck':
|
|
shouldOverride = true;
|
|
handleCheck(!checkedRef.value);
|
|
break;
|
|
case 'toggleSelect':
|
|
shouldOverride = true;
|
|
NTree.handleSelect(props.tmNode);
|
|
break;
|
|
case 'toggleExpand':
|
|
shouldOverride = true;
|
|
handleSwitcherClick();
|
|
shouldOverride = true;
|
|
break;
|
|
case 'none':
|
|
shouldOverride = true;
|
|
shouldOverride = true;
|
|
return;
|
|
case 'default':
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (!shouldOverride) {
|
|
_handleClick(e);
|
|
}
|
|
}
|
|
(_b = (_a = resolvedNodePropsRef.value) === null || _a === void 0 ? void 0 : _a.onClick) === null || _b === void 0 ? void 0 : _b.call(_a, e);
|
|
}
|
|
function handleContentClick(e) {
|
|
if (blockLineRef.value)
|
|
return;
|
|
handleNodeClick(e);
|
|
}
|
|
function handleLineClick(e) {
|
|
if (!blockLineRef.value)
|
|
return;
|
|
handleNodeClick(e);
|
|
}
|
|
function handleCheck(checked) {
|
|
NTree.handleCheck(props.tmNode, checked);
|
|
}
|
|
// Dnd
|
|
function handleDragStart(e) {
|
|
NTree.handleDragStart({
|
|
event: e,
|
|
node: props.tmNode
|
|
});
|
|
}
|
|
function handleDragEnter(e) {
|
|
if (e.currentTarget !== e.target) {
|
|
return;
|
|
}
|
|
NTree.handleDragEnter({
|
|
event: e,
|
|
node: props.tmNode
|
|
});
|
|
}
|
|
function handleDragOver(e) {
|
|
e.preventDefault(); // if not prevent, drop event won't be fired...
|
|
NTree.handleDragOver({
|
|
event: e,
|
|
node: props.tmNode
|
|
});
|
|
}
|
|
function handleDragEnd(e) {
|
|
NTree.handleDragEnd({
|
|
event: e,
|
|
node: props.tmNode
|
|
});
|
|
}
|
|
function handleDragLeave(e) {
|
|
if (e.currentTarget !== e.target) {
|
|
return;
|
|
}
|
|
NTree.handleDragLeave({
|
|
event: e,
|
|
node: props.tmNode
|
|
});
|
|
}
|
|
function handleDrop(e) {
|
|
e.preventDefault();
|
|
if (droppingPositionRef.value !== null) {
|
|
NTree.handleDrop({
|
|
event: e,
|
|
node: props.tmNode,
|
|
dropPosition: droppingPositionRef.value
|
|
});
|
|
}
|
|
}
|
|
const indentNodes = (0, vue_1.computed)(() => {
|
|
const { clsPrefix } = props;
|
|
const { value: indent } = indentRef;
|
|
if (showLineRef.value) {
|
|
const indentNodes = [];
|
|
let cursor = props.tmNode.parent;
|
|
while (cursor) {
|
|
if (cursor.isLastChild) {
|
|
indentNodes.push((0, vue_1.h)("div", { class: `${clsPrefix}-tree-node-indent` },
|
|
(0, vue_1.h)("div", { style: { width: `${indent}px` } })));
|
|
}
|
|
else {
|
|
indentNodes.push((0, vue_1.h)("div", { class: [
|
|
`${clsPrefix}-tree-node-indent`,
|
|
`${clsPrefix}-tree-node-indent--show-line`
|
|
] },
|
|
(0, vue_1.h)("div", { style: { width: `${indent}px` } })));
|
|
}
|
|
cursor = cursor.parent;
|
|
}
|
|
return indentNodes.reverse();
|
|
}
|
|
else {
|
|
return (0, seemly_1.repeat)(props.tmNode.level, (0, vue_1.h)("div", { class: `${props.clsPrefix}-tree-node-indent` },
|
|
(0, vue_1.h)("div", { style: { width: `${indent}px` } })));
|
|
}
|
|
});
|
|
return {
|
|
showDropMark: (0, vooks_1.useMemo)(() => {
|
|
const { value: draggingNode } = draggingNodeRef;
|
|
if (!draggingNode)
|
|
return;
|
|
const { value: droppingPosition } = droppingPositionRef;
|
|
if (!droppingPosition)
|
|
return;
|
|
const { value: droppingMouseNode } = droppingMouseNodeRef;
|
|
if (!droppingMouseNode) {
|
|
return;
|
|
}
|
|
const { tmNode } = props;
|
|
if (tmNode.key === droppingMouseNode.key)
|
|
return true;
|
|
return false;
|
|
}),
|
|
showDropMarkAsParent: (0, vooks_1.useMemo)(() => {
|
|
const { value: droppingNodeParent } = droppingNodeParentRef;
|
|
if (!droppingNodeParent)
|
|
return false;
|
|
const { tmNode } = props;
|
|
const { value: droppingPosition } = droppingPositionRef;
|
|
if (droppingPosition === 'before' || droppingPosition === 'after') {
|
|
return droppingNodeParent.key === tmNode.key;
|
|
}
|
|
return false;
|
|
}),
|
|
pending: (0, vooks_1.useMemo)(() => NTree.pendingNodeKeyRef.value === props.tmNode.key),
|
|
loading: (0, vooks_1.useMemo)(() => NTree.loadingKeysRef.value.has(props.tmNode.key)),
|
|
highlight: (0, vooks_1.useMemo)(() => {
|
|
var _a;
|
|
return (_a = NTree.highlightKeySetRef.value) === null || _a === void 0 ? void 0 : _a.has(props.tmNode.key);
|
|
}),
|
|
checked: checkedRef,
|
|
indeterminate: (0, vooks_1.useMemo)(() => NTree.displayedIndeterminateKeysRef.value.includes(props.tmNode.key)),
|
|
selected: (0, vooks_1.useMemo)(() => NTree.mergedSelectedKeysRef.value.includes(props.tmNode.key)),
|
|
expanded: (0, vooks_1.useMemo)(() => NTree.mergedExpandedKeysRef.value.includes(props.tmNode.key)),
|
|
disabled: disabledRef,
|
|
checkable: checkableRef,
|
|
mergedCheckOnClick: mergedCheckOnClickRef,
|
|
checkboxDisabled: checkboxDisabledRef,
|
|
selectable: selectableRef,
|
|
expandOnClick: NTree.expandOnClickRef,
|
|
internalScrollable: NTree.internalScrollableRef,
|
|
draggable: NTree.draggableRef,
|
|
blockLine: blockLineRef,
|
|
nodeProps: resolvedNodePropsRef,
|
|
checkboxFocusable: NTree.internalCheckboxFocusableRef,
|
|
droppingPosition: droppingPositionRef,
|
|
droppingOffsetLevel: droppingOffsetLevelRef,
|
|
indent: indentRef,
|
|
checkboxPlacement: checkboxPlacementRef,
|
|
showLine: showLineRef,
|
|
contentInstRef,
|
|
contentElRef,
|
|
indentNodes,
|
|
handleCheck,
|
|
handleDrop,
|
|
handleDragStart,
|
|
handleDragEnter,
|
|
handleDragOver,
|
|
handleDragEnd,
|
|
handleDragLeave,
|
|
handleLineClick,
|
|
handleContentClick,
|
|
handleSwitcherClick
|
|
};
|
|
},
|
|
render() {
|
|
const { tmNode, clsPrefix, checkable, expandOnClick, selectable, selected, checked, highlight, draggable, blockLine, indent, indentNodes, disabled, pending, internalScrollable, nodeProps, checkboxPlacement } = this;
|
|
// drag start not inside
|
|
// it need to be append to node itself, not wrapper
|
|
const dragEventHandlers = draggable && !disabled
|
|
? {
|
|
onDragenter: this.handleDragEnter,
|
|
onDragleave: this.handleDragLeave,
|
|
onDragend: this.handleDragEnd,
|
|
onDrop: this.handleDrop,
|
|
onDragover: this.handleDragOver
|
|
}
|
|
: undefined;
|
|
// In non virtual mode, there's no evidence that which element should be
|
|
// scrolled to, so we need data-key to query the target element.
|
|
const dataKey = internalScrollable ? (0, _utils_1.createDataKey)(tmNode.key) : undefined;
|
|
const checkboxOnRight = checkboxPlacement === 'right';
|
|
const checkboxNode = checkable ? ((0, vue_1.h)(TreeNodeCheckbox_1.default, { indent: indent, right: checkboxOnRight, focusable: this.checkboxFocusable, disabled: disabled || this.checkboxDisabled, clsPrefix: clsPrefix, checked: this.checked, indeterminate: this.indeterminate, onCheck: this.handleCheck })) : null;
|
|
return ((0, vue_1.h)("div", Object.assign({ class: `${clsPrefix}-tree-node-wrapper` }, dragEventHandlers),
|
|
(0, vue_1.h)("div", Object.assign({}, (blockLine ? nodeProps : undefined), { class: [
|
|
`${clsPrefix}-tree-node`,
|
|
{
|
|
[`${clsPrefix}-tree-node--selected`]: selected,
|
|
[`${clsPrefix}-tree-node--checkable`]: checkable,
|
|
[`${clsPrefix}-tree-node--highlight`]: highlight,
|
|
[`${clsPrefix}-tree-node--pending`]: pending,
|
|
[`${clsPrefix}-tree-node--disabled`]: disabled,
|
|
[`${clsPrefix}-tree-node--selectable`]: selectable,
|
|
[`${clsPrefix}-tree-node--clickable`]: selectable || expandOnClick || this.mergedCheckOnClick
|
|
},
|
|
nodeProps === null || nodeProps === void 0 ? void 0 : nodeProps.class
|
|
], "data-key": dataKey, draggable: draggable && blockLine, onClick: this.handleLineClick, onDragstart: draggable && blockLine && !disabled
|
|
? this.handleDragStart
|
|
: undefined }),
|
|
indentNodes,
|
|
tmNode.isLeaf && this.showLine ? ((0, vue_1.h)("div", { class: [
|
|
`${clsPrefix}-tree-node-indent`,
|
|
`${clsPrefix}-tree-node-indent--show-line`,
|
|
tmNode.isLeaf && `${clsPrefix}-tree-node-indent--is-leaf`,
|
|
tmNode.isLastChild &&
|
|
`${clsPrefix}-tree-node-indent--last-child`
|
|
] },
|
|
(0, vue_1.h)("div", { style: { width: `${indent}px` } }))) : ((0, vue_1.h)(TreeNodeSwitcher_1.default, { clsPrefix: clsPrefix, expanded: this.expanded, selected: selected, loading: this.loading, hide: tmNode.isLeaf, tmNode: this.tmNode, indent: indent, onClick: this.handleSwitcherClick })),
|
|
!checkboxOnRight ? checkboxNode : null,
|
|
(0, vue_1.h)(TreeNodeContent_1.default, { ref: "contentInstRef", clsPrefix: clsPrefix, checked: checked, selected: selected, onClick: this.handleContentClick, nodeProps: blockLine ? undefined : nodeProps, onDragstart: draggable && !blockLine && !disabled
|
|
? this.handleDragStart
|
|
: undefined, tmNode: tmNode }),
|
|
draggable
|
|
? this.showDropMark
|
|
? (0, dnd_1.renderDropMark)({
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
el: this.contentElRef.value,
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
position: this.droppingPosition,
|
|
offsetLevel: this.droppingOffsetLevel,
|
|
indent
|
|
})
|
|
: this.showDropMarkAsParent
|
|
? (0, dnd_1.renderDropMark)({
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
el: this.contentElRef.value,
|
|
position: 'inside',
|
|
offsetLevel: this.droppingOffsetLevel,
|
|
indent
|
|
})
|
|
: null
|
|
: null,
|
|
checkboxOnRight ? checkboxNode : null)));
|
|
}
|
|
});
|
|
exports.default = TreeNode;
|