UNPKG

15.8 kBJavaScriptView Raw
1import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
2import _extends from 'babel-runtime/helpers/extends';
3import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
4import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
5import _inherits from 'babel-runtime/helpers/inherits';
6import React, { Children } from 'react';
7import PropTypes from 'prop-types';
8import { polyfill } from 'react-lifecycles-compat';
9import Checkbox from '../checkbox';
10import Radio from '../radio';
11import { func, log } from '../util';
12import zhCN from '../locale/zh-cn';
13import SelectionRow from './selection/row';
14import Col from './column';
15import { statics } from './util';
16
17var makeChain = func.makeChain;
18
19
20var unique = function unique(arr) {
21 var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'this';
22
23 var temp = {},
24 ret = [];
25 arr.forEach(function (item) {
26 var value = void 0;
27 if (key === 'this') {
28 value = item;
29 } else {
30 value = item[key];
31 }
32 if (!temp[value]) {
33 ret.push(item);
34 temp[value] = true;
35 }
36 });
37 return ret;
38};
39
40export default function selection(BaseComponent) {
41 var _class, _temp;
42
43 /** Table */
44 var SelectionTable = (_temp = _class = function (_React$Component) {
45 _inherits(SelectionTable, _React$Component);
46
47 function SelectionTable(props, context) {
48 _classCallCheck(this, SelectionTable);
49
50 var _this = _possibleConstructorReturn(this, _React$Component.call(this, props, context));
51
52 _this.addSelection = function (columns) {
53 var _this$props = _this.props,
54 prefix = _this$props.prefix,
55 rowSelection = _this$props.rowSelection,
56 size = _this$props.size;
57
58 var attrs = rowSelection.columnProps && rowSelection.columnProps() || {};
59
60 if (!columns.find(function (record) {
61 return record.key === 'selection';
62 })) {
63 columns.unshift(_extends({
64 key: 'selection',
65 title: _this.renderSelectionHeader.bind(_this),
66 cell: _this.renderSelectionBody.bind(_this),
67 width: size === 'small' ? 34 : 50,
68 className: prefix + 'table-selection ' + prefix + 'table-prerow',
69 __normalized: true
70 }, attrs));
71 }
72 };
73
74 _this.renderSelectionHeader = function () {
75 var onChange = _this.selectAllRow,
76 attrs = {},
77 _this$props2 = _this.props,
78 rowSelection = _this$props2.rowSelection,
79 primaryKey = _this$props2.primaryKey,
80 dataSource = _this$props2.dataSource,
81 entireDataSource = _this$props2.entireDataSource,
82 locale = _this$props2.locale,
83 selectedRowKeys = _this.state.selectedRowKeys,
84 mode = rowSelection.mode ? rowSelection.mode : 'multiple';
85
86
87 var checked = !!selectedRowKeys.length;
88 var indeterminate = false;
89
90 var source = entireDataSource || dataSource;
91
92 _this.flatDataSource(source).filter(function (record, index) {
93 if (!rowSelection.getProps) {
94 return true;
95 } else {
96 return !(rowSelection.getProps(record, index) || {}).disabled;
97 }
98 }).map(function (record) {
99 return record[primaryKey];
100 }).forEach(function (id) {
101 if (selectedRowKeys.indexOf(id) === -1) {
102 checked = false;
103 } else {
104 indeterminate = true;
105 }
106 });
107 attrs.onClick = makeChain(function (e) {
108 e.stopPropagation();
109 }, attrs.onClick);
110
111 var userAttrs = rowSelection.titleProps && rowSelection.titleProps() || {};
112
113 if (checked) {
114 indeterminate = false;
115 }
116 return [mode === 'multiple' ? React.createElement(Checkbox, _extends({
117 key: '_total',
118 indeterminate: indeterminate,
119 'aria-label': locale.selectAll,
120 checked: checked,
121 onChange: onChange
122 }, attrs, userAttrs)) : null, rowSelection.titleAddons && rowSelection.titleAddons()];
123 };
124
125 _this.renderSelectionBody = function (value, index, record) {
126 var _this$props3 = _this.props,
127 rowSelection = _this$props3.rowSelection,
128 primaryKey = _this$props3.primaryKey;
129 var selectedRowKeys = _this.state.selectedRowKeys;
130
131 var mode = rowSelection.mode ? rowSelection.mode : 'multiple';
132 var checked = selectedRowKeys.indexOf(record[primaryKey]) > -1;
133 var onChange = _this.selectOneRow.bind(_this, index, record);
134 var attrs = rowSelection.getProps ? rowSelection.getProps(record, index) || {} : {};
135
136 attrs.onClick = makeChain(function (e) {
137 e.stopPropagation();
138 }, attrs.onClick);
139 return mode === 'multiple' ? React.createElement(Checkbox, _extends({ checked: checked, onChange: onChange }, attrs)) : React.createElement(Radio, _extends({ checked: checked, onChange: onChange }, attrs));
140 };
141
142 _this.selectAllRow = function (checked, e) {
143 var ret = [].concat(_this.state.selectedRowKeys),
144 _this$props4 = _this.props,
145 rowSelection = _this$props4.rowSelection,
146 primaryKey = _this$props4.primaryKey,
147 dataSource = _this$props4.dataSource,
148 entireDataSource = _this$props4.entireDataSource,
149 selectedRowKeys = _this.state.selectedRowKeys,
150 getProps = rowSelection.getProps;
151
152 var attrs = {},
153 records = [];
154
155 var source = entireDataSource ? entireDataSource : dataSource;
156
157 _this.flatDataSource(source).forEach(function (record, index) {
158 var id = record[primaryKey];
159 if (getProps) {
160 attrs = getProps(record, index) || {};
161 }
162 // 反选和全选的时候不要丢弃禁用项的选中状态
163 if (checked && (!attrs.disabled || selectedRowKeys.indexOf(id) > -1)) {
164 ret.push(id);
165 records.push(record);
166 } else if (attrs.disabled && selectedRowKeys.indexOf(id) > -1) {
167 ret.push(id);
168 records.push(record);
169 } else {
170 var i = ret.indexOf(id);
171 i > -1 && ret.splice(i, 1);
172 }
173 });
174
175 records = unique(records, primaryKey);
176 if (typeof rowSelection.onSelectAll === 'function') {
177 rowSelection.onSelectAll(checked, records);
178 }
179 _this.triggerSelection(rowSelection, unique(ret), records);
180 e.stopPropagation();
181 };
182
183 _this.state = {
184 selectedRowKeys: props.rowSelection && 'selectedRowKeys' in props.rowSelection ? props.rowSelection.selectedRowKeys || [] : []
185 };
186 return _this;
187 }
188
189 SelectionTable.prototype.getChildContext = function getChildContext() {
190 return {
191 rowSelection: this.props.rowSelection,
192 selectedRowKeys: this.state.selectedRowKeys
193 };
194 };
195
196 SelectionTable.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps) {
197 if (nextProps.rowSelection && 'selectedRowKeys' in nextProps.rowSelection) {
198 var selectedRowKeys = nextProps.rowSelection.selectedRowKeys || [];
199 return {
200 selectedRowKeys: selectedRowKeys
201 };
202 }
203
204 return null;
205 };
206
207 SelectionTable.prototype.normalizeChildren = function normalizeChildren(children) {
208 var _props = this.props,
209 prefix = _props.prefix,
210 rowSelection = _props.rowSelection,
211 size = _props.size;
212
213 if (rowSelection) {
214 children = Children.map(children, function (child, index) {
215 return React.cloneElement(child, {
216 key: index
217 });
218 });
219
220 var attrs = rowSelection.columnProps && rowSelection.columnProps() || {};
221
222 children.unshift(React.createElement(Col, _extends({
223 key: 'selection',
224 title: this.renderSelectionHeader.bind(this),
225 cell: this.renderSelectionBody.bind(this),
226 width: size === 'small' ? 34 : 50,
227 className: prefix + 'table-selection ' + prefix + 'table-prerow',
228 __normalized: true
229 }, attrs)));
230 return children;
231 }
232 return children;
233 };
234
235 SelectionTable.prototype.selectOneRow = function selectOneRow(index, record, checked, e) {
236 var selectedRowKeys = [].concat(this.state.selectedRowKeys),
237 i = void 0;
238 var _props2 = this.props,
239 primaryKey = _props2.primaryKey,
240 rowSelection = _props2.rowSelection,
241 dataSource = _props2.dataSource,
242 entireDataSource = _props2.entireDataSource,
243 mode = rowSelection.mode ? rowSelection.mode : 'multiple',
244 id = record[primaryKey];
245
246 if (!id) {
247 log.warning('Can\'t get value from record using given ' + primaryKey + ' as primaryKey.');
248 }
249 if (mode === 'multiple') {
250 if (checked) {
251 selectedRowKeys.push(id);
252 } else {
253 i = selectedRowKeys.indexOf(id);
254 selectedRowKeys.splice(i, 1);
255 }
256 } else if (checked) {
257 selectedRowKeys = [id];
258 }
259 var totalDS = dataSource;
260 if (Array.isArray(entireDataSource) && entireDataSource.length > dataSource.length) {
261 totalDS = entireDataSource;
262 }
263 var records = unique(totalDS.filter(function (item) {
264 return selectedRowKeys.indexOf(item[primaryKey]) > -1;
265 }), primaryKey);
266 if (typeof rowSelection.onSelect === 'function') {
267 rowSelection.onSelect(checked, record, records);
268 }
269
270 this.triggerSelection(rowSelection, selectedRowKeys, records);
271
272 e.stopPropagation();
273 };
274
275 SelectionTable.prototype.triggerSelection = function triggerSelection(rowSelection, selectedRowKeys, records) {
276 if (!('selectedRowKeys' in rowSelection)) {
277 this.setState({
278 selectedRowKeys: selectedRowKeys
279 });
280 }
281 if (typeof rowSelection.onChange === 'function') {
282 rowSelection.onChange(selectedRowKeys, records);
283 }
284 };
285
286 SelectionTable.prototype.flatDataSource = function flatDataSource(dataSource) {
287 var ret = dataSource;
288 var listHeader = this.context.listHeader;
289
290
291 if (listHeader) {
292 ret = [];
293 var hasChildrenSelection = listHeader.hasChildrenSelection,
294 hasSelection = listHeader.hasSelection;
295
296 dataSource.forEach(function (item) {
297 var children = item.children;
298 // 如果需要渲染selection才将这条记录插入到dataSource
299 // 或者没有孩子节点
300 if (hasSelection) {
301 ret.push(item);
302 }
303 if (children && hasChildrenSelection) {
304 ret = ret.concat(children);
305 }
306 });
307 }
308 return ret;
309 };
310
311 SelectionTable.prototype.render = function render() {
312 /* eslint-disable prefer-const */
313 var _props3 = this.props,
314 rowSelection = _props3.rowSelection,
315 components = _props3.components,
316 children = _props3.children,
317 columns = _props3.columns,
318 others = _objectWithoutProperties(_props3, ['rowSelection', 'components', 'children', 'columns']);
319
320 var useColumns = columns && !children;
321
322 if (rowSelection) {
323 if (useColumns) {
324 this.addSelection(columns);
325 } else {
326 children = this.normalizeChildren(children || []);
327 }
328 components = _extends({}, components);
329 components.Row = components.Row || SelectionRow;
330 }
331 return React.createElement(BaseComponent, _extends({}, others, { columns: columns, components: components, children: children }));
332 };
333
334 return SelectionTable;
335 }(React.Component), _class.SelectionRow = SelectionRow, _class.propTypes = _extends({
336 /**
337 * 是否启用选择模式
338 * @property {Function} getProps `Function(record, index)=>Object` 获取selection的默认属性
339 * @property {Function} onChange `Function(selectedRowKeys:Array, records:Array)` 选择改变的时候触发的事件,**注意:** 其中records只会包含当前dataSource的数据,很可能会小于selectedRowKeys的长度。
340 * @property {Function} onSelect `Function(selected:Boolean, record:Object, records:Array)` 用户手动选择/取消选择某行的回调
341 * @property {Function} onSelectAll `Function(selected:Boolean, records:Array)` 用户手动选择/取消选择所有行的回调
342 * @property {Array} selectedRowKeys 设置了此属性,将rowSelection变为受控状态,接收值为该行数据的primaryKey的值
343 * @property {String} mode 选择selection的模式, 可选值为`single`, `multiple`,默认为`multiple`
344 * @property {Function} columnProps `Function()=>Object` 选择列 的props,例如锁列、对齐等,可使用`Table.Column` 的所有参数
345 * @property {Function} titleProps `Function()=>Object` 选择列 表头的props,仅在 `multiple` 模式下生效
346 */
347 rowSelection: PropTypes.object,
348 primaryKey: PropTypes.oneOfType([PropTypes.symbol, PropTypes.string]),
349 dataSource: PropTypes.array,
350 entireDataSource: PropTypes.array
351 }, BaseComponent.propTypes), _class.defaultProps = _extends({}, BaseComponent.defaultProps, {
352 locale: zhCN.Table,
353 primaryKey: 'id',
354 prefix: 'next-'
355 }), _class.contextTypes = {
356 listHeader: PropTypes.any
357 }, _class.childContextTypes = {
358 rowSelection: PropTypes.object,
359 selectedRowKeys: PropTypes.array
360 }, _temp);
361 SelectionTable.displayName = 'SelectionTable';
362
363 statics(SelectionTable, BaseComponent);
364 return polyfill(SelectionTable);
365}
\No newline at end of file