UNPKG

zent

Version:

一套前端设计语言和基于React的实现

557 lines (494 loc) 18.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports['default'] = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _class, _temp; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _assign = require('zent-utils/lodash/assign'); var _assign2 = _interopRequireDefault(_assign); var _classnames2 = require('zent-utils/classnames'); var _classnames3 = _interopRequireDefault(_classnames2); var _Checkbox = require('./components/Checkbox'); var _Checkbox2 = _interopRequireDefault(_Checkbox); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 记录是否已经触发收起展开逻辑 // 防止出现闪烁的bug var isTriggerSlide = false; var deepClone = function deepClone(arr) { var i = void 0; var copy = void 0; if (Array.isArray(arr)) { copy = arr.slice(0); for (i = 0; i < copy.length; i += 1) { copy[i] = deepClone(copy[i]); } return copy; } else if ((typeof arr === 'undefined' ? 'undefined' : _typeof(arr)) === 'object') { return (0, _assign2['default'])({}, arr); } return arr; }; var toggleSlide = function toggleSlide(el, isClose) { if (!isClose) { el.style.display = 'block'; el.style.height = 0; } var maxDelay = 300; var height = el.scrollHeight; var speed = Math.max(height / maxDelay, 0.5); // px/ms var sum = 0; var start = null; var animate = function animate(timestamp) { if (!start) start = timestamp; var progress = timestamp - start; sum = progress * speed; el.style.height = (isClose ? height - sum : sum) + 'px'; if (height < sum) { if (isClose) { el.style.display = 'none'; } el.style.height = ''; isTriggerSlide = false; } else { window.requestAnimationFrame(animate); } }; window.requestAnimationFrame(animate); }; var Tree = (_temp = _class = function (_Component) { _inherits(Tree, _Component); function Tree(props) { _classCallCheck(this, Tree); var _this = _possibleConstructorReturn(this, (Tree.__proto__ || Object.getPrototypeOf(Tree)).call(this, props)); _this.isInitial = true; _this.isDataUpdate = false; _this.state = { checkedTree: {} }; return _this; } _createClass(Tree, [{ key: 'componentWillMount', value: function componentWillMount() { // init checkedTree var _props = this.props, data = _props.data, dataType = _props.dataType; var formatData = this.formatDataIntoTree(data, dataType); this.setState({ checkedTree: this.formatDataIntoCheckedTree(formatData) }); } }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { if (nextProps.data !== this.props.data) { // update checkTree this.isDataUpdate = true; var data = this.formatDataIntoTree(nextProps.data, nextProps.dataType); this.setState({ checkedTree: this.formatDataIntoCheckedTree(data) }); } } }, { key: 'formatDataIntoTree', value: function formatDataIntoTree(data, dataType) { var roots = []; if (dataType === 'plain') { var isRoot = this.props.isRoot; var map = {}; data.forEach(function (node) { if (!node.isLeaf) { node.children = []; } map[node.id] = node; }); Object.keys(map).forEach(function (key) { var node = map[key]; var isRootNode = isRoot && isRoot(node) || node.parentId === 0 || node.parentId === undefined || node.parentId === '0'; if (isRootNode) { roots.push(node); } else if (map[node.parentId]) { // 防止只删除父节点没有子节点的情况 map[node.parentId].children.push(node); } }); } else if (dataType === 'tree') { roots = data; } else { // console.error(`The dataType should be declared as plain/tree, but your dataType is ${dataType}, Please check your config.`) } return roots; } }, { key: 'formatDataIntoCheckedTree', value: function formatDataIntoCheckedTree(data) { var checkedTree = {}; if (this.isInitial) { checkedTree = this.initialCheckedTree(data); this.isInitial = false; } else if (this.isDataUpdate) { checkedTree = this.reloadCheckedTree(data); this.isDataUpdate = false; } this.updateWholeCheckedTree(checkedTree); return checkedTree; } }, { key: 'isSwitcherExpanded', value: function isSwitcherExpanded(node) { return !node.parentNode.classList.contains('off'); } }, { key: 'handleExpandClick', value: function handleExpandClick(root, e) { var _this2 = this; var loadMore = this.props.loadMore; if (loadMore) { if (!root.children || root.children.length === 0) { e.persist(); loadMore(root).then(function () { _this2.handleFoldClick(root, e); })['catch'](function () {}); return; } } this.handleFoldClick(root, e); } }, { key: 'handleFoldClick', value: function handleFoldClick(root, e) { if (!isTriggerSlide) { var onExpand = this.props.onExpand; var switcher = e.target; var elp = switcher.parentNode; elp.classList.toggle('off'); var isClose = !this.isSwitcherExpanded(switcher); if (onExpand) { onExpand(root, { isExpanded: !isClose }); } var el = elp.nextSibling; // no content, unmount switcher if (!el) { switcher.remove(); return; } isTriggerSlide = true; toggleSlide(el, isClose); } } }, { key: 'triggerSwitcherClick', value: function triggerSwitcherClick(root, e) { var _props2 = this.props, autoExpandOnSelect = _props2.autoExpandOnSelect, onSelect = _props2.onSelect; var target = e.currentTarget; if (onSelect) { onSelect(root, target); } if (target && autoExpandOnSelect) { var switcher = target.parentNode.previousSibling; if (switcher) { switcher.click(); } } } }, { key: 'handleCheckboxClick', value: function handleCheckboxClick(root) { var onCheck = this.props.onCheck; var checkedTree = this.state.checkedTree; this.updateCheckedTree(root.id, checkedTree[root.id].t !== 2 ? 2 : 0); if (onCheck) { onCheck(Object.keys(checkedTree).filter(function (k) { return checkedTree[k].t === 2; }).map(function (x) { if (typeof root.id === 'number') { x = +x; } return x; })); } } }, { key: 'updateUpstream', value: function updateUpstream(id, type, checkedTree) { if (!id) return; if (type === 2) { checkedTree[id].t = Object.keys(checkedTree).filter(function (x) { return checkedTree[x].p === id; }).every(function (x) { return checkedTree[x].t === 2; }) ? 2 : 1; } else if (type === 1) { checkedTree[id].t = 1; } else if (type === 0) { checkedTree[id].t = Object.keys(checkedTree).filter(function (x) { return checkedTree[x].p === id; }).every(function (x) { return checkedTree[x].t === 0; }) ? 0 : 1; } if (checkedTree[id].p) { this.updateUpstream(checkedTree[id].p, checkedTree[id].t, checkedTree); } } }, { key: 'updateDownstream', value: function updateDownstream(id, type, checkedTree) { var _this3 = this; if (!id) return; checkedTree[id].t = type; var childrenId = Object.keys(checkedTree).filter(function (x) { return checkedTree[x].p === id; }); if (childrenId.length > 0) { childrenId.forEach(function (childId) { _this3.updateDownstream(childId, type, checkedTree); }); } } }, { key: 'updateCheckedTree', value: function updateCheckedTree(id, type) { var _this4 = this; var checkedTree = this.state.checkedTree; var parentId = checkedTree[id].p; var childrenId = Object.keys(checkedTree).filter(function (x) { return checkedTree[x].p === id.toString(); }); checkedTree[id].t = type; this.updateUpstream(parentId, type, checkedTree); childrenId.forEach(function (childId) { _this4.updateDownstream(childId, type, checkedTree); }); this.setState({ checkedTree: checkedTree }); } }, { key: 'updateCheckedTreeRecursive', value: function updateCheckedTreeRecursive(root, parentId, func) { var _this5 = this; func(root, parentId); if (root.children && root.children.length > 0) { root.children.forEach(function (child) { _this5.updateCheckedTreeRecursive(child, root.id, func); }); } } }, { key: 'updateWholeCheckedTree', value: function updateWholeCheckedTree(checkedTree) { var _this6 = this; Object.keys(checkedTree).forEach(function (id) { if (checkedTree[id].t === 2) { _this6.updateUpstream(id, 2, checkedTree); _this6.updateDownstream(id, 2, checkedTree); } }); } }, { key: 'initialCheckedTree', value: function initialCheckedTree(data) { var _this7 = this; var newCheckedTree = {}; var defaultCheckedKeys = this.props.defaultCheckedKeys; data.forEach(function (tree) { _this7.updateCheckedTreeRecursive(tree, '', function (root, parentId) { var isSetDefault = defaultCheckedKeys && defaultCheckedKeys.find(function (x) { return x === root.id; }) >= 0; newCheckedTree[root.id] = { p: parentId.toString(), t: isSetDefault ? 2 : 0 }; }); }); return newCheckedTree; } }, { key: 'reloadCheckedTree', value: function reloadCheckedTree(data) { var _this8 = this; var newCheckedTree = {}; var checkedTree = this.state.checkedTree; data.forEach(function (tree) { _this8.updateCheckedTreeRecursive(tree, '', function (root, parentId) { newCheckedTree[root.id] = { p: parentId.toString(), t: checkedTree[root.id] ? checkedTree[root.id].t : 0 }; }); }); return newCheckedTree; } }, { key: 'renderSwitcher', value: function renderSwitcher(root) { var _props3 = this.props, foldable = _props3.foldable, loadMore = _props3.loadMore; var className = (0, _classnames3['default'])('switcher'); if (!root.isLeaf && (loadMore || root.children && root.children.length > 0)) { return _react2['default'].createElement('icon', { className: className, onClick: foldable && this.handleExpandClick.bind(this, root) }); } } }, { key: 'renderCheckbox', value: function renderCheckbox(root) { var _props4 = this.props, checkable = _props4.checkable, disabledCheckedKeys = _props4.disabledCheckedKeys; var isDisabled = (disabledCheckedKeys || []).find(function (key) { return key === root.id; }) >= 0; if (checkable) { return _react2['default'].createElement(_Checkbox2['default'], { onCheck: this.handleCheckboxClick.bind(this, root), type: this.state.checkedTree[root.id].t, disabled: isDisabled }); } } }, { key: 'renderOperations', value: function renderOperations(root) { var opts = this.props.operations; if (opts) { var optNodes = opts.map(function (opt) { var shouldRender = opt.shouldRender || function () { return true; }; return shouldRender(root) && _react2['default'].createElement( 'span', { key: opt.name + '-' + root.id, onClick: opt.action.bind(null, root), className: 'opt' }, _react2['default'].createElement('icon', { className: opt.icon }), opt.name ); }); return _react2['default'].createElement( 'div', { className: 'operation' }, optNodes ); } } // TODO: // Support selectable // Support disable select // Custom switcher // Add Cursor Style // make style beautiful }, { key: 'renderTreeNodes', value: function renderTreeNodes(roots) { var _this9 = this; var _props5 = this.props, loadMore = _props5.loadMore, prefix = _props5.prefix, expandAll = _props5.expandAll; if (roots && roots.length > 0) { return roots.map(function (root) { // 单独节点的expand属性具有最高优先级,如果expand没有设置会根据是否设置loadMore // 来判断是否收起,因为需要loadMore的节点是没有内容的,需要收起。在以上情况都不发生 // 的情况下以expandAll为准 var isShowChildren = expandAll; if (loadMore) { isShowChildren = root.expand; } var barClassName = (0, _classnames3['default'])(prefix + '-tree-bar', { off: !isShowChildren }); return _react2['default'].createElement( 'li', { key: '' + root.id }, _react2['default'].createElement( 'div', { className: barClassName }, _this9.renderSwitcher(root), _react2['default'].createElement( 'div', { className: 'zent-tree-node' }, _this9.renderCheckbox(root), _react2['default'].createElement( 'span', { className: 'content', onClick: _this9.triggerSwitcherClick.bind(_this9, root) }, _this9.props.render ? _this9.props.render(root) : root.title ), _this9.renderOperations(root) ) ), root.children && root.children.length > 0 && _react2['default'].createElement( 'ul', { key: 'ul-' + root.id, className: prefix + '-tree-child', style: isShowChildren ? {} : { display: 'none' } }, _this9.renderTreeNodes(root.children) ) ); }); } } }, { key: 'render', value: function render() { var _props6 = this.props, commonStyle = _props6.commonStyle, data = _props6.data, dataType = _props6.dataType, prefix = _props6.prefix, size = _props6.size; var roots = this.formatDataIntoTree(deepClone(data), dataType); var treeNodes = this.renderTreeNodes(roots); var classNames = (0, _classnames3['default'])(prefix + '-tree', _defineProperty({}, prefix + '-tree-' + size, size !== 'medium')); return _react2['default'].createElement( 'ul', { className: classNames, style: commonStyle }, treeNodes ); } }]); return Tree; }(_react.Component), _class.propTypes = { dataType: _react.PropTypes.oneOf(['plain', 'tree']), data: _react.PropTypes.arrayOf(_react.PropTypes.object), isRoot: _react.PropTypes.func, loadMore: _react.PropTypes.func, foldable: _react.PropTypes.bool, checkable: _react.PropTypes.bool, autoExpandOnSelect: _react.PropTypes.bool, defaultCheckedKeys: _react.PropTypes.arrayOf(_react.PropTypes.any), disabledCheckedKeys: _react.PropTypes.arrayOf(_react.PropTypes.any), onCheck: _react.PropTypes.func, onExpand: _react.PropTypes.func, onSelect: _react.PropTypes.func, size: _react.PropTypes.oneOf(['large', 'medium', 'small']), operations: _react.PropTypes.arrayOf(_react.PropTypes.object), render: _react.PropTypes.func, prefix: _react.PropTypes.string }, _class.defaultProps = { autoExpandOnSelect: true, dataType: 'tree', foldable: true, checkable: false, size: 'medium', prefix: 'zent' }, _temp); exports['default'] = Tree; module.exports = exports['default'];