zent
Version:
一套前端设计语言和基于React的实现
557 lines (494 loc) • 18.4 kB
JavaScript
'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'];