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 || this.notRowDrag) 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 | event.preventDefault()
|
171 | event.stopPropagation();
|
172 | let currentKey = event.dataTransfer.getData("text");
|
173 | let targetKey = target.getAttribute("data-row-key");
|
174 |
|
175 | if(!targetKey || targetKey === currentKey)return;
|
176 | if(target.nodeName.toUpperCase() === "TR"){
|
177 | this.synchronizeTableTr(currentKey,null);
|
178 | this.synchronizeTableTr(targetKey,null);
|
179 | }
|
180 | onDragRow && onDragRow(currentKey,targetKey);
|
181 | };
|
182 |
|
183 | |
184 |
|
185 |
|
186 | getTouchDom = (event) => {
|
187 | let currentLocation = event.changedTouches[0];
|
188 | let realTarget = document.elementFromPoint(currentLocation.clientX, currentLocation.clientY);
|
189 | return realTarget;
|
190 | }
|
191 |
|
192 | |
193 |
|
194 |
|
195 | onTouchStart = (e) => {
|
196 | e.stopPropagation()
|
197 | let {onDragRowStart} = this.props;
|
198 | let event = Event.getEvent(e) ,
|
199 | _target = Event.getTarget(event),
|
200 | target = _target.parentNode;
|
201 |
|
202 | if (target.tagName === 'TR') {
|
203 |
|
204 | this.currentIndex = target.getAttribute("data-row-key");
|
205 |
|
206 | onDragRowStart && onDragRowStart(this.currentIndex);
|
207 | }else{
|
208 |
|
209 | this.canBeTouch = false
|
210 | }
|
211 |
|
212 | }
|
213 |
|
214 | onTouchMove = (e) => {
|
215 |
|
216 | if (!this.canBeTouch) return;
|
217 | e.stopPropagation()
|
218 | let event = Event.getEvent(e);
|
219 | event.preventDefault();
|
220 | let touchTarget = this.getTouchDom(event),
|
221 | target = touchTarget.parentNode,
|
222 | targetKey = target.getAttribute("data-row-key");
|
223 | if(!targetKey || targetKey === this.currentIndex)return;
|
224 | if(target.nodeName.toUpperCase() === "TR"){
|
225 | if(this.cacheCurrentIndex !== targetKey){
|
226 | this.cacheCurrentIndex && this.synchronizeTableTr(this.cacheCurrentIndex,null);
|
227 | this.synchronizeTableTr(targetKey,true);
|
228 | }
|
229 | }
|
230 | }
|
231 |
|
232 | |
233 |
|
234 |
|
235 | onTouchEnd = (e) => {
|
236 |
|
237 | if(!this.canBeTouch){
|
238 | this.canBeTouch = true
|
239 | return
|
240 | }
|
241 |
|
242 | e.stopPropagation()
|
243 | let {onDragRow} = this.props;
|
244 | let event = Event.getEvent(e),
|
245 | currentKey = this.currentIndex,
|
246 | touchTarget = this.getTouchDom(event),
|
247 | target = touchTarget.parentNode,
|
248 | targetKey = target.getAttribute("data-row-key");
|
249 | if(!targetKey || targetKey === currentKey)return;
|
250 | if(target.nodeName.toUpperCase() === "TR"){
|
251 | this.synchronizeTableTr(currentKey,null);
|
252 | this.synchronizeTableTr(targetKey,null);
|
253 | }
|
254 |
|
255 | onDragRow && onDragRow(currentKey,targetKey);
|
256 | }
|
257 |
|
258 | |
259 |
|
260 |
|
261 |
|
262 | synchronizeTableTrShadow = ()=>{
|
263 | let {contentTable,index} = this.props;
|
264 |
|
265 | let cont = contentTable.querySelector('.u-table-scroll table tbody').getElementsByTagName("tr")[index],
|
266 | trs = cont.getBoundingClientRect(),
|
267 | fixed_left_trs = contentTable.querySelector('.u-table-fixed-left table tbody'),
|
268 | fixed_right_trs = contentTable.querySelector('.u-table-fixed-right table tbody');
|
269 | fixed_left_trs = fixed_left_trs && fixed_left_trs.getElementsByTagName("tr")[index].getBoundingClientRect();
|
270 | fixed_right_trs = fixed_right_trs && fixed_right_trs.getElementsByTagName("tr")[index].getBoundingClientRect()
|
271 |
|
272 | let div = document.createElement("div");
|
273 | let style = "wdith:"+(trs.width + (fixed_left_trs ? fixed_left_trs.width : 0) + (fixed_right_trs ? fixed_right_trs.width : 0))+"px";
|
274 | style += ";height:"+ trs.height+"px";
|
275 | style += ";classname:"+ cont.className;
|
276 | div.setAttribute("style",style);
|
277 | return div;
|
278 | }
|
279 |
|
280 |
|
281 | |
282 |
|
283 |
|
284 | synchronizeTableTr = (currentIndex,type)=>{
|
285 | if(type){
|
286 | this.cacheCurrentIndex = currentIndex;
|
287 | }
|
288 | let {contentTable} = this.props;
|
289 | let _table_trs = contentTable.querySelector('.u-table-scroll table tbody'),
|
290 | _table_fixed_left_trs = contentTable.querySelector('.u-table-fixed-left table tbody'),
|
291 | _table_fixed_right_trs = contentTable.querySelector('.u-table-fixed-right table tbody');
|
292 |
|
293 | _table_trs = _table_trs?_table_trs:contentTable.querySelector('.u-table table tbody');
|
294 |
|
295 | this.synchronizeTrStyle(_table_trs,currentIndex,type);
|
296 | if(_table_fixed_left_trs){
|
297 | this.synchronizeTrStyle(_table_fixed_left_trs,currentIndex,type);
|
298 | }
|
299 | if(_table_fixed_right_trs){
|
300 | this.synchronizeTrStyle(_table_fixed_right_trs,currentIndex,type);
|
301 | }
|
302 | }
|
303 |
|
304 | |
305 |
|
306 |
|
307 | synchronizeTrStyle = (_elementBody,id,type)=>{
|
308 | let {contentTable} = this.props,
|
309 | trs = _elementBody.getElementsByTagName("tr"),
|
310 | currentObj;
|
311 | for (let index = 0; index < trs.length; index++) {
|
312 | const element = trs[index];
|
313 | if(element.getAttribute("data-row-key") == id){
|
314 | currentObj = element;
|
315 | }
|
316 | }
|
317 | if(type){
|
318 | currentObj && currentObj.setAttribute("style","border-bottom:2px solid #02B1FD");
|
319 | }else{
|
320 | currentObj && currentObj.setAttribute("style","");
|
321 | }
|
322 | }
|
323 |
|
324 | onDragEnter = (e) => {
|
325 | let event = Event.getEvent(e) ,
|
326 | _target = Event.getTarget(event),target = _target.parentNode;
|
327 | let currentIndex = target.getAttribute("data-row-key");
|
328 | if(!currentIndex || currentIndex === this.currentIndex)return;
|
329 | if(target.nodeName.toUpperCase() === "TR"){
|
330 | this.synchronizeTableTr(currentIndex,true);
|
331 | }
|
332 | }
|
333 |
|
334 | onDragLeave = (e) => {
|
335 | let event = Event.getEvent(e) ,
|
336 | _target = Event.getTarget(event),target = _target.parentNode;
|
337 | let currentIndex = target.getAttribute("data-row-key");
|
338 | if(!currentIndex || currentIndex === this.currentIndex)return;
|
339 | if(target.nodeName.toUpperCase() === "TR"){
|
340 | this.synchronizeTableTr(currentIndex,null);
|
341 | }
|
342 | }
|
343 |
|
344 | componentDidUpdate(prevProps) {
|
345 | const { rowDraggAble,syncRowHeight } = this.props;
|
346 | if(!this.event){
|
347 | this.event = true;
|
348 | if(rowDraggAble){
|
349 | this.initEvent();
|
350 | }
|
351 | }
|
352 | if(this.props.treeType){
|
353 | this.setRowParentIndex();
|
354 | }
|
355 |
|
356 |
|
357 |
|
358 | this.setRowHeight()
|
359 | }
|
360 |
|
361 | componentWillUnmount() {
|
362 | const { record, onDestroy, index,rowDraggAble } = this.props;
|
363 | onDestroy(record, index);
|
364 | if (this.unsubscribe) {
|
365 | this.unsubscribe();
|
366 | }
|
367 | if(rowDraggAble){
|
368 | this.removeDragAbleEvent();
|
369 | }
|
370 | }
|
371 |
|
372 |
|
373 | setRowHeight() {
|
374 | const { setRowHeight , expandedContentHeight=0,fixed,fixedIndex} = this.props
|
375 | if (!setRowHeight || !this.element || fixed) return
|
376 | setRowHeight(this.element.clientHeight + expandedContentHeight, fixedIndex)
|
377 | }
|
378 | setRowParentIndex(){
|
379 | const {index,setRowParentIndex,fixedIndex,rootIndex} = this.props;
|
380 | setRowParentIndex(rootIndex<0?index:rootIndex,fixedIndex);
|
381 |
|
382 | }
|
383 |
|
384 | onRowClick(event) {
|
385 |
|
386 |
|
387 |
|
388 | event.persist();
|
389 | const {
|
390 | record,
|
391 | index,
|
392 | onRowClick,
|
393 | expandable,
|
394 | expandRowByClick,
|
395 | expanded,
|
396 | onExpand,
|
397 | fixedIndex,
|
398 | onRowDoubleClick
|
399 | } = this.props;
|
400 | if (expandable && expandRowByClick) {
|
401 | onExpand(!expanded, record, fixedIndex,event);
|
402 | }
|
403 | if(!onRowDoubleClick){
|
404 | onRowClick(record, fixedIndex, event);
|
405 | return;
|
406 | }
|
407 | this.set((e)=> {
|
408 | onRowClick(record, fixedIndex, event);
|
409 | });
|
410 | }
|
411 |
|
412 | onRowDoubleClick(event) {
|
413 | const { record, index, onRowDoubleClick,fixedIndex } = this.props;
|
414 | this.clear();
|
415 | onRowDoubleClick && onRowDoubleClick(record, fixedIndex, event);
|
416 | }
|
417 |
|
418 | onMouseEnter(e) {
|
419 | const { onHover, hoverKey,fixedIndex,syncHover,record } = this.props;
|
420 | if(syncHover){
|
421 | this.setState({ hovered: true });
|
422 | }
|
423 | onHover(true, hoverKey,e,fixedIndex,record);
|
424 | }
|
425 |
|
426 | onMouseLeave(e) {
|
427 |
|
428 | const { onHover, hoverKey ,fixedIndex,syncHover,record} = this.props;
|
429 | if(syncHover){
|
430 | this.setState({ hovered: false });
|
431 | }
|
432 | onHover(false, hoverKey,e,fixedIndex,record);
|
433 | }
|
434 |
|
435 | stopRowDrag = (isStop) => {
|
436 | const {rowDraggAble} = this.props;
|
437 | const {notRowDrag} = this.state;
|
438 | if(rowDraggAble && isStop!== notRowDrag) {
|
439 | this.setState({
|
440 | notRowDrag: isStop
|
441 | })
|
442 | }
|
443 | }
|
444 |
|
445 | set =(fn)=> {
|
446 | this.clear();
|
447 | this._timeout = window.setTimeout(fn, 300);
|
448 | }
|
449 |
|
450 | clear =(event)=> {
|
451 | if (this._timeout) {
|
452 | window.clearTimeout(this._timeout);
|
453 | }
|
454 | }
|
455 |
|
456 | bindElement = (el)=> {
|
457 | this.element = el
|
458 | }
|
459 |
|
460 | render() {
|
461 | const {
|
462 | clsPrefix, columns, record, height, visible, index,onPaste,
|
463 | expandIconColumnIndex, expandIconAsCell, expanded, useDragHandle,rowDraggAble,
|
464 | expandable, onExpand, needIndentSpaced, indent, indentSize,isHiddenExpandIcon,fixed,bodyDisplayInRow
|
465 | ,expandedIcon,collapsedIcon, hoverKey,lazyStartIndex,lazyEndIndex, expandIconCellWidth, getCellClassName
|
466 | } = this.props;
|
467 | const {notRowDrag} = this.state;
|
468 | let showSum = false;
|
469 | let { className } = this.props;
|
470 | if (this.state.hovered) {
|
471 | className += ` ${clsPrefix}-hover`;
|
472 | }
|
473 |
|
474 | if(className.indexOf('sumrow')>-1){
|
475 | showSum = true;
|
476 | }
|
477 | const cells = [];
|
478 |
|
479 | const expandIcon = (
|
480 | <ExpandIcon
|
481 | expandable={expandable}
|
482 | clsPrefix={clsPrefix}
|
483 | onExpand={onExpand}
|
484 | needIndentSpaced={needIndentSpaced}
|
485 | expanded={expanded}
|
486 | record={record}
|
487 | expandedIcon={expandedIcon}
|
488 | collapsedIcon={collapsedIcon}
|
489 | isHiddenExpandIcon={isHiddenExpandIcon}
|
490 | />
|
491 | );
|
492 | let isExpandIconAsCell = expandIconAsCell ? `${clsPrefix}-expand-columns-in-body` : '';
|
493 | var expandIndexInThisTable
|
494 | if(this.props.fixed === 'right'){
|
495 | expandIndexInThisTable = expandIconColumnIndex - this.props.leftColumnsLength-this.props.centerColumnsLength
|
496 | }else {
|
497 | expandIndexInThisTable = expandIconColumnIndex
|
498 | }
|
499 | for (let i = 0; i < columns.length; i++) {
|
500 | if (expandIconAsCell && i === 0) {
|
501 | showSum ? cells.push(<td width={expandIconCellWidth}></td>) :
|
502 | cells.push(
|
503 | <td
|
504 | className={`${clsPrefix}-expand-icon-cell ${isExpandIconAsCell}`}
|
505 | key={`rc-table-expand-icon-cell-${i}`}
|
506 | width={expandIconCellWidth}
|
507 | >
|
508 | {expandIcon}
|
509 | </td>
|
510 | );
|
511 | }
|
512 |
|
513 | const isColumnHaveExpandIcon = (expandIconAsCell || showSum)
|
514 | ? false : (i === expandIndexInThisTable);
|
515 | cells.push(
|
516 | <TableCell
|
517 | clsPrefix={clsPrefix}
|
518 | record={record}
|
519 | indentSize={indentSize}
|
520 | indent={indent}
|
521 | index={index}
|
522 | column={columns[i]}
|
523 | key={index + "_"+(columns[i].key || columns[i].dataIndex || i)}
|
524 | fixed= {fixed}
|
525 | showSum={showSum}
|
526 | expandIcon={(isColumnHaveExpandIcon) ? expandIcon : null}
|
527 | bodyDisplayInRow = {bodyDisplayInRow}
|
528 | lazyStartIndex={lazyStartIndex}
|
529 | lazyEndIndex={lazyEndIndex}
|
530 | onPaste={onPaste}
|
531 | stopRowDrag={this.stopRowDrag}
|
532 | col={i}
|
533 | getCellClassName = {getCellClassName}
|
534 | />
|
535 | );
|
536 | }
|
537 | const style = { height ,...record?record.style:undefined};
|
538 | if (!visible) {
|
539 | style.display = 'none';
|
540 | }
|
541 | if(record && record._checked){
|
542 | className += ' selected';
|
543 | }
|
544 |
|
545 | if(rowDraggAble && !useDragHandle && !notRowDrag) {
|
546 | className += ' row-dragg-able'
|
547 | }
|
548 |
|
549 | return (
|
550 | <tr
|
551 | draggable={rowDraggAble && !useDragHandle && !notRowDrag}
|
552 | onClick={this.onRowClick}
|
553 | onDoubleClick={this.onRowDoubleClick}
|
554 | onMouseEnter={this.onMouseEnter}
|
555 | onMouseLeave={this.onMouseLeave}
|
556 | className={`${clsPrefix} ${className} ${clsPrefix}-level-${indent}`}
|
557 | style={style}
|
558 | data-row-key={record && record.key?record.key:hoverKey}
|
559 |
|
560 | ref={this.bindElement}
|
561 | >
|
562 | {cells.length>0?cells:<td style={{width:0,padding:0}}></td>}
|
563 | </tr>
|
564 | );
|
565 | }
|
566 | };
|
567 |
|
568 | TableRow.propTypes = propTypes;
|
569 | TableRow.defaultProps = defaultProps;
|
570 |
|
571 | export default TableRow;
|