TreeNode.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = void 0;
  7. var _vue = require("vue");
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  10. var _contextTypes = require("./contextTypes");
  11. var _Indent = _interopRequireDefault(require("./Indent"));
  12. var _treeUtil = require("./utils/treeUtil");
  13. var _props = require("./props");
  14. var _classNames = _interopRequireDefault(require("../_util/classNames"));
  15. var _warning = require("../vc-util/warning");
  16. var _pickAttrs = _interopRequireDefault(require("../_util/pickAttrs"));
  17. var _eagerComputed = _interopRequireDefault(require("../_util/eagerComputed"));
  18. var __rest = void 0 && (void 0).__rest || function (s, e) {
  19. var t = {};
  20. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  21. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  22. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  23. }
  24. return t;
  25. };
  26. const ICON_OPEN = 'open';
  27. const ICON_CLOSE = 'close';
  28. const defaultTitle = '---';
  29. var _default = exports.default = (0, _vue.defineComponent)({
  30. compatConfig: {
  31. MODE: 3
  32. },
  33. name: 'ATreeNode',
  34. inheritAttrs: false,
  35. props: _props.treeNodeProps,
  36. isTreeNode: 1,
  37. setup(props, _ref) {
  38. let {
  39. attrs,
  40. slots,
  41. expose
  42. } = _ref;
  43. (0, _warning.warning)(!('slots' in props.data), `treeData slots is deprecated, please use ${Object.keys(props.data.slots || {}).map(key => '`v-slot:' + key + '` ')}instead`);
  44. const dragNodeHighlight = (0, _vue.shallowRef)(false);
  45. const context = (0, _contextTypes.useInjectTreeContext)();
  46. const {
  47. expandedKeysSet,
  48. selectedKeysSet,
  49. loadedKeysSet,
  50. loadingKeysSet,
  51. checkedKeysSet,
  52. halfCheckedKeysSet
  53. } = (0, _contextTypes.useInjectKeysState)();
  54. const {
  55. dragOverNodeKey,
  56. dropPosition,
  57. keyEntities
  58. } = context.value;
  59. const mergedTreeNodeProps = (0, _vue.computed)(() => {
  60. return (0, _treeUtil.getTreeNodeProps)(props.eventKey, {
  61. expandedKeysSet: expandedKeysSet.value,
  62. selectedKeysSet: selectedKeysSet.value,
  63. loadedKeysSet: loadedKeysSet.value,
  64. loadingKeysSet: loadingKeysSet.value,
  65. checkedKeysSet: checkedKeysSet.value,
  66. halfCheckedKeysSet: halfCheckedKeysSet.value,
  67. dragOverNodeKey,
  68. dropPosition,
  69. keyEntities
  70. });
  71. });
  72. const expanded = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.expanded);
  73. const selected = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.selected);
  74. const checked = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.checked);
  75. const loaded = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.loaded);
  76. const loading = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.loading);
  77. const halfChecked = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.halfChecked);
  78. const dragOver = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.dragOver);
  79. const dragOverGapTop = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.dragOverGapTop);
  80. const dragOverGapBottom = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.dragOverGapBottom);
  81. const pos = (0, _eagerComputed.default)(() => mergedTreeNodeProps.value.pos);
  82. const selectHandle = (0, _vue.shallowRef)();
  83. const hasChildren = (0, _vue.computed)(() => {
  84. const {
  85. eventKey
  86. } = props;
  87. const {
  88. keyEntities
  89. } = context.value;
  90. const {
  91. children
  92. } = keyEntities[eventKey] || {};
  93. return !!(children || []).length;
  94. });
  95. const isLeaf = (0, _vue.computed)(() => {
  96. const {
  97. isLeaf
  98. } = props;
  99. const {
  100. loadData
  101. } = context.value;
  102. const has = hasChildren.value;
  103. if (isLeaf === false) {
  104. return false;
  105. }
  106. return isLeaf || !loadData && !has || loadData && loaded.value && !has;
  107. });
  108. const nodeState = (0, _vue.computed)(() => {
  109. if (isLeaf.value) {
  110. return null;
  111. }
  112. return expanded.value ? ICON_OPEN : ICON_CLOSE;
  113. });
  114. const isDisabled = (0, _vue.computed)(() => {
  115. const {
  116. disabled
  117. } = props;
  118. const {
  119. disabled: treeDisabled
  120. } = context.value;
  121. return !!(treeDisabled || disabled);
  122. });
  123. const isCheckable = (0, _vue.computed)(() => {
  124. const {
  125. checkable
  126. } = props;
  127. const {
  128. checkable: treeCheckable
  129. } = context.value;
  130. // Return false if tree or treeNode is not checkable
  131. if (!treeCheckable || checkable === false) return false;
  132. return treeCheckable;
  133. });
  134. const isSelectable = (0, _vue.computed)(() => {
  135. const {
  136. selectable
  137. } = props;
  138. const {
  139. selectable: treeSelectable
  140. } = context.value;
  141. // Ignore when selectable is undefined or null
  142. if (typeof selectable === 'boolean') {
  143. return selectable;
  144. }
  145. return treeSelectable;
  146. });
  147. const renderArgsData = (0, _vue.computed)(() => {
  148. const {
  149. data,
  150. active,
  151. checkable,
  152. disableCheckbox,
  153. disabled,
  154. selectable
  155. } = props;
  156. return (0, _extends2.default)((0, _extends2.default)({
  157. active,
  158. checkable,
  159. disableCheckbox,
  160. disabled,
  161. selectable
  162. }, data), {
  163. dataRef: data,
  164. data,
  165. isLeaf: isLeaf.value,
  166. checked: checked.value,
  167. expanded: expanded.value,
  168. loading: loading.value,
  169. selected: selected.value,
  170. halfChecked: halfChecked.value
  171. });
  172. });
  173. const instance = (0, _vue.getCurrentInstance)();
  174. const eventData = (0, _vue.computed)(() => {
  175. const {
  176. eventKey
  177. } = props;
  178. const {
  179. keyEntities
  180. } = context.value;
  181. const {
  182. parent
  183. } = keyEntities[eventKey] || {};
  184. return (0, _extends2.default)((0, _extends2.default)({}, (0, _treeUtil.convertNodePropsToEventData)((0, _extends2.default)({}, props, mergedTreeNodeProps.value))), {
  185. parent
  186. });
  187. });
  188. const dragNodeEvent = (0, _vue.reactive)({
  189. eventData,
  190. eventKey: (0, _vue.computed)(() => props.eventKey),
  191. selectHandle,
  192. pos,
  193. key: instance.vnode.key
  194. });
  195. expose(dragNodeEvent);
  196. const onSelectorDoubleClick = e => {
  197. const {
  198. onNodeDoubleClick
  199. } = context.value;
  200. onNodeDoubleClick(e, eventData.value);
  201. };
  202. const onSelect = e => {
  203. if (isDisabled.value) return;
  204. const {
  205. onNodeSelect
  206. } = context.value;
  207. e.preventDefault();
  208. onNodeSelect(e, eventData.value);
  209. };
  210. const onCheck = e => {
  211. if (isDisabled.value) return;
  212. const {
  213. disableCheckbox
  214. } = props;
  215. const {
  216. onNodeCheck
  217. } = context.value;
  218. if (!isCheckable.value || disableCheckbox) return;
  219. e.preventDefault();
  220. const targetChecked = !checked.value;
  221. onNodeCheck(e, eventData.value, targetChecked);
  222. };
  223. const onSelectorClick = e => {
  224. // Click trigger before select/check operation
  225. const {
  226. onNodeClick
  227. } = context.value;
  228. onNodeClick(e, eventData.value);
  229. if (isSelectable.value) {
  230. onSelect(e);
  231. } else {
  232. onCheck(e);
  233. }
  234. };
  235. const onMouseEnter = e => {
  236. const {
  237. onNodeMouseEnter
  238. } = context.value;
  239. onNodeMouseEnter(e, eventData.value);
  240. };
  241. const onMouseLeave = e => {
  242. const {
  243. onNodeMouseLeave
  244. } = context.value;
  245. onNodeMouseLeave(e, eventData.value);
  246. };
  247. const onContextmenu = e => {
  248. const {
  249. onNodeContextMenu
  250. } = context.value;
  251. onNodeContextMenu(e, eventData.value);
  252. };
  253. const onDragStart = e => {
  254. const {
  255. onNodeDragStart
  256. } = context.value;
  257. e.stopPropagation();
  258. dragNodeHighlight.value = true;
  259. onNodeDragStart(e, dragNodeEvent);
  260. try {
  261. // ie throw error
  262. // firefox-need-it
  263. e.dataTransfer.setData('text/plain', '');
  264. } catch (error) {
  265. // empty
  266. }
  267. };
  268. const onDragEnter = e => {
  269. const {
  270. onNodeDragEnter
  271. } = context.value;
  272. e.preventDefault();
  273. e.stopPropagation();
  274. onNodeDragEnter(e, dragNodeEvent);
  275. };
  276. const onDragOver = e => {
  277. const {
  278. onNodeDragOver
  279. } = context.value;
  280. e.preventDefault();
  281. e.stopPropagation();
  282. onNodeDragOver(e, dragNodeEvent);
  283. };
  284. const onDragLeave = e => {
  285. const {
  286. onNodeDragLeave
  287. } = context.value;
  288. e.stopPropagation();
  289. onNodeDragLeave(e, dragNodeEvent);
  290. };
  291. const onDragEnd = e => {
  292. const {
  293. onNodeDragEnd
  294. } = context.value;
  295. e.stopPropagation();
  296. dragNodeHighlight.value = false;
  297. onNodeDragEnd(e, dragNodeEvent);
  298. };
  299. const onDrop = e => {
  300. const {
  301. onNodeDrop
  302. } = context.value;
  303. e.preventDefault();
  304. e.stopPropagation();
  305. dragNodeHighlight.value = false;
  306. onNodeDrop(e, dragNodeEvent);
  307. };
  308. // Disabled item still can be switch
  309. const onExpand = e => {
  310. const {
  311. onNodeExpand
  312. } = context.value;
  313. if (loading.value) return;
  314. onNodeExpand(e, eventData.value);
  315. };
  316. const isDraggable = () => {
  317. const {
  318. data
  319. } = props;
  320. const {
  321. draggable
  322. } = context.value;
  323. return !!(draggable && (!draggable.nodeDraggable || draggable.nodeDraggable(data)));
  324. };
  325. // ==================== Render: Drag Handler ====================
  326. const renderDragHandler = () => {
  327. const {
  328. draggable,
  329. prefixCls
  330. } = context.value;
  331. return draggable && (draggable === null || draggable === void 0 ? void 0 : draggable.icon) ? (0, _vue.createVNode)("span", {
  332. "class": `${prefixCls}-draggable-icon`
  333. }, [draggable.icon]) : null;
  334. };
  335. const renderSwitcherIconDom = () => {
  336. var _a, _b, _c;
  337. const {
  338. switcherIcon: switcherIconFromProps = slots.switcherIcon || ((_a = context.value.slots) === null || _a === void 0 ? void 0 : _a[(_c = (_b = props.data) === null || _b === void 0 ? void 0 : _b.slots) === null || _c === void 0 ? void 0 : _c.switcherIcon])
  339. } = props;
  340. const {
  341. switcherIcon: switcherIconFromCtx
  342. } = context.value;
  343. const switcherIcon = switcherIconFromProps || switcherIconFromCtx;
  344. // if switcherIconDom is null, no render switcher span
  345. if (typeof switcherIcon === 'function') {
  346. return switcherIcon(renderArgsData.value);
  347. }
  348. return switcherIcon;
  349. };
  350. // Load data to avoid default expanded tree without data
  351. const syncLoadData = () => {
  352. //const { expanded, loading, loaded } = props;
  353. const {
  354. loadData,
  355. onNodeLoad
  356. } = context.value;
  357. if (loading.value) {
  358. return;
  359. }
  360. // read from state to avoid loadData at same time
  361. if (loadData && expanded.value && !isLeaf.value) {
  362. // We needn't reload data when has children in sync logic
  363. // It's only needed in node expanded
  364. if (!hasChildren.value && !loaded.value) {
  365. onNodeLoad(eventData.value);
  366. }
  367. }
  368. };
  369. (0, _vue.onMounted)(() => {
  370. syncLoadData();
  371. });
  372. (0, _vue.onUpdated)(() => {
  373. // https://github.com/vueComponent/ant-design-vue/issues/4835
  374. syncLoadData();
  375. });
  376. // Switcher
  377. const renderSwitcher = () => {
  378. const {
  379. prefixCls
  380. } = context.value;
  381. // if switcherIconDom is null, no render switcher span
  382. const switcherIconDom = renderSwitcherIconDom();
  383. if (isLeaf.value) {
  384. return switcherIconDom !== false ? (0, _vue.createVNode)("span", {
  385. "class": (0, _classNames.default)(`${prefixCls}-switcher`, `${prefixCls}-switcher-noop`)
  386. }, [switcherIconDom]) : null;
  387. }
  388. const switcherCls = (0, _classNames.default)(`${prefixCls}-switcher`, `${prefixCls}-switcher_${expanded.value ? ICON_OPEN : ICON_CLOSE}`);
  389. return switcherIconDom !== false ? (0, _vue.createVNode)("span", {
  390. "onClick": onExpand,
  391. "class": switcherCls
  392. }, [switcherIconDom]) : null;
  393. };
  394. // Checkbox
  395. const renderCheckbox = () => {
  396. var _a, _b;
  397. const {
  398. disableCheckbox
  399. } = props;
  400. const {
  401. prefixCls
  402. } = context.value;
  403. const disabled = isDisabled.value;
  404. const checkable = isCheckable.value;
  405. if (!checkable) return null;
  406. return (0, _vue.createVNode)("span", {
  407. "class": (0, _classNames.default)(`${prefixCls}-checkbox`, checked.value && `${prefixCls}-checkbox-checked`, !checked.value && halfChecked.value && `${prefixCls}-checkbox-indeterminate`, (disabled || disableCheckbox) && `${prefixCls}-checkbox-disabled`),
  408. "onClick": onCheck
  409. }, [(_b = (_a = context.value).customCheckable) === null || _b === void 0 ? void 0 : _b.call(_a)]);
  410. };
  411. const renderIcon = () => {
  412. const {
  413. prefixCls
  414. } = context.value;
  415. return (0, _vue.createVNode)("span", {
  416. "class": (0, _classNames.default)(`${prefixCls}-iconEle`, `${prefixCls}-icon__${nodeState.value || 'docu'}`, loading.value && `${prefixCls}-icon_loading`)
  417. }, null);
  418. };
  419. const renderDropIndicator = () => {
  420. const {
  421. disabled,
  422. eventKey
  423. } = props;
  424. const {
  425. draggable,
  426. dropLevelOffset,
  427. dropPosition,
  428. prefixCls,
  429. indent,
  430. dropIndicatorRender,
  431. dragOverNodeKey,
  432. direction
  433. } = context.value;
  434. const rootDraggable = draggable !== false;
  435. // allowDrop is calculated in Tree.tsx, there is no need for calc it here
  436. const showIndicator = !disabled && rootDraggable && dragOverNodeKey === eventKey;
  437. return showIndicator ? dropIndicatorRender({
  438. dropPosition,
  439. dropLevelOffset,
  440. indent,
  441. prefixCls,
  442. direction
  443. }) : null;
  444. };
  445. // Icon + Title
  446. const renderSelector = () => {
  447. var _a, _b, _c, _d, _e, _f;
  448. const {
  449. // title = slots.title ||
  450. // context.value.slots?.[props.data?.slots?.title] ||
  451. // context.value.slots?.title,
  452. // selected,
  453. icon = slots.icon,
  454. // loading,
  455. data
  456. } = props;
  457. const title = slots.title || ((_a = context.value.slots) === null || _a === void 0 ? void 0 : _a[(_c = (_b = props.data) === null || _b === void 0 ? void 0 : _b.slots) === null || _c === void 0 ? void 0 : _c.title]) || ((_d = context.value.slots) === null || _d === void 0 ? void 0 : _d.title) || props.title;
  458. const {
  459. prefixCls,
  460. showIcon,
  461. icon: treeIcon,
  462. loadData
  463. // slots: contextSlots,
  464. } = context.value;
  465. const disabled = isDisabled.value;
  466. const wrapClass = `${prefixCls}-node-content-wrapper`;
  467. // Icon - Still show loading icon when loading without showIcon
  468. let $icon;
  469. if (showIcon) {
  470. const currentIcon = icon || ((_e = context.value.slots) === null || _e === void 0 ? void 0 : _e[(_f = data === null || data === void 0 ? void 0 : data.slots) === null || _f === void 0 ? void 0 : _f.icon]) || treeIcon;
  471. $icon = currentIcon ? (0, _vue.createVNode)("span", {
  472. "class": (0, _classNames.default)(`${prefixCls}-iconEle`, `${prefixCls}-icon__customize`)
  473. }, [typeof currentIcon === 'function' ? currentIcon(renderArgsData.value) : currentIcon]) : renderIcon();
  474. } else if (loadData && loading.value) {
  475. $icon = renderIcon();
  476. }
  477. // Title
  478. let titleNode;
  479. if (typeof title === 'function') {
  480. titleNode = title(renderArgsData.value);
  481. // } else if (contextSlots.titleRender) {
  482. // titleNode = contextSlots.titleRender(renderArgsData.value);
  483. } else {
  484. titleNode = title;
  485. }
  486. titleNode = titleNode === undefined ? defaultTitle : titleNode;
  487. const $title = (0, _vue.createVNode)("span", {
  488. "class": `${prefixCls}-title`
  489. }, [titleNode]);
  490. return (0, _vue.createVNode)("span", {
  491. "ref": selectHandle,
  492. "title": typeof title === 'string' ? title : '',
  493. "class": (0, _classNames.default)(`${wrapClass}`, `${wrapClass}-${nodeState.value || 'normal'}`, !disabled && (selected.value || dragNodeHighlight.value) && `${prefixCls}-node-selected`),
  494. "onMouseenter": onMouseEnter,
  495. "onMouseleave": onMouseLeave,
  496. "onContextmenu": onContextmenu,
  497. "onClick": onSelectorClick,
  498. "onDblclick": onSelectorDoubleClick
  499. }, [$icon, $title, renderDropIndicator()]);
  500. };
  501. return () => {
  502. const _a = (0, _extends2.default)((0, _extends2.default)({}, props), attrs),
  503. {
  504. eventKey,
  505. isLeaf,
  506. isStart,
  507. isEnd,
  508. domRef,
  509. active,
  510. data,
  511. onMousemove,
  512. selectable
  513. } = _a,
  514. otherProps = __rest(_a, ["eventKey", "isLeaf", "isStart", "isEnd", "domRef", "active", "data", "onMousemove", "selectable"]);
  515. const {
  516. prefixCls,
  517. filterTreeNode,
  518. keyEntities,
  519. dropContainerKey,
  520. dropTargetKey,
  521. draggingNodeKey
  522. } = context.value;
  523. const disabled = isDisabled.value;
  524. const dataOrAriaAttributeProps = (0, _pickAttrs.default)(otherProps, {
  525. aria: true,
  526. data: true
  527. });
  528. const {
  529. level
  530. } = keyEntities[eventKey] || {};
  531. const isEndNode = isEnd[isEnd.length - 1];
  532. const mergedDraggable = isDraggable();
  533. const draggableWithoutDisabled = !disabled && mergedDraggable;
  534. const dragging = draggingNodeKey === eventKey;
  535. const ariaSelected = selectable !== undefined ? {
  536. 'aria-selected': !!selectable
  537. } : undefined;
  538. // console.log(1);
  539. return (0, _vue.createVNode)("div", (0, _objectSpread2.default)((0, _objectSpread2.default)({
  540. "ref": domRef,
  541. "class": (0, _classNames.default)(attrs.class, `${prefixCls}-treenode`, {
  542. [`${prefixCls}-treenode-disabled`]: disabled,
  543. [`${prefixCls}-treenode-switcher-${expanded.value ? 'open' : 'close'}`]: !isLeaf,
  544. [`${prefixCls}-treenode-checkbox-checked`]: checked.value,
  545. [`${prefixCls}-treenode-checkbox-indeterminate`]: halfChecked.value,
  546. [`${prefixCls}-treenode-selected`]: selected.value,
  547. [`${prefixCls}-treenode-loading`]: loading.value,
  548. [`${prefixCls}-treenode-active`]: active,
  549. [`${prefixCls}-treenode-leaf-last`]: isEndNode,
  550. [`${prefixCls}-treenode-draggable`]: draggableWithoutDisabled,
  551. dragging,
  552. 'drop-target': dropTargetKey === eventKey,
  553. 'drop-container': dropContainerKey === eventKey,
  554. 'drag-over': !disabled && dragOver.value,
  555. 'drag-over-gap-top': !disabled && dragOverGapTop.value,
  556. 'drag-over-gap-bottom': !disabled && dragOverGapBottom.value,
  557. 'filter-node': filterTreeNode && filterTreeNode(eventData.value)
  558. }),
  559. "style": attrs.style,
  560. "draggable": draggableWithoutDisabled,
  561. "aria-grabbed": dragging,
  562. "onDragstart": draggableWithoutDisabled ? onDragStart : undefined,
  563. "onDragenter": mergedDraggable ? onDragEnter : undefined,
  564. "onDragover": mergedDraggable ? onDragOver : undefined,
  565. "onDragleave": mergedDraggable ? onDragLeave : undefined,
  566. "onDrop": mergedDraggable ? onDrop : undefined,
  567. "onDragend": mergedDraggable ? onDragEnd : undefined,
  568. "onMousemove": onMousemove
  569. }, ariaSelected), dataOrAriaAttributeProps), [(0, _vue.createVNode)(_Indent.default, {
  570. "prefixCls": prefixCls,
  571. "level": level,
  572. "isStart": isStart,
  573. "isEnd": isEnd
  574. }, null), renderDragHandler(), renderSwitcher(), renderCheckbox(), renderSelector()]);
  575. };
  576. }
  577. });