UNPKG

zent

Version:

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

607 lines (528 loc) 18.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); var _defineProperty3 = _interopRequireDefault(_defineProperty2); var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _typeof2 = require('babel-runtime/helpers/typeof'); var _typeof3 = _interopRequireDefault(_typeof2); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _checkbox = require('../checkbox'); var _checkbox2 = _interopRequireDefault(_checkbox); var _assign = require('lodash/assign'); var _assign2 = _interopRequireDefault(_assign); var _clone = require('lodash/clone'); var _clone2 = _interopRequireDefault(_clone); var _find = require('lodash/find'); var _find2 = _interopRequireDefault(_find); var _classnames2 = require('classnames'); var _classnames3 = _interopRequireDefault(_classnames2); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _Loading = require('./components/Loading'); var _Loading2 = _interopRequireDefault(_Loading); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } // 记录是否已经触发收起展开逻辑 // 防止出现闪烁的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' : (0, _typeof3['default'])(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 _ref3 = _react2['default'].createElement(_Loading2['default'], null); var Tree = function (_ref) { (0, _inherits3['default'])(Tree, _ref); function Tree() { var _ref2; var _temp, _this, _ret; (0, _classCallCheck3['default'])(this, Tree); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = (0, _possibleConstructorReturn3['default'])(this, (_ref2 = Tree.__proto__ || Object.getPrototypeOf(Tree)).call.apply(_ref2, [this].concat(args))), _this), _this.isInitial = true, _this.isDataUpdate = false, _this.state = { checkedTree: {}, loadingNode: [] }, _temp), (0, _possibleConstructorReturn3['default'])(_this, _ret); } (0, _createClass3['default'])(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 = {}; var orderRecord = []; data.forEach(function (node, index) { if (!node.isLeaf) { node.children = []; } map[node.id] = node; orderRecord[index] = node.id; }); orderRecord.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; var loadingNode = this.state.loadingNode; if (loadMore) { if (!root.children || root.children.length === 0) { e.persist(); this.setState({ loadingNode: [root.id].concat((0, _toConsumableArray3['default'])(loadingNode)) }); loadMore(root).then(function () { _this2.setState({ loadingNode: loadingNode.filter(function (x) { return x !== root.id; }) }); _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; // shallow clone // We can reuse most of the nodes var checkedTree = (0, _clone2['default'])(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 && (0, _find2['default'])(defaultCheckedKeys, 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; if (!root.isLeaf && (loadMore || root.children && root.children.length > 0)) { return _react2['default'].createElement('i', { className: 'switcher', 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 && (0, _find2['default'])(disabledCheckedKeys, function (key) { return key === root.id; }) >= 0; if (checkable) { return _react2['default'].createElement(_checkbox2['default'], { onChange: this.handleCheckboxClick.bind(this, root), checked: this.state.checkedTree[root.id].t === 2, indeterminate: this.state.checkedTree[root.id].t === 1, 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' }, typeof opt.icon === 'string' ? _react2['default'].createElement('i', { className: opt.icon }) : opt.icon, ' ', opt.name ); }); return _react2['default'].createElement( 'div', { className: 'operation' }, optNodes ); } } }, { key: 'renderTreeNodes', value: function renderTreeNodes(roots) { var _this9 = this; var loadingNode = this.state.loadingNode; var _props5 = this.props, loadMore = _props5.loadMore, prefix = _props5.prefix, expandAll = _props5.expandAll, render = _props5.render; 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), loadingNode.indexOf(root.id) > -1 ? _ref3 : null, _react2['default'].createElement( 'span', { className: 'content', onClick: _this9.triggerSwitcherClick.bind(_this9, root) }, render ? 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', (0, _defineProperty3['default'])({}, prefix + '-tree-' + size, size !== 'medium')); return _react2['default'].createElement( 'ul', { className: classNames, style: commonStyle }, treeNodes ); } }]); return Tree; }(_react.PureComponent || _react.Component); Tree.propTypes = { dataType: _propTypes2['default'].oneOf(['plain', 'tree']), data: _propTypes2['default'].arrayOf(_propTypes2['default'].object), isRoot: _propTypes2['default'].func, loadMore: _propTypes2['default'].func, foldable: _propTypes2['default'].bool, checkable: _propTypes2['default'].bool, autoExpandOnSelect: _propTypes2['default'].bool, defaultCheckedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].any), disabledCheckedKeys: _propTypes2['default'].arrayOf(_propTypes2['default'].any), onCheck: _propTypes2['default'].func, onExpand: _propTypes2['default'].func, onSelect: _propTypes2['default'].func, size: _propTypes2['default'].oneOf(['large', 'medium', 'small']), operations: _propTypes2['default'].arrayOf(_propTypes2['default'].object), render: _propTypes2['default'].func, prefix: _propTypes2['default'].string }; Tree.defaultProps = { autoExpandOnSelect: true, dataType: 'tree', foldable: true, checkable: false, size: 'medium', prefix: 'zent' }; exports['default'] = Tree;