UNPKG

@daphneb/phonereporting

Version:

289 lines (251 loc) 11.9 kB
/* See License / Disclaimer https://raw.githubusercontent.com/DynamicTyped/Griddle/master/LICENSE */ 'use strict'; var React = require('react'); var GridTitle = require('./gridTitle.jsx'); var GridRowContainer = require('./gridRowContainer.jsx'); var ColumnProperties = require('./columnProperties.js'); var RowProperties = require('./rowProperties.js'); var GridTable = React.createClass({ displayName: 'GridTable', getDefaultProps: function getDefaultProps() { return { "data": [], "columnSettings": null, "rowSettings": null, "sortSettings": null, "multipleSelectionSettings": null, "className": "", "enableInfiniteScroll": false, "nextPage": null, "hasMorePages": false, "useFixedHeader": false, "useFixedLayout": true, "paddingHeight": null, "rowHeight": null, "filterByColumn": null, "infiniteScrollLoadTreshold": null, "bodyHeight": null, "useGriddleStyles": true, "useGriddleIcons": true, "isSubGriddle": false, "parentRowCollapsedClassName": "parent-row", "parentRowExpandedClassName": "parent-row expanded", "parentRowCollapsedComponent": "▶", "parentRowExpandedComponent": "▼", "externalLoadingComponent": null, "externalIsLoading": false, "onRowClick": null, "onRowMouseEnter": null, "onRowMouseLeave": null, "onRowWillMount": null, "onRowWillUnmount": null }; }, getInitialState: function getInitialState() { return { scrollTop: 0, scrollHeight: this.props.bodyHeight, clientHeight: this.props.bodyHeight }; }, componentDidMount: function componentDidMount() { // After the initial render, see if we need to load additional pages. this.gridScroll(); }, componentDidUpdate: function componentDidUpdate(prevProps, prevState) { // After the subsequent renders, see if we need to load additional pages. this.gridScroll(); }, gridScroll: function gridScroll() { if (this.props.enableInfiniteScroll && !this.props.externalIsLoading) { // If the scroll height is greater than the current amount of rows displayed, update the page. var scrollable = this.refs.scrollable; var scrollTop = scrollable.scrollTop; var scrollHeight = scrollable.scrollHeight; var clientHeight = scrollable.clientHeight; // If the scroll position changed and the difference is greater than a row height if (this.props.rowHeight !== null && this.state.scrollTop !== scrollTop && Math.abs(this.state.scrollTop - scrollTop) >= this.getAdjustedRowHeight()) { var newState = { scrollTop: scrollTop, scrollHeight: scrollHeight, clientHeight: clientHeight }; // Set the state to the new state this.setState(newState); } // Determine the diff by subtracting the amount scrolled by the total height, taking into consideratoin // the spacer's height. var scrollHeightDiff = scrollHeight - (scrollTop + clientHeight) - this.props.infiniteScrollLoadTreshold; // Make sure that we load results a little before reaching the bottom. var compareHeight = scrollHeightDiff * 0.6; if (compareHeight <= this.props.infiniteScrollLoadTreshold) { this.props.nextPage(); } } }, verifyProps: function verifyProps() { if (this.props.columnSettings === null) { console.error("gridTable: The columnSettings prop is null and it shouldn't be"); } if (this.props.rowSettings === null) { console.error("gridTable: The rowSettings prop is null and it shouldn't be"); } }, getAdjustedRowHeight: function getAdjustedRowHeight() { return this.props.rowHeight + this.props.paddingHeight * 2; // account for padding. }, getNodeContent: function getNodeContent() { this.verifyProps(); var that = this; //figure out if we need to wrap the group in one tbody or many var anyHasChildren = false; // If the data is still being loaded, don't build the nodes unless this is an infinite scroll table. if (!this.props.externalIsLoading || this.props.enableInfiniteScroll) { var nodeData = that.props.data; var aboveSpacerRow = null; var belowSpacerRow = null; var usingDefault = false; // If we have a row height specified, only render what's going to be visible. if (this.props.enableInfiniteScroll && this.props.rowHeight !== null && this.refs.scrollable !== undefined) { var adjustedHeight = that.getAdjustedRowHeight(); var visibleRecordCount = Math.ceil(that.state.clientHeight / adjustedHeight); // Inspired by : http://jsfiddle.net/vjeux/KbWJ2/9/ var displayStart = Math.max(0, Math.floor(that.state.scrollTop / adjustedHeight) - visibleRecordCount * 0.25); var displayEnd = Math.min(displayStart + visibleRecordCount * 1.25, this.props.data.length - 1); // Split the amount of nodes. nodeData = nodeData.slice(displayStart, displayEnd + 1); // Set the above and below nodes. var aboveSpacerRowStyle = { height: displayStart * adjustedHeight + "px" }; aboveSpacerRow = React.createElement('tr', { key: 'above-' + aboveSpacerRowStyle.height, style: aboveSpacerRowStyle }); var belowSpacerRowStyle = { height: (this.props.data.length - displayEnd) * adjustedHeight + "px" }; belowSpacerRow = React.createElement('tr', { key: 'below-' + belowSpacerRowStyle.height, style: belowSpacerRowStyle }); } var nodes = nodeData.map(function (row, index) { var hasChildren = typeof row["children"] !== "undefined" && row["children"].length > 0; var uniqueId = that.props.rowSettings.getRowKey(row, index); //at least one item in the group has children. if (hasChildren) { anyHasChildren = hasChildren; } return React.createElement(GridRowContainer, { useGriddleStyles: that.props.useGriddleStyles, isSubGriddle: that.props.isSubGriddle, parentRowExpandedClassName: that.props.parentRowExpandedClassName, parentRowCollapsedClassName: that.props.parentRowCollapsedClassName, parentRowExpandedComponent: that.props.parentRowExpandedComponent, parentRowCollapsedComponent: that.props.parentRowCollapsedComponent, data: row, key: uniqueId + '-container', uniqueId: uniqueId, columnSettings: that.props.columnSettings, rowSettings: that.props.rowSettings, paddingHeight: that.props.paddingHeight, multipleSelectionSettings: that.props.multipleSelectionSettings, rowHeight: that.props.rowHeight, hasChildren: hasChildren, tableClassName: that.props.className, onRowClick: that.props.onRowClick, onRowMouseEnter: that.props.onRowMouseEnter, onRowMouseLeave: that.props.onRowMouseLeave, onRowWillMount: that.props.onRowWillMount, onRowWillUnmount: that.props.onRowWillUnmount }); }); // no data section if (this.props.showNoData) { var colSpan = this.props.columnSettings.getVisibleColumnCount(); nodes.push(React.createElement('tr', { key: 'no-data-section' }, React.createElement('td', { colSpan: colSpan }, this.props.noDataSection))); } // Add the spacer rows for nodes we're not rendering. if (aboveSpacerRow) { nodes.unshift(aboveSpacerRow); } if (belowSpacerRow) { nodes.push(belowSpacerRow); } // Send back the nodes. return { nodes: nodes, anyHasChildren: anyHasChildren }; } else { return null; } }, render: function render() { var that = this; var nodes = []; // for if we need to wrap the group in one tbody or many var anyHasChildren = false; // Grab the nodes to render var nodeContent = this.getNodeContent(); if (nodeContent) { nodes = nodeContent.nodes; anyHasChildren = nodeContent.anyHasChildren; } var gridStyle = null; var loadingContent = null; var tableStyle = { width: "100%" }; if (this.props.useFixedLayout) { tableStyle.tableLayout = "fixed"; } if (this.props.enableInfiniteScroll) { // If we're enabling infinite scrolling, we'll want to include the max height of the grid body + allow scrolling. gridStyle = { "position": "relative", "overflowY": "scroll", "height": this.props.bodyHeight + "px", "width": "100%" }; } // If we're currently loading, populate the loading content if (this.props.externalIsLoading) { var defaultLoadingStyle = null; var defaultColSpan = null; if (this.props.useGriddleStyles) { defaultLoadingStyle = { textAlign: "center", paddingBottom: "40px" }; } defaultColSpan = this.props.columnSettings.getVisibleColumnCount(); var loadingComponent = this.props.externalLoadingComponent ? React.createElement(this.props.externalLoadingComponent, null) : React.createElement('div', null, 'Loading...'); loadingContent = React.createElement('tbody', null, React.createElement('tr', null, React.createElement('td', { style: defaultLoadingStyle, colSpan: defaultColSpan }, loadingComponent))); } //construct the table heading component var tableHeading = this.props.showTableHeading ? React.createElement(GridTitle, { useGriddleStyles: this.props.useGriddleStyles, useGriddleIcons: this.props.useGriddleIcons, sortSettings: this.props.sortSettings, multipleSelectionSettings: this.props.multipleSelectionSettings, columnSettings: this.props.columnSettings, filterByColumn: this.props.filterByColumn, rowSettings: this.props.rowSettings }) : undefined; //check to see if any of the rows have children... if they don't wrap everything in a tbody so the browser doesn't auto do this if (!anyHasChildren) { nodes = React.createElement('tbody', null, nodes); } var pagingContent = React.createElement('tbody', null); if (this.props.showPager) { var pagingStyles = this.props.useGriddleStyles ? { padding: "0px", backgroundColor: "#EDEDED", border: "0px", color: "#222", height: this.props.showNoData ? "20px" : null } : null; pagingContent = React.createElement('tbody', null, React.createElement('tr', null, React.createElement('td', { colSpan: this.props.multipleSelectionSettings.isMultipleSelection ? this.props.columnSettings.getVisibleColumnCount() + 1 : this.props.columnSettings.getVisibleColumnCount(), style: pagingStyles, className: 'footer-container' }, !this.props.showNoData ? this.props.pagingContent : null))); } // If we have a fixed header, split into two tables. if (this.props.useFixedHeader) { if (this.props.useGriddleStyles) { tableStyle.tableLayout = "fixed"; } return React.createElement('div', null, React.createElement('table', { className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null }, tableHeading), React.createElement('div', { ref: 'scrollable', onScroll: this.gridScroll, style: gridStyle }, React.createElement('table', { className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null }, nodes, loadingContent, pagingContent))); } return React.createElement('div', { ref: 'scrollable', onScroll: this.gridScroll, style: gridStyle }, React.createElement('table', { className: this.props.className, style: this.props.useGriddleStyles && tableStyle || null }, tableHeading, nodes, loadingContent, pagingContent)); } }); module.exports = GridTable;