1 | import React, { Component } from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import { Event,EventUtil} from "./lib/utils";
|
4 | import TableCell from './TableCell';
|
5 | import ExpandIcon from './ExpandIcon';
|
6 |
|
7 | const propTypes = {
|
8 | onDestroy: PropTypes.func,
|
9 | onRowClick: PropTypes.func,
|
10 | onRowDoubleClick: PropTypes.func,
|
11 | record: PropTypes.object,
|
12 | clsPrefix: PropTypes.string,
|
13 | expandIconColumnIndex: PropTypes.number,
|
14 | onHover: PropTypes.func,
|
15 | columns: PropTypes.array,
|
16 | height: PropTypes.oneOfType([
|
17 | PropTypes.string,
|
18 | PropTypes.number,
|
19 | ]),
|
20 | visible: PropTypes.bool,
|
21 | index: PropTypes.number,
|
22 | hoverKey: PropTypes.any,
|
23 | expanded: PropTypes.bool,
|
24 | expandable: PropTypes.any,
|
25 | onExpand: PropTypes.func,
|
26 | needIndentSpaced: PropTypes.bool,
|
27 | className: PropTypes.string,
|
28 | indent: PropTypes.number,
|
29 | indentSize: PropTypes.number,
|
30 | expandIconAsCell: PropTypes.bool,
|
31 | expandRowByClick: PropTypes.bool,
|
32 | store: PropTypes.object.isRequired,
|
33 | rowDraggAble: PropTypes.bool,
|
34 | onDragRow: PropTypes.func,
|
35 | onDragRowStart: PropTypes.func,
|
36 | syncRowHeight:PropTypes.bool
|
37 | };
|
38 |
|
39 | const defaultProps = {
|
40 | onRowClick() {},
|
41 |
|
42 | onDestroy() {},
|
43 | expandIconColumnIndex: 0,
|
44 | expandRowByClick: false,
|
45 | onHover() {},
|
46 | className:'',
|
47 | setRowParentIndex:()=>{},
|
48 | rowDraggAble:false,
|
49 |
|
50 | syncRowHeight:false
|
51 | };
|
52 |
|
53 | class TableRow extends Component{
|
54 | constructor(props){
|
55 | super(props);
|
56 | this._timeout = null;
|
57 | this.state = {
|
58 | hovered: false,
|
59 | };
|
60 | this.onRowClick = this.onRowClick.bind(this);
|
61 | this.onRowDoubleClick = this.onRowDoubleClick.bind(this);
|
62 | this.onMouseEnter = this.onMouseEnter.bind(this);
|
63 | this.onMouseLeave = this.onMouseLeave.bind(this);
|
64 | this.expandHeight = 0;
|
65 | this.event = false;
|
66 | this.cacheCurrentIndex = null;
|
67 | this.canBeTouch = true
|
68 | }
|
69 |
|
70 |
|
71 | componentDidMount() {
|
72 | const { store, hoverKey,treeType,rowDraggAble } = this.props;
|
73 | this.unsubscribe = store.subscribe(() => {
|
74 | if (store.getState().currentHoverKey === hoverKey) {
|
75 | this.setState({ hovered: true });
|
76 | } else if (this.state.hovered === true) {
|
77 | this.setState({ hovered: false });
|
78 | }
|
79 | });
|
80 |
|
81 | this.setRowHeight()
|
82 | if(treeType){
|
83 | this.setRowParentIndex();
|
84 | }
|
85 | }
|
86 |
|
87 | |
88 |
|
89 |
|
90 | initEvent=()=>{
|
91 | let events = [
|
92 | {key:'touchstart', fun:this.onTouchStart},
|
93 | {key:'touchmove', fun:this.onTouchMove},
|
94 | {key:'touchend', fun:this.onTouchEnd},
|
95 |
|
96 | {key:'dragstart',fun:this.onDragStart},
|
97 | {key:'dragover', fun:this.onDragOver},
|
98 | {key:'drop', fun:this.onDrop},
|
99 | {key:'dragenter', fun:this.onDragEnter},
|
100 | {key:'dragleave', fun:this.onDragLeave},
|
101 | ];
|
102 | this.eventListen(events,'',this.element);
|
103 | }
|
104 |
|
105 | |
106 |
|
107 |
|
108 | removeDragAbleEvent=()=>{
|
109 | let events = [
|
110 | {key:'touchstart', fun:this.onTouchStart},
|
111 | {key:'touchmove', fun:this.onTouchMove},
|
112 | {key:'touchend', fun:this.onTouchEnd},
|
113 |
|
114 | {key:'dragstart',fun:this.onDragStart},
|
115 | {key:'dragover', fun:this.onDragOver},
|
116 | {key:'drop', fun:this.onDrop},
|
117 | {key:'dragenter', fun:this.onDragEnter},
|
118 | {key:'dragleave', fun:this.onDragLeave},
|
119 | ];
|
120 | this.eventListen(events,'remove',this.element);
|
121 | }
|
122 |
|
123 |
|
124 | |
125 |
|
126 |
|
127 | eventListen(events,type,eventSource){
|
128 | for (let i = 0; i < events.length; i++) {
|
129 | const _event = events[i];
|
130 | if(type === "remove"){
|
131 | EventUtil.removeHandler(eventSource,_event.key,_event.fun);
|
132 | }else{
|
133 | EventUtil.addHandler(eventSource,_event.key,_event.fun);
|
134 | }
|
135 | }
|
136 | }
|
137 |
|
138 | |
139 |
|
140 |
|
141 | onDragStart = (e) => {
|
142 | let {onDragRowStart} = this.props;
|
143 | if (!this.props.rowDraggAble) return;
|
144 | let event = Event.getEvent(e) ,
|
145 | target = Event.getTarget(event);
|
146 | if (target.tagName === 'TD') {
|
147 | target = target.parentNode;
|
148 | }
|
149 | this.currentIndex = target.getAttribute("data-row-key");
|
150 | this._dragCurrent = target;
|
151 | event.dataTransfer.effectAllowed = "move";
|
152 | event.dataTransfer.setData("Text", this.currentIndex);
|
153 | onDragRowStart && onDragRowStart(this.currentIndex);
|
154 | }
|
155 |
|
156 | onDragOver = (e) => {
|
157 | let event = Event.getEvent(e);
|
158 | event.preventDefault();
|
159 | };
|
160 |
|
161 | |
162 |
|
163 |
|
164 |
|
165 | onDrop = (e) => {
|
166 | let {onDragRow} = this.props;
|
167 | let event = Event.getEvent(e) ,
|
168 | _target = Event.getTarget(event),
|
169 | target = _target.parentNode;
|
170 |
|
171 | let currentKey = event.dataTransfer.getData("text");
|
172 | let targetKey = target.getAttribute("data-row-key");
|
173 |
|
174 | if(!targetKey || targetKey === currentKey)return;
|
175 | if(target.nodeName.toUpperCase() === "TR"){
|
176 | this.synchronizeTableTr(currentKey,null);
|
177 | this.synchronizeTableTr(targetKey,null);
|
178 | }
|
179 | onDragRow && onDragRow(currentKey,targetKey);
|
180 | };
|
181 |
|
182 | |
183 |
|
184 |
|
185 | getTouchDom = (event) => {
|
186 | let currentLocation = event.changedTouches[0];
|
187 | let realTarget = document.elementFromPoint(currentLocation.clientX, currentLocation.clientY);
|
188 | return realTarget;
|
189 | }
|
190 |
|
191 | |
192 |
|
193 |
|
194 | onTouchStart = (e) => {
|
195 | e.stopPropagation()
|
196 | let {onDragRowStart} = this.props;
|
197 | let event = Event.getEvent(e) ,
|
198 | _target = Event.getTarget(event),
|
199 | target = _target.parentNode;
|
200 |
|
201 | if (target.tagName === 'TR') {
|
202 |
|
203 | this.currentIndex = target.getAttribute("data-row-key");
|
204 |
|
205 | onDragRowStart && onDragRowStart(this.currentIndex);
|
206 | }else{
|
207 |
|
208 | this.canBeTouch = false
|
209 | }
|
210 |
|
211 | }
|
212 |
|
213 | onTouchMove = (e) => {
|
214 |
|
215 | if (!this.canBeTouch) return;
|
216 | e.stopPropagation()
|
217 | let event = Event.getEvent(e);
|
218 | event.preventDefault();
|
219 | let touchTarget = this.getTouchDom(event),
|
220 | target = touchTarget.parentNode,
|
221 | targetKey = target.getAttribute("data-row-key");
|
222 | if(!targetKey || targetKey === this.currentIndex)return;
|
223 | if(target.nodeName.toUpperCase() === "TR"){
|
224 | if(this.cacheCurrentIndex !== targetKey){
|
225 | this.cacheCurrentIndex && this.synchronizeTableTr(this.cacheCurrentIndex,null);
|
226 | this.synchronizeTableTr(targetKey,true);
|
227 | }
|
228 | }
|
229 | }
|
230 |
|
231 | |
232 |
|
233 |
|
234 | onTouchEnd = (e) => {
|
235 |
|
236 | if(!this.canBeTouch){
|
237 | this.canBeTouch = true
|
238 | return
|
239 | }
|
240 |
|
241 | e.stopPropagation()
|
242 | let {onDragRow} = this.props;
|
243 | let event = Event.getEvent(e),
|
244 | currentKey = this.currentIndex,
|
245 | touchTarget = this.getTouchDom(event),
|
246 | target = touchTarget.parentNode,
|
247 | targetKey = target.getAttribute("data-row-key");
|
248 | if(!targetKey || targetKey === currentKey)return;
|
249 | if(target.nodeName.toUpperCase() === "TR"){
|
250 | this.synchronizeTableTr(currentKey,null);
|
251 | this.synchronizeTableTr(targetKey,null);
|
252 | }
|
253 |
|
254 | onDragRow && onDragRow(currentKey,targetKey);
|
255 | }
|
256 |
|
257 | |
258 |
|
259 |
|
260 |
|
261 | synchronizeTableTrShadow = ()=>{
|
262 | let {contentTable,index} = this.props;
|
263 |
|
264 | let cont = contentTable.querySelector('.u-table-scroll table tbody').getElementsByTagName("tr")[index],
|
265 | trs = cont.getBoundingClientRect(),
|
266 | fixed_left_trs = contentTable.querySelector('.u-table-fixed-left table tbody'),
|
267 | fixed_right_trs = contentTable.querySelector('.u-table-fixed-right table tbody');
|
268 | fixed_left_trs = fixed_left_trs && fixed_left_trs.getElementsByTagName("tr")[index].getBoundingClientRect();
|
269 | fixed_right_trs = fixed_right_trs && fixed_right_trs.getElementsByTagName("tr")[index].getBoundingClientRect()
|
270 |
|
271 | let div = document.createElement("div");
|
272 | let style = "wdith:"+(trs.width + (fixed_left_trs ? fixed_left_trs.width : 0) + (fixed_right_trs ? fixed_right_trs.width : 0))+"px";
|
273 | style += ";height:"+ trs.height+"px";
|
274 | style += ";classname:"+ cont.className;
|
275 | div.setAttribute("style",style);
|
276 | return div;
|
277 | }
|
278 |
|
279 |
|
280 | |
281 |
|
282 |
|
283 | synchronizeTableTr = (currentIndex,type)=>{
|
284 | if(type){
|
285 | this.cacheCurrentIndex = currentIndex;
|
286 | }
|
287 | let {contentTable} = this.props;
|
288 | let _table_trs = contentTable.querySelector('.u-table-scroll table tbody'),
|
289 | _table_fixed_left_trs = contentTable.querySelector('.u-table-fixed-left table tbody'),
|
290 | _table_fixed_right_trs = contentTable.querySelector('.u-table-fixed-right table tbody');
|
291 |
|
292 | _table_trs = _table_trs?_table_trs:contentTable.querySelector('.u-table table tbody');
|
293 |
|
294 | this.synchronizeTrStyle(_table_trs,currentIndex,type);
|
295 | if(_table_fixed_left_trs){
|
296 | this.synchronizeTrStyle(_table_fixed_left_trs,currentIndex,type);
|
297 | }
|
298 | if(_table_fixed_right_trs){
|
299 | this.synchronizeTrStyle(_table_fixed_right_trs,currentIndex,type);
|
300 | }
|
301 | }
|
302 |
|
303 | |
304 |
|
305 |
|
306 | synchronizeTrStyle = (_elementBody,id,type)=>{
|
307 | let {contentTable} = this.props,
|
308 | trs = _elementBody.getElementsByTagName("tr"),
|
309 | currentObj;
|
310 | for (let index = 0; index < trs.length; index++) {
|
311 | const element = trs[index];
|
312 | if(element.getAttribute("data-row-key") == id){
|
313 | currentObj = element;
|
314 | }
|
315 | }
|
316 | if(type){
|
317 | currentObj && currentObj.setAttribute("style","border-bottom:2px solid #02B1FD");
|
318 | }else{
|
319 | currentObj && currentObj.setAttribute("style","");
|
320 | }
|
321 | }
|
322 |
|
323 | onDragEnter = (e) => {
|
324 | let event = Event.getEvent(e) ,
|
325 | _target = Event.getTarget(event),target = _target.parentNode;
|
326 | let currentIndex = target.getAttribute("data-row-key");
|
327 | if(!currentIndex || currentIndex === this.currentIndex)return;
|
328 | if(target.nodeName.toUpperCase() === "TR"){
|
329 | this.synchronizeTableTr(currentIndex,true);
|
330 | }
|
331 | }
|
332 |
|
333 | onDragLeave = (e) => {
|
334 | let event = Event.getEvent(e) ,
|
335 | _target = Event.getTarget(event),target = _target.parentNode;
|
336 | let currentIndex = target.getAttribute("data-row-key");
|
337 | if(!currentIndex || currentIndex === this.currentIndex)return;
|
338 | if(target.nodeName.toUpperCase() === "TR"){
|
339 | this.synchronizeTableTr(currentIndex,null);
|
340 | }
|
341 | }
|
342 |
|
343 | componentDidUpdate(prevProps) {
|
344 | const { rowDraggAble,syncRowHeight } = this.props;
|
345 | if(!this.event){
|
346 | this.event = true;
|
347 | if(rowDraggAble){
|
348 | this.initEvent();
|
349 | }
|
350 | }
|
351 | if(this.props.treeType){
|
352 | this.setRowParentIndex();
|
353 | }
|
354 | if(syncRowHeight){
|
355 | this.setRowHeight()
|
356 | }
|
357 | }
|
358 |
|
359 | componentWillUnmount() {
|
360 | const { record, onDestroy, index,rowDraggAble } = this.props;
|
361 | onDestroy(record, index);
|
362 | if (this.unsubscribe) {
|
363 | this.unsubscribe();
|
364 | }
|
365 | if(rowDraggAble){
|
366 | this.removeDragAbleEvent();
|
367 | }
|
368 | }
|
369 |
|
370 |
|
371 | setRowHeight() {
|
372 | const { setRowHeight , expandedContentHeight=0,fixed,fixedIndex} = this.props
|
373 | if (!setRowHeight || !this.element || fixed) return
|
374 | setRowHeight(this.element.clientHeight + expandedContentHeight, fixedIndex)
|
375 | }
|
376 | setRowParentIndex(){
|
377 | const {index,setRowParentIndex,fixedIndex,rootIndex} = this.props;
|
378 | setRowParentIndex(rootIndex<0?index:rootIndex,fixedIndex);
|
379 |
|
380 | }
|
381 |
|
382 | onRowClick(event) {
|
383 |
|
384 |
|
385 |
|
386 | event.persist();
|
387 | const {
|
388 | record,
|
389 | index,
|
390 | onRowClick,
|
391 | expandable,
|
392 | expandRowByClick,
|
393 | expanded,
|
394 | onExpand,
|
395 | fixedIndex,
|
396 | onRowDoubleClick
|
397 | } = this.props;
|
398 | if (expandable && expandRowByClick) {
|
399 | onExpand(!expanded, record, fixedIndex,event);
|
400 | }
|
401 | if(!onRowDoubleClick){
|
402 | onRowClick(record, fixedIndex, event);
|
403 | return;
|
404 | }
|
405 | this.set((e)=> {
|
406 | onRowClick(record, fixedIndex, event);
|
407 | });
|
408 | }
|
409 |
|
410 | onRowDoubleClick(event) {
|
411 | const { record, index, onRowDoubleClick,fixedIndex } = this.props;
|
412 | this.clear();
|
413 | onRowDoubleClick && onRowDoubleClick(record, fixedIndex, event);
|
414 | }
|
415 |
|
416 | onMouseEnter(e) {
|
417 | const { onHover, hoverKey,fixedIndex,syncHover,record } = this.props;
|
418 | if(syncHover){
|
419 | this.setState({ hovered: true });
|
420 | }
|
421 | onHover(true, hoverKey,e,fixedIndex,record);
|
422 | }
|
423 |
|
424 | onMouseLeave(e) {
|
425 |
|
426 | const { onHover, hoverKey ,fixedIndex,syncHover,record} = this.props;
|
427 | if(syncHover){
|
428 | this.setState({ hovered: false });
|
429 | }
|
430 | onHover(false, hoverKey,e,fixedIndex,record);
|
431 | }
|
432 |
|
433 | set =(fn)=> {
|
434 | this.clear();
|
435 | this._timeout = window.setTimeout(fn, 300);
|
436 | }
|
437 |
|
438 | clear =(event)=> {
|
439 | if (this._timeout) {
|
440 | window.clearTimeout(this._timeout);
|
441 | }
|
442 | }
|
443 |
|
444 | bindElement = (el)=> {
|
445 | this.element = el
|
446 | }
|
447 |
|
448 | render() {
|
449 | const {
|
450 | clsPrefix, columns, record, height, visible, index,onPaste,
|
451 | expandIconColumnIndex, expandIconAsCell, expanded, useDragHandle,rowDraggAble,
|
452 | expandable, onExpand, needIndentSpaced, indent, indentSize,isHiddenExpandIcon,fixed,bodyDisplayInRow
|
453 | ,expandedIcon,collapsedIcon, hoverKey,lazyStartIndex,lazyEndIndex, expandIconCellWidth
|
454 | } = this.props;
|
455 | let showSum = false;
|
456 | let { className } = this.props;
|
457 | if (this.state.hovered) {
|
458 | className += ` ${clsPrefix}-hover`;
|
459 | }
|
460 |
|
461 | if(className.indexOf('sumrow')>-1){
|
462 | showSum = true;
|
463 | }
|
464 | const cells = [];
|
465 |
|
466 | const expandIcon = (
|
467 | <ExpandIcon
|
468 | expandable={expandable}
|
469 | clsPrefix={clsPrefix}
|
470 | onExpand={onExpand}
|
471 | needIndentSpaced={needIndentSpaced}
|
472 | expanded={expanded}
|
473 | record={record}
|
474 | expandedIcon={expandedIcon}
|
475 | collapsedIcon={collapsedIcon}
|
476 | isHiddenExpandIcon={isHiddenExpandIcon}
|
477 | />
|
478 | );
|
479 | let isExpandIconAsCell = expandIconAsCell ? `${clsPrefix}-expand-columns-in-body` : '';
|
480 | var expandIndexInThisTable
|
481 | if(this.props.fixed === 'right'){
|
482 | expandIndexInThisTable = expandIconColumnIndex - this.props.leftColumnsLength-this.props.centerColumnsLength
|
483 | }else {
|
484 | expandIndexInThisTable = expandIconColumnIndex
|
485 | }
|
486 | for (let i = 0; i < columns.length; i++) {
|
487 | if (expandIconAsCell && i === 0) {
|
488 | showSum ? cells.push(<td width={expandIconCellWidth}></td>) :
|
489 | cells.push(
|
490 | <td
|
491 | className={`${clsPrefix}-expand-icon-cell ${isExpandIconAsCell}`}
|
492 | key={`rc-table-expand-icon-cell-${i}`}
|
493 | width={expandIconCellWidth}
|
494 | >
|
495 | {expandIcon}
|
496 | </td>
|
497 | );
|
498 | }
|
499 |
|
500 | const isColumnHaveExpandIcon = (expandIconAsCell || showSum)
|
501 | ? false : (i === expandIndexInThisTable);
|
502 | cells.push(
|
503 | <TableCell
|
504 | clsPrefix={clsPrefix}
|
505 | record={record}
|
506 | indentSize={indentSize}
|
507 | indent={indent}
|
508 | index={index}
|
509 | column={columns[i]}
|
510 | key={index + "_"+(columns[i].key || columns[i].dataIndex || i)}
|
511 | fixed= {fixed}
|
512 | showSum={showSum}
|
513 | expandIcon={(isColumnHaveExpandIcon) ? expandIcon : null}
|
514 | bodyDisplayInRow = {bodyDisplayInRow}
|
515 | lazyStartIndex={lazyStartIndex}
|
516 | lazyEndIndex={lazyEndIndex}
|
517 | onPaste={onPaste}
|
518 | col={i}
|
519 | />
|
520 | );
|
521 | }
|
522 | const style = { height ,...record?record.style:undefined};
|
523 | if (!visible) {
|
524 | style.display = 'none';
|
525 | }
|
526 | if(record && record._checked){
|
527 | className += ' selected';
|
528 | }
|
529 | return (
|
530 | <tr
|
531 | draggable={rowDraggAble && !useDragHandle}
|
532 | onClick={this.onRowClick}
|
533 | onDoubleClick={this.onRowDoubleClick}
|
534 | onMouseEnter={this.onMouseEnter}
|
535 | onMouseLeave={this.onMouseLeave}
|
536 | className={`${clsPrefix} ${className} ${clsPrefix}-level-${indent}`}
|
537 | style={style}
|
538 | data-row-key={record && record.key?record.key:hoverKey}
|
539 |
|
540 | ref={this.bindElement}
|
541 | >
|
542 | {cells.length>0?cells:<td style={{width:0,padding:0}}></td>}
|
543 | </tr>
|
544 | );
|
545 | }
|
546 | };
|
547 |
|
548 | TableRow.propTypes = propTypes;
|
549 | TableRow.defaultProps = defaultProps;
|
550 |
|
551 | export default TableRow;
|