UNPKG

27.3 kBJavaScriptView Raw
1
2/*!
3 * EyzyTree v0.0.4
4 * (c) 2018 amsik
5 * Released under the MIT License.
6 */
7
8(function (global, factory) {
9 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) :
10 typeof define === 'function' && define.amd ? define(['react'], factory) :
11 (global.EyzyTree = factory(global.React));
12}(this, (function (React) { 'use strict';
13
14 React = React && React.hasOwnProperty('default') ? React['default'] : React;
15
16 /*! *****************************************************************************
17 Copyright (c) Microsoft Corporation. All rights reserved.
18 Licensed under the Apache License, Version 2.0 (the "License"); you may not use
19 this file except in compliance with the License. You may obtain a copy of the
20 License at http://www.apache.org/licenses/LICENSE-2.0
21
22 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
24 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
25 MERCHANTABLITY OR NON-INFRINGEMENT.
26
27 See the Apache Version 2.0 License for specific language governing permissions
28 and limitations under the License.
29 ***************************************************************************** */
30 /* global Reflect, Promise */
31
32 var extendStatics = function(d, b) {
33 extendStatics = Object.setPrototypeOf ||
34 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
35 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
36 return extendStatics(d, b);
37 };
38
39 function __extends(d, b) {
40 extendStatics(d, b);
41 function __() { this.constructor = d; }
42 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
43 }
44
45 var __assign = function() {
46 __assign = Object.assign || function __assign(t) {
47 for (var s, i = 1, n = arguments.length; i < n; i++) {
48 s = arguments[i];
49 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
50 }
51 return t;
52 };
53 return __assign.apply(this, arguments);
54 };
55
56 var hasOwn = {}.hasOwnProperty;
57 function cn(args) {
58 var result = [];
59 for (var key in args) {
60 if (hasOwn.call(args, key) && args[key]) {
61 result.push(key);
62 }
63 }
64 return result.join(' ');
65 }
66
67 function shallowEqual(objA, objB, keys) {
68 if (objA === objB) {
69 return true;
70 }
71 for (var i = 0; i < keys.length; i++) {
72 var key = keys[i];
73 var valueA = objA[key];
74 var valueB = objB[key];
75 if (valueA !== valueB) {
76 return false;
77 }
78 }
79 return true;
80 }
81
82 var hasChild = function (node) {
83 return node.isBatch || Array.isArray(node.child) && node.child.length > 0;
84 };
85 var comparingKeys = [
86 'id', 'checked', 'selected', 'child'
87 ];
88 var TreeNode = /** @class */ (function (_super) {
89 __extends(TreeNode, _super);
90 function TreeNode() {
91 var _this = _super !== null && _super.apply(this, arguments) || this;
92 _this.handleSelect = function (event) {
93 if (_this.props.disabled) {
94 return;
95 }
96 if (_this.props.onSelect) {
97 _this.props.onSelect(_this.getNode(), event);
98 }
99 };
100 _this.handleCheck = function () {
101 if (_this.props.disabled || _this.props.disabledCheckbox) {
102 return;
103 }
104 if (_this.props.onCheck) {
105 _this.props.onCheck(_this.getNode());
106 }
107 };
108 _this.handleExpand = function () {
109 if (_this.props.onExpand) {
110 _this.props.onExpand(_this.getNode());
111 }
112 };
113 _this.handleDoubleClick = function (e) {
114 if (_this.props.onDoubleClick) {
115 _this.props.onDoubleClick(_this.getNode());
116 }
117 };
118 _this.renderCheckbox = function () {
119 if (!_this.props.checkable || _this.props.hidenCheckbox) {
120 return null;
121 }
122 var Checkbox = _this.props.checkboxRenderer;
123 if (!Checkbox) {
124 return React.createElement("span", { className: "node-checkbox", onMouseUp: _this.handleCheck });
125 }
126 return (React.createElement("span", { className: "node-checkbox-overrided", onMouseUp: _this.handleCheck },
127 React.createElement(Checkbox, { node: _this.getNode() })));
128 };
129 _this.renderArrow = function () {
130 var ArrowRenderer = _this.props.arrowRenderer;
131 if (!hasChild(_this.props)) {
132 return React.createElement("span", { className: "node-noop" });
133 }
134 if (!ArrowRenderer) {
135 return React.createElement("span", { className: "node-arrow", onMouseUp: _this.handleExpand });
136 }
137 return (React.createElement("span", { className: "node-arrow-extended", onMouseUp: _this.handleExpand },
138 React.createElement(ArrowRenderer, { node: _this.getNode() })));
139 };
140 return _this;
141 }
142 TreeNode.prototype.shouldComponentUpdate = function (nextProps) {
143 return !shallowEqual(this.props, nextProps, comparingKeys);
144 };
145 TreeNode.prototype.getNode = function () {
146 var _a = this.props, id = _a.id, checked = _a.checked, selected = _a.selected, text = _a.text, child = _a.child, expanded = _a.expanded, disabled = _a.disabled, parent = _a.parent, isBatch = _a.isBatch;
147 var node = {
148 id: id,
149 checked: checked,
150 selected: selected,
151 text: text,
152 child: child,
153 parent: parent
154 };
155 if (void 0 !== expanded) {
156 node.expanded = expanded;
157 }
158 if (void 0 !== disabled) {
159 node.disabled = disabled;
160 }
161 if (void 0 !== isBatch) {
162 node.isBatch = isBatch;
163 }
164 return node;
165 };
166 TreeNode.prototype.render = function () {
167 var _a = this.props, loading = _a.loading, checked = _a.checked, selected = _a.selected, children = _a.children, expanded = _a.expanded, disabled = _a.disabled, disabledCheckbox = _a.disabledCheckbox, indeterminate = _a.indeterminate, TextRenderer = _a.textRenderer;
168 var text = this.props.text;
169 var nodeContentClass = cn({
170 'node-content': true,
171 'has-child': hasChild(this.props),
172 'selected': selected,
173 'checked': checked,
174 'expanded': expanded,
175 'disabled': disabled,
176 'loading': loading,
177 'disabled-checkbox': disabledCheckbox,
178 'indeterminate': !checked && indeterminate
179 });
180 // console.log('RENDERING:', text)
181 return (React.createElement("li", { className: "tree-node" },
182 React.createElement("div", { className: nodeContentClass },
183 this.renderArrow(),
184 this.renderCheckbox(),
185 React.createElement("span", { className: "node-text", onMouseUp: this.handleSelect, onDoubleClick: this.handleDoubleClick }, TextRenderer ? React.createElement(TextRenderer, { node: this.getNode() }) : text)),
186 hasChild(this.props) && expanded &&
187 React.createElement("ul", { className: "node-child" }, children)));
188 };
189 return TreeNode;
190 }(React.Component));
191
192 function recurseDown(obj, fn, excludeSelf) {
193 var res;
194 if (Array.isArray(obj)) {
195 return obj.map(function (node) { return recurseDown(node, fn); });
196 }
197 if (obj[0]) {
198 return Object.keys(obj).map(function (key) { return recurseDown(obj[key], fn); });
199 }
200 if (!excludeSelf) {
201 res = fn(obj);
202 }
203 if (res !== false && obj.child && obj.child.length) {
204 res = recurseDown(obj.child, fn);
205 }
206 return res;
207 }
208 function rootElement(obj) {
209 var node = obj.parent;
210 while (node) {
211 if (!node.parent) {
212 return node;
213 }
214 node = node.parent;
215 }
216 return null;
217 }
218 function traverseUp(obj, fn) {
219 var node = obj.parent;
220 while (node) {
221 if (false === fn(node) || !node.parent) {
222 return;
223 }
224 node = node.parent;
225 }
226 }
227
228 var hasOwnProp = {}.hasOwnProperty;
229 function isArray(obj) {
230 return Array.isArray(obj);
231 }
232 function isFunction(value) {
233 return 'function' === typeof value;
234 }
235 function copyArray(arr) {
236 return arr.concat([]);
237 }
238 function copyObject(obj) {
239 var newObj = {};
240 for (var i in obj) {
241 if (hasOwnProp.call(obj, i)) {
242 newObj[i] = isArray(obj[i]) ? copyArray(obj[i]) : obj[i];
243 }
244 }
245 return newObj;
246 }
247 function isRoot(node) {
248 return node && !node.parent;
249 }
250 function isLeaf(node) {
251 return node.child && 0 === node.child.length;
252 }
253 function isNodeIndeterminate(node, treeCheckedNodes, indeterminateNodes) {
254 if (!node.child.length) {
255 return false;
256 }
257 var hasIndeterminate = node.child.some(function (child) {
258 return !child.disabled && !child.disabledCheckbox && -1 !== indeterminateNodes.indexOf(child.id);
259 });
260 if (hasIndeterminate) {
261 return true;
262 }
263 var uncheckedNodes = node.child.reduce(function (count, item) {
264 if (true !== item.disabled && true !== item.disabledCheckbox && -1 === treeCheckedNodes.indexOf(item.id)) {
265 count++;
266 }
267 return count;
268 }, 0);
269 return uncheckedNodes > 0 && uncheckedNodes < node.child.length;
270 }
271
272 function replaceChild(node) {
273 if (!node || !node.child) {
274 return node;
275 }
276 node.child = copyArray(node.child);
277 node.child.forEach(function (child) {
278 var replaced = replaceChild(child);
279 replaced.parent = node;
280 return replaced;
281 });
282 return node;
283 }
284 function getItemById(id, targetState) {
285 return Object.keys(targetState)
286 .find(function (k) { return targetState[k].id === id; }) || null;
287 }
288 function getNodeIndex(nodeId, parent, nodesLength) {
289 if (parent.child) {
290 var childIndex_1 = null;
291 parent.child.some(function (node, i) {
292 if (nodeId === node.id) {
293 childIndex_1 = i;
294 return true;
295 }
296 return false;
297 });
298 return childIndex_1;
299 }
300 for (var i = 0; i < nodesLength; i++) {
301 if (parent[i].id === nodeId) {
302 return i;
303 }
304 }
305 return null;
306 }
307 function updateChildNodes(parentNode) {
308 parentNode.child.forEach(function (child) {
309 child.parent = parentNode;
310 });
311 return parentNode;
312 }
313 var State = /** @class */ (function () {
314 function State(state, stateLength) {
315 this.state = state;
316 this.stateLength = stateLength;
317 }
318 State.prototype.updateRootNode = function (node, key, value) {
319 var i = getItemById(node.id, this.state);
320 var newObj = copyObject(node);
321 if (key) {
322 node[key] = value;
323 newObj[key] = value;
324 }
325 if (null !== i) {
326 this.state[i] = updateChildNodes(newObj);
327 }
328 };
329 State.prototype.updateLeafNode = function (node, key, value) {
330 var root = rootElement(node);
331 var parentNode = node.parent;
332 if (!parentNode || !root || !parentNode.child) {
333 return;
334 }
335 var index = getNodeIndex(node.id, parentNode, this.stateLength);
336 if (null === index) {
337 return;
338 }
339 node[key] = value;
340 parentNode.child[index][key] = value;
341 this.updateRootNode(replaceChild(root));
342 };
343 State.prototype.set = function (id, key, value) {
344 var node = this.getNodeById(id);
345 if (!node) {
346 return this.state;
347 }
348 if (isRoot(node)) {
349 this.updateRootNode(node, key, value);
350 }
351 else {
352 this.updateLeafNode(node, key, value);
353 }
354 return this.state;
355 };
356 State.prototype.getNodeById = function (id) {
357 var node = null;
358 recurseDown(this.state, function (obj) {
359 if (obj.id === id) {
360 node = obj;
361 return false;
362 }
363 });
364 return node;
365 };
366 State.prototype.get = function () {
367 return this.state;
368 };
369 return State;
370 }());
371
372 function s4() {
373 return Math.floor((1 + Math.random()) * 0x10000)
374 .toString(16)
375 .substring(1);
376 }
377 function uuid() {
378 return s4() + '-' + s4();
379 }
380
381 function parseNode(data, parentNode) {
382 if (!data || !Array.isArray(data)) {
383 return [];
384 }
385 var parent = parentNode || null;
386 if ('string' === typeof data) {
387 return [
388 { text: data, id: uuid(), parent: parent, child: [] }
389 ];
390 }
391 return data.map(function (node) {
392 if ('string' === typeof node) {
393 return {
394 id: uuid(),
395 text: node,
396 parent: parent,
397 child: []
398 };
399 }
400 node.id = node.id || uuid();
401 node.child = Array.isArray(node.child)
402 ? parseNode(node.child, node)
403 : [];
404 node.parent = parent;
405 return node;
406 });
407 }
408
409 var EyzyTree = /** @class */ (function (_super) {
410 __extends(EyzyTree, _super);
411 function EyzyTree(props) {
412 var _this = _super.call(this, props) || this;
413 _this.stateCache = null;
414 _this.selectedNodes = [];
415 _this.checkedNodes = [];
416 _this.indeterminateNodes = [];
417 _this.refreshIndeterminateState = function (id, willBeChecked, shouldRender) {
418 var checkedNodes = copyArray(_this.checkedNodes);
419 var indeterminateNodes = copyArray(_this.indeterminateNodes);
420 var state = _this.getState();
421 var childIds = [];
422 var node = state.getNodeById(id);
423 if (!node) {
424 return;
425 }
426 recurseDown(node, function (child) {
427 if (!child.disabled && !child.disabledCheckbox && id !== child.id) {
428 childIds.push(child.id);
429 }
430 });
431 if (willBeChecked) {
432 checkedNodes.push.apply(checkedNodes, childIds);
433 }
434 else {
435 checkedNodes = checkedNodes.filter(function (nodeId) { return !~childIds.indexOf(nodeId); });
436 }
437 traverseUp(node, function (parentNode) {
438 if (parentNode.disabledCheckbox || parentNode.disabled) {
439 return false;
440 }
441 var isIndeterminate = isNodeIndeterminate(parentNode, checkedNodes, indeterminateNodes);
442 var id = parentNode.id;
443 if (isIndeterminate) {
444 !~indeterminateNodes.indexOf(id) && indeterminateNodes.push(id);
445 checkedNodes = checkedNodes.filter(function (nodeId) { return nodeId !== id; });
446 }
447 else {
448 indeterminateNodes = indeterminateNodes.filter(function (nodeId) { return nodeId !== id; });
449 if (willBeChecked) {
450 checkedNodes.push(id);
451 }
452 else {
453 checkedNodes = checkedNodes.filter(function (nodeId) { return nodeId !== id; });
454 }
455 }
456 });
457 indeterminateNodes = indeterminateNodes.filter(function (nodeId) { return !~checkedNodes.indexOf(nodeId); });
458 _this.checkedNodes.forEach(function (id) {
459 if (-1 !== _this.checkedNodes.indexOf(id)) {
460 state.set(id, 'checked', false);
461 }
462 });
463 _this.indeterminateNodes.forEach(function (id) {
464 if (-1 !== _this.indeterminateNodes.indexOf(id)) {
465 state.set(id, 'indeterminate', false);
466 }
467 });
468 checkedNodes.forEach(function (id) { return state.set(id, 'checked', true); });
469 indeterminateNodes.forEach(function (id) { return state.set(id, 'indeterminate', true); });
470 _this.checkedNodes = checkedNodes;
471 _this.indeterminateNodes = indeterminateNodes;
472 if (false !== shouldRender) {
473 _this.updateState(state, true);
474 }
475 };
476 _this.getState = function () {
477 return _this.stateCache || new State(_this.state, _this.stateLength);
478 };
479 _this.updateState = function (state, clearCache) {
480 if (clearCache) {
481 _this.setState(state);
482 _this.stateCache = null;
483 return;
484 }
485 if (_this.stateCache) {
486 return;
487 }
488 _this.setState(state);
489 };
490 _this.useState = function (state, cb) {
491 _this.stateCache = state;
492 cb();
493 };
494 _this.select = function (node, ignoreEvent) {
495 var state = _this.getState();
496 _this.selectedNodes = _this.selectedNodes.filter(function (nodeId) {
497 var node = state.getNodeById(nodeId);
498 if (node) {
499 state.set(node.id, 'selected', false);
500 if (true !== ignoreEvent && _this.props.onUnSelect) {
501 _this.props.onUnSelect(node);
502 }
503 }
504 return false;
505 });
506 state.set(node.id, 'selected', true);
507 _this.selectedNodes.push(node.id);
508 _this.updateState(state.get());
509 if (true !== ignoreEvent && _this.props.onSelect) {
510 _this.props.onSelect(node);
511 }
512 };
513 _this.check = function (node) {
514 var state = _this.getState();
515 var willBeChecked = !node.checked;
516 var id = node.id;
517 state.set(id, 'checked', willBeChecked);
518 if (willBeChecked) {
519 _this.checkedNodes = _this.checkedNodes.concat([id]);
520 }
521 else {
522 _this.checkedNodes = _this.checkedNodes.filter(function (checkedId) { return id !== checkedId; });
523 }
524 if (_this.props.selectOnCheck) {
525 _this.useState(state, function () {
526 _this.select(node);
527 });
528 }
529 if (_this.props.autoCheckChildren !== false) {
530 _this.useState(state, function () {
531 _this.refreshIndeterminateState(node.id, willBeChecked);
532 });
533 }
534 else {
535 _this.updateState(state.get(), true);
536 }
537 if (_this.props.onCheck) {
538 _this.props.onCheck(node);
539 }
540 };
541 _this.expand = function (node) {
542 if (node.isBatch) {
543 return _this.loadChild(node);
544 }
545 if (!node.child.length) {
546 return;
547 }
548 var state = _this.getState();
549 state.set(node.id, 'expanded', !node.expanded);
550 if (_this.props.selectOnExpand && !node.selected) {
551 _this.useState(state, function () {
552 _this.select(node);
553 });
554 }
555 _this.updateState(state.get(), true);
556 if (_this.props.onExpand) {
557 _this.props.onExpand(node, !!node.expanded);
558 }
559 };
560 _this.handleDoubleClick = function (node) {
561 if (node.disabled || !node.child.length || _this.props.expandOnSelect) {
562 return;
563 }
564 _this.expand(node);
565 if (_this.props.onDoubleClick) {
566 _this.props.onDoubleClick(node);
567 }
568 };
569 _this.handleSelect = function (node, event) {
570 _this.select(node);
571 var _a = _this.props, checkOnSelect = _a.checkOnSelect, expandOnSelect = _a.expandOnSelect, checkable = _a.checkable;
572 if (checkable && checkOnSelect && !node.disabledCheckbox) {
573 _this.check(node);
574 }
575 else if (expandOnSelect) {
576 _this.expand(node);
577 }
578 };
579 _this.loadChild = function (node) {
580 var fetchData = _this.props.fetchData;
581 if (!fetchData || !isFunction(fetchData)) {
582 return;
583 }
584 var result = fetchData(node);
585 if (!result || !result.then) {
586 throw new Error('`fetchData` property must return a Promise');
587 }
588 var state = _this.getState();
589 var autoCheckChildren = _this.props.autoCheckChildren;
590 var id = node.id;
591 state.set(id, 'loading', true);
592 result.then(function (nodes) {
593 var child = parseNode(nodes).map(function (obj) {
594 obj.parent = node;
595 return obj;
596 });
597 state.set(id, 'loading', false);
598 state.set(id, 'expanded', true);
599 state.set(id, 'isBatch', false);
600 state.set(id, 'child', child);
601 recurseDown(state.getNodeById(id), function (obj) {
602 if (id == obj.id || !obj.checked) {
603 return;
604 }
605 _this.checkedNodes.push(obj.id);
606 if (!isLeaf(obj) || autoCheckChildren === false) {
607 return;
608 }
609 _this.useState(state, function () {
610 _this.refreshIndeterminateState(obj.id, !!obj.checked, false);
611 });
612 });
613 _this.updateState(state.get(), true);
614 });
615 _this.updateState(state.get());
616 };
617 _this.renderNode = function (node) {
618 var treePropsKeys = [
619 'checkable', 'arrowRenderer', 'textRenderer', 'checkboxRenderer'
620 ];
621 var treeProps = treePropsKeys.reduce(function (props, key) {
622 if (_this.props[key]) {
623 props[key] = _this.props[key];
624 }
625 return props;
626 }, {});
627 return (React.createElement(TreeNode, __assign({ key: node.id, node: node, onSelect: _this.handleSelect, onDoubleClick: _this.handleDoubleClick, onCheck: _this.check, onExpand: _this.expand }, treeProps, node), node.expanded ? node.child.map(_this.renderNode) : null));
628 };
629 var data = parseNode(props.data);
630 var stateObject = {};
631 data.forEach(function (item, i) {
632 stateObject[i] = item;
633 });
634 recurseDown(stateObject, function (obj) {
635 if (obj.selected) {
636 _this.selectedNodes.push(obj.id);
637 }
638 if (obj.checked) {
639 _this.checkedNodes.push(obj.id);
640 }
641 });
642 var state = new State(stateObject, data.length);
643 _this.checkedNodes.forEach(function (id) {
644 var node = state.getNodeById(id);
645 if (node && isLeaf(node) && _this.props.autoCheckChildren !== false) {
646 _this.useState(state, function () {
647 _this.refreshIndeterminateState(id, true, false);
648 });
649 }
650 });
651 _this.stateLength = data.length;
652 _this.state = state.get();
653 _this.stateCache = null;
654 return _this;
655 }
656 EyzyTree.prototype.render = function () {
657 var nodes = [];
658 var props = this.props;
659 var treeClass = 'theme' in props
660 ? 'eyzy-tree ' + props.theme
661 : 'eyzy-tree eyzy-theme';
662 for (var i = 0; i < this.stateLength; i++) {
663 nodes.push(this.renderNode(this.state[i]));
664 }
665 return (React.createElement("ul", { className: treeClass }, nodes));
666 };
667 EyzyTree.TreeNode = TreeNode;
668 return EyzyTree;
669 }(React.Component));
670
671 return EyzyTree;
672
673})));
674//# sourceMappingURL=eyzy-tree.umd.js.map