frc-ui
Version:
React Web UI
299 lines (298 loc) • 13.2 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import React from 'react';
import classNames from 'classnames';
import Item from './Item';
import { Insert_Type, Render_Type, Scroll_Type } from './types';
class Tree extends React.PureComponent {
constructor(props) {
super(props);
this.showColorKeys = [];
this.type = Scroll_Type.ALL;
this.showCount = 0;
this.resize = () => {
const { rowHeight, fixedTopBottom } = this.props;
const { tops, options, bottoms } = this.state;
if (this.wrap && fixedTopBottom) {
const height = this.wrap.clientHeight;
const width = this.wrap.clientWidth;
if (width !== this.state.width || height !== this.state.height) {
this.setState({ width, height });
}
const length = (options || []).length + (tops || []).length + (bottoms || []).length;
let type;
if (length * rowHeight < height) {
type = Scroll_Type.ALL;
}
else {
type = Scroll_Type.CONTAINER;
}
if (type !== this.type || this.showCount !== (options || []).length) {
this.showCount = (options || []).length;
this.type = type;
const opts = this.update(this.getOptions());
this.setState(opts);
}
}
};
this.getProps = (prop) => {
return this.props[prop];
};
this.saveRef = (name) => (ele) => {
this[name] = ele;
};
this.update = (options = []) => {
const { rowHeight } = this.props;
const { height } = this.state;
if (height && options.length * rowHeight > height) {
this.type = Scroll_Type.CONTAINER;
}
else {
this.type = Scroll_Type.ALL;
}
if (this.type !== Scroll_Type.CONTAINER) {
return { tops: [], bottoms: [], options };
}
const tops = [], opts = [], bottoms = [];
let start = Insert_Type.TOP;
for (let i = 0; i < options.length; i++) {
const o = options[i];
if (o.index === 0) {
if (start === Insert_Type.TOP) {
tops.push(o);
}
else {
start = Insert_Type.BOTTOM;
bottoms.push(o);
}
}
else {
start = Insert_Type.MIDDLE;
opts.push(o);
}
}
return { tops, options: opts, bottoms };
};
this.onChange = (option) => {
return (type, flag) => {
const { rowHeight, onChange, onExpand } = this.props;
const { height } = this.state;
const selectedKeys = this.state.selectedKeys || [];
const expandedKeys = this.state.expandedKeys || [];
const { value } = option;
let keys;
switch (type) {
case 'check':
keys = selectedKeys;
if (flag) {
if (keys.indexOf(value) < 0) {
keys = [...selectedKeys, value];
}
}
else {
keys = selectedKeys.filter((v) => v !== value);
}
this.showColorKeys = this.getSelectedPath(keys);
this.setState({ selectedKeys: keys }, () => {
if (typeof onChange === 'function') {
onChange(keys || [], option);
}
});
break;
case 'expand':
keys = expandedKeys;
if (flag) {
if (keys.indexOf(value) < 0) {
keys = [...expandedKeys, value];
}
}
else {
const cKeys = this.expandKeys(value);
keys = keys.filter((v) => cKeys.indexOf(v) < 0);
}
let options = this.getOptions(keys);
if (height && options.length * rowHeight > height) {
const childKeys = this.getChildKeys(option.index === 0 ? option.value : option.parent);
keys = keys.filter((k) => childKeys.indexOf(k) > -1);
}
options = this.getOptions(keys);
const opts = this.update(options);
this.setState(Object.assign({ expandedKeys: keys }, opts), () => {
if (typeof onExpand === 'function') {
onExpand(keys || [], option);
}
});
break;
}
};
};
this.getChildKeys = (value, options = this.props.options, keys = [], flag = false) => {
for (let i = 0; i < options.length; i++) {
const option = options[i];
if (option.value === value || flag) {
keys.push(option.value);
const children = option.children || [];
if (children.length > 0) {
keys = this.getChildKeys(value, children, keys, true);
}
}
}
return keys;
};
this.expandKeys = (value, options = this.props.options, keys = [], found = false) => {
options.forEach((o) => {
const children = o.children || [];
if (children.length > 0) {
if (o.value === value || found) {
keys.push(o.value);
}
keys = this.expandKeys(value, children, keys, o.value === value || found);
}
});
return keys;
};
this.getSelectedPath = (selectedKeys, options = this.props.options, keys = []) => {
options.forEach((o) => {
const children = o.children || [];
if (children.length > 0) {
this.getSelectedPath(selectedKeys, children, keys);
}
if (selectedKeys.indexOf(o.value) > -1 || children.some((c) => keys.indexOf(c.value) > -1)) {
keys.push(o.value);
}
});
return keys;
};
this.getOptions = (expandedKeys = this.state.expandedKeys || [], options = this.props.options, opt = [], index = 0, parentExpanded = true, parent = '') => {
options = options || [];
const expandPlace = options.some((o) => o.children && o.children.length > 0);
options.forEach((o) => {
const { children } = o, other = __rest(o, ["children"]);
const expandEnable = children && children.length > 0;
const one = Object.assign(Object.assign({ expandEnable }, other), { index, expandPlace, parent });
const expanded = expandEnable && expandedKeys.indexOf(o.value) > -1;
if (index === 0)
parent = o.value;
if (parentExpanded) {
opt.push(one);
}
if (expandEnable) {
this.getOptions(expandedKeys, children || [], opt, index + 1, expanded, parent);
}
});
return opt;
};
this.getStyle = (type) => {
const { rowHeight } = this.props;
const opts = this.state[type.toString()];
const style = {};
if (opts.length <= 0) {
style.display = 'none';
return style;
}
style.height = opts.length * rowHeight;
return style;
};
this.renderItem = (type) => {
const { prefix, rowHeight, clickRow } = this.props;
const options = this.state[type.toString()];
const { selectedKeys, expandedKeys, width } = this.state;
return options.map((o) => {
return (React.createElement(Item, { key: `${o.value}-${Math.random()}`, prefix: prefix, option: o, clickRow: clickRow, parentWidth: width || 100, rowHeight: rowHeight || 22, hasSelected: this.showColorKeys.indexOf(o.value) > -1, expanded: (expandedKeys || []).indexOf(o.value) > -1, checked: (selectedKeys || []).indexOf(o.value) > -1, onChange: this.onChange(o) }));
});
};
this.showColorKeys = this.getSelectedPath(props.selectedKeys || [], props.options);
this.state = {
selectedKeys: props.selectedKeys || [],
expandedKeys: props.expandedKeys || [],
tops: [],
options: [],
bottoms: [],
width: 100,
height: 100
};
}
componentWillMount() {
this.setState({ options: this.getOptions() });
}
componentDidMount() {
if (this.wrap) {
this.resize();
this.wrap.addEventListener('resize', this.resize);
}
window.addEventListener('resize', this.resize);
}
componentWillReceiveProps(nextProps) {
let state = {};
if (nextProps.selectedKeys !== this.props.selectedKeys) {
state.selectedKeys = nextProps.selectedKeys || [];
this.showColorKeys = this.getSelectedPath(state.selectedKeys, nextProps.options);
}
if (nextProps.expandedKeys !== this.props.expandedKeys) {
state.expandedKeys = nextProps.expandedKeys || [];
}
if (nextProps.options !== this.props.options) {
state.tops = [];
state.bottoms = [];
state.options = this.getOptions(state.expandedKeys || this.state.expandedKeys, nextProps.options);
state = Object.assign(Object.assign({}, state), this.update(state.options));
if (Object.prototype.hasOwnProperty.call(state, 'selectedKeys')) {
this.showColorKeys = this.getSelectedPath(state.selectedKeys || [], nextProps.options);
}
else {
this.showColorKeys = this.getSelectedPath(this.state.selectedKeys || [], nextProps.options);
}
}
else {
if (!!state.expandedKeys) {
state.options = this.getOptions(state.expandedKeys);
state = Object.assign(Object.assign({}, state), this.update(state.options));
}
}
if (Object.keys(state).length > 0) {
this.setState(state, this.resize);
}
}
render() {
const { className, prefix } = this.props;
const cls = classNames(`${prefix}`, className);
const fixedTop = `${prefix}-fixed-top`;
const fixedBottom = `${prefix}-fixed-bottom`;
const topStyle = this.getStyle(Render_Type.tops);
const bottomStyle = this.getStyle(Render_Type.bottoms);
const containerStyle = {};
const innerStyle = {};
if (this.type === Scroll_Type.CONTAINER) {
innerStyle.height = '100%';
innerStyle.overflowY = 'hidden';
innerStyle.paddingTop = topStyle.height || 0;
innerStyle.paddingBottom = bottomStyle.height || 0;
containerStyle.overflowY = 'auto';
containerStyle.height = '100%';
}
return (React.createElement("div", { className: cls, ref: this.saveRef('wrap') },
React.createElement("div", { className: `${prefix}-inner`, style: innerStyle },
React.createElement("div", { className: fixedTop, style: topStyle }, this.renderItem(Render_Type.tops)),
React.createElement("div", { className: `${prefix}-container`, style: containerStyle }, this.renderItem(Render_Type.options)),
React.createElement("div", { className: fixedBottom, style: bottomStyle }, this.renderItem(Render_Type.bottoms)))));
}
}
Tree.defaultProps = {
prefix: 'swc-tree',
options: [],
selectedKeys: [],
expandedKeys: [],
rowHeight: 22,
fixedTopBottom: true,
clickRow: true
};
export default Tree;