treeUtil.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.convertDataToEntities = convertDataToEntities;
  7. exports.convertNodePropsToEventData = convertNodePropsToEventData;
  8. exports.convertTreeToData = convertTreeToData;
  9. exports.fillFieldNames = fillFieldNames;
  10. exports.flattenTreeData = flattenTreeData;
  11. exports.getKey = getKey;
  12. exports.getTreeNodeProps = getTreeNodeProps;
  13. exports.traverseDataNodes = traverseDataNodes;
  14. exports.warningWithoutKey = warningWithoutKey;
  15. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  16. var _util = require("../util");
  17. var _warning = require("../../vc-util/warning");
  18. var _propsUtil = require("../../_util/props-util");
  19. var _omit = _interopRequireDefault(require("../../_util/omit"));
  20. var __rest = void 0 && (void 0).__rest || function (s, e) {
  21. var t = {};
  22. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  23. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  24. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  25. }
  26. return t;
  27. };
  28. function getKey(key, pos) {
  29. if (key !== null && key !== undefined) {
  30. return key;
  31. }
  32. return pos;
  33. }
  34. function fillFieldNames(fieldNames) {
  35. const {
  36. title,
  37. _title,
  38. key,
  39. children
  40. } = fieldNames || {};
  41. const mergedTitle = title || 'title';
  42. return {
  43. title: mergedTitle,
  44. _title: _title || [mergedTitle],
  45. key: key || 'key',
  46. children: children || 'children'
  47. };
  48. }
  49. /**
  50. * Warning if TreeNode do not provides key
  51. */
  52. function warningWithoutKey(treeData, fieldNames) {
  53. const keys = new Map();
  54. function dig(list) {
  55. let path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
  56. (list || []).forEach(treeNode => {
  57. const key = treeNode[fieldNames.key];
  58. const children = treeNode[fieldNames.children];
  59. (0, _warning.warning)(key !== null && key !== undefined, `Tree node must have a certain key: [${path}${key}]`);
  60. const recordKey = String(key);
  61. (0, _warning.warning)(!keys.has(recordKey) || key === null || key === undefined, `Same 'key' exist in the Tree: ${recordKey}`);
  62. keys.set(recordKey, true);
  63. dig(children, `${path}${recordKey} > `);
  64. });
  65. }
  66. dig(treeData);
  67. }
  68. /**
  69. * Convert `children` of Tree into `treeData` structure.
  70. */
  71. function convertTreeToData(rootNodes) {
  72. function dig() {
  73. let node = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  74. const treeNodes = (0, _propsUtil.filterEmpty)(node);
  75. return treeNodes.map(treeNode => {
  76. var _a, _b, _c, _d;
  77. // Filter invalidate node
  78. if (!(0, _util.isTreeNode)(treeNode)) {
  79. (0, _warning.warning)(!treeNode, 'Tree/TreeNode can only accept TreeNode as children.');
  80. return null;
  81. }
  82. const slots = treeNode.children || {};
  83. const key = treeNode.key;
  84. const props = {};
  85. for (const [k, v] of Object.entries(treeNode.props)) {
  86. props[(0, _propsUtil.camelize)(k)] = v;
  87. }
  88. const {
  89. isLeaf,
  90. checkable,
  91. selectable,
  92. disabled,
  93. disableCheckbox
  94. } = props;
  95. // 默认值为 undefined
  96. const newProps = {
  97. isLeaf: isLeaf || isLeaf === '' || undefined,
  98. checkable: checkable || checkable === '' || undefined,
  99. selectable: selectable || selectable === '' || undefined,
  100. disabled: disabled || disabled === '' || undefined,
  101. disableCheckbox: disableCheckbox || disableCheckbox === '' || undefined
  102. };
  103. const slotsProps = (0, _extends2.default)((0, _extends2.default)({}, props), newProps);
  104. const {
  105. title = (_a = slots.title) === null || _a === void 0 ? void 0 : _a.call(slots, slotsProps),
  106. icon = (_b = slots.icon) === null || _b === void 0 ? void 0 : _b.call(slots, slotsProps),
  107. switcherIcon = (_c = slots.switcherIcon) === null || _c === void 0 ? void 0 : _c.call(slots, slotsProps)
  108. } = props,
  109. rest = __rest(props, ["title", "icon", "switcherIcon"]);
  110. const children = (_d = slots.default) === null || _d === void 0 ? void 0 : _d.call(slots);
  111. const dataNode = (0, _extends2.default)((0, _extends2.default)((0, _extends2.default)({}, rest), {
  112. title,
  113. icon,
  114. switcherIcon,
  115. key,
  116. isLeaf
  117. }), newProps);
  118. const parsedChildren = dig(children);
  119. if (parsedChildren.length) {
  120. dataNode.children = parsedChildren;
  121. }
  122. return dataNode;
  123. });
  124. }
  125. return dig(rootNodes);
  126. }
  127. /**
  128. * Flat nest tree data into flatten list. This is used for virtual list render.
  129. * @param treeNodeList Origin data node list
  130. * @param expandedKeys
  131. * need expanded keys, provides `true` means all expanded (used in `rc-tree-select`).
  132. */
  133. function flattenTreeData(treeNodeList, expandedKeys, fieldNames) {
  134. const {
  135. _title: fieldTitles,
  136. key: fieldKey,
  137. children: fieldChildren
  138. } = fillFieldNames(fieldNames);
  139. const expandedKeySet = new Set(expandedKeys === true ? [] : expandedKeys);
  140. const flattenList = [];
  141. function dig(list) {
  142. let parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  143. return list.map((treeNode, index) => {
  144. const pos = (0, _util.getPosition)(parent ? parent.pos : '0', index);
  145. const mergedKey = getKey(treeNode[fieldKey], pos);
  146. // Pick matched title in field title list
  147. let mergedTitle;
  148. for (let i = 0; i < fieldTitles.length; i += 1) {
  149. const fieldTitle = fieldTitles[i];
  150. if (treeNode[fieldTitle] !== undefined) {
  151. mergedTitle = treeNode[fieldTitle];
  152. break;
  153. }
  154. }
  155. // Add FlattenDataNode into list
  156. const flattenNode = (0, _extends2.default)((0, _extends2.default)({}, (0, _omit.default)(treeNode, [...fieldTitles, fieldKey, fieldChildren])), {
  157. title: mergedTitle,
  158. key: mergedKey,
  159. parent,
  160. pos,
  161. children: null,
  162. data: treeNode,
  163. isStart: [...(parent ? parent.isStart : []), index === 0],
  164. isEnd: [...(parent ? parent.isEnd : []), index === list.length - 1]
  165. });
  166. flattenList.push(flattenNode);
  167. // Loop treeNode children
  168. if (expandedKeys === true || expandedKeySet.has(mergedKey)) {
  169. flattenNode.children = dig(treeNode[fieldChildren] || [], flattenNode);
  170. } else {
  171. flattenNode.children = [];
  172. }
  173. return flattenNode;
  174. });
  175. }
  176. dig(treeNodeList);
  177. return flattenList;
  178. }
  179. /**
  180. * Traverse all the data by `treeData`.
  181. * Please not use it out of the `rc-tree` since we may refactor this code.
  182. */
  183. function traverseDataNodes(dataNodes, callback,
  184. // To avoid too many params, let use config instead of origin param
  185. config) {
  186. let mergedConfig = {};
  187. if (typeof config === 'object') {
  188. mergedConfig = config;
  189. } else {
  190. mergedConfig = {
  191. externalGetKey: config
  192. };
  193. }
  194. mergedConfig = mergedConfig || {};
  195. // Init config
  196. const {
  197. childrenPropName,
  198. externalGetKey,
  199. fieldNames
  200. } = mergedConfig;
  201. const {
  202. key: fieldKey,
  203. children: fieldChildren
  204. } = fillFieldNames(fieldNames);
  205. const mergeChildrenPropName = childrenPropName || fieldChildren;
  206. // Get keys
  207. let syntheticGetKey;
  208. if (externalGetKey) {
  209. if (typeof externalGetKey === 'string') {
  210. syntheticGetKey = node => node[externalGetKey];
  211. } else if (typeof externalGetKey === 'function') {
  212. syntheticGetKey = node => externalGetKey(node);
  213. }
  214. } else {
  215. syntheticGetKey = (node, pos) => getKey(node[fieldKey], pos);
  216. }
  217. // Process
  218. function processNode(node, index, parent, pathNodes) {
  219. const children = node ? node[mergeChildrenPropName] : dataNodes;
  220. const pos = node ? (0, _util.getPosition)(parent.pos, index) : '0';
  221. const connectNodes = node ? [...pathNodes, node] : [];
  222. // Process node if is not root
  223. if (node) {
  224. const key = syntheticGetKey(node, pos);
  225. const data = {
  226. node,
  227. index,
  228. pos,
  229. key,
  230. parentPos: parent.node ? parent.pos : null,
  231. level: parent.level + 1,
  232. nodes: connectNodes
  233. };
  234. callback(data);
  235. }
  236. // Process children node
  237. if (children) {
  238. children.forEach((subNode, subIndex) => {
  239. processNode(subNode, subIndex, {
  240. node,
  241. pos,
  242. level: parent ? parent.level + 1 : -1
  243. }, connectNodes);
  244. });
  245. }
  246. }
  247. processNode(null);
  248. }
  249. /**
  250. * Convert `treeData` into entity records.
  251. */
  252. function convertDataToEntities(dataNodes) {
  253. let {
  254. initWrapper,
  255. processEntity,
  256. onProcessFinished,
  257. externalGetKey,
  258. childrenPropName,
  259. fieldNames
  260. } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  261. let /** @deprecated Use `config.externalGetKey` instead */
  262. legacyExternalGetKey = arguments.length > 2 ? arguments[2] : undefined;
  263. // Init config
  264. const mergedExternalGetKey = externalGetKey || legacyExternalGetKey;
  265. const posEntities = {};
  266. const keyEntities = {};
  267. let wrapper = {
  268. posEntities,
  269. keyEntities
  270. };
  271. if (initWrapper) {
  272. wrapper = initWrapper(wrapper) || wrapper;
  273. }
  274. traverseDataNodes(dataNodes, item => {
  275. const {
  276. node,
  277. index,
  278. pos,
  279. key,
  280. parentPos,
  281. level,
  282. nodes
  283. } = item;
  284. const entity = {
  285. node,
  286. nodes,
  287. index,
  288. key,
  289. pos,
  290. level
  291. };
  292. const mergedKey = getKey(key, pos);
  293. posEntities[pos] = entity;
  294. keyEntities[mergedKey] = entity;
  295. // Fill children
  296. entity.parent = posEntities[parentPos];
  297. if (entity.parent) {
  298. entity.parent.children = entity.parent.children || [];
  299. entity.parent.children.push(entity);
  300. }
  301. if (processEntity) {
  302. processEntity(entity, wrapper);
  303. }
  304. }, {
  305. externalGetKey: mergedExternalGetKey,
  306. childrenPropName,
  307. fieldNames
  308. });
  309. if (onProcessFinished) {
  310. onProcessFinished(wrapper);
  311. }
  312. return wrapper;
  313. }
  314. /**
  315. * Get TreeNode props with Tree props.
  316. */
  317. function getTreeNodeProps(key, _ref) {
  318. let {
  319. expandedKeysSet,
  320. selectedKeysSet,
  321. loadedKeysSet,
  322. loadingKeysSet,
  323. checkedKeysSet,
  324. halfCheckedKeysSet,
  325. dragOverNodeKey,
  326. dropPosition,
  327. keyEntities
  328. } = _ref;
  329. const entity = keyEntities[key];
  330. const treeNodeProps = {
  331. eventKey: key,
  332. expanded: expandedKeysSet.has(key),
  333. selected: selectedKeysSet.has(key),
  334. loaded: loadedKeysSet.has(key),
  335. loading: loadingKeysSet.has(key),
  336. checked: checkedKeysSet.has(key),
  337. halfChecked: halfCheckedKeysSet.has(key),
  338. pos: String(entity ? entity.pos : ''),
  339. parent: entity.parent,
  340. // [Legacy] Drag props
  341. // Since the interaction of drag is changed, the semantic of the props are
  342. // not accuracy, I think it should be finally removed
  343. dragOver: dragOverNodeKey === key && dropPosition === 0,
  344. dragOverGapTop: dragOverNodeKey === key && dropPosition === -1,
  345. dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1
  346. };
  347. return treeNodeProps;
  348. }
  349. function convertNodePropsToEventData(props) {
  350. const {
  351. data,
  352. expanded,
  353. selected,
  354. checked,
  355. loaded,
  356. loading,
  357. halfChecked,
  358. dragOver,
  359. dragOverGapTop,
  360. dragOverGapBottom,
  361. pos,
  362. active,
  363. eventKey
  364. } = props;
  365. const eventData = (0, _extends2.default)((0, _extends2.default)({
  366. dataRef: data
  367. }, data), {
  368. expanded,
  369. selected,
  370. checked,
  371. loaded,
  372. loading,
  373. halfChecked,
  374. dragOver,
  375. dragOverGapTop,
  376. dragOverGapBottom,
  377. pos,
  378. active,
  379. eventKey,
  380. key: eventKey
  381. });
  382. if (!('props' in eventData)) {
  383. Object.defineProperty(eventData, 'props', {
  384. get() {
  385. (0, _warning.warning)(false, 'Second param return from event is node data instead of TreeNode instance. Please read value directly instead of reading from `props`.');
  386. return props;
  387. }
  388. });
  389. }
  390. return eventData;
  391. }