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