1 | import React from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import { Table, Column, Cell } from 'fixed-data-table-2';
|
4 | import classNames from 'classnames';
|
5 | import * as Constants from './constants';
|
6 | import * as CellUtils from './CellUtils';
|
7 | import { HeaderCell } from './HeaderCell';
|
8 | import { TextCell } from './TextCell';
|
9 | import TouchWrapper from './TouchWrapper';
|
10 | import { RETURNED_DATA_TYPES } from './constants';
|
11 | import _ from 'lodash';
|
12 | import { StyleSheet, css } from 'aphrodite';
|
13 |
|
14 | export class HugeTable extends React.Component {
|
15 | static propTypes = {
|
16 | data: PropTypes.arrayOf(PropTypes.object),
|
17 | options: PropTypes.shape({
|
18 | height: PropTypes.number,
|
19 | width: PropTypes.number,
|
20 | mixedContentImage: PropTypes.func,
|
21 | tableScrolled: PropTypes.func,
|
22 | id: PropTypes.string,
|
23 | maxTitleWidth: PropTypes.number,
|
24 | maxContentWidth: PropTypes.number,
|
25 | minColumnWidth: PropTypes.number,
|
26 | rowNumberColumnWidth: PropTypes.number,
|
27 | fontDetails: PropTypes.string,
|
28 | headerOffsetWidth: PropTypes.number,
|
29 | }),
|
30 | schema: PropTypes.arrayOf(PropTypes.shape({
|
31 | name: PropTypes.string,
|
32 | type: PropTypes.string,
|
33 | })),
|
34 | renderers: PropTypes.shape(RETURNED_DATA_TYPES.reduce((initial, next) => {
|
35 | return {
|
36 | ...initial,
|
37 | [next]: PropTypes.func,
|
38 | };
|
39 | }, {HEADER: PropTypes.func})),
|
40 | onSchemaChange: PropTypes.func,
|
41 | resizeByContent: PropTypes.bool,
|
42 | hideRowNumbers: PropTypes.bool,
|
43 | showScrollingArrows: PropTypes.bool,
|
44 | scrollToNewColumn: PropTypes.bool,
|
45 | onScrollToNewColumn: PropTypes.func,
|
46 | rowHeight: PropTypes.number,
|
47 | headerHeight: PropTypes.number,
|
48 | cellPadding: PropTypes.shape ({
|
49 | top: PropTypes.number,
|
50 | bottom: PropTypes.number,
|
51 | left: PropTypes.number,
|
52 | right: PropTypes.number,
|
53 | }),
|
54 | lineHeight: PropTypes.number,
|
55 | buttonColumnWidth: PropTypes.number,
|
56 | activeColumnIndex: PropTypes.number,
|
57 | onActiveColumnChange: PropTypes.func,
|
58 | scrollToColumn: PropTypes.number,
|
59 | disableClickEvents: PropTypes.bool,
|
60 | resizeableColumns: PropTypes.bool,
|
61 | reorderableColumns: PropTypes.bool,
|
62 | }
|
63 |
|
64 | static defaultProps = {
|
65 | resizeableColumns: true,
|
66 | reorderableColumns: true,
|
67 | };
|
68 |
|
69 | constructor(props) {
|
70 | super(props);
|
71 | const
|
72 | cellPadding = props.cellPadding || Constants.CELL_PADDING,
|
73 | lineHeight = props.lineHeight || Constants.LINE_HEIGHT,
|
74 | headerHeight = props.headerHeight || Constants.HEADER_HEIGHT,
|
75 | rowHeight = props.rowHeight || Constants.ROW_HEIGHT;
|
76 | this.state = {
|
77 | columnWidths: {},
|
78 | isColumnResizing: undefined,
|
79 | columnNameToDataTypeMap: {},
|
80 | columnOrder: [],
|
81 | currentSchema: [],
|
82 | shouldActivateLeftScroll: false,
|
83 | shouldActivateRightScroll: false,
|
84 | scrollLeft: 0,
|
85 | cellPadding,
|
86 | lineHeight,
|
87 | headerHeight,
|
88 | rowHeight,
|
89 | contentHeight: 500,
|
90 | contentWidth: 500,
|
91 | };
|
92 |
|
93 | this.uniqueId = props.options.id || null;
|
94 | if (this.uniqueId){
|
95 | this.savedColumnsWidth = JSON.parse(localStorage.getItem('huge-table-column-widths')) || {};
|
96 | this.savedColumnsWidth[this.uniqueId] = this.savedColumnsWidth[this.uniqueId] || {};
|
97 | }
|
98 |
|
99 | this.maxTitleWidth = props.options.maxTitleWidth || Constants.MAX_TITLE_WIDTH;
|
100 | this.maxContentWidth = props.options.maxContentWidth || Constants.MAX_CONTENT_WIDTH;
|
101 | this.fontDetails = props.options.fontDetails || Constants.FONT_DETAILS;
|
102 | this.minColumnWidth = props.options.minColumnWidth || Constants.MIN_COLUMN_WIDTH;
|
103 | this.headerOffsetWidth = props.options.headerOffsetWidth || 0;
|
104 | }
|
105 |
|
106 | componentDidMount() {
|
107 | this.generateColumnToDataTypeMap(this.props.schema);
|
108 | this.generateColumnWidths(this.props.schema, this.props.options.width);
|
109 | this.generateInitialColumnOrder(this.props.schema);
|
110 | this.checkForScrollArrows(this.state.scrollLeft);
|
111 | }
|
112 |
|
113 | componentWillReceiveProps(nextProps) {
|
114 | if(this.props.schema !== nextProps.schema) {
|
115 | this.generateColumnToDataTypeMap(nextProps.schema);
|
116 | this.generateInitialColumnOrder(nextProps.schema);
|
117 | }
|
118 |
|
119 | if(this.props.schema !== nextProps.schema || this.props.options.width !== nextProps.options.width) {
|
120 | this.generateColumnWidths(nextProps.schema, nextProps.options.width);
|
121 | this.checkForScrollArrows(this.state.scrollLeft);
|
122 | }
|
123 |
|
124 | if(this.props.data.length !== nextProps.data.length) {
|
125 | this.setContentHeight(nextProps.data);
|
126 | }
|
127 | }
|
128 |
|
129 | componentDidUpdate(prevProps, prevState) {
|
130 | if (prevState.columnOrder !== this.state.columnOrder && !_.isEqual(prevState.columnOrder, this.state.columnOrder)) {
|
131 | this.reorderSchema(this.props.schema, this.state.columnOrder);
|
132 | }
|
133 | if (prevState.currentSchema !== this.state.currentSchema && !_.isEqual(prevState.currentSchema, this.state.currentSchema)) {
|
134 | this.onSchemaChange(this.state.currentSchema, prevState.currentSchema);
|
135 | this.checkForScrollArrows(this.state.scrollLeft);
|
136 | }
|
137 |
|
138 | if (prevState.currentSchema < this.state.currentSchema && this.state.shouldShowScrolls) {
|
139 | this.scrollNewColumnIntoView();
|
140 | this.checkForScrollArrows(this.state.scrollLeft);
|
141 | }
|
142 |
|
143 | if (prevProps.activeColumnIndex !== this.props.activeColumnIndex && this.props.onActiveColumnChange) {
|
144 | this.props.onActiveColumnChange();
|
145 | }
|
146 |
|
147 | }
|
148 |
|
149 | onScrollEnd = (scrollLeft) => {
|
150 | this.setState({ scrollLeft });
|
151 | }
|
152 |
|
153 | onSchemaChange = (schema, prevSchema) => {
|
154 | if (this.props.onSchemaChange) {
|
155 | this.props.onSchemaChange(schema, prevSchema);
|
156 | }
|
157 | }
|
158 |
|
159 | scrollNewColumnIntoView = () => {
|
160 | if (this.refs.table && this.props.scrollToNewColumn) {
|
161 | this.scrollAndCheckForArrows(this.refs.table.state.maxScrollX);
|
162 | if (this.props.onScrollToNewColumn) {
|
163 | this.props.onScrollToNewColumn();
|
164 | }
|
165 | }
|
166 | }
|
167 |
|
168 | reorderSchema = (schema, columnOrder) => {
|
169 | const newSchema = [];
|
170 | columnOrder.forEach(col => {
|
171 | const newSchemaItem = schema.find(s => (s.id || s.name) === col);
|
172 | if (newSchemaItem) {
|
173 | newSchema.push(newSchemaItem);
|
174 | }
|
175 | });
|
176 | this.setState({ currentSchema: newSchema });
|
177 | }
|
178 |
|
179 | setContentHeight = (data) => {
|
180 | this.setState({
|
181 | contentHeight: this.state.rowHeight * data.length + this.state.headerHeight,
|
182 | });
|
183 | }
|
184 |
|
185 | generateInitialColumnOrder = (schema) => {
|
186 | const columnOrder = schema.map(schemaItem => schemaItem.id || schemaItem.name);
|
187 | this.setState({
|
188 | columnOrder,
|
189 | });
|
190 | this.reorderSchema(schema, columnOrder);
|
191 | }
|
192 |
|
193 | generateColumnToDataTypeMap = (schema) => {
|
194 | const columnNameToDataTypeMap = {};
|
195 |
|
196 | schema.forEach((schemaItem) => {
|
197 | columnNameToDataTypeMap[schemaItem.name] = schemaItem.type;
|
198 | });
|
199 |
|
200 | this.setState({columnNameToDataTypeMap});
|
201 | }
|
202 |
|
203 | generateColumnWidths = (schema, width, columnKey, newColumnWidth) => {
|
204 | const columnWidths = {};
|
205 | let isColumnResizing;
|
206 | let contentWidth;
|
207 |
|
208 |
|
209 | const calculatedWidth = (width - Constants.ROW_NUMBER_COLUMN_WIDTH - 5 - (schema.length * 2)) / Math.max(schema.length, 1);
|
210 | const defaultColumnWidth = Math.max(calculatedWidth, this.minColumnWidth);
|
211 |
|
212 | schema.forEach((schemaItem) => {
|
213 | const maxColumnWidth = this.props.resizeByContent ? this.getMaxColumnWidth(schemaItem, this.minColumnWidth) : defaultColumnWidth;
|
214 | if (this.uniqueId){
|
215 |
|
216 | if (this.props.data.length > 0 && this.props.resizeByContent) {
|
217 | this.state.columnWidths[schemaItem.id || schemaItem.name] = this.savedColumnsWidth[this.uniqueId][schemaItem.id || schemaItem.name] || maxColumnWidth || this.state.columnWidths[schemaItem.id || schemaItem.name] || defaultColumnWidth;
|
218 | } else {
|
219 | this.state.columnWidths[schemaItem.id || schemaItem.name] = this.savedColumnsWidth[this.uniqueId][schemaItem.id || schemaItem.name] || this.state.columnWidths[schemaItem.id || schemaItem.name] || maxColumnWidth || defaultColumnWidth;
|
220 | }
|
221 | } else {
|
222 | this.state.columnWidths[schemaItem.id || schemaItem.name] = this.state.columnWidths[schemaItem.id || schemaItem.name] || maxColumnWidth || defaultColumnWidth;
|
223 | }
|
224 | columnWidths[schemaItem.id || schemaItem.name] = this.state.columnWidths[schemaItem.id || schemaItem.name];
|
225 | });
|
226 |
|
227 | if (columnKey) {
|
228 | columnWidths[columnKey] = newColumnWidth;
|
229 | if (this.uniqueId){
|
230 | this.savedColumnsWidth[this.uniqueId][columnKey] = newColumnWidth;
|
231 | localStorage.setItem('huge-table-column-widths', JSON.stringify(this.savedColumnsWidth));
|
232 | }
|
233 | isColumnResizing = false;
|
234 | }
|
235 |
|
236 | contentWidth = schema.reduce((sum, item) => sum + columnWidths[item.id || item.name], 0) + Constants.ROW_NUMBER_COLUMN_WIDTH;
|
237 | this.setState({
|
238 | columnWidths,
|
239 | isColumnResizing,
|
240 | contentWidth,
|
241 | });
|
242 | }
|
243 |
|
244 | getMaxColumnWidth = (schemaItem, defaultColumnWidth) => {
|
245 | let maxColumnWidth = 0;
|
246 |
|
247 | if (schemaItem.type !== Constants.ColumnTypes.IMAGE) {
|
248 | this.props.data.forEach(row => {
|
249 | const cellContent = this.getCellContent(row, schemaItem);
|
250 | const cellText = this.getCellText(cellContent);
|
251 | const cellColumnWidth = this.getContentSize(cellText, this.fontDetails);
|
252 | maxColumnWidth = maxColumnWidth > cellColumnWidth ? maxColumnWidth : cellColumnWidth;
|
253 | });
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | if (maxColumnWidth < this.maxTitleWidth) {
|
259 | const titleWidth = this.getContentSize(schemaItem.name, this.fontDetails) + this.headerOffsetWidth;
|
260 | maxColumnWidth = Math.max(titleWidth, maxColumnWidth);
|
261 | maxColumnWidth = Math.min(maxColumnWidth, this.maxTitleWidth);
|
262 | } else {
|
263 | maxColumnWidth = Math.min(this.maxContentWidth, maxColumnWidth);
|
264 | }
|
265 | }
|
266 | return maxColumnWidth > defaultColumnWidth ? maxColumnWidth : defaultColumnWidth;
|
267 | }
|
268 |
|
269 | getContentSize = (txt, font) => {
|
270 | this.element = document.createElement('canvas');
|
271 | this.context = this.element.getContext('2d');
|
272 | this.context.font = font;
|
273 | const tsize = {'width':this.context.measureText(txt).width};
|
274 | return tsize.width;
|
275 | }
|
276 |
|
277 | setMaxHeaderWidth = (field) => {
|
278 | let maxColumnWidth = this.getContentSize(field.name, this.fontDetails) + this.headerOffsetWidth;
|
279 | maxColumnWidth = maxColumnWidth > this.minColumnWidth ? maxColumnWidth : this.minColumnWidth;
|
280 |
|
281 | if (this.uniqueId){
|
282 | this.savedColumnsWidth[this.uniqueId][field.id] = maxColumnWidth;
|
283 | localStorage.setItem('huge-table-column-widths', JSON.stringify(this.savedColumnsWidth));
|
284 | }
|
285 |
|
286 | return maxColumnWidth;
|
287 | }
|
288 |
|
289 | resizeHeader = (field) => {
|
290 | const columnWidths = { ...this.state.columnWidths };
|
291 |
|
292 | columnWidths[field.id] = this.setMaxHeaderWidth(field);
|
293 |
|
294 | this.setState({
|
295 | columnWidths,
|
296 | });
|
297 | }
|
298 |
|
299 | resizeAllHeaders = (fields) => {
|
300 | const columnWidths = { ...this.state.columnWidths };
|
301 |
|
302 | fields.forEach(field => {
|
303 | columnWidths[field.id] = this.setMaxHeaderWidth(field);
|
304 | });
|
305 |
|
306 | this.setState({
|
307 | columnWidths,
|
308 | });
|
309 | }
|
310 |
|
311 | getCellContent = (row, schemaItem) => {
|
312 | let content;
|
313 | if (schemaItem.type === Constants.ColumnTypes.TEXT) {
|
314 | const cellData = Array.isArray(row[schemaItem.name]) ? row[schemaItem.name][0] : row[schemaItem.name];
|
315 | if (cellData !== undefined) {
|
316 | content = cellData.text !== undefined ? cellData.text : '';
|
317 | } else {
|
318 | content = '';
|
319 | }
|
320 | } else if (schemaItem.type === Constants.ColumnTypes.IMAGE) {
|
321 | content = '';
|
322 | } else {
|
323 | content = row[schemaItem.name + '/_text'] !== undefined ? row[schemaItem.name + '/_text'] : row[schemaItem.name];
|
324 | }
|
325 | return content;
|
326 | }
|
327 |
|
328 | getCellText = cellContent => {
|
329 | if (Array.isArray(cellContent)) {
|
330 | return this.getCellText(cellContent[0]);
|
331 | } else if (typeof cellContent === 'object') {
|
332 | return JSON.stringify(cellContent);
|
333 | } else {
|
334 | return cellContent;
|
335 | }
|
336 | }
|
337 |
|
338 | createColumn = (schemaItem, idx) => {
|
339 | let width = this.state.columnWidths[schemaItem.id || schemaItem.name];
|
340 | const lastColumn = idx === (this.state.currentSchema.length - 1) && this.state.currentSchema.length > 1;
|
341 | if (this.state.shouldShowScrolls && lastColumn) {
|
342 |
|
343 | width = width + 120;
|
344 | }
|
345 | let cellClass = '', headerClass = '';
|
346 | if (this.props.showScrollingArrows && this.state.shouldShowScrolls) {
|
347 | if (this.props.hideRowNumbers && idx === 0) {
|
348 | cellClass = 'hugetable-index-column nudge';
|
349 | } else if (lastColumn) {
|
350 | cellClass = 'last-column';
|
351 | }
|
352 | }
|
353 |
|
354 | if (idx === this.props.activeColumnIndex) {
|
355 | cellClass = `${cellClass} active-column`;
|
356 | headerClass = 'active-column-header';
|
357 | }
|
358 |
|
359 | return (
|
360 | <Column
|
361 | cellClassName={cellClass}
|
362 | headerClassName={headerClass}
|
363 | header={props => this.renderHeader({...props, cellData: {main: schemaItem.name}})}
|
364 | columnKey={schemaItem.id || schemaItem.name}
|
365 | minWidth={this.minColumnWidth}
|
366 | width={width}
|
367 | cell={(props) => this.cellRenderer({...props, schemaItem })}
|
368 | key={schemaItem.name}
|
369 | isResizable={this.props.resizeableColumns}
|
370 | isReorderable={this.props.reorderableColumns}
|
371 | />
|
372 | );
|
373 | }
|
374 |
|
375 | renderHeader = (props) => {
|
376 | if(this.props.renderers && this.props.renderers.HEADER && typeof this.props.renderers.HEADER === 'function') {
|
377 | return (
|
378 | <Cell>
|
379 | {this.props.renderers.HEADER(props)}
|
380 | </Cell>
|
381 | );
|
382 | } else {
|
383 | return <HeaderCell {...props} />;
|
384 | }
|
385 | }
|
386 |
|
387 | getCellStyles = (columnDataType) => {
|
388 | let cellStyles = {};
|
389 |
|
390 | if (columnDataType == Constants.ColumnTypes.IMAGE) {
|
391 | cellStyles = StyleSheet.create({
|
392 | cellStyle: {
|
393 | paddingTop: Constants.IMAGE_CELL_PADDING.cellPaddingTop,
|
394 | paddingBottom: Constants.IMAGE_CELL_PADDING.cellPaddingBottom,
|
395 | paddingLeft: Constants.IMAGE_CELL_PADDING.cellPaddingLeft,
|
396 | paddingRight: Constants.IMAGE_CELL_PADDING.cellPaddingRight,
|
397 | },
|
398 | });
|
399 | } else {
|
400 | cellStyles = StyleSheet.create({
|
401 | cellStyle: {
|
402 | paddingTop: Constants.CELL_PADDING.cellPaddingTop,
|
403 | paddingBottom: Constants.CELL_PADDING.cellPaddingBottom,
|
404 | paddingLeft: Constants.CELL_PADDING.cellPaddingLeft,
|
405 | paddingRight: Constants.CELL_PADDING.cellPaddingRight,
|
406 | },
|
407 | });
|
408 | }
|
409 | return (cellStyles);
|
410 | };
|
411 |
|
412 | cellRenderer = ({rowIndex, width, height, schemaItem}) => {
|
413 | const rowObject = this.props.data[rowIndex];
|
414 | const cellData = {};
|
415 | cellData.main = rowObject[schemaItem.name];
|
416 | Constants.RETURNED_DATA_TYPES.forEach(dataType => {
|
417 | cellData[dataType] = rowObject[schemaItem.name + '/_' + dataType] || null;
|
418 | });
|
419 | const columnDataType = this.state.columnNameToDataTypeMap[schemaItem.name];
|
420 | const cellCustomRenderer = this.props.renderers && this.props.renderers[columnDataType];
|
421 | cellData.type = columnDataType;
|
422 |
|
423 | return (
|
424 | <Cell className={css(this.getCellStyles(columnDataType).cellStyle)}>
|
425 | {CellUtils.getComponentDataType({
|
426 | disableClickEvents: this.props.disableClickEvents,
|
427 | columnDataType,
|
428 | cellData,
|
429 | width,
|
430 | height,
|
431 | columnKey: schemaItem.id || schemaItem.name,
|
432 | mixedContentImage: this.props.options.mixedContentImage,
|
433 | cellCustomRenderer,
|
434 | rowIndex,
|
435 |
|
436 | })}
|
437 | </Cell>
|
438 | );
|
439 | }
|
440 |
|
441 | onColumnResizeEndCallback = (newColumnWidth, columnKey) => {
|
442 | this.generateColumnWidths(this.props.schema, this.props.options.width, columnKey, newColumnWidth);
|
443 | }
|
444 |
|
445 | onScroll = (scrollLeft, scrollTop) => {
|
446 | this.setState({
|
447 | scrollLeft: scrollLeft ? scrollLeft : this.state.scrollLeft,
|
448 | scrollTop,
|
449 | });
|
450 | if(this.props.options.tableScrolled) {
|
451 | this.props.options.tableScrolled(scrollLeft, scrollTop);
|
452 | }
|
453 | }
|
454 |
|
455 | onContentDimensionsChange = (contentHeight, contentWidth) => {
|
456 | this.setState({
|
457 | contentWidth,
|
458 | contentHeight,
|
459 | });
|
460 | }
|
461 |
|
462 | onColumnReorderEndCallback = (event) => {
|
463 | const columnOrder = this.state.columnOrder.filter((columnKey) => {
|
464 | return columnKey !== event.reorderColumn;
|
465 | });
|
466 |
|
467 | if (event.columnAfter) {
|
468 | const index = columnOrder.indexOf(event.columnAfter);
|
469 | columnOrder.splice(index, 0, event.reorderColumn);
|
470 | } else {
|
471 | columnOrder.push(event.reorderColumn);
|
472 | }
|
473 | this.setState({
|
474 | columnOrder,
|
475 | });
|
476 | }
|
477 |
|
478 | handleMouseEnter = (scrollVal) => {
|
479 | this.intervalId = setInterval(() => this.moveScrollPos(scrollVal), 10);
|
480 | }
|
481 |
|
482 | stopScrollInterval = () => {
|
483 | clearInterval(this.intervalId);
|
484 | this.intervalId = undefined;
|
485 | }
|
486 |
|
487 | moveScrollPos = (val) => {
|
488 | if (this.state.scrollLeft === 0 && val >= 0 || this.state.scrollLeft > 0) {
|
489 | const scrollLeft = this.state.scrollLeft + val >= 0 ? this.state.scrollLeft + val : 0;
|
490 | this.scrollAndCheckForArrows(scrollLeft);
|
491 | }
|
492 | if (this.state.scrollLeft >= this.refs.table.state.maxScrollX) {
|
493 | this.stopScrollInterval();
|
494 | }
|
495 | }
|
496 |
|
497 | calcElementsWidth = (elementsArr) => {
|
498 | return elementsArr.map(e => e.getBoundingClientRect().width).reduce((i, n) => i+n, 0);
|
499 | }
|
500 |
|
501 | getChildElements = () => {
|
502 | const headerContainer = this.getHeaderContainer();
|
503 | const childElements = headerContainer ? Array.from(this.getHeaderContainer().children) : [];
|
504 | return childElements;
|
505 | }
|
506 |
|
507 | handleScroll = (scrollLeft) => {
|
508 | this.setState({
|
509 | scrollLeft,
|
510 | });
|
511 | return true;
|
512 | }
|
513 |
|
514 | checkForScrollArrows = (scrollLeft, allElementsWidth) => {
|
515 | const ALL_ELEMENTS_WIDTH = allElementsWidth ? allElementsWidth : this.calcElementsWidth(this.getChildElements());
|
516 | const shouldShowScrolls = ALL_ELEMENTS_WIDTH > this.props.options.width && this.props.showScrollingArrows;
|
517 | this.setState({
|
518 | shouldShowScrolls,
|
519 | shouldActivateLeftScroll: scrollLeft > 0,
|
520 | shouldActivateRightScroll: ALL_ELEMENTS_WIDTH-1 > (this.props.options.width + scrollLeft),
|
521 | });
|
522 | return true;
|
523 | }
|
524 |
|
525 | scrollAndCheckForArrows(scrollLeft) {
|
526 | this.checkForScrollArrows(scrollLeft);
|
527 | this.handleScroll(scrollLeft);
|
528 | }
|
529 |
|
530 | getListContainerWidth = () => {
|
531 | return this.getHeaderContainer().getBoundingClientRect().width;
|
532 | }
|
533 |
|
534 | getHeaderContainer = () => {
|
535 | const headerCell = document.querySelector('.hugetable-index-column');
|
536 | return headerCell ? headerCell.parentElement : null;
|
537 | }
|
538 |
|
539 | render() {
|
540 | const tableWidth = this.props.options.width;
|
541 | const tableHeight = this.props.options.height - this.state.headerHeight;
|
542 | const rowNumberColumnWidth = this.props.options.rowNumberColumnWidth ? this.props.options.rowNumberColumnWidth : Constants.ROW_NUMBER_COLUMN_WIDTH;
|
543 |
|
544 | let leftScroll, rightScroll;
|
545 | if(this.state.shouldShowScrolls) {
|
546 | // increase the size of the row number column so there is no overlap
|
547 | leftScroll = (
|
548 | <section style={{ height: this.state.headerHeight }} className={classNames('scroll-toggle', 'left', {'active': this.state.shouldActivateLeftScroll})} onMouseEnter={() => this.handleMouseEnter(-10)} onMouseLeave={() => this.stopScrollInterval()}>
|
549 | <i className="fa fa-chevron-left fa-lg"></i>
|
550 | </section>
|
551 | );
|
552 |
|
553 | rightScroll = (
|
554 | <section style={{ height: this.state.headerHeight }} className={classNames('scroll-toggle', 'right', {'active': this.state.shouldActivateRightScroll})} onMouseEnter={() => this.handleMouseEnter(10)} onMouseLeave={() => this.stopScrollInterval()}>
|
555 | <i className="fa fa-chevron-right fa-lg"></i>
|
556 | </section>
|
557 | );
|
558 | }
|
559 |
|
560 | return (
|
561 | <TouchWrapper
|
562 | onScroll={this.onScroll}
|
563 | tableWidth={tableWidth}
|
564 | tableHeight={tableHeight}
|
565 | contentWidth={this.state.contentWidth}
|
566 | contentHeight={this.state.contentHeight}
|
567 | >
|
568 | <div style={{ position: 'relative', height: tableHeight, width: tableWidth }}>
|
569 | {leftScroll}
|
570 | {rightScroll}
|
571 | <Table
|
572 | onHorizontalScroll={this.checkForScrollArrows}
|
573 | onScrollEnd={this.onScrollEnd}
|
574 | ref="table"
|
575 | rowHeight={this.state.rowHeight}
|
576 | rowsCount={this.props.data.length}
|
577 | width={tableWidth}
|
578 | scrollLeft={this.state.scrollLeft}
|
579 | scrollTop={this.state.scrollTop}
|
580 | height={tableHeight}
|
581 | headerHeight={this.state.headerHeight}
|
582 | isColumnResizing={this.state.isColumnResizing}
|
583 | onColumnResizeEndCallback={this.onColumnResizeEndCallback}
|
584 | onContentDimensionsChange={this.onContentDimensionsChange}
|
585 | onColumnReorderEndCallback={this.onColumnReorderEndCallback}
|
586 | scrollToColumn={this.props.scrollToColumn}
|
587 | isColumnReordering={false}
|
588 |
|
589 | >
|
590 | {(() => {
|
591 | if (!this.props.hideRowNumbers) {
|
592 | return (
|
593 | <Column
|
594 | cellClassName="hugetable-index-column"
|
595 | key="hugetable-index-column"
|
596 | columnKey="hugetable-index-column"
|
597 | width={rowNumberColumnWidth}
|
598 | header={props => this.renderHeader({...props, cellData: {main: '#'}})}
|
599 | cell={(props) => <Cell><TextCell {...props} cellData={{main: props.rowIndex+1}}/></Cell>}
|
600 | />
|
601 | );
|
602 | }
|
603 | })()}
|
604 | {this.state.currentSchema.map(this.createColumn)}
|
605 | {(() => {
|
606 | if (this.state.shouldShowScrolls) {
|
607 | return (
|
608 | <Column
|
609 | cellClassName="huge-table-right-scroll-column"
|
610 | key="huge-table-right-scroll-column"
|
611 | columnKey="huge-table-right-scroll-column"
|
612 | width={this.props.buttonColumnWidth ? 40 + this.props.buttonColumnWidth : 40}
|
613 | header={props => this.renderHeader({...props, cellData: {main: ''}})}
|
614 | cell={(props) => <Cell><TextCell {...props} cellData={{main: ''}}/></Cell>}
|
615 | />
|
616 | );
|
617 | }
|
618 | })()}
|
619 | </Table>
|
620 | </div>
|
621 | </TouchWrapper>
|
622 | );
|
623 | }
|
624 | }
|